Compare commits

...
273 Commits
Author SHA1 Message Date
lightningterror 3206094545 GameDB: Add full mipmap and trilinear ps2 to Hard Hitter games.
Improves ground texture rendering.
2023-02-10 22:24:33 +01:00
Stenzekandrefractionpcsx2 5cfae80701 GL/OpenGL: Add a hidden [EmuCore/GS] DisableGLDownloadPBO option
.. to disable the use of PBOs when reading back.
2023-02-10 14:38:21 +00:00
JordanTheToasterandrefractionpcsx2 b4d140c6bb GameDB: Fixes for 187 Ride or Die
Add autoflush to soften bloom and HPO Special Texture to fix misaligned bloom.
2023-02-10 14:15:51 +00:00
Stenzekandrefractionpcsx2 c65eb3c3ee GS/HW: Fix crash with AVX2 due to unaligned pitch 2023-02-10 14:15:33 +00:00
Mrlinkwiiandlightningterror eec0984dbe Gamedb: remove skipdraw from Need for Speed - Undercover 2023-02-10 14:47:52 +01:00
Stenzekandrefractionpcsx2 9b1163f959 GS/HW: Use sampler for clamp/repeat when it's redundant
But only for local memory sources (not targets), it causes issues with
upscaling otherwise.
2023-02-10 11:20:37 +00:00
Stenzekandrefractionpcsx2 5b5edc506d Misc: Warning fixes 2023-02-10 11:20:37 +00:00
refractionpcsx2 b30b4375e7 GS: Detect 16bit source copy in to 32bit target shuffle 2023-02-10 11:19:41 +00:00
Stenzekandrefractionpcsx2 1b0c03d892 GS/HW: Fix fixed/invalid TEX0 case in TimeSplitters 2 2023-02-10 03:43:10 +00:00
ZiemasandGitHub bca49184e7 Debugger: Fix missing return path. (#8094) 2023-02-09 19:48:54 +00:00
Stenzekandlightningterror 26d6c33163 GSRunner: Clear bindings and disable game settings 2023-02-09 17:29:47 +01:00
Ziemasandrefractionpcsx2 9420615317 Implement thread listing for IOP
Abstracts away threads behind a common interface for both EE and IOP
2023-02-09 15:49:56 +00:00
Stenzekandrefractionpcsx2 7198c6b8c6 GS: Use u32 instead of size_t for index storage
These are never going to be greater than 2^32-1, and they're truncated
in a bunch of places anyway.
2023-02-09 14:54:42 +00:00
Stenzekandrefractionpcsx2 9513864851 GS: Make prim a template parameter for auto flush
It's force inlined into VertexKick(), which also has prim as a template
parameter.
2023-02-09 14:54:42 +00:00
Stenzekandrefractionpcsx2 f9b8aa1862 GS: Handle index swap case for auto flush
DirectX and OpenGL no longer have different draw splitting.
2023-02-09 14:54:42 +00:00
refractionpcsx2 34371c070c Mcd-Folder: Prevent crash trying to delete non-existent node. 2023-02-09 14:06:21 +00:00
Stenzekandrefractionpcsx2 d6099dd263 GS/Vulkan: Use Bresenham line rasterization when supported 2023-02-09 13:42:05 +00:00
Stenzekandrefractionpcsx2 a1bc39141e PAD: Fix trigger deadzone/scale setting 2023-02-09 12:30:20 +00:00
Connor McLaughlinandrefractionpcsx2 13ed41d077 GS/DX11: Disable multisampling in rasterizer state 2023-02-09 11:13:42 +00:00
Stenzekandrefractionpcsx2 8a0a8f718f GameDB: Remove preloading disable for a bunch of games
These are fine now.
2023-02-09 10:51:06 +00:00
Stenzekandrefractionpcsx2 7d08a54ad9 GS/HW: Optimize TC source size based on CLAMP 2023-02-09 10:51:06 +00:00
Stenzekandrefractionpcsx2 b9b47e3ec7 GS/OGL: Fix upload row length for texture Update() 2023-02-09 10:51:06 +00:00
refractionpcsx2 16989f2122 GS-HW: On overwrite of large incompatible format texture, erase old. 2023-02-09 10:50:40 +00:00
Berylskidandrefractionpcsx2 892d3a370d GameDB: Fix texture flickers of Armored Core Nexus 2023-02-09 09:37:17 +00:00
Stenzekandlightningterror 6af7ca9867 PAD: Fix invert in deadzone computation 2023-02-09 10:03:55 +01:00
Stenzekandlightningterror c3c354f794 PAD: Add trigger deadzone/sensitivity settings 2023-02-09 10:03:55 +01:00
Stenzekandlightningterror 43572a1560 Qt: Mark widget binder functions as inline
Should also fix the unused warning without using [[maybe_unused]];
2023-02-09 10:03:55 +01:00
Stenzekandlightningterror 79daed63ee Qt: Handle multiplier in controller settings 2023-02-09 10:03:55 +01:00
Stenzekandlightningterror 21d3ad86d4 Qt: Make controller settings page scrollable 2023-02-09 10:03:55 +01:00
Stenzekandlightningterror 31ebe842e8 Qt: Add per-bind sensitivity/deadzone controls (shift-click) 2023-02-09 10:03:55 +01:00
eyfixandGitHub 88487de72f USB: Add values to GunCon2 config. (#8078) 2023-02-09 09:55:23 +01:00
Harukaandlightningterror 616da8c99d CDVD: simplify code 2023-02-09 09:52:00 +01:00
Harukaandlightningterror ec8712cceb CDVD: use DevCon logging instead of stdout / stderr 2023-02-09 09:52:00 +01:00
Harukaandlightningterror 3d6923b2a1 CDVD: implement SetSpindleSpeed on macOS 2023-02-09 09:52:00 +01:00
Harukaandlightningterror f04337becf CDVD: fix macOS CD reading 2023-02-09 09:52:00 +01:00
Harukaandlightningterror 9a5dd4c19d CDVD: macOS physical disc support 2023-02-09 09:52:00 +01:00
lightningterror 643e0b1039 GameDB: Add Autoflush hw fix to MGS3 Subsistence.
Fixes lens flare.
2023-02-09 07:06:21 +01:00
Stenzekandlightningterror 330061a6e7 GS/OGL: Fix offseted downloads not being offset
Fixes background screen effect in Gradius V.
2023-02-09 07:04:50 +01:00
Stenzekandlightningterror 0a292715cf GS/OGL: Align texture uploads to 64 bytes
Fixes potential crash in some games with odd-sized targets
and preloading (e.g. Densha De Go).
2023-02-09 07:04:50 +01:00
Berylskidandlightningterror 52f034a513 GameDB: Add missing quatation marks in memcardFilters for Armored Core Last Raven 2023-02-08 17:32:49 +01:00
Stenzekandlightningterror 25e05388ba Qt: Open fullscreen window on same display as main 2023-02-08 17:29:59 +01:00
JordanTheToasterandlightningterror 7ad9a1af03 GameDB: Add Paltex to Gacharoku
Stops the hash cache from being silly and exploding.
2023-02-08 17:29:22 +01:00
refractionpcsx2 9346c69343 GS-HW: Iterate dirty rects in reverse to join existing ones. 2023-02-08 00:05:44 +00:00
refractionpcsx2 4a3f0ccf96 GS-HW: Process dirty rects separately, improved Tex in RT compatibility 2023-02-08 00:05:44 +00:00
refractionpcsx2 52a1396e29 GSDumpRunner: Fix new options, add missing Preload Frame 2023-02-07 23:40:01 +00:00
JordanTheToasterandrefractionpcsx2 f556dd2584 GameDB: Add missing The Godfather fixes
Adds missing fixes for other entry's of The Godfarther.
2023-02-07 23:26:04 +00:00
refractionpcsx2 aea5c09825 GSDumpRunner: Ability to enable manual hw hacks for testing 2023-02-07 22:31:36 +00:00
refractionpcsx2 8c3c9a1219 GSDumpRunner: Tweaks to reduce console messages and redundant frame dumps 2023-02-07 22:31:36 +00:00
eyfixandGitHub a4f1f383a7 USB/LightGun/GunCon2: Fix wrong code of GunCon2. (#8066)
240 is used for the default screen height elsewhere in the file.
BID_SHOOT_OFFSCREEN is already handled at line 295.
2023-02-07 06:21:48 +01:00
JordanTheToasterandlightningterror ee73c5c1b5 GameDB: Various small fixes
Fixes for Transformers The Game to fix bloom and mipmapping issues and add missing db entrys.
2023-02-07 06:19:59 +01:00
refractionpcsx2 c2904a4633 GS-HW: Don't enable merge sprite in native resolution 2023-02-06 23:59:06 +00:00
JordanTheToasterandlightningterror 6faa2249f9 GameDB: Add Disable InstantVU to MGS 3 Subsistence
Disables InstantVU1 to fix missing letters in text such as the letter E also adds more fixes and missing fixes for Forever Kingdom / Evergrace 2.
2023-02-07 00:24:47 +01:00
lightningterror 119c3acfe7 GS-tc: Cleanup hw texturecache.
Initializations, constants, casts.
2023-02-07 00:22:46 +01:00
lightningterror 138a2683f2 USB: Fix Variable is assigned a value that is never used warning.
Codacy.
2023-02-07 00:22:46 +01:00
PCSX2 Botandlightningterror 463637fa10 PAD: Update to latest controller database. 2023-02-07 00:19:55 +01:00
refractionpcsx2 d5aab926bf GameDB: Add Game Fix for Scandal 2023-02-05 17:40:02 +00:00
KamFretoZandGitHub 37ba04b770 GameDB: Fixes for "Toy Story 3" & "WALL-E" (#8045) 2023-02-05 14:53:09 +00:00
refractionpcsx2 3d0b7dee71 GameDB: Update K-1 Grand Prix fixes to use Instant DMA instead.
This seems to be more reliable in correcting the issue, and for some reason the old way is no longer working properly.
2023-02-05 14:50:36 +00:00
JordanTheToasterandrefractionpcsx2 a287c2caac GameDB: Add Align Sprite to Football Kingdom
Fixes vertical lines.
2023-02-05 14:42:58 +00:00
Stenzekandrefractionpcsx2 1b673d9dd0 GS/HW: Simplify m_vertex/m_index
Switches DX11 to a larger streaming buffer, adds missing texture copy
counter for colclip.
2023-02-04 12:30:24 +00:00
Stenzekandrefractionpcsx2 d10621c201 GS/DX11: Use annotations for debug messages 2023-02-04 12:30:24 +00:00
Ziemasandrefractionpcsx2 e1d6dfc324 Add command line boot and debug option 2023-02-04 12:30:07 +00:00
Stenzekandrefractionpcsx2 130ea2a7ca PAD: Fix pressure getting set to 1 after modifier 2023-02-04 12:29:53 +00:00
Stenzekandrefractionpcsx2 c8d53253d2 Qt: Defer application quit on window close
Fixes Mac builds crashing when the Metal renderer tries to clear the
layer on a non-existant window.
2023-02-04 12:29:44 +00:00
Stenzekandrefractionpcsx2 5c67438925 VMManager: Only exit CPU execution if we were running
Fixes crash if you were paused when you shut down the VM with the EE
interpreter enabled.
2023-02-04 12:29:44 +00:00
lightningterror 1012dba8d7 GameDB: Add basic mipmap to Narc and Tom & Jerry War of the Whiskers.
Fixes textures.
2023-02-03 23:51:05 +01:00
Mrlinkwiiandrefractionpcsx2 e8d43f53d9 GameDB: fixes for 'Tom & Jerry - War of the Whiskers' & 'Brave - The Search for Spirit Dancer'' 2023-02-03 18:19:42 +00:00
RedDevilusandrefractionpcsx2 a0e8ce4b13 Qt: Fix compatibility string
Playable rating was missing which is the most common rating for PCSX2. There are some other issues like the images look bad for star rating and some other stuff. Also resize the compatibility table width a bit.
2023-02-03 16:09:46 +00:00
refractionpcsx2 0e35b3edcb GS: Extend things to handle the alpha blended clear in NARC/Brave 2023-02-03 15:17:10 +00:00
refractionpcsx2 25bb5851ec GS-HW: Fix special CLUT case that uses preloading. 2023-02-03 15:17:10 +00:00
refractionpcsx2 80b0bc0869 GS-HW: Adjust clear detection for clears with FBMSK 2023-02-03 15:17:10 +00:00
refractionpcsx2 c05743b7b9 GS-HW: Improve FBW=1 clear for Singstar games 2023-02-03 15:17:10 +00:00
Stenzekandrefractionpcsx2 7c2a1f0f37 GS: Vectorize CLUT rect update 2023-02-03 14:36:37 +00:00
Stenzekandrefractionpcsx2 0b8b9e75d1 GS: Don't do CLUT auto flush test on invalid PRIM
Fixes OOB array access in Xenosaga I's cutscenes.
2023-02-03 14:36:37 +00:00
refractionpcsx2 d65c343e91 GameDB: Add preload to Siren 2 2023-02-03 06:54:56 +00:00
refractionpcsx2 cd8e7cc947 GS-HW: Queue preloads from Local->Local moves on CPU also 2023-02-03 06:54:56 +00:00
refractionpcsx2 0df5cf2e91 GS-CLUT: Handle invalidation on wrapping writes 2023-02-03 01:55:25 +00:00
refractionpcsx2 412275e40d GS: Convert ee write list to vector, fix some bugs. 2023-02-03 00:09:54 +00:00
refractionpcsx2 4c7ad66bd7 GS-HW: Check for CLUT upload before invalidating or running on GPU.
Clean up some preload code and improve the detection.
2023-02-03 00:09:54 +00:00
refractionpcsx2 8ac21357c3 GS-HW: Force preload 1 frame after reset 2023-02-03 00:09:54 +00:00
refractionpcsx2 2fd88b901b GS-TC: Don't clear on reset, only invalidate frames.
Fixes bug with counting writes before flushing.
Track what textures are used as frames.

It's possible that further to this the PCRTC disables on CSR reset, but we need to test this first, but that would fix the logo at the bottom when booting through the bios in Software mode.
2023-02-03 00:09:54 +00:00
refractionpcsx2 5697759d9e GS-HW: Try to make Preload Frame Data slightly less gross.
These changes make sure there's a matching EE transfer to texture allocation in that frame, if not, then don't allocate anything. This should reduce bad data being loaded in to the Rt.

Preload replaced for Simple 2000 Series Vol. 114 - The Onna Okappichi Torimonochou, preload worked by chance (but no more), disable depth works.
2023-02-03 00:09:54 +00:00
refractionpcsx2 ee0042c768 GameDB: Remove no longer needed Preload Frame settings 2023-02-03 00:09:54 +00:00
refractionpcsx2 a6212f1388 GS-HW: Always preload new frames for PCRTC if none found. 2023-02-03 00:09:54 +00:00
refractionpcsx2 7bfea60b35 GS-TC: Tex In RT expand target match 2023-02-02 23:46:05 +00:00
refractionpcsx2 beee740dc8 GameDB: Add Mipmapping to Jak X, replace FMV fix on Snowboard Heaven 2023-02-02 23:46:05 +00:00
refractionpcsx2 e31387b8bc GS-TC: Don't Tex in RT on old targets/PCRTC only frames. 2023-02-02 23:46:05 +00:00
TheLastRarandrefractionpcsx2 3586a12c46 DEV9: Remove pcap dumper
Never worked in Qt
2023-02-02 21:13:52 +00:00
TheLastRarandrefractionpcsx2 bf21254b13 DEV9: Pcap loop instead of returning on invalid packet
Should improve pcap bridged performance when lots of unrelated network traffic is present.
2023-02-02 21:13:52 +00:00
TheLastRarandrefractionpcsx2 dc9f61e70a DEV9: Add classes for editing packets and make PCAP use them 2023-02-02 21:13:52 +00:00
TheLastRarandrefractionpcsx2 3028998a43 DEV9: Move most of the pcap methods into PCAPAdapter
Also includes the following changes;
pcap_io_running checks replaced with assets in send/recv
pcap_io_running checks replaces checks on hpcap being non null.
Don't cast header->len from unsigned to signed when checking for jumbo frames
Log dropping jumbo frames
Free pcap filter code
Check return value of GetMACAddress() and handle appropriately.
2023-02-02 21:13:52 +00:00
TheLastRarandrefractionpcsx2 42511ce8d8 DEV9: Remove unneeded headers
by providing a typedef for Adapter
2023-02-02 21:13:52 +00:00
RedDevilusandrefractionpcsx2 c245d2134f GameDB: Driver Parallel Lines + Godfather + ...
Godfather: remove on-screen garbage
Driver Parallel Lines: Reduce misaligned bloom issues
Simple 2000 Series Vol. 109 - The Taxi 2: name fix to be Chauffeur and not like train driver (Utenshi to Untenshu)
Rimococoron
2023-02-02 14:22:06 +00:00
JordanTheToasterandrefractionpcsx2 f01884537d GameDB: Assorted fixes
Fixes the name of GT-R 400 and adds round sprite to fix lines in menus and text and corrects the name of 40k Fire Warrior to correctly have a space.
2023-02-01 10:23:11 +00:00
Mrlinkwiiandrefractionpcsx2 b48fb0d4da Misc : label & comment fixes
Misc : remove old comments
labeler: Add labels for Translations
2023-02-01 10:22:12 +00:00
RedDevilusandrefractionpcsx2 7a6470a19d CI: Add RetroAchievements/Rcheevos labels for PRs
Beats doing it manually labels for Rcheevos.
2023-02-01 09:39:30 +00:00
Silentandrefractionpcsx2 bfd8fc771a Qt: Clear the status text after gamelist scanning
Improves UI parity with DuckStation.
2023-02-01 09:38:46 +00:00
Connor McLaughlinandlightningterror f96ca4ac1f GS/OGL: Fix syntax error in fragment shader 2023-02-01 09:04:52 +01:00
TheLastRarandrefractionpcsx2 937bfce68e DEV9: Better match HDD size per-game UI to rest of settings 2023-01-31 21:23:05 +00:00
TheLastRarandrefractionpcsx2 5869d35d85 DEV9: Consider placeholderText when opening File dialog
Per-game settings store the global setting as placeholderText.
If no per-game setting is present we can prefill the dialog with the global setting, before falling back to a default value
2023-01-31 21:23:05 +00:00
TheLastRarandrefractionpcsx2 8d3325e6cd DEV9: Fix HDD file overwrite check 2023-01-31 21:23:05 +00:00
TheLastRarandrefractionpcsx2 4badb5b975 DEV9: Fix HddEnable not enabling UI correctly in per-game settings 2023-01-31 21:23:05 +00:00
TheLastRarandrefractionpcsx2 7e4ff233ec DEV9: Fix Per-game HDD path
SettingWidgetBinder isn't capable of handling this yet
2023-01-31 21:23:05 +00:00
refractionpcsx2 0e3397239d GS: Correct GSIMR/GSCSR reg init, regression from previous release 2023-01-31 16:55:45 +00:00
refractionpcsx2 08bae3da2e GS: Fix h/vsync counters on mode change/sync. 2023-01-31 14:56:48 +00:00
refractionpcsx2 4b49c8bd6e GS: Correct CSR behaviour on mode change 2023-01-31 14:56:48 +00:00
refractionpcsx2 c1bd1fcbd4 GS: Clear Privilage registers on GS Reset via CSR 2023-01-31 14:56:48 +00:00
TheLastRarandrefractionpcsx2 1c3379f082 Qt: Connect close instead of accept for the close button 2023-01-31 02:06:09 +00:00
Mrlinkwiiandrefractionpcsx2 86c97a8ba3 GameDB: fixes for Megaman X Command Mission 2023-01-30 20:55:18 +00:00
lightningterror 8e6c18d3f4 emitter: Ignore Wmissing-braces warnings on clang. 2023-01-30 20:32:33 +01:00
Goatman13andrefractionpcsx2 f1e80c466d IPU: Reset threshold on IPU reset. 2023-01-30 19:13:50 +00:00
Mrlinkwiiandrefractionpcsx2 9a542bcb20 GameDB: fixes for Simple 2000 Series Vol. 48 2023-01-30 17:31:00 +00:00
JordanTheToasterandrefractionpcsx2 290c8ec420 GameDB: Various Tekken fixes
Disables preloading entirely on Tekken Tag Tournament and Tekken 4 and adds missing fix comments and missing db entry's for both games.
2023-01-30 14:03:58 +00:00
Mrlinkwiiandrefractionpcsx2 517ccd5e40 GameDB:fixes for Dragon Quest VIII - Journey of the Cursed King 2023-01-29 17:14:17 +00:00
JordanTheToasterandrefractionpcsx2 bb7bbe0a60 GameDB: Add full Mipmapping to HP COS
Adds full mipmapping and trilinear (PS2) to harry potter and the chamber of secrets to fix blurry textures also adds a missing DB entry.
2023-01-29 16:17:35 +00:00
TellowKrinkleandrefractionpcsx2 ca25a31d79 GS: Display output ignores TEXA 2023-01-29 10:39:33 +00:00
RedDevilusandrefractionpcsx2 e804e99013 GameDB: Harry Potter and the Chamber of Secrets
No texture preloading for Harry Potter and the chamber of secrets to improve performance.
2023-01-28 22:56:12 +00:00
Stenzekandrefractionpcsx2 f447aded57 Qt: Better handle VM-requesting-shutdown case
This was a bit wonky in batch mode before. Now all possible exit paths
close the application at the same point.
2023-01-28 13:40:55 +00:00
Stenzekandrefractionpcsx2 c596a51593 VMManager: Exit the CPU rec immediately on stopping 2023-01-28 13:40:55 +00:00
Stenzekandrefractionpcsx2 ed26368a3a Achievements: Fix race in notifications
GS thread might not initialize fullscreen UI before data finishes
parsing.
2023-01-28 13:40:41 +00:00
Stenzekandrefractionpcsx2 1b40e4aaca Qt: Fix -nogui/-batch closing 2023-01-28 02:51:02 +00:00
Stenzekandrefractionpcsx2 84d7fe550b GSDumpReplayer: Fix frame limiting 2023-01-28 02:51:02 +00:00
TheLastRarandrefractionpcsx2 e68d507659 DEV9: Unify GetAdapter method definitions
by providing a typedef for Adapter
2023-01-27 18:52:29 +00:00
TheLastRarandrefractionpcsx2 2db1e8fb81 DEV9: Move logic for getting MAC address into AdapterUtils 2023-01-27 18:52:29 +00:00
JordanTheToasterandrefractionpcsx2 df674d4056 GameDB: Correct use of Norway PAL code
Uses the correct flag instead of a spooky question mark.
2023-01-27 18:51:54 +00:00
Silentandrefractionpcsx2 21dcda147c Host: Fix a context menu regression from #7960 2023-01-27 18:46:20 +00:00
JordanTheToasterandrefractionpcsx2 201d5ba219 Docs: Update sponsors in README 2023-01-27 17:59:01 +00:00
JordanTheToasterandrefractionpcsx2 2728462d77 GameDB: A variety of fixes
Fixes to names of games depth line fixes and misaligned bloom galore.
2023-01-27 17:59:01 +00:00
Silentandrefractionpcsx2 f73b497b67 Host/VMManager: Remove save state cache invalidation and just populate lists every time
Fixes issues where inexistant save states are listed in dropdowns
2023-01-27 13:52:58 +00:00
Silentandrefractionpcsx2 d2bdb85dc8 SaveState: Add a distinct error message when the file doesn't exist
It doesn't make sense to say that the file is not a valid archive,
because it doesn't exist in the first place.
2023-01-27 13:52:58 +00:00
Tyler Wildingandrefractionpcsx2 3572b4752e translations: initial run of lupdate for base english strings
lupdate.exe -recursive '.' -ts ./Translations/pcsx2-qt_en.ts -source-language en
2023-01-27 11:11:32 +00:00
Toastarrrandrefractionpcsx2 20de162a55 OSD: Fix invisible inputs
OSD: Show all button inputs and their pressure when available
2023-01-27 11:10:47 +00:00
TheLastRarandrefractionpcsx2 64a8e66bac DEV9: Sockets, Treat UDP connections with nearby src/dst ports as fixed
Only doing this for equal ports proved too strict for some games.
2023-01-27 11:02:29 +00:00
TheLastRarandrefractionpcsx2 ccc1874a4b DEV9: Correct a few socket logs 2023-01-27 11:02:29 +00:00
Stenzekandrefractionpcsx2 4fec896378 Qt: Make behavior between both update checks consistent 2023-01-27 10:37:00 +00:00
Stenzekandrefractionpcsx2 d485fcb3ee GameList: Fix double CDVD open 2023-01-26 18:26:32 +00:00
Stenzekandrefractionpcsx2 c9498c3cec CDVD: Don't report host error on iso detect fail
We don't want it popping up while scanning the game list.
2023-01-26 18:26:32 +00:00
Stenzekandrefractionpcsx2 62fffaf56f GzippedFileReader: Fix freeing potentially-invalid pointer 2023-01-26 18:26:32 +00:00
Stenzekandrefractionpcsx2 553a5cc455 CDVD: Remove exceptions 2023-01-26 11:11:36 +00:00
Stenzekandrefractionpcsx2 957ec1d3d3 VTLB: Add option to pause on TLB miss
Rather than making it contingent on dev builds.
2023-01-26 11:11:36 +00:00
Stenzekandrefractionpcsx2 00c158387b x86/iR5900: Use event test to break execution on exit
Particularly relevant for TLB misses, we want to stop execution as soon
as possible.
2023-01-26 11:11:36 +00:00
Stenzekandrefractionpcsx2 d12fa690c0 R5900: Remove exceptions 2023-01-26 11:11:36 +00:00
Stenzekandrefractionpcsx2 94226e83ba Common: Purge EventSource 2023-01-26 11:11:36 +00:00
Stenzekandrefractionpcsx2 4cf041f6cb Common: Move VirtualMemory related functionality to core
Also rewrites page fault handling to not use EventSource junk.
2023-01-26 11:11:36 +00:00
icup321andrefractionpcsx2 1b86a6e6f8 GameDB: Fixes for Incredibles - ROTU 2023-01-26 09:44:59 +00:00
Stenzekandrefractionpcsx2 6e907ae618 vtlb: Remove upper/lower 32-bit unmapped split
This was only necessary on 32-bit because the sign bit was abused for
representing handlers. Since we're 64-bit only, we use bit 63, which
won't clash with the guest's 32-bit virtual address.
2023-01-26 09:41:13 +00:00
Stenzekandrefractionpcsx2 39dde85d03 Qt: Fix -Wunused-lambda-capture warning 2023-01-26 09:28:13 +00:00
Stenzekandrefractionpcsx2 8bb9170865 Build: Enable RTTI for Clang debug builds
Qt tries to dynamic_cast as part of an assertion, which aborts at
runtime. When we next rebuild Qt, we'll disable RTTI in Qt, so this will
be a non-issue. But until then, this change makes debug clang builds
usable.
2023-01-26 09:28:13 +00:00
TellowKrinkleandTellowKrinkle 2cd5ce6aea GHActions: Update release pipeline for MultiISA 2023-01-25 18:27:06 -06:00
Florin9doiandrefractionpcsx2 64fbaff82b DInput: Support for up to 128 buttons 2023-01-25 20:46:44 +00:00
Stenzekandrefractionpcsx2 15a38f5f9d x86/iR5900: Remove reset atomics
These only ever get changed on the EE thread now, this ain't no wx mess.
2023-01-25 15:51:53 +00:00
Stenzekandrefractionpcsx2 4c1d93a322 VMManager: Defer reset when running
Stops us resetting during the event test, which can leave things in a
pretty messed up state.
2023-01-25 15:51:53 +00:00
Silentandrefractionpcsx2 6a40959f3a DInputSource: Use wil on m_dinput_module 2023-01-25 13:21:51 +00:00
Mrlinkwiiandrefractionpcsx2 c4bf297f42 GameDB: clean up comments 2023-01-25 13:15:58 +00:00
Stenzekandrefractionpcsx2 da1b408f97 GS: Remove config.h
It conflicts with the main PCSX2 Config.h, and the defines don't need to
be set in the global namespace anymore.
2023-01-25 13:15:17 +00:00
Stenzekandrefractionpcsx2 91c3e3b684 GS/SW: Use rip-relative addressing for constants 2023-01-25 13:15:17 +00:00
Stenzekandrefractionpcsx2 609a44aaf2 GS/SW: Move code buffer into main memory map 2023-01-25 13:15:17 +00:00
Stenzekandrefractionpcsx2 3d84443bcf GS/SW: Share JIT code between all threads 2023-01-25 13:15:17 +00:00
Stenzekandrefractionpcsx2 56046d4db8 GS/SW: Move scanline local data to rasterizer 2023-01-25 13:15:17 +00:00
Stenzekandrefractionpcsx2 90fc037833 GS/SW: Share global data between threads 2023-01-25 13:15:17 +00:00
Stenzekandrefractionpcsx2 ee4eadf7a6 GS/SW: Make local a function parameter to DrawScanline 2023-01-25 13:15:17 +00:00
Stenzekandrefractionpcsx2 3292121e67 GS/SW: Make local a function parameter to SetupPrim
.. and associated 32-bit removal.
2023-01-25 13:15:17 +00:00
Stenzekandrefractionpcsx2 c8416b820b GS/SW: Combine IDrawScanline and GSDrawScanline 2023-01-25 13:15:17 +00:00
Stenzekandrefractionpcsx2 c9d229e336 OpenGLHostDisplay: Set colour mask before drawing OSD
Fixes OSD getting messed up when the GS output is turned off.
2023-01-25 12:08:43 +00:00
pgertandGitHub bfbcd7a949 GameDB: Force English in Tomb Raider - The Angel of Darkness US (#7950)
Due to a game bug, the game will crash if your BIOS language is set to French or Spanish due to missing files on the disc.
2023-01-25 10:29:23 +00:00
JordanTheToasterandrefractionpcsx2 bf2ba3c4d1 GameDB: Add missing demos
Adds some missing PAL demos to the DB.
2023-01-24 18:31:36 +00:00
Stenzekandrefractionpcsx2 9d50d44c99 GS: Show VRAM usage in statistics 2023-01-24 10:38:03 +00:00
Stenzekandrefractionpcsx2 e76afee12d GS/TextureCache: Only expand target on write on TBW match 2023-01-24 10:20:42 +00:00
TheLastRarandrefractionpcsx2 06ef51db2e DEV9: Move NetLib functions into header and mark as inline 2023-01-23 18:47:28 +00:00
TheLastRarandrefractionpcsx2 a85a2a3cc5 DEV9: Make use of MAC_Address struct 2023-01-23 18:47:28 +00:00
TheLastRarandrefractionpcsx2 8fbecbcdd7 DEV9: Add MAC_Address struct 2023-01-23 18:47:28 +00:00
TheLastRarandrefractionpcsx2 b386f78d68 DEV9: Make use of WriteIPAddress 2023-01-23 18:47:28 +00:00
TheLastRarandrefractionpcsx2 095757044a DEV9: Add IP_Address helpers to NetLib 2023-01-23 18:47:28 +00:00
PCSX2 Botandlightningterror 9b3b8aa4de PAD: Update to latest controller database. 2023-01-23 17:05:04 +01:00
Connor McLaughlinandlightningterror 4932834441 GSRunner: Release globals on shutdown 2023-01-23 16:49:24 +01:00
refractionpcsx2andlightningterror 8773ebf64b VM: Queue shutdown message when called from inside emulation. 2023-01-23 16:45:58 +01:00
Connor McLaughlinandlightningterror f628795b3f GS/Vulkan: Don't apply TFX state on utility draw 2023-01-23 15:01:57 +01:00
lightningterror 0c78bda328 GS-hw: Fix texture shuffle assert which broke debug builds. 2023-01-23 14:48:40 +01:00
lightningterror d9f4bc70fb common-ogl: Fix Shader compiled with warnings log spam on gl.
Observed on intel igpu.
2023-01-23 14:48:40 +01:00
lightningterror ddd2ea5f4d GS-gl/vk: Cleanup some logs.
Instead of ifdefing the longs use Devcon, does the same thing.
Hide point expansion logs behind dev/debug build.
2023-01-23 14:48:40 +01:00
JordanTheToasterandrefractionpcsx2 a326303956 GameDB: Fixes for TC SC Pandora Tomorrow
Fixes for black loading screens and misaligned bloom.
2023-01-23 09:47:19 +00:00
refractionpcsx2 ba1eba98ea GS/Debug: Fix bitfield reading in fprintf for cross compatibility. 2023-01-22 23:49:40 +00:00
refractionpcsx2 8282ebce40 GS-HW: Don't optimise clamp on shuffle 2023-01-22 23:12:19 +00:00
Berylskidandrefractionpcsx2 4c3b7c45cf GameDB: Remove Preload Frame Data for AC Last Raven
On SLPS-25462, disabling Preload Frame Data no longer causes black screens during missions, so it seems no longer necessary.
2023-01-22 16:18:39 +00:00
JordanTheToasterandrefractionpcsx2 668251274a GameDB: Disable Instant VU in Kim Possible WTS
Disables Instant VU to dramatically decrease the load the game puts on the EE and VU for seemingly no reason.
2023-01-22 15:51:38 +00:00
KFZandGitHub e79fc72950 GameDB: Fixes for SpongeBob - The Movie (#7936) 2023-01-22 15:51:22 +00:00
JordanTheToasterandrefractionpcsx2 bcda41120e GameDB: Add Autoflush to Dynasty Warriors 5 Xtreme
Autoflush fixes the missing sun luminosity.
2023-01-22 15:01:54 +00:00
Mrlinkwiiandrefractionpcsx2 80fc00bb05 GameDB: fixes for 'Snowboard Heaven' 2023-01-21 18:39:45 +00:00
refractionpcsx2 f71ccab811 GameDB: Remove BFF deinterlacing from Alpine Racer 3, no longer required 2023-01-21 18:14:13 +00:00
refractionpcsx2 795951a2e8 Build: Fix some VS filers. 2023-01-21 18:14:13 +00:00
refractionpcsx2 d62999ed16 GS: Don't do fast clear if SCANMSK is enabled. 2023-01-21 18:14:13 +00:00
lightningterrorandrefractionpcsx2 9b1699a5a4 GS-hw: Cleanup GS memory clear.
Create IsConstantDirectWriteMemClear function to reduce code duplication and making code cleaner.
2023-01-21 17:01:32 +00:00
Stenzekandrefractionpcsx2 88c1f00b62 GS: Add audio capture and custom resolution 2023-01-21 16:56:57 +00:00
Stenzekandrefractionpcsx2 6834367a3e GS: Move video capture encoding onto its own thread 2023-01-21 16:56:57 +00:00
Stenzekandrefractionpcsx2 dedcf21a37 GSCapture: Make readback for capture asynchronous 2023-01-21 16:56:57 +00:00
Stenzekandrefractionpcsx2 a747a5f9fa SPU2: Make SndOut.h compile in isolation 2023-01-21 16:56:57 +00:00
Stenzekandrefractionpcsx2 fcfb9865df GS: Add GSDownloadTexture (so we can download more than one at once) 2023-01-21 16:56:57 +00:00
JordanTheToasterandrefractionpcsx2 aa1e9cc9fa GameDB: Add AutoFlush to Battle For Volcano Island
Adds autoflush to fix texture corruptions.
2023-01-21 16:02:08 +00:00
Silentandrefractionpcsx2 9b7d21891d GameDB: Correct Colin McRae Rally 3 sun rendering 2023-01-21 14:18:17 +00:00
lightningterror df19baed37 labeler: Add labels to shader files changes based on renderer. 2023-01-21 01:28:59 +01:00
7848f6a1c5 GameDB: Syphon Filter: The Omega Strain Beta Speed Fix (#7926)
Co-authored-by: Leyo1 <71053461+Leyo1@users.noreply.github.com>
2023-01-20 22:57:25 +00:00
JordanTheToasterandrefractionpcsx2 14e128337d GameDB: Add missing Bratz The Movie fix
Adds a missing fix for the NTSC-U version of the game.
2023-01-20 22:56:31 +00:00
lightningterror cb314f0a0b labeler: PAD labels are unified now. 2023-01-20 18:38:54 +01:00
OymatandGitHub ddb313fd2b GameDB: Add Mipmapping and Trilinear to Parappa the Rapper 2 (#7924)
Closes https://github.com/PCSX2/pcsx2/issues/7922
2023-01-20 15:53:13 +00:00
lightningterror 8f183955a0 GS-vk: Fix sample_4_index shader.
Macro conditions conditions should return a value.

Fixes bad shader issues on games that trigger it.
Fixes Star Ocean shadows.
Fixes Keroro Gunsou - Mero Mero Battle Royale text.

Make the rounding consistent accross all renderers.
2023-01-20 10:18:03 +01:00
Mrlinkwiiandrefractionpcsx2 536a4162c4 GameDB: upscaling fixes for 'TOCA Race Driver' 2023-01-19 21:47:36 +00:00
TheLastRarandlightningterror 41a47f99f7 DEV9: Use unique_ptr via typedef for ifadddrs buffer 2023-01-19 14:56:18 +01:00
TheLastRarandlightningterror 31fa1ea21e DEV9: AdapterUtils formatting 2023-01-19 14:56:18 +01:00
Stenzekandrefractionpcsx2 fb49c71118 SPU2: Clean up some unused/conditionally used functions 2023-01-19 11:02:13 +00:00
Stenzekandrefractionpcsx2 0b87cfc7d4 SPU2: Clamp output to 32767 instead of 32512
Another air-ism which doesn't make much sense.
2023-01-19 11:02:13 +00:00
Stenzekandrefractionpcsx2 76fa37019e SPU2: Use 16-bit samples for output
It's clamped to 16-bit in the output anyway.

Volume application is moved to the audio thread, so the stretcher has
higher precision if the user chooses a low volume.

Also vectorizes the int->float conversion (since it happens on the EE
thread, it's beneficial for performance).
2023-01-19 11:02:13 +00:00
Tokman5andrefractionpcsx2 d94e861a78 GS: Add video folder and support additional arguments for video dumping 2023-01-19 10:39:22 +00:00
OymatandGitHub d9b537d334 GameDB: Add SoftwareRendererFMVHack to Onimusha: Warlords (#7916)
close https://github.com/PCSX2/pcsx2/issues/7787
2023-01-18 19:15:43 +00:00
Stenzekandrefractionpcsx2 93c2081d3f USB: Remove readerwriterqueue
Not used anymore, apparently forgot to remove this in the USB refactor.
2023-01-18 10:08:46 +00:00
5ad8ed43fd GameDB: Syphon Filter: The Omega Strain PAL speed fix patch (#7806)
Co-authored-by: Leyo1 <71053461+Leyo1@users.noreply.github.com>
2023-01-17 20:21:13 +00:00
Mrlinkwiiandrefractionpcsx2 1f4416a77a GameDB: upscale fixes for 'Lord of the Rings, The - The Two Towers' 2023-01-17 19:26:13 +00:00
Mrlinkwiiandrefractionpcsx2 e9d4dba64b GameDB: fixes for 'Dreamworks Madagascar' 2023-01-17 11:15:42 +00:00
lightningterrorandrefractionpcsx2 3a2307a5c6 GS-hw: Cleanup GSRendererHW.
Constants, initializations, casts, broken commented out logs and more.
Remove unused/duplicate function EmulateAtst.
2023-01-16 20:34:10 +00:00
Stenzekandrefractionpcsx2 d6c1af1a0c IPU: Combine source files to work around an LTO bug in clang 15
Works around an LTO bug which seems to occur in clang 15, but not in
clang 12. The entire else branch in the 0 case in get_non_intra_block()
was being removed...

Fixes Burnout 3 crashing in clang builds.
2023-01-16 20:13:46 +00:00
JordanTheToasterandrefractionpcsx2 f6cb7ca01d GameDB: Add HPO Normal to WWE 2008 and 2009
Fixes slight blur on people and depth bleed that happens on the right hand side.
2023-01-16 18:19:27 +00:00
PCSX2 Botandlightningterror bc0fdc49e0 PAD: Update to latest controller database. 2023-01-16 17:18:26 +01:00
Stenzekandlightningterror 43ccb63eb5 Qt: Add DS4/DS5 LED settings 2023-01-16 14:08:01 +01:00
Ty Lamontagneandrefractionpcsx2 a0000a8547 Debugger: Implement boot and debug
Creates a breakpoint automatically on the ELF entry point
2023-01-15 17:05:35 +00:00
Stenzekandlightningterror a37ff0c4f2 GS/Vulkan: Fix incorrect clamp in CreateSurface() 2023-01-15 17:40:15 +01:00
Stenzekandlightningterror e449ad7472 GS/TextureCache: Check PSM matches before expanding target
Mercenaries is doing a 128x4095 write in PSMT4, which when upscaling,
goes beyond the limits of most GPUs.
2023-01-15 17:40:15 +01:00
Stenzekandlightningterror a718a785b3 GS/TextureCache: Don't recycle resized target textures
They're probably going to be oddly-sized.
2023-01-15 17:40:15 +01:00
Stenzekandrefractionpcsx2 ea7cc08832 GameDB: Remove preload frame from Burnout games
Doesn't appear to be needed with GPU CLUT?
2023-01-15 16:20:40 +00:00
Stenzekandrefractionpcsx2 a342f4c7e9 GS/HW: Adjust Burnout CRC hack to stop hash cache spiking 2023-01-15 16:20:40 +00:00
JordanTheToasterandrefractionpcsx2 0af2657bbc UI: More text descriptions for options
Adds more text descriptions for various options to help understand what a setting does better.
2023-01-15 14:49:05 +00:00
Stenzekandlightningterror 451c2a244f SPU2: Fix sound output
Regression from a603aed7db
2023-01-15 12:48:47 +01:00
lightningterror a603aed7db SPU2: Update WriteSamples function commented out code to work properly when enabled. 2023-01-15 11:10:46 +01:00
lightningterror f6bbf410f1 SPU2: Remove dynamic tuning commented out code.
No longer works as it relied on wx.
2023-01-15 11:10:46 +01:00
lightningterror 018692edd0 SPU2: Cleanup SndOut.cpp
const, casts, constexpr, initializations.
2023-01-15 11:10:46 +01:00
pgertandGitHub 2740785df5 UI: Correct Error-messages: "SSE4.1" not "SSE4" (#7890) 2023-01-14 23:06:56 +00:00
Stenzekandrefractionpcsx2 613a9964a1 FullscreenUI: Fix descriptor use-after-free when deleting state 2023-01-14 14:07:30 +00:00
Ty Lamontagneandlightningterror 2ef2f5db1d Debugger: Fix step out 2023-01-14 12:51:14 +01:00
Ty Lamontagneandrefractionpcsx2 577e15a949 Debugger Expressions: Add 'target', 'load', and 'store' reference
target -> The evaluated target of the load or the store, 0 if the opcode is not a memory access
load -> The evaluated target of a load, is 0 if the opcode is not loading
store -> The evaluated target of a store, is 0 if the opcode is not storing

Fixes the disassembly widget mouse click handler
Fixes the breakpoint dialog not setting the breakpoint address or condition cpu (oops)
2023-01-14 01:58:04 +00:00
Mrlinkwiiandrefractionpcsx2 58ff3e6c0d GameDB: add missing serial 2023-01-13 23:57:13 +00:00
Stenzekandrefractionpcsx2 80c471a939 Dmac: Fix incorrect condition for OPH flag hack
Fixes tutorial level in Naruto - Uzumaki Chronicles.
2023-01-13 12:20:12 +00:00
refractionpcsx2 b78fca7b91 GameDB: Add Half-Pixel Offset for Sega Superstars Tennis 2023-01-13 10:26:41 +00:00
Connor McLaughlinandrefractionpcsx2 be76092195 USB: Correct Keyboardmania binding list 2023-01-13 09:31:27 +00:00
Stenzekandrefractionpcsx2 771d3c3c9d CI: Retry downloading commands on Linux
The Azure Ubuntu package server, in particular, seems to be very
unreliable. Hopefully within 10 attempts it'll complete the package
download in such cases.
2023-01-13 09:30:46 +00:00
arcum42andrefractionpcsx2 8c21765c0f cmake: Turn back on some warnings that no longer need to be turned off. 2023-01-13 09:27:29 +00:00
TellowKrinkleandTellowKrinkle a2e3522862 GS:MTL: Implement clut shaders 2023-01-13 00:43:47 -04:00
Mrlinkwiiandrefractionpcsx2 e20c2210f5 GameDB: fixes for Made Man 2023-01-12 20:56:51 +00:00
lightningterror 11f3fecd11 GS-d3d: Fix Wmissing-braces warnings. 2023-01-12 16:26:56 +01:00
lightningterror 1a5d7c1c5d Qt: Fix Wunused-const-variable and Wunused-function warnings. 2023-01-12 16:26:56 +01:00
Connor McLaughlinandlightningterror 0bca1aab74 Misc: Latest round of warning cleanups 2023-01-12 11:04:29 +01:00
Connor McLaughlinandlightningterror 95fa15f902 Vulkan: Use pool of semaphores instead of per-image
Some drivers apparently don't iterate images in the order you expect.
2023-01-12 11:03:21 +01:00
lightningterror d586582489 GS: Purge leftover wx tooltips. 2023-01-12 01:38:35 +01:00
Stenzekandrefractionpcsx2 7ef46eaa29 GameDB: Swap some CPU CLUT games for GPU CLUT
Burnout series, NFS Most Wanted.
2023-01-11 23:37:43 +00:00
Stenzekandrefractionpcsx2 38957625ad GameDatabase: Add GPUTargetCLUT 2023-01-11 23:37:43 +00:00
Stenzekandrefractionpcsx2 d30e076dbd GS: Add GPU Target CLUT 2023-01-11 23:37:43 +00:00
Stenzekandrefractionpcsx2 0619555232 GS/HW: Use texel fetch/load instead of sampler for palettes
Saves a multiply in the shaders in some cases, and frees up one
descriptor slot.
2023-01-11 23:37:43 +00:00
Stenzekandrefractionpcsx2 3ffa5eb613 GS: Add const to GSDirtyRect functions 2023-01-11 23:37:43 +00:00
Mrlinkwiiandrefractionpcsx2 c60583c6bb GameDB: fixes for Battle for Volcano Island 2023-01-11 23:10:14 +00:00
Stenzekandrefractionpcsx2 4cf7a1086d GS/HW: Adjust Barnyard fix for Jurassic Park and Nicktoons Unite
Draws its mipmaps at runtime in a very similar way, except with 24-bit
textures as well as 16/32-bit.
2023-01-11 22:40:04 +00:00
RedDevilusandrefractionpcsx2 fa75006ca9 VMManager: Increase software thread count on multicore (4+) CPUs
3 is a nice compromise if you have 4 core or more but for some games higher numbers like 8 or even higher would work, however for a lot of games it would perhaps even reduce the performance compared to 3 software rendering threads or in more likelihood have diminishing returns.

Keep in mind that this is just a general situation, in actual use it might be less extra performance (if at all) as you have expected.
2023-01-11 21:48:36 +00:00
RedDevilusandrefractionpcsx2 d28b2fa057 Qt: Lower audio ms + Tooltip (affinity+Cycle skip)
Lowering 100 ms audio latency to 60 ms.
Makes 100 mixing latency with 20 output latency (120) into a new default of 80 ms which is 50% lower but still is enough headroom as 40 ms even for less capable machines is too high.

Adding tooltip for Affinity Control
Changing tooltip for Cycle Skip from None to Disabled as that is a valid option.
2023-01-11 18:56:42 +00:00
arcum42andlightningterror 0a90765ed0 build: -Wno-maybe-uninitialized is a gcc only warning. 2023-01-11 00:55:21 +01:00
arcum42andlightningterror 2892f629f0 build/QT: Unmute the warnings for deprecation & overloading virtuals. Fix assorted warnings. Mute 'maybe initialized' warnings. Add a policy to take care of LTO warnings in cmake. 2023-01-11 00:55:21 +01:00
Mrlinkwiiandrefractionpcsx2 5be05853c6 GameDB: fixes for Hawk Kawasaki Racing 2023-01-10 21:00:43 +00:00
JordanTheToasterandlightningterror 0f569ac5cb Format: Clang format System.cpp 2023-01-10 16:18:26 +01:00
JordanTheToasterandlightningterror b725c1e8e0 System: Remove unused extensions
PCSX2 does not even boot on SSE2 or SSE3 systems and we do not use SSE4a so we should remove it SSE4.1 / 4.2 is a requirement so no use being here either.
2023-01-10 16:18:26 +01:00
JordanTheToasterandlightningterror 4d418d1bb5 Emitter: Remove old unused code
Irrelevant and outdated code that is no longer needed.
2023-01-10 16:18:26 +01:00
Ty Lamontagneandlightningterror 752594f69a Debugger Breakpoints: Implement the user data role in the model
Consistent with the other models, and saves some awkward usage in the cpu widget where we have to interpret the variant as a string, to then convert it to a uint. I like this better as it provides an easy interface to get the 'raw' breakpoint data out of the model.
2023-01-10 13:57:06 +01:00
Ty Lamontagneandlightningterror b6125e97e9 Debugger Stack frames: (Refactor) Use model based widgets 2023-01-10 13:57:06 +01:00
Ty Lamontagneandlightningterror c00caa886e Debugger Threads: (Refactor) Use model based widgets 2023-01-10 13:57:06 +01:00
Ty Lamontagneandlightningterror 37540d1c68 Debugger Breakpoints: (Refactor) Use some reflection and item models 2023-01-10 13:57:06 +01:00
lightningterror 8fca67f0d6 FullscreenUI: Cleanup remnants of spu2 interpolation mode. 2023-01-10 13:47:41 +01:00
PCSX2 Botandlightningterror 13f891c34f PAD: Update to latest controller database. 2023-01-09 17:05:52 +01:00
JordanTheToasterandrefractionpcsx2 f924ab721a SPU2: Purge interpolation options
Removes the options menu for interpolation as all but gaussian will be removed.
2023-01-08 15:19:51 +00:00
JordanTheToasterandrefractionpcsx2 ae3708edc6 GameDB: Correct Blood Omen 2 name
Corrects Blood Omen 2s name to properly say "The Legacy of Kain".
2023-01-08 14:08:54 +00:00
312 changed files with 23246 additions and 13361 deletions
+18 -6
View File
@@ -32,6 +32,8 @@
- '**/GameIndex.*'
'Installer | Package':
- 'build.sh'
'Translations':
- 'pcsx2-qt/Translations/*'
# Tools / Features
'Debugger':
@@ -45,6 +47,9 @@
'TAS Functionality':
- 'pcsx2/Recording/*'
- 'pcsx2/Recording/**/*'
'RetroAchievements':
- 'pcsx2/Frontend/Achievements.*'
- 'pcsx2/Achievements.*'
# Emulation Components
'Counters':
@@ -64,21 +69,31 @@
'GS':
- 'pcsx2/GS/*'
- 'pcsx2/GS/**/*'
- 'bin/resources/shaders/*'
- 'bin/resources/shaders/**/*'
'GS: Direct3D 11':
- 'pcsx2/GS/Renderers/DX11/*'
- 'pcsx2/GS/Renderers/DX11/**/*'
- 'bin/resources/shaders/dx11/*'
- 'bin/resources/shaders/dx11/**/*'
'GS: Direct3D 12':
- 'pcsx2/GS/Renderers/DX12/*'
- 'pcsx2/GS/Renderers/DX12/**/*'
- 'bin/resources/shaders/dx11/*'
- 'bin/resources/shaders/dx11/**/*'
'GS: Hardware':
- 'pcsx2/GS/Renderers/HW/*'
- 'pcsx2/GS/Renderers/HW/**/*'
'GS: OpenGL':
- 'pcsx2/GS/Renderers/OpenGL/*'
- 'pcsx2/GS/Renderers/OpenGL/**/*'
- 'bin/resources/shaders/opengl/*'
- 'bin/resources/shaders/opengl/**/*'
'GS: Vulkan':
- 'pcsx2/GS/Renderers/Vulkan/*'
- 'pcsx2/GS/Renderers/Vulkan/**/*'
- 'bin/resources/shaders/vulkan/*'
- 'bin/resources/shaders/vulkan/**/*'
'GS: Metal':
- 'pcsx2/GS/Renderers/Metal/*'
- 'pcsx2/GS/Renderers/Metal/**/*'
@@ -102,12 +117,9 @@
'Memory Card':
- 'pcsx2/gui/MemoryCard*'
- 'pcsx2/gui/**/MemoryCard*'
'PAD: Linux/Mac':
- 'pcsx2/PAD/Linux/*'
- 'pcsx2/PAD/Linux/**/*'
'PAD: Windows':
- 'pcsx2/PAD/Windows/*'
- 'pcsx2/PAD/Windows/**/*'
'PAD':
- 'pcsx2/PAD/*'
- 'pcsx2/PAD/**/*'
'SPU2':
- 'pcsx2/SPU2/*'
- 'pcsx2/SPU2/**/*'
+2 -15
View File
@@ -9,25 +9,12 @@ on:
- master
jobs:
build_linux_qt_sse4:
build_linux_qt:
name: "AppImage"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt SSE4"
jobName: "Qt"
compiler: clang
cmakeflags: ""
simd: "SSE4"
buildAppImage: true
secrets: inherit
build_linux_qt_avx2:
name: "AppImage"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt AVX2"
detail: ""
compiler: clang
cmakeflags: "-DARCH_FLAG=-march=haswell"
simd: "AVX2"
buildAppImage: true
secrets: inherit
+2 -7
View File
@@ -28,10 +28,6 @@ on:
required: false
type: string
default: ""
simd:
required: false
type: string
default: ""
cheats_url:
required: false
type: string
@@ -63,7 +59,6 @@ jobs:
OS: linux
GUI_FRAMEWORK: QT
ARCH: ${{ inputs.platform }}
SIMD: ${{ inputs.simd }}
EVENT_NAME: ${{ github.event_name }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_NUM: ${{ github.event.pull_request.number }}
@@ -79,8 +74,8 @@ jobs:
uses: actions/cache@v3
with:
path: .ccache
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.simd }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.simd }} ${{ inputs.detail }} ccache
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache
- name: Install Packages
env:
-1
View File
@@ -49,7 +49,6 @@ jobs:
OS: macos
GUI_FRAMEWORK: ${{ inputs.gui }}
ARCH: ${{ inputs.platform }}
SIMD: ''
EVENT_NAME: ${{ github.event_name }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_NUM: ${{ github.event.pull_request.number }}
+14 -18
View File
@@ -8,32 +8,28 @@ on:
jobs:
# Build Everything
# Linux
build_linux_qt_sse4:
build_linux_qt:
if: github.repository == 'PCSX2/pcsx2'
name: "Linux - AppImage SSE4"
name: "Linux"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt"
compiler: clang
cmakeflags: ""
simd: "SSE4"
buildAppImage: true
secrets: inherit
build_linux_qt_avx2:
if: github.repository == 'PCSX2/pcsx2'
name: "Linux - AppImage AVX2"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt"
detail: ""
compiler: clang
cmakeflags: "-DARCH_FLAG=-march=haswell"
simd: "AVX2"
buildAppImage: true
secrets: inherit
# Windows
build_windows_qt:
if: github.repository == 'PCSX2/pcsx2'
name: "Windows"
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt
configuration: CMake
buildSystem: cmake
secrets: inherit
build_qt_sse4:
if: github.repository == 'PCSX2/pcsx2'
name: "Windows - SSE4"
@@ -67,8 +63,8 @@ jobs:
upload_artifacts:
if: github.repository == 'PCSX2/pcsx2'
needs:
- build_linux_qt_sse4
- build_linux_qt_avx2
- build_linux_qt
- build_windows_qt
- build_qt_sse4
- build_qt_avx2
- build_macos_qt
@@ -21,7 +21,7 @@ NAME=""
if [ "${OS}" == "macos" ]; then
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}"
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") || ("$OS" == "linux" && "$GUI_FRAMEWORK" == "QT") ]]; then
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") ]]; then
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}-${SIMD}"
else
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}"
@@ -25,6 +25,9 @@
#
# For more information, please refer to <http://unlicense.org/>
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
source "$SCRIPTDIR/functions.sh"
if [ "$#" -ne 4 ]; then
echo "Syntax: $0 <path to pcsx2 directory> <path to build directory> <deps prefix> <output name>"
exit 1
@@ -190,7 +193,7 @@ declare -a QTPLUGINS=(
set -e
if [ ! -f appimagetool-x86_64.AppImage ]; then
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
retry_command wget -O appimagetool-x86_64.AppImage https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod +x appimagetool-x86_64.AppImage
fi
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
function retry_command {
# Package servers tend to be unreliable at times..
# Retry a bunch of times.
local RETRIES=10
for i in $(seq 1 "$RETRIES"); do
"$@" && break
if [ "$i" == "$RETRIES" ]; then
echo "Command \"$@\" failed after ${RETRIES} retries."
exit 1
fi
done
}
@@ -1,5 +1,8 @@
#!/bin/bash
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
source "$SCRIPTDIR/functions.sh"
set -e
# Packages - Build and Qt
@@ -57,18 +60,18 @@ declare -a PCSX2_PACKAGES=(
)
if [ "${COMPILER}" = "gcc" ]; then
BUILD_PACKAGES+=("g++-10")
BUILD_PACKAGES+=("g++-10")
else
BUILD_PACKAGES+=("llvm-12" "lld-12" "clang-12")
BUILD_PACKAGES+=("llvm-12" "lld-12" "clang-12")
fi
sudo apt-get -qq update
retry_command sudo apt-get -qq update && break
# Install packages needed for building
echo "Will install the following packages for building - ${BUILD_PACKAGES[*]}"
sudo apt-get -y install "${BUILD_PACKAGES[@]}"
retry_command sudo apt-get -y install "${BUILD_PACKAGES[@]}"
# Install packages needed by pcsx2
PCSX2_PACKAGES=("${PCSX2_PACKAGES[@]}")
echo "Will install the following packages for pcsx2 - ${PCSX2_PACKAGES[*]}"
sudo apt-get -y install "${PCSX2_PACKAGES[@]}"
retry_command sudo apt-get -y install "${PCSX2_PACKAGES[@]}"
+4
View File
@@ -2,6 +2,10 @@
# versions as well, avoiding setting policies.
cmake_minimum_required(VERSION 3.12...3.24)
#Enabling this cmake policy gets rid of warnings regarding LTO.
cmake_policy(SET CMP0069 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
message(FATAL_ERROR "PCSX2 does not support in-tree builds. Please make a build directory that is not the PCSX2 source directory and generate your CMake project there using either `cmake -B build_directory` or by running cmake from the build directory.")
endif()
File diff suppressed because it is too large Load Diff
+25 -10
View File
@@ -69,7 +69,7 @@
03000000c82d00000121000000000000,8BitDo SN30 Pro for Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001130000000000000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001130000000000000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001230000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001330000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
@@ -383,7 +383,7 @@
0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows,
030000008f0e00001030000000000000,Mayflash Sega Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,
030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -407,7 +407,6 @@
03000000c62400002b89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c62400001a89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c62400001b89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows,
03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows,
@@ -484,8 +483,8 @@
030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows,
030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,leftshoulder:b10,leftstick:b1,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,
03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,
03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,
030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows,
@@ -542,8 +541,9 @@
030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows,
030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,x:b0,y:b5,back:b2,guide:b10,start:b3,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpleft:b14,dpdown:b13,dpright:b15,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,
03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -798,7 +798,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001130000000020000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001130000000020000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001330000001000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001330000000020000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -882,6 +882,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X,
0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,dpdown:b28,dpleft:b30,dpright:b26,dpup:b24,leftshoulder:b10,lefttrigger:b14,rightshoulder:b12,righttrigger:b4,start:b18,x:b6,y:b8,platform:Mac OS X,
0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,
03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,platform:Mac OS X,
03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
@@ -898,6 +899,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000d620000011a7000010050000,Nintendo Switch PowerA Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,platform:Mac OS X,
030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X,
030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
@@ -920,6 +922,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000005e040000e002000001000000,PXN P30 Pro Mobile,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000222c00000225000000010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000222c00000020000000010000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
@@ -941,7 +944,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Mac OS X,
030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c0500006802000002100000,Rii RK707,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b3,righttrigger:b9,rightx:a2,righty:a3,start:b1,x:b15,y:b12,platform:Mac OS X,
03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000006f0e00008701000005010000,Rock Candy Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Mac OS X,
03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Mac OS X,
03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,
@@ -1032,7 +1037,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000631000014010000,8BitDo Pro 2 Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00001030000011010000,8BitDo Pro 2 Wired Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000020000000000000,8BitDo Pro 2 Wired Controller for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
06000000c82d00000020000006010000,8BitDo Pro 2 Wired Controller for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
@@ -1055,7 +1063,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000260000011010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001330000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1118,12 +1126,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000007e0500003703000000000000,GameCube Adapter,a:b0,b:b1,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,
19000000030000000300000002030000,GameForce Controller,a:b1,b:b0,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
@@ -1234,8 +1244,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000242f0000f700000001010000,Mayflash Magic S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
0300000025090000e803000001010000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux,
@@ -1287,6 +1299,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux,
03000000d620000013a7000011010000,Nintendo Switch PowerA Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000007e0500000920000000026803,Nintendo Switch Pro Controller,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Linux,
030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
@@ -1317,7 +1330,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00008501000011010000,PDP Nintendo Switch Fightpad Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00008701000011010000,PDP Rock Nintendo Switch Candy Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006f0e00000901000011010000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1375,6 +1387,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux,
03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -1406,6 +1419,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00008701000011010000,Rock Candy Switch Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000a306000023f6000011010000,Saitek Cyborg V1 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
@@ -1435,6 +1449,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+37 -1
View File
@@ -23,7 +23,8 @@ cbuffer cb0 : register(b0)
float4 BGColor;
int EMODA;
int EMODC;
int cb0_pad[2];
int DOFFSET;
int cb0_pad;
};
static const float3x3 rgb2yuv =
@@ -291,6 +292,41 @@ PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
return output;
}
PS_OUTPUT ps_convert_clut_4(PS_INPUT input)
{
// Borrowing the YUV constant buffer.
float2 scale = BGColor.xy;
uint2 offset = uint2(uint(EMODA), uint(EMODC)) + uint(DOFFSET);
// CLUT4 is easy, just two rows of 8x8.
uint index = uint(input.p.x);
uint2 pos = uint2(index % 8u, index / 8u);
int2 final = int2(floor(float2(offset + pos) * scale));
PS_OUTPUT output;
output.c = Texture.Load(int3(final, 0), 0);
return output;
}
PS_OUTPUT ps_convert_clut_8(PS_INPUT input)
{
float2 scale = BGColor.xy;
uint2 offset = uint2(uint(EMODA), uint(EMODC));
uint index = min(uint(input.p.x) + uint(DOFFSET), 255u);
// CLUT is arranged into 8 groups of 16x2, with the top-right and bottom-left quadrants swapped.
// This can probably be done better..
uint subgroup = (index / 8u) % 4u;
uint2 pos;
pos.x = (index % 8u) + ((subgroup >= 2u) ? 8u : 0u);
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
int2 final = int2(floor(float2(offset + pos) * scale));
PS_OUTPUT output;
output.c = Texture.Load(int3(final, 0), 0);
return output;
}
PS_OUTPUT ps_yuv(PS_INPUT input)
{
PS_OUTPUT output;
+44 -34
View File
@@ -21,6 +21,8 @@
#define PS_FST 0
#define PS_WMS 0
#define PS_WMT 0
#define PS_ADJS 0
#define PS_ADJT 0
#define PS_AEM_FMT FMT_32
#define PS_AEM 0
#define PS_TFX 0
@@ -42,7 +44,6 @@
#define PS_CHANNEL_FETCH 0
#define PS_TALES_OF_ABYSS_HLE 0
#define PS_URBAN_CHAOS_HLE 0
#define PS_INVALID_TEX0 0
#define PS_SCALE_FACTOR 1.0
#define PS_HDR 0
#define PS_COLCLIP 0
@@ -130,7 +131,6 @@ Texture2D<float4> Palette : register(t1);
Texture2D<float4> RtTexture : register(t2);
Texture2D<float> PrimMinTexture : register(t3);
SamplerState TextureSampler : register(s0);
SamplerState PaletteSampler : register(s1);
#ifdef DX12
cbuffer cb0 : register(b0)
@@ -159,10 +159,10 @@ cbuffer cb1
float2 TA;
float MaxDepthPS;
float Af;
uint4 MskFix;
uint4 FbMask;
float4 HalfTexel;
float4 MinMax;
float4 STRange;
int4 ChannelShuffle;
float2 TC_OffsetHack;
float2 STScale;
@@ -184,7 +184,20 @@ float4 sample_c(float2 uv, float uv_w)
// As of 2018 this issue is still present.
uv = (trunc(uv * WH.zw) + float2(0.5, 0.5)) / WH.zw;
}
#if !PS_ADJS && !PS_ADJT
uv *= STScale;
#else
#if PS_ADJS
uv.x = (uv.x - STRange.x) * STRange.z;
#else
uv.x = uv.x * STScale.x;
#endif
#if PS_ADJT
uv.y = (uv.y - STRange.y) * STRange.w;
#else
uv.y = uv.y * STScale.y;
#endif
#endif
#if PS_AUTOMATIC_LOD == 1
return Texture.Sample(TextureSampler, uv);
@@ -207,19 +220,19 @@ float4 sample_c(float2 uv, float uv_w)
#endif
}
float4 sample_p(float u)
float4 sample_p(uint u)
{
return Palette.Sample(PaletteSampler, u);
return Palette.Load(int3(int(u), 0, 0));
}
float4 sample_p_norm(float u)
{
return sample_p(uint(u * 255.5f));
}
float4 clamp_wrap_uv(float4 uv)
{
float4 tex_size;
if (PS_INVALID_TEX0 == 1)
tex_size = WH.zwzw;
else
tex_size = WH.xyxy;
float4 tex_size = WH.xyxy;
if(PS_WMS == PS_WMT)
{
@@ -234,7 +247,7 @@ float4 clamp_wrap_uv(float4 uv)
// textures. Fixes Xenosaga's hair issue.
uv = frac(uv);
#endif
uv = (float4)(((uint4)(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
uv = (float4)(((uint4)(uv * tex_size) & asuint(MinMax.xyxy)) | asuint(MinMax.zwzw)) / tex_size;
}
}
else
@@ -248,7 +261,7 @@ float4 clamp_wrap_uv(float4 uv)
#if PS_FST == 0
uv.xz = frac(uv.xz);
#endif
uv.xz = (float2)(((uint2)(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
uv.xz = (float2)(((uint2)(uv.xz * tex_size.xx) & asuint(MinMax.xx)) | asuint(MinMax.zz)) / tex_size.xx;
}
if(PS_WMT == 2)
{
@@ -259,7 +272,7 @@ float4 clamp_wrap_uv(float4 uv)
#if PS_FST == 0
uv.yw = frac(uv.yw);
#endif
uv.yw = (float2)(((uint2)(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
uv.yw = (float2)(((uint2)(uv.yw * tex_size.yy) & asuint(MinMax.yy)) | asuint(MinMax.ww)) / tex_size.yy;
}
}
@@ -278,7 +291,7 @@ float4x4 sample_4c(float4 uv, float uv_w)
return c;
}
float4 sample_4_index(float4 uv, float uv_w)
uint4 sample_4_index(float4 uv, float uv_w)
{
float4 c;
@@ -288,25 +301,26 @@ float4 sample_4_index(float4 uv, float uv_w)
c.w = sample_c(uv.zw, uv_w).a;
// Denormalize value
uint4 i = uint4(c * 255.0f + 0.5f);
uint4 i = uint4(c * 255.5f);
if (PS_PAL_FMT == 1)
{
// 4HL
c = float4(i & 0xFu) / 255.0f;
return i & 0xFu;
}
else if (PS_PAL_FMT == 2)
{
// 4HH
c = float4(i >> 4u) / 255.0f;
return i >> 4u;
}
else
{
// 8
return i;
}
// Most of texture will hit this code so keep normalized float value
// 8 bits
return c * 255./256 + 0.5/256;
}
float4x4 sample_4p(float4 u)
float4x4 sample_4p(uint4 u)
{
float4x4 c;
@@ -348,7 +362,7 @@ float4 fetch_c(int2 uv)
int2 clamp_wrap_uv_depth(int2 uv)
{
int4 mask = (int4)MskFix << 4;
int4 mask = asint(MinMax) << 4;
if (PS_WMS == PS_WMT)
{
if (PS_WMS == 2)
@@ -468,7 +482,7 @@ float4 fetch_red(int2 xy)
rt = fetch_raw_color(xy);
}
return sample_p(rt.r) * 255.0f;
return sample_p_norm(rt.r) * 255.0f;
}
float4 fetch_green(int2 xy)
@@ -485,7 +499,7 @@ float4 fetch_green(int2 xy)
rt = fetch_raw_color(xy);
}
return sample_p(rt.g) * 255.0f;
return sample_p_norm(rt.g) * 255.0f;
}
float4 fetch_blue(int2 xy)
@@ -502,19 +516,19 @@ float4 fetch_blue(int2 xy)
rt = fetch_raw_color(xy);
}
return sample_p(rt.b) * 255.0f;
return sample_p_norm(rt.b) * 255.0f;
}
float4 fetch_alpha(int2 xy)
{
float4 rt = fetch_raw_color(xy);
return sample_p(rt.a) * 255.0f;
return sample_p_norm(rt.a) * 255.0f;
}
float4 fetch_rgb(int2 xy)
{
float4 rt = fetch_raw_color(xy);
float4 c = float4(sample_p(rt.r).r, sample_p(rt.g).g, sample_p(rt.b).b, 1.0);
float4 c = float4(sample_p_norm(rt.r).r, sample_p_norm(rt.g).g, sample_p_norm(rt.b).b, 1.0);
return c * 255.0f;
}
@@ -671,11 +685,7 @@ float4 fog(float4 c, float f)
float4 ps_color(PS_INPUT input)
{
#if PS_FST == 0 && PS_INVALID_TEX0 == 1
// Re-normalize coordinate from invalid GS to corrected texture size
float2 st = (input.t.xy * WH.xy) / (input.t.w * WH.zw);
float2 st_int = (input.ti.zw * WH.xy) / (input.t.w * WH.zw);
#elif PS_FST == 0
#if PS_FST == 0
float2 st = input.t.xy / input.t.w;
float2 st_int = input.ti.zw / input.t.w;
#else
@@ -75,13 +75,12 @@ layout(std140, binding = 0) uniform cb21
float MaxDepthPS;
float Af;
uvec4 MskFix;
uvec4 FbMask;
vec4 HalfTexel;
vec4 MinMax;
vec4 STRange;
ivec4 ChannelShuffle;
@@ -92,11 +91,6 @@ layout(std140, binding = 0) uniform cb21
};
#endif
//layout(std140, binding = 22) uniform cb22
//{
// vec4 rt_size;
//};
//////////////////////////////////////////////////////////////////////
// Default Sampler
//////////////////////////////////////////////////////////////////////
+35
View File
@@ -314,6 +314,41 @@ void ps_hdr_resolve()
}
#endif
#ifdef ps_convert_clut_4
uniform uvec3 offset;
uniform vec2 scale;
void ps_convert_clut_4()
{
// CLUT4 is easy, just two rows of 8x8.
uint index = uint(gl_FragCoord.x) + offset.z;
uvec2 pos = uvec2(index % 8u, index / 8u);
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * scale));
SV_Target0 = texelFetch(TextureSampler, final, 0);
}
#endif
#ifdef ps_convert_clut_8
uniform uvec3 offset;
uniform vec2 scale;
void ps_convert_clut_8()
{
uint index = min(uint(gl_FragCoord.x) + offset.z, 255u);
// CLUT is arranged into 8 groups of 16x2, with the top-right and bottom-left quadrants swapped.
// This can probably be done better..
uint subgroup = (index / 8u) % 4u;
uvec2 pos;
pos.x = (index % 8u) + ((subgroup >= 2u) ? 8u : 0u);
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * scale));
SV_Target0 = texelFetch(TextureSampler, final, 0);
}
#endif
#ifdef ps_yuv
uniform ivec2 EMOD;
+38 -32
View File
@@ -109,7 +109,20 @@ vec4 sample_c(vec2 uv)
// As of 2018 this issue is still present.
uv = (trunc(uv * WH.zw) + vec2(0.5, 0.5)) / WH.zw;
#endif
uv *= STScale;
#if !PS_ADJS && !PS_ADJT
uv *= STScale;
#else
#if PS_ADJS
uv.x = (uv.x - STRange.x) * STRange.z;
#else
uv.x = uv.x * STScale.x;
#endif
#if PS_ADJT
uv.y = (uv.y - STRange.y) * STRange.w;
#else
uv.y = uv.y * STScale.y;
#endif
#endif
#if PS_AUTOMATIC_LOD == 1
return texture(TextureSampler, uv);
@@ -133,19 +146,20 @@ vec4 sample_c(vec2 uv)
#endif
}
vec4 sample_p(float idx)
vec4 sample_p(uint idx)
{
return texture(PaletteSampler, vec2(idx, 0.0f));
return texelFetch(PaletteSampler, ivec2(int(idx), 0), 0);
}
vec4 sample_p_norm(float u)
{
return sample_p(uint(u * 255.5f));
}
vec4 clamp_wrap_uv(vec4 uv)
{
vec4 uv_out = uv;
#if PS_INVALID_TEX0 == 1
vec4 tex_size = WH.zwzw;
#else
vec4 tex_size = WH.xyxy;
#endif
#if PS_WMS == PS_WMT
@@ -157,7 +171,7 @@ vec4 clamp_wrap_uv(vec4 uv)
// textures. Fixes Xenosaga's hair issue.
uv = fract(uv);
#endif
uv_out = vec4((uvec4(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
uv_out = vec4((uvec4(uv * tex_size) & floatBitsToUint(MinMax.xyxy)) | floatBitsToUint(MinMax.zwzw)) / tex_size;
#endif
#else // PS_WMS != PS_WMT
@@ -169,7 +183,7 @@ vec4 clamp_wrap_uv(vec4 uv)
#if PS_FST == 0
uv.xz = fract(uv.xz);
#endif
uv_out.xz = vec2((uvec2(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
uv_out.xz = vec2((uvec2(uv.xz * tex_size.xx) & floatBitsToUint(MinMax.xx)) | floatBitsToUint(MinMax.zz)) / tex_size.xx;
#endif
@@ -180,7 +194,7 @@ vec4 clamp_wrap_uv(vec4 uv)
#if PS_FST == 0
uv.yw = fract(uv.yw);
#endif
uv_out.yw = vec2((uvec2(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
uv_out.yw = vec2((uvec2(uv.yw * tex_size.yy) & floatBitsToUint(MinMax.yy)) | floatBitsToUint(MinMax.ww)) / tex_size.yy;
#endif
#endif
@@ -202,7 +216,7 @@ mat4 sample_4c(vec4 uv)
return c;
}
vec4 sample_4_index(vec4 uv)
uvec4 sample_4_index(vec4 uv)
{
vec4 c;
@@ -218,26 +232,22 @@ vec4 sample_4_index(vec4 uv)
c.z = sample_c(uv.xw).a;
c.w = sample_c(uv.zw).a;
uvec4 i = uvec4(c * 255.0f + 0.5f); // Denormalize value
uvec4 i = uvec4(c * 255.5f); // Denormalize value
#if PS_PAL_FMT == 1
// 4HL
return vec4(i & 0xFu) / 255.0f;
return i & 0xFu;
#elif PS_PAL_FMT == 2
// 4HH
return vec4(i >> 4u) / 255.0f;
return i >> 4u;
#else
// Most of texture will hit this code so keep normalized float value
// 8 bits
return c;
// 8
return i;
#endif
}
mat4 sample_4p(vec4 u)
mat4 sample_4p(uvec4 u)
{
mat4 c;
@@ -287,7 +297,7 @@ ivec2 clamp_wrap_uv_depth(ivec2 uv)
// Keep the full precision
// It allow to multiply the ScalingFactor before the 1/16 coeff
ivec4 mask = ivec4(MskFix) << 4;
ivec4 mask = floatBitsToInt(MinMax) << 4;
#if PS_WMS == PS_WMT
@@ -398,7 +408,7 @@ vec4 fetch_red()
#else
vec4 rt = fetch_raw_color();
#endif
return sample_p(rt.r) * 255.0f;
return sample_p_norm(rt.r) * 255.0f;
}
vec4 fetch_green()
@@ -409,7 +419,7 @@ vec4 fetch_green()
#else
vec4 rt = fetch_raw_color();
#endif
return sample_p(rt.g) * 255.0f;
return sample_p_norm(rt.g) * 255.0f;
}
vec4 fetch_blue()
@@ -420,19 +430,19 @@ vec4 fetch_blue()
#else
vec4 rt = fetch_raw_color();
#endif
return sample_p(rt.b) * 255.0f;
return sample_p_norm(rt.b) * 255.0f;
}
vec4 fetch_alpha()
{
vec4 rt = fetch_raw_color();
return sample_p(rt.a) * 255.0f;
return sample_p_norm(rt.a) * 255.0f;
}
vec4 fetch_rgb()
{
vec4 rt = fetch_raw_color();
vec4 c = vec4(sample_p(rt.r).r, sample_p(rt.g).g, sample_p(rt.b).b, 1.0f);
vec4 c = vec4(sample_p_norm(rt.r).r, sample_p_norm(rt.g).g, sample_p_norm(rt.b).b, 1.0f);
return c * 255.0f;
}
@@ -590,11 +600,7 @@ void fog(inout vec4 C, float f)
vec4 ps_color()
{
//FIXME: maybe we can set gl_Position.w = q in VS
#if (PS_FST == 0) && (PS_INVALID_TEX0 == 1)
// Re-normalize coordinate from invalid GS to corrected texture size
vec2 st = (PSin.t_float.xy * WH.xy) / (vec2(PSin.t_float.w) * WH.zw);
vec2 st_int = (PSin.t_int.zw * WH.xy) / (vec2(PSin.t_float.w) * WH.zw);
#elif (PS_FST == 0)
#if (PS_FST == 0)
vec2 st = PSin.t_float.xy / vec2(PSin.t_float.w);
vec2 st_int = PSin.t_int.zw / vec2(PSin.t_float.w);
#else
+43
View File
@@ -274,6 +274,49 @@ void ps_convert_rgba_8i()
}
#endif
#ifdef ps_convert_clut_4
layout(push_constant) uniform cb10
{
vec2 scale;
uvec2 offset;
uint doffset;
};
void ps_convert_clut_4()
{
// CLUT4 is easy, just two rows of 8x8.
uint index = uint(gl_FragCoord.x) + doffset;
uvec2 pos = uvec2(index % 8u, index / 8u);
ivec2 final = ivec2(floor(vec2(offset + pos) * scale));
o_col0 = texelFetch(samp0, final, 0);
}
#endif
#ifdef ps_convert_clut_8
layout(push_constant) uniform cb10
{
vec2 scale;
uvec2 offset;
uint doffset;
};
void ps_convert_clut_8()
{
uint index = min(uint(gl_FragCoord.x) + doffset, 255u);
// CLUT is arranged into 8 groups of 16x2, with the top-right and bottom-left quadrants swapped.
// This can probably be done better..
uint subgroup = (index / 8u) % 4u;
uvec2 pos;
pos.x = (index % 8u) + ((subgroup >= 2u) ? 8u : 0u);
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
ivec2 final = ivec2(floor(vec2(offset + pos) * scale));
o_col0 = texelFetch(samp0, final, 0);
}
#endif
#ifdef ps_yuv
layout(push_constant) uniform cb10
{
+43 -35
View File
@@ -312,6 +312,8 @@ void main()
#define PS_FST 0
#define PS_WMS 0
#define PS_WMT 0
#define PS_ADJS 0
#define PS_ADJT 0
#define PS_FMT FMT_32
#define PS_AEM 0
#define PS_TFX 0
@@ -332,7 +334,6 @@ void main()
#define PS_CHANNEL_FETCH 0
#define PS_TALES_OF_ABYSS_HLE 0
#define PS_URBAN_CHAOS_HLE 0
#define PS_INVALID_TEX0 0
#define PS_SCALE_FACTOR 1.0
#define PS_HDR 0
#define PS_COLCLIP 0
@@ -361,10 +362,10 @@ layout(std140, set = 0, binding = 1) uniform cb1
vec2 TA;
float MaxDepthPS;
float Af;
uvec4 MskFix;
uvec4 FbMask;
vec4 HalfTexel;
vec4 MinMax;
vec4 STRange;
ivec4 ChannelShuffle;
vec2 TC_OffsetHack;
vec2 STScale;
@@ -390,7 +391,7 @@ layout(location = 0) out vec4 o_col0;
#endif
layout(set = 1, binding = 0) uniform sampler2D Texture;
layout(set = 1, binding = 1) uniform sampler2D Palette;
layout(set = 1, binding = 1) uniform texture2D Palette;
#if PS_FEEDBACK_LOOP_IS_NEEDED
#ifndef DISABLE_TEXTURE_BARRIER
@@ -420,7 +421,20 @@ vec4 sample_c(vec2 uv)
// As of 2018 this issue is still present.
uv = (trunc(uv * WH.zw) + vec2(0.5, 0.5)) / WH.zw;
#endif
#if !PS_ADJS && !PS_ADJT
uv *= STScale;
#else
#if PS_ADJS
uv.x = (uv.x - STRange.x) * STRange.z;
#else
uv.x = uv.x * STScale.x;
#endif
#if PS_ADJT
uv.y = (uv.y - STRange.y) * STRange.w;
#else
uv.y = uv.y * STScale.y;
#endif
#endif
#if PS_AUTOMATIC_LOD == 1
return texture(Texture, uv);
@@ -443,20 +457,19 @@ vec4 sample_c(vec2 uv)
#endif
}
vec4 sample_p(float u)
vec4 sample_p(uint idx)
{
return texture(Palette, vec2(u, 0.0f));
return texelFetch(Palette, ivec2(int(idx), 0), 0);
}
vec4 sample_p_norm(float u)
{
return sample_p(uint(u * 255.5f));
}
vec4 clamp_wrap_uv(vec4 uv)
{
vec4 tex_size;
#if PS_INVALID_TEX0
tex_size = WH.zwzw;
#else
tex_size = WH.xyxy;
#endif
vec4 tex_size = WH.xyxy;
#if PS_WMS == PS_WMT
{
@@ -471,7 +484,7 @@ vec4 clamp_wrap_uv(vec4 uv)
// textures. Fixes Xenosaga's hair issue.
uv = fract(uv);
#endif
uv = vec4((uvec4(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
uv = vec4((uvec4(uv * tex_size) & floatBitsToUint(MinMax.xyxy)) | floatBitsToUint(MinMax.zwzw)) / tex_size;
}
#endif
}
@@ -486,7 +499,7 @@ vec4 clamp_wrap_uv(vec4 uv)
#if PS_FST == 0
uv.xz = fract(uv.xz);
#endif
uv.xz = vec2((uvec2(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
uv.xz = vec2((uvec2(uv.xz * tex_size.xx) & floatBitsToUint(MinMax.xx)) | floatBitsToUint(MinMax.zz)) / tex_size.xx;
}
#endif
#if PS_WMT == 2
@@ -498,7 +511,7 @@ vec4 clamp_wrap_uv(vec4 uv)
#if PS_FST == 0
uv.yw = fract(uv.yw);
#endif
uv.yw = vec2((uvec2(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
uv.yw = vec2((uvec2(uv.yw * tex_size.yy) & floatBitsToUint(MinMax.yy)) | floatBitsToUint(MinMax.ww)) / tex_size.yy;
}
#endif
}
@@ -519,7 +532,7 @@ mat4 sample_4c(vec4 uv)
return c;
}
vec4 sample_4_index(vec4 uv)
uvec4 sample_4_index(vec4 uv)
{
vec4 c;
@@ -529,22 +542,21 @@ vec4 sample_4_index(vec4 uv)
c.w = sample_c(uv.zw).a;
// Denormalize value
uvec4 i = uvec4(c * 255.0f + 0.5f);
uvec4 i = uvec4(c * 255.5f);
#if PS_PAL_FMT == 1
// 4HL
c = vec4(i & 0xFu) / 255.0f;
return i & 0xFu;
#elif PS_PAL_FMT == 2
// 4HH
c = vec4(i >> 4u) / 255.0f;
return i >> 4u;
#else
// 8
return i;
#endif
// Most of texture will hit this code so keep normalized float value
// 8 bits
return c * 255./256 + 0.5/256;
}
mat4 sample_4p(vec4 u)
mat4 sample_4p(uvec4 u)
{
mat4 c;
@@ -586,7 +598,7 @@ vec4 fetch_c(ivec2 uv)
ivec2 clamp_wrap_uv_depth(ivec2 uv)
{
ivec4 mask = ivec4(MskFix << 4);
ivec4 mask = floatBitsToInt(MinMax) << 4;
#if (PS_WMS == PS_WMT)
{
#if (PS_WMS == 2)
@@ -709,7 +721,7 @@ vec4 fetch_red(ivec2 xy)
rt = fetch_raw_color(xy);
#endif
return sample_p(rt.r) * 255.0f;
return sample_p_norm(rt.r) * 255.0f;
}
vec4 fetch_green(ivec2 xy)
@@ -723,7 +735,7 @@ vec4 fetch_green(ivec2 xy)
rt = fetch_raw_color(xy);
#endif
return sample_p(rt.g) * 255.0f;
return sample_p_norm(rt.g) * 255.0f;
}
vec4 fetch_blue(ivec2 xy)
@@ -737,19 +749,19 @@ vec4 fetch_blue(ivec2 xy)
rt = fetch_raw_color(xy);
#endif
return sample_p(rt.b) * 255.0f;
return sample_p_norm(rt.b) * 255.0f;
}
vec4 fetch_alpha(ivec2 xy)
{
vec4 rt = fetch_raw_color(xy);
return sample_p(rt.a) * 255.0f;
return sample_p_norm(rt.a) * 255.0f;
}
vec4 fetch_rgb(ivec2 xy)
{
vec4 rt = fetch_raw_color(xy);
vec4 c = vec4(sample_p(rt.r).r, sample_p(rt.g).g, sample_p(rt.b).b, 1.0);
vec4 c = vec4(sample_p_norm(rt.r).r, sample_p_norm(rt.g).g, sample_p_norm(rt.b).b, 1.0);
return c * 255.0f;
}
@@ -903,11 +915,7 @@ vec4 fog(vec4 c, float f)
vec4 ps_color()
{
#if PS_FST == 0 && PS_INVALID_TEX0 == 1
// Re-normalize coordinate from invalid GS to corrected texture size
vec2 st = (vsIn.t.xy * WH.xy) / (vsIn.t.w * WH.zw);
vec2 st_int = (vsIn.ti.zw * WH.xy) / (vsIn.t.w * WH.zw);
#elif PS_FST == 0
#if PS_FST == 0
vec2 st = vsIn.t.xy / vsIn.t.w;
vec2 st_int = vsIn.ti.zw / vsIn.t.w;
#else
+3 -13
View File
@@ -201,27 +201,22 @@ endif()
# Note: future GCC (aka GCC 5.1.1) has less false positive so warning could maybe put back
# -Wno-unused-function: warn for function not used in release build
# -Wno-unused-value: lots of warning for this kind of statements "0 && ...". There are used to disable some parts of code in release/dev build.
# -Wno-overloaded-virtual: Gives a fair number of warnings under clang over in the wxwidget gui section of the code.
# -Wno-deprecated-declarations: The USB plugins dialogs are written in straight gtk 2, which gives a million deprecated warnings. Suppress them until we can deal with them.
# -Wno-format*: Yeah, these need to be taken care of, but...
# -Wno-stringop-truncation: Who comes up with these compiler warnings, anyways?
# -Wno-stringop-overflow: Probably the same people as this one...
# -Wno-maybe-uninitialized: Lots of gcc warnings like "test.GSVector8i::<anonymous>.GSVector8i::<unnamed union>::m may be used uninitialized" if this is removed.
if (MSVC)
set(DEFAULT_WARNINGS)
else()
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-attributes -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers -Wno-deprecated-declarations -Wno-format -Wno-format-security -Wno-overloaded-virtual)
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-attributes -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers -Wno-format -Wno-format-security)
if (NOT USE_ICC)
list(APPEND DEFAULT_WARNINGS -Wno-unused-value)
endif()
endif()
if (USE_CLANG)
list(APPEND DEFAULT_WARNINGS -Wno-overloaded-virtual)
endif()
if (USE_GCC)
list(APPEND DEFAULT_WARNINGS -Wno-stringop-truncation -Wno-stringop-overflow)
list(APPEND DEFAULT_WARNINGS -Wno-stringop-truncation -Wno-stringop-overflow -Wno-maybe-uninitialized )
endif()
@@ -232,11 +227,6 @@ elseif(NOT MSVC)
set(AGGRESSIVE_WARNING -Wstrict-aliasing -Wstrict-overflow=1)
endif()
if (USE_CLANG)
# -Wno-deprecated-register: glib issue...
list(APPEND DEFAULT_WARNINGS -Wno-deprecated-register -Wno-c++14-extensions)
endif()
if (USE_PGO_GENERATE OR USE_PGO_OPTIMIZE)
add_compile_options("-fprofile-dir=${CMAKE_SOURCE_DIR}/profile")
endif()
+1 -5
View File
@@ -10,16 +10,14 @@ add_library(common)
# x86emitter sources
target_sources(common PRIVATE
AlignedMalloc.cpp
VirtualMemory.cpp
EventSource.inl
SafeArray.inl
Console.cpp
CrashHandler.cpp
DynamicLibrary.cpp
EventSource.cpp
Exceptions.cpp
FastJmp.cpp
FileSystem.cpp
General.cpp
Image.cpp
HTTPDownloader.cpp
MemorySettingsInterface.cpp
@@ -71,7 +69,6 @@ target_sources(common PRIVATE
DynamicLibrary.h
Easing.h
EnumOps.h
EventSource.h
Exceptions.h
FastJmp.h
FileSystem.h
@@ -88,7 +85,6 @@ target_sources(common PRIVATE
MD5Digest.h
MRCHelpers.h
Path.h
PageFaultSource.h
PrecompiledHeader.h
ProgressCallback.h
ReadbackSpinManager.h
-94
View File
@@ -1,94 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <list>
#include <mutex>
// --------------------------------------------------------------------------------------
// EventSource< template EvtType >
// --------------------------------------------------------------------------------------
template <typename ListenerType>
class EventSource
{
public:
typedef typename ListenerType::EvtParams EvtParams;
typedef typename std::list<ListenerType*> ListenerList;
typedef typename ListenerList::iterator ListenerIterator;
protected:
typedef typename ListenerList::const_iterator ConstIterator;
ListenerList m_listeners;
// This is a cached copy of the listener list used to handle standard dispatching, which
// allows for self-modification of the EventSource's listener list by the listeners.
// Translation: The dispatcher uses this copy instead, to avoid iterator invalidation.
ListenerList m_cache_copy;
bool m_cache_valid;
std::mutex m_listeners_lock;
public:
EventSource()
{
m_cache_valid = false;
}
virtual ~EventSource() = default;
virtual ListenerIterator Add(ListenerType& listener);
virtual void Remove(ListenerType& listener);
virtual void Remove(const ListenerIterator& listenerHandle);
void Add(ListenerType* listener)
{
if (listener == NULL)
return;
Add(*listener);
}
void Remove(ListenerType* listener)
{
if (listener == NULL)
return;
Remove(*listener);
}
void Dispatch(const EvtParams& params);
protected:
virtual ListenerIterator _AddFast_without_lock(ListenerType& listener);
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& params);
};
// --------------------------------------------------------------------------------------
// IEventDispatcher
// --------------------------------------------------------------------------------------
// This class is used as a base interface for EventListeners. It allows the listeners to do
// customized dispatching of several event types into "user friendly" function overrides.
//
template <typename EvtParams>
class IEventDispatcher
{
protected:
IEventDispatcher() {}
public:
virtual ~IEventDispatcher() = default;
virtual void DispatchEvent(const EvtParams& params) = 0;
};
-110
View File
@@ -1,110 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/Exceptions.h"
#include "common/Console.h"
template <typename ListenerType>
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType& listener)
{
std::unique_lock locker(m_listeners_lock);
// Check for duplicates before adding the event.
if (IsDebugBuild)
{
ListenerIterator iter = m_listeners.begin();
while (iter != m_listeners.end())
{
if ((*iter) == &listener)
return iter;
++iter;
}
}
return _AddFast_without_lock(listener);
}
template <typename ListenerType>
void EventSource<ListenerType>::Remove(ListenerType& listener)
{
std::unique_lock locker(m_listeners_lock);
m_cache_valid = false;
m_listeners.remove(&listener);
}
template <typename ListenerType>
void EventSource<ListenerType>::Remove(const ListenerIterator& listenerHandle)
{
std::unique_lock locker(m_listeners_lock);
m_cache_valid = false;
m_listeners.erase(listenerHandle);
}
template <typename ListenerType>
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock(ListenerType& listener)
{
m_cache_valid = false;
m_listeners.push_front(&listener);
return m_listeners.begin();
}
template <typename ListenerType>
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& evtparams)
{
while (iter != iend)
{
try
{
(*iter)->DispatchEvent(evtparams);
}
catch (Exception::RuntimeError& ex)
{
if (IsDevBuild)
{
pxFailDev(("Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage()).c_str());
}
else
{
Console.Error("Ignoring runtime error thrown from event listener: %s", ex.FormatDiagnosticMessage().c_str());
}
}
catch (BaseException& ex)
{
if (IsDevBuild)
{
ex.DiagMsg() = "Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
throw;
}
Console.Error("Ignoring non-runtime BaseException thrown from event listener: %s", ex.FormatDiagnosticMessage().c_str());
}
++iter;
}
}
template <typename ListenerType>
void EventSource<ListenerType>::Dispatch(const EvtParams& evtparams)
{
if (!m_cache_valid)
{
m_cache_copy = m_listeners;
m_cache_valid = true;
}
if (m_cache_copy.empty())
return;
_DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams);
}
-27
View File
@@ -74,33 +74,6 @@ namespace Exception
virtual BaseException* Clone() const = 0;
};
// --------------------------------------------------------------------------------------
// Ps2Generic Exception
// --------------------------------------------------------------------------------------
// This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
//
// Implementation note: does not derive from BaseException, so that we can use different
// catch block hierarchies to handle them (if needed).
//
// Translation Note: Currently these exceptions are never translated. English/diagnostic
// format only. :)
//
class Ps2Generic
{
protected:
std::string m_message; // a "detailed" message of what disastrous thing has occurred!
public:
virtual ~Ps2Generic() = default;
virtual u32 GetPc() const = 0;
virtual bool IsDelaySlot() const = 0;
virtual std::string& Message() { return m_message; }
virtual void Rethrow() const = 0;
virtual Ps2Generic* Clone() const = 0;
};
// Some helper macros for defining the standard constructors of internationalized constructors
// Parameters:
// classname - Yeah, the name of this class being defined. :)
+4 -1
View File
@@ -60,7 +60,10 @@ namespace GL
GLint info_log_length = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
if (status == GL_FALSE || info_log_length > 0)
// Log will create a new line when there are no warnings so let's set a minimum log length of 1.
constexpr int info_log_min_length = 1;
if (status == GL_FALSE || info_log_length > info_log_min_length)
{
std::string info_log;
info_log.resize(info_log_length + 1);
+23 -4
View File
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -14,7 +14,26 @@
*/
#include "PrecompiledHeader.h"
#include "EventSource.h"
#include "EventSource.inl"
#include "General.h"
//template class EventSource< int >;
// --------------------------------------------------------------------------------------
// PageProtectionMode (implementations)
// --------------------------------------------------------------------------------------
std::string PageProtectionMode::ToString() const
{
std::string modeStr;
if (m_read)
modeStr += "Read";
if (m_write)
modeStr += "Write";
if (m_exec)
modeStr += "Exec";
if (modeStr.empty())
return "NoAccess";
if (modeStr.length() <= 5)
modeStr += "Only";
return modeStr;
}
+14
View File
@@ -116,6 +116,14 @@ static __fi PageProtectionMode PageAccess_Any()
return PageProtectionMode().All();
}
struct PageFaultInfo
{
uptr pc;
uptr addr;
};
using PageFaultHandler = bool(*)(const PageFaultInfo& info);
// --------------------------------------------------------------------------------------
// HostSys
// --------------------------------------------------------------------------------------
@@ -141,6 +149,12 @@ namespace HostSys
extern void DestroySharedMemory(void* ptr);
extern void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode);
extern void UnmapSharedMemory(void* baseaddr, size_t size);
/// Installs the specified page fault handler. Only one handler can be active at once.
bool InstallPageFaultHandler(PageFaultHandler handler);
/// Removes the page fault handler. handler is only specified to check against the active callback.
void RemovePageFaultHandler(PageFaultHandler handler);
}
class SharedMemoryMappingArea
+90 -38
View File
@@ -21,13 +21,15 @@
#include <fcntl.h>
#include <unistd.h>
#include <mutex>
#include "fmt/core.h"
#include "common/Align.h"
#include "common/PageFaultSource.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/Exceptions.h"
#include "common/General.h"
// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean
// the same thing.
@@ -44,34 +46,57 @@
#include <ucontext.h>
#endif
extern void SignalExit(int sig);
static std::recursive_mutex s_exception_handler_mutex;
static PageFaultHandler s_exception_handler_callback;
static bool s_in_exception_handler;
static const uptr m_pagemask = getpagesize() - 1;
#if defined(__APPLE__)
#ifdef __APPLE__
static struct sigaction s_old_sigbus_action;
#else
static struct sigaction s_old_sigsegv_action;
#endif
static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
{
#ifdef __APPLE__
const struct sigaction& sa = s_old_sigbus_action;
#else
const struct sigaction& sa = s_old_sigsegv_action;
#endif
if (sa.sa_flags & SA_SIGINFO)
{
sa.sa_sigaction(signal, siginfo, ctx);
}
else if (sa.sa_handler == SIG_DFL)
{
// Re-raising the signal would just queue it, and since we'd restore the handler back to us,
// we'd end up right back here again. So just abort, because that's probably what it'd do anyway.
abort();
}
else if (sa.sa_handler != SIG_IGN)
{
sa.sa_handler(signal);
}
}
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
{
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
// for page fault handling. On linux, there is a single signal handler for the whole
// process, but the handler is executed by the thread that caused the exception.
// Executing the handler concurrently from multiple threads wouldn't go down well.
std::unique_lock lock(s_exception_handler_mutex);
// Prevent recursive exception filtering.
if (s_in_exception_handler)
{
CallExistingSignalHandler(signal, siginfo, ctx);
return;
}
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
// from the context of the current thread and stackframe. So long as the thread is not
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
// be safe even on the main thread.
// (in other words, stdio limitations only really apply to process-level asynchronous
// signals)
// Note: Use of stdio functions isn't safe here. Avoid console logs,
// assertions, file logs, or just about anything else useful.
// Note: Use of stdio functions isn't safe here. Avoid console logs, assertions, file logs,
// or just about anything else useful. However, that's really only a concern if the signal
// occurred within those functions. The logging which we do only happens when the exception
// occurred within JIT code.
#if defined(__APPLE__) && defined(__x86_64__)
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__rip);
@@ -81,35 +106,62 @@ static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
void* const exception_pc = nullptr;
#endif
// Note: This signal can be accessed by the EE or MTVU thread
// Source_PageFault is a global variable with its own state information
// so for now we lock this exception code unless someone can fix this better...
std::unique_lock lock(PageFault_Mutex);
const PageFaultInfo pfi{(uptr)exception_pc, (uptr)siginfo->si_addr & ~__pagemask};
Source_PageFault->Dispatch(PageFaultInfo((uptr)exception_pc, (uptr)siginfo->si_addr & ~m_pagemask));
s_in_exception_handler = true;
// resumes execution right where we left off (re-executes instruction that
// caused the SIGSEGV).
if (Source_PageFault->WasHandled())
const bool handled = s_exception_handler_callback(pfi);
s_in_exception_handler = false;
// Resumes execution right where we left off (re-executes instruction that caused the SIGSEGV).
if (handled)
return;
std::fprintf(stderr, "Unhandled page fault @ 0x%08x", siginfo->si_addr);
pxFailRel("Unhandled page fault");
// Call old signal handler, which will likely dump core.
CallExistingSignalHandler(signal, siginfo, ctx);
}
void _platform_InstallSignalHandler()
bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
{
Console.WriteLn("Installing POSIX SIGSEGV handler...");
struct sigaction sa;
std::unique_lock lock(s_exception_handler_mutex);
pxAssertRel(!s_exception_handler_callback, "A page fault handler is already registered.");
if (!s_exception_handler_callback)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SysPageFaultSignalFilter;
#if defined(__APPLE__)
// MacOS uses SIGBUS for memory permission violations
sigaction(SIGBUS, &sa, &s_old_sigbus_action);
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SysPageFaultSignalFilter;
#ifdef __APPLE__
// MacOS uses SIGBUS for memory permission violations
if (sigaction(SIGBUS, &sa, &s_old_sigbus_action) != 0)
return false;
#else
sigaction(SIGSEGV, &sa, &s_old_sigsegv_action);
if (sigaction(SIGSEGV, &sa, &s_old_sigsegv_action) != 0)
return false;
#endif
}
s_exception_handler_callback = handler;
return true;
}
void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
{
std::unique_lock lock(s_exception_handler_mutex);
pxAssertRel(!s_exception_handler_callback || s_exception_handler_callback == handler,
"Not removing the same handler previously registered.");
if (!s_exception_handler_callback)
return;
s_exception_handler_callback = nullptr;
struct sigaction sa;
#ifdef __APPLE__
sigaction(SIGBUS, &s_old_sigbus_action, &sa);
#else
sigaction(SIGSEGV, &s_old_sigsegv_action, &sa);
#endif
}
+14 -1
View File
@@ -153,6 +153,9 @@ namespace Vulkan
m_provoking_vertex = {};
m_provoking_vertex.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT;
m_line_rasterization_state = {};
m_line_rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
// set defaults
SetNoCullRasterizationState();
SetNoDepthTestState();
@@ -255,7 +258,17 @@ namespace Vulkan
m_ci.pRasterizationState = &m_rasterization_state;
}
void GraphicsPipelineBuilder::SetLineWidth(float width) { m_rasterization_state.lineWidth = width; }
void GraphicsPipelineBuilder::SetLineWidth(float width)
{
m_rasterization_state.lineWidth = width;
}
void GraphicsPipelineBuilder::SetLineRasterizationMode(VkLineRasterizationModeEXT mode)
{
Util::AddPointerToChain(&m_rasterization_state, &m_line_rasterization_state);
m_line_rasterization_state.lineRasterizationMode = mode;
}
void GraphicsPipelineBuilder::SetMultisamples(u32 multisamples, bool per_sample_shading)
{
+2
View File
@@ -96,6 +96,7 @@ namespace Vulkan
void SetRasterizationState(VkPolygonMode polygon_mode, VkCullModeFlags cull_mode, VkFrontFace front_face);
void SetLineWidth(float width);
void SetLineRasterizationMode(VkLineRasterizationModeEXT mode);
void SetMultisamples(u32 multisamples, bool per_sample_shading);
void SetNoCullRasterizationState();
@@ -157,6 +158,7 @@ namespace Vulkan
VkPipelineMultisampleStateCreateInfo m_multisample_state;
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT m_provoking_vertex;
VkPipelineRasterizationLineStateCreateInfoEXT m_line_rasterization_state;
};
class ComputePipelineBuilder
+16
View File
@@ -458,6 +458,8 @@ namespace Vulkan
SupportsExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, false);
m_optional_extensions.vk_ext_calibrated_timestamps =
SupportsExtension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, false);
m_optional_extensions.vk_ext_line_rasterization =
SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
m_optional_extensions.vk_khr_driver_properties =
SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
m_optional_extensions.vk_arm_rasterization_order_attachment_access =
@@ -654,12 +656,19 @@ namespace Vulkan
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
if (m_optional_extensions.vk_ext_provoking_vertex)
{
provoking_vertex_feature.provokingVertexLast = VK_TRUE;
Util::AddPointerToChain(&device_info, &provoking_vertex_feature);
}
if (m_optional_extensions.vk_ext_line_rasterization)
{
line_rasterization_feature.bresenhamLines = VK_TRUE;
Util::AddPointerToChain(&device_info, &line_rasterization_feature);
}
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
{
rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess = VK_TRUE;
@@ -724,12 +733,16 @@ namespace Vulkan
VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
// add in optional feature structs
if (m_optional_extensions.vk_ext_provoking_vertex)
Util::AddPointerToChain(&features2, &provoking_vertex_features);
if (m_optional_extensions.vk_ext_line_rasterization)
Util::AddPointerToChain(&features2, &line_rasterization_feature);
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
Util::AddPointerToChain(&features2, &rasterization_order_access_feature);
@@ -739,6 +752,7 @@ namespace Vulkan
// confirm we actually support it
m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE);
m_optional_extensions.vk_arm_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
m_optional_extensions.vk_ext_line_rasterization &= (line_rasterization_feature.bresenhamLines == VK_TRUE);
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
void** pNext = &properties2.pNext;
@@ -789,6 +803,8 @@ namespace Vulkan
Console.WriteLn("VK_EXT_provoking_vertex is %s",
m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_line_rasterization is %s",
m_optional_extensions.vk_ext_line_rasterization ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_calibrated_timestamps is %s",
m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported");
Console.WriteLn("VK_ARM_rasterization_order_attachment_access is %s",
+1
View File
@@ -52,6 +52,7 @@ namespace Vulkan
bool vk_ext_provoking_vertex : 1;
bool vk_ext_memory_budget : 1;
bool vk_ext_calibrated_timestamps : 1;
bool vk_ext_line_rasterization : 1;
bool vk_khr_driver_properties : 1;
bool vk_arm_rasterization_order_attachment_access : 1;
bool vk_khr_fragment_shader_barycentric : 1;
+36 -36
View File
@@ -637,7 +637,7 @@ namespace Vulkan
}
m_images.reserve(image_count);
m_current_image = (image_count - 1);
m_current_image = 0;
for (u32 i = 0; i < image_count; i++)
{
SwapChainImage image;
@@ -650,31 +650,36 @@ namespace Vulkan
return false;
}
const VkSemaphoreCreateInfo semaphore_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0};
res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &image.available_semaphore);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
return false;
}
res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &image.rendering_finished_semaphore);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
vkDestroySemaphore(g_vulkan_context->GetDevice(), image.available_semaphore, nullptr);
return false;
}
image.framebuffer = image.texture.CreateFramebuffer(m_load_render_pass);
if (image.framebuffer == VK_NULL_HANDLE)
return false;
m_images.emplace_back(std::move(image));
}
m_semaphores.reserve(image_count);
m_current_semaphore = (image_count - 1);
for (u32 i = 0; i < image_count; i++)
{
ImageSemaphores sema;
const VkSemaphoreCreateInfo semaphore_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0};
res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &sema.available_semaphore);
if (res != VK_SUCCESS)
{
vkDestroySemaphore(g_vulkan_context->GetDevice(), image.rendering_finished_semaphore, nullptr);
vkDestroySemaphore(g_vulkan_context->GetDevice(), image.available_semaphore, nullptr);
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
return false;
}
m_images.emplace_back(std::move(image));
res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &sema.rendering_finished_semaphore);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
vkDestroySemaphore(g_vulkan_context->GetDevice(), sema.available_semaphore, nullptr);
return false;
}
m_semaphores.push_back(sema);
}
return true;
@@ -685,11 +690,16 @@ namespace Vulkan
for (auto& it : m_images)
{
// Images themselves are cleaned up by the swap chain object
vkDestroySemaphore(g_vulkan_context->GetDevice(), it.rendering_finished_semaphore, nullptr);
vkDestroySemaphore(g_vulkan_context->GetDevice(), it.available_semaphore, nullptr);
vkDestroyFramebuffer(g_vulkan_context->GetDevice(), it.framebuffer, nullptr);
}
m_images.clear();
for (auto& it : m_semaphores)
{
vkDestroySemaphore(g_vulkan_context->GetDevice(), it.rendering_finished_semaphore, nullptr);
vkDestroySemaphore(g_vulkan_context->GetDevice(), it.available_semaphore, nullptr);
}
m_semaphores.clear();
m_image_acquire_result.reset();
}
@@ -712,21 +722,11 @@ namespace Vulkan
if (!m_swap_chain)
return VK_ERROR_SURFACE_LOST_KHR;
// Unfortunately we can't query the image before providing the semaphore.
// So, let's hope we get it correct.
const u32 expected_image = (m_current_image + 1) % static_cast<u32>(m_images.size());
const VkResult res = vkAcquireNextImageKHR(g_vulkan_context->GetDevice(), m_swap_chain, UINT64_MAX,
m_images[expected_image].available_semaphore, VK_NULL_HANDLE, &m_current_image);
if (res == VK_SUCCESS)
{
// Did we get the correct image? If not, we'll just swap the semaphore handles so it lines up.
if (m_current_image != expected_image)
{
std::swap(m_images[expected_image].available_semaphore, m_images[m_current_image].available_semaphore);
DevCon.WriteLn("Predicted wrong image (expected %u, got %u), swapped semaphores", expected_image, m_current_image);
}
}
// Use a different semaphore for each image.
m_current_semaphore = (m_current_semaphore + 1) % static_cast<u32>(m_semaphores.size());
const VkResult res = vkAcquireNextImageKHR(g_vulkan_context->GetDevice(), m_swap_chain, UINT64_MAX,
m_semaphores[m_current_semaphore].available_semaphore, VK_NULL_HANDLE, &m_current_image);
m_image_acquire_result = res;
return res;
}
+10 -4
View File
@@ -70,10 +70,10 @@ namespace Vulkan
__fi VkFramebuffer GetCurrentFramebuffer() const { return m_images[m_current_image].framebuffer; }
__fi VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; }
__fi VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; }
__fi VkSemaphore GetImageAvailableSemaphore() const { return m_images[m_current_image].available_semaphore; }
__fi const VkSemaphore* GetImageAvailableSemaphorePtr() const { return &m_images[m_current_image].available_semaphore; }
__fi VkSemaphore GetRenderingFinishedSemaphore() const { return m_images[m_current_image].rendering_finished_semaphore; }
__fi const VkSemaphore* GetRenderingFinishedSemaphorePtr() const { return &m_images[m_current_image].rendering_finished_semaphore; }
__fi VkSemaphore GetImageAvailableSemaphore() const { return m_semaphores[m_current_semaphore].available_semaphore; }
__fi const VkSemaphore* GetImageAvailableSemaphorePtr() const { return &m_semaphores[m_current_semaphore].available_semaphore; }
__fi VkSemaphore GetRenderingFinishedSemaphore() const { return m_semaphores[m_current_semaphore].rendering_finished_semaphore; }
__fi const VkSemaphore* GetRenderingFinishedSemaphorePtr() const { return &m_semaphores[m_current_semaphore].rendering_finished_semaphore; }
VkResult AcquireNextImage();
void ReleaseCurrentImage();
@@ -107,6 +107,10 @@ namespace Vulkan
VkImage image;
Texture texture;
VkFramebuffer framebuffer;
};
struct ImageSemaphores
{
VkSemaphore available_semaphore;
VkSemaphore rendering_finished_semaphore;
};
@@ -123,7 +127,9 @@ namespace Vulkan
VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE;
std::vector<SwapChainImage> m_images;
std::vector<ImageSemaphores> m_semaphores;
u32 m_current_image = 0;
u32 m_current_semaphore = 0;
std::optional<VkResult> m_image_acquire_result;
};
} // namespace Vulkan
+57 -39
View File
@@ -17,60 +17,78 @@
#include "common/Align.h"
#include "common/RedtapeWindows.h"
#include "common/PageFaultSource.h"
#include "common/Console.h"
#include "common/General.h"
#include "common/Exceptions.h"
#include "common/StringUtil.h"
#include "common/AlignedMalloc.h"
#include "fmt/core.h"
#include "common/Assertions.h"
#include "fmt/core.h"
#include "fmt/format.h"
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
{
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
#include <mutex>
#if defined(_M_AMD64)
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Rip);
#else
void* const exception_pc = nullptr;
#endif
// Note: This exception can be accessed by the EE or MTVU thread
// Source_PageFault is a global variable with its own state information
// so for now we lock this exception code unless someone can fix this better...
std::unique_lock lock(PageFault_Mutex);
Source_PageFault->Dispatch(PageFaultInfo((uptr)exception_pc, (uptr)eps->ExceptionRecord->ExceptionInformation[1]));
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
}
static std::recursive_mutex s_exception_handler_mutex;
static PageFaultHandler s_exception_handler_callback;
static void* s_exception_handler_handle;
static bool s_in_exception_handler;
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
{
// Prevent recursive exception filtering by catching the exception from the filter here.
// In the event that the filter causes an access violation (happened during shutdown
// because Source_PageFault was deallocated), this will allow the debugger to catch the
// exception.
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
// work but I don't fully understand why some do and some don't.
__try
{
return DoSysPageFaultExceptionFilter(eps);
}
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Executing the handler concurrently from multiple threads wouldn't go down well.
std::unique_lock lock(s_exception_handler_mutex);
// Prevent recursive exception filtering.
if (s_in_exception_handler)
return EXCEPTION_CONTINUE_SEARCH;
// Only interested in page faults.
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Rip);
const PageFaultInfo pfi{(uptr)exception_pc, (uptr)eps->ExceptionRecord->ExceptionInformation[1]};
s_in_exception_handler = true;
const bool handled = s_exception_handler_callback(pfi);
s_in_exception_handler = false;
return handled ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
}
bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
{
std::unique_lock lock(s_exception_handler_mutex);
pxAssertRel(!s_exception_handler_callback, "A page fault handler is already registered.");
if (!s_exception_handler_handle)
{
s_exception_handler_handle = AddVectoredExceptionHandler(TRUE, SysPageFaultExceptionFilter);
if (!s_exception_handler_handle)
return false;
}
s_exception_handler_callback = handler;
return true;
}
void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
{
std::unique_lock lock(s_exception_handler_mutex);
pxAssertRel(!s_exception_handler_callback || s_exception_handler_callback == handler,
"Not removing the same handler previously registered.");
s_exception_handler_callback = nullptr;
if (s_exception_handler_handle)
{
RemoveVectoredExceptionHandler(s_exception_handler_handle);
s_exception_handler_handle = {};
}
}
void _platform_InstallSignalHandler()
{
#ifdef _WIN64 // We don't handle SEH properly on Win64 so use a vectored exception handler instead
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
#endif
}
static DWORD ConvertToWinApi(const PageProtectionMode& mode)
{
DWORD winmode = PAGE_NOACCESS;
+1 -3
View File
@@ -70,6 +70,7 @@
<ClCompile Include="FastJmp.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="General.cpp" />
<ClCompile Include="GL\Context.cpp" />
<ClCompile Include="GL\ContextWGL.cpp" />
<ClCompile Include="GL\Program.cpp" />
@@ -90,7 +91,6 @@
<ClCompile Include="StringUtil.cpp" />
<ClCompile Include="SettingsWrapper.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="VirtualMemory.cpp" />
<ClCompile Include="Vulkan\vk_mem_alloc.cpp" />
<ClCompile Include="Vulkan\Builders.cpp" />
<ClCompile Include="Vulkan\Context.cpp" />
@@ -130,7 +130,6 @@
<ClCompile Include="emitter\WinCpuDetect.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="EventSource.inl" />
<MASM Include="FastJmp.asm" />
<None Include="Vulkan\EntryPoints.inl" />
</ItemGroup>
@@ -178,7 +177,6 @@
<ClInclude Include="SettingsWrapper.h" />
<ClInclude Include="Assertions.h" />
<ClInclude Include="Console.h" />
<ClInclude Include="EventSource.h" />
<ClInclude Include="Exceptions.h" />
<ClInclude Include="General.h" />
<ClInclude Include="MathUtils.h" />
+1 -9
View File
@@ -67,9 +67,6 @@
<ClCompile Include="emitter\simd.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VirtualMemory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="emitter\WinCpuDetect.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -211,6 +208,7 @@
<ClCompile Include="WAVWriter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="General.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlignedMalloc.h">
@@ -234,9 +232,6 @@
<ClInclude Include="emitter\implement\dwshift.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EventSource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Exceptions.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -532,9 +527,6 @@
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="EventSource.inl">
<Filter>Source Files</Filter>
</None>
<None Include="Vulkan\EntryPoints.inl">
<Filter>Source Files\Vulkan</Filter>
</None>
+6
View File
@@ -16,6 +16,12 @@
#include "common/emitter/internal.h"
#include "common/emitter/tools.h"
// warning: suggest braces around initialization of subobject [-Wmissing-braces]
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-braces"
#endif
namespace x86Emitter
{
const xImplAVX_Move xVMOVAPS = {0x00, 0x28, 0x29};
-17
View File
@@ -170,23 +170,6 @@ void x86capabilities::CountCores()
{
Identify();
s32 regs[4];
u32 cmds;
cpuid(regs, 0x80000000);
cmds = regs[0];
// detect multicore for AMD cpu
if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD))
{
// AMD note: they don't support hyperthreading, but they like to flag this true
// anyway. Let's force-unflag it until we come up with a better solution.
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
// not seem to do this) --air
hasMultiThreading = 0;
}
// This will assign values into LogicalCores and PhysicalCores
CountLogicalCores();
}
+3
View File
@@ -0,0 +1,3 @@
files:
- source: pcsx2-qt/Translations/pcsx2-qt_en.ts
translation: '/pcsx2-qt/Translations/pcsx2-qt_%two_letters_code%.ts'
+44 -11
View File
@@ -48,6 +48,7 @@
#include "pcsx2/HostDisplay.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/INISettingsInterface.h"
#include "pcsx2/PAD/Host/PAD.h"
#include "pcsx2/PerformanceMetrics.h"
#include "pcsx2/VMManager.h"
@@ -79,6 +80,7 @@ static std::optional<bool> s_use_window;
// Owned by the GS thread.
static u32 s_dump_frame_number = 0;
static u32 s_loop_number = s_loop_count;
bool GSRunner::InitializeConfig()
{
@@ -102,6 +104,13 @@ bool GSRunner::InitializeConfig()
// we don't need any sound output
si.SetStringValue("SPU2/Output", "OutputModule", "nullout");
// none of the bindings are going to resolve to anything
PAD::ClearPortBindings(si, 0);
si.ClearSection("Hotkeys");
// make sure any gamesettings inis in your tree don't get loaded
si.SetBoolValue("EmuCore", "EnablePerGameSettings", false);
// force logging
si.SetBoolValue("Logging", "EnableSystemConsole", true);
si.SetBoolValue("Logging", "EnableTimestamps", true);
@@ -273,13 +282,15 @@ void Host::ReleaseHostDisplay(bool clear_state)
bool Host::BeginPresentFrame(bool frame_skip)
{
// when we wrap around, don't race other files
GSJoinSnapshotThreads();
// queue dumping of this frame
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
GSQueueSnapshot(dump_path);
if (s_loop_number == 0)
{
// when we wrap around, don't race other files
GSJoinSnapshotThreads();
// queue dumping of this frame
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
GSQueueSnapshot(dump_path);
}
if (g_host_display->BeginPresent(frame_skip))
return true;
@@ -351,10 +362,6 @@ void Host::OnSaveStateSaved(const std::string_view& filename)
{
}
void Host::InvalidateSaveStateCache()
{
}
void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false */)
{
pxFailRel("Not implemented");
@@ -377,7 +384,7 @@ void Host::SetFullscreen(bool enabled)
{
}
void Host::RequestExit(bool save_state_if_running)
void Host::RequestExit(bool allow_confirm)
{
}
@@ -523,6 +530,29 @@ static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& param
s_settings_interface.SetIntValue("EmuCore/GS", "Renderer", static_cast<int>(type));
continue;
}
else if (CHECK_ARG_PARAM("-renderhacks"))
{
std::string str(argv[++i]);
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks", true);
if(str.find("af") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_AutoFlush", true);
if (str.find("cpufb") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_CPU_FB_Conversion", true);
if (str.find("dds") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisableDepthSupport", true);
if (str.find("dpi") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisablePartialInvalidation", true);
if (str.find("dsf") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisableSafeFeatures", true);
if (str.find("tinrt") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_TextureInsideRt", true);
if (str.find("plf") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "preload_frame_with_gs_data", true);
continue;
}
else if (CHECK_ARG_PARAM("-logfile"))
{
const char* logfile = argv[++i];
@@ -631,6 +661,7 @@ int main(int argc, char* argv[])
// apply new settings (e.g. pick up renderer change)
VMManager::ApplySettings();
GSDumpReplayer::SetIsDumpRunner(true);
if (VMManager::Initialize(params))
{
@@ -644,6 +675,7 @@ int main(int argc, char* argv[])
InputManager::CloseSources();
VMManager::Internal::ReleaseMemory();
VMManager::Internal::ReleaseGlobals();
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
GSRunner::DestroyPlatformWindow();
@@ -654,6 +686,7 @@ void Host::CPUThreadVSync()
{
// update GS thread copy of frame number
GetMTGS().RunOnGSThread([frame_number = GSDumpReplayer::GetFrameNumber()]() { s_dump_frame_number = frame_number; });
GetMTGS().RunOnGSThread([loop_number = GSDumpReplayer::GetLoopCount()]() { s_loop_number = loop_number; });
// process any window messages (but we shouldn't really have any)
GSRunner::PumpPlatformMessages();
+10 -5
View File
@@ -16,7 +16,7 @@ def is_gs_path(path):
return False
def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
def run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, gspath):
args = [runner]
gsname = Path(gspath).name
while gsname.rfind('.') >= 0:
@@ -28,6 +28,10 @@ def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
if renderer is not None:
args.extend(["-renderer", renderer])
if renderhacks is not None:
args.extend(["-renderhacks", renderhacks])
args.extend(["-dumpdir", real_dumpdir])
args.extend(["-logfile", os.path.join(real_dumpdir, "emulog.txt")])
@@ -46,7 +50,7 @@ def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
subprocess.run(args)
def run_regression_tests(runner, gsdir, dumpdir, renderer, parallel=1):
def run_regression_tests(runner, gsdir, dumpdir, renderer, renderhacks, parallel=1):
paths = glob.glob(gsdir + "/*.*", recursive=True)
gamepaths = list(filter(is_gs_path, paths))
@@ -57,10 +61,10 @@ def run_regression_tests(runner, gsdir, dumpdir, renderer, parallel=1):
if parallel <= 1:
for game in gamepaths:
run_regression_test(runner, dumpdir, renderer, parallel, game)
run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, game)
else:
print("Processing %u games on %u processors" % (len(gamepaths), parallel))
func = partial(run_regression_test, runner, dumpdir, renderer, parallel)
func = partial(run_regression_test, runner, dumpdir, renderer, parallel, renderhacks)
pool = multiprocessing.Pool(parallel)
pool.map(func, gamepaths)
pool.close()
@@ -76,10 +80,11 @@ if __name__ == "__main__":
parser.add_argument("-dumpdir", action="store", required=True, help="Base directory to dump frames to")
parser.add_argument("-renderer", action="store", required=False, help="Renderer to use")
parser.add_argument("-parallel", action="store", type=int, default=1, help="Number of proceeses to run")
parser.add_argument("-renderhacks", action="store", required=False, help="Enable HW Renering hacks")
args = parser.parse_args()
if not run_regression_tests(args.runner, os.path.realpath(args.gsdir), os.path.realpath(args.dumpdir), args.renderer, args.parallel):
if not run_regression_tests(args.runner, os.path.realpath(args.gsdir), os.path.realpath(args.dumpdir), args.renderer, args.renderhacks, args.parallel):
sys.exit(1)
else:
sys.exit(0)
+1 -1
View File
@@ -465,7 +465,7 @@ void AutoUpdaterDialog::downloadUpdateClicked()
else if (result == 1)
{
// updater started. since we're a modal on the main window, we have to queue this.
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit, Qt::QueuedConnection);
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, true));
done(0);
}
+9
View File
@@ -11,6 +11,8 @@ target_sources(pcsx2-qt PRIVATE
AutoUpdaterDialog.cpp
AutoUpdaterDialog.h
AutoUpdaterDialog.ui
ColorPickerButton.cpp
ColorPickerButton.h
CoverDownloadDialog.cpp
CoverDownloadDialog.h
CoverDownloadDialog.ui
@@ -50,6 +52,7 @@ target_sources(pcsx2-qt PRIVATE
Settings/ControllerBindingWidget_DualShock2.ui
Settings/ControllerBindingWidgets.cpp
Settings/ControllerBindingWidgets.h
Settings/ControllerLEDSettingsDialog.ui
Settings/ControllerGlobalSettingsWidget.cpp
Settings/ControllerGlobalSettingsWidget.h
Settings/ControllerGlobalSettingsWidget.ui
@@ -134,6 +137,12 @@ target_sources(pcsx2-qt PRIVATE
Debugger/BreakpointDialog.cpp
Debugger/BreakpointDialog.h
Debugger/BreakpointDialog.ui
Debugger/Models/BreakpointModel.cpp
Debugger/Models/BreakpointModel.h
Debugger/Models/ThreadModel.cpp
Debugger/Models/ThreadModel.h
Debugger/Models/StackModel.cpp
Debugger/Models/StackModel.h
Tools/InputRecording/NewInputRecordingDlg.cpp
Tools/InputRecording/NewInputRecordingDlg.h
Tools/InputRecording/NewInputRecordingDlg.ui
+66
View File
@@ -0,0 +1,66 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "ColorPickerButton.h"
#include "QtUtils.h"
#include <QtWidgets/QColorDialog>
ColorPickerButton::ColorPickerButton(QWidget* parent)
: QPushButton(parent)
{
connect(this, &QPushButton::clicked, this, &ColorPickerButton::onClicked);
updateBackgroundColor();
}
u32 ColorPickerButton::color()
{
return m_color;
}
void ColorPickerButton::setColor(u32 rgb)
{
if (m_color == rgb)
return;
m_color = rgb;
updateBackgroundColor();
}
void ColorPickerButton::updateBackgroundColor()
{
setStyleSheet(QStringLiteral("background-color: #%1;").arg(static_cast<uint>(m_color), 8, 16, QChar('0')));
}
void ColorPickerButton::onClicked()
{
const u32 red = (m_color >> 16) & 0xff;
const u32 green = (m_color >> 8) & 0xff;
const u32 blue = m_color & 0xff;
const QColor initial(QColor::fromRgb(red, green, blue));
const QColor selected(QColorDialog::getColor(initial, QtUtils::GetRootWidget(this), tr("Select LED Color")));
// QColorDialog returns Invalid on cancel, and apparently initial == Invalid is true...
if (!selected.isValid() || initial == selected)
return;
const u32 new_rgb =
(static_cast<u32>(selected.red()) << 16) | (static_cast<u32>(selected.green()) << 8) | static_cast<u32>(selected.blue());
m_color = new_rgb;
updateBackgroundColor();
emit colorChanged(new_rgb);
}
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -15,17 +15,28 @@
#pragma once
class GSCodeBuffer
#include "common/Pcsx2Defs.h"
#include <QtWidgets/QPushButton>
class ColorPickerButton : public QPushButton
{
std::vector<void*> m_buffers;
size_t m_blocksize;
size_t m_pos, m_reserved;
u8* m_ptr;
Q_OBJECT
public:
GSCodeBuffer(size_t blocksize = 4096 * 64); // 256k
virtual ~GSCodeBuffer();
ColorPickerButton(QWidget* parent);
void* GetBuffer(size_t size);
void ReleaseBuffer(size_t size);
Q_SIGNALS:
void colorChanged(quint32 new_color);
public Q_SLOTS:
quint32 color();
void setColor(quint32 rgb);
private Q_SLOTS:
void onClicked();
private:
void updateBackgroundColor();
u32 m_color = 0;
};
+88 -110
View File
@@ -23,10 +23,11 @@
#include <QtWidgets/QDialog>
#include <QtWidgets/QMessageBox>
BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu)
BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, BreakpointModel& model)
: QDialog(parent)
, m_cpu(cpu)
, m_purpose(BPDIALOG_PURPOSE::CREATE)
, m_purpose(PURPOSE::CREATE)
, m_bpModel(model)
{
m_ui.setupUi(this);
@@ -37,43 +38,42 @@ BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu)
connect(m_ui.rdoMemory, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
}
BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, BreakPoint* bp)
BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, BreakpointModel& model, BreakpointMemcheck bp_mc, int rowIndex)
: QDialog(parent)
, m_cpu(cpu)
, m_purpose(BPDIALOG_PURPOSE::EDIT_BP)
, m_bp(bp)
, m_purpose(PURPOSE::EDIT)
, m_bpModel(model)
, m_bp_mc(bp_mc)
, m_rowIndex(rowIndex)
{
m_ui.setupUi(this);
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(m_bp->addr, 16));
if (m_bp->hasCond)
m_ui.txtCondition->setText(QString::fromLocal8Bit(&m_bp->cond.expressionString[0]));
m_ui.chkEnable->setChecked(m_bp->enabled);
connect(m_ui.rdoExecute, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
connect(m_ui.rdoMemory, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
m_ui.rdoExecute->toggle();
}
BreakpointDialog::BreakpointDialog(QWidget* parent, DebugInterface* cpu, MemCheck* mc)
: QDialog(parent)
, m_cpu(cpu)
, m_purpose(BPDIALOG_PURPOSE::EDIT_MC)
, m_mc(mc)
{
m_ui.setupUi(this);
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
{
m_ui.rdoExecute->setChecked(true);
m_ui.chkEnable->setChecked(bp->enabled);
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(bp->addr, 16));
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(m_mc->start, 16));
m_ui.txtSize->setText(QString::number(m_mc->end - m_mc->start, 16).toUpper());
m_ui.chkLog->setChecked(m_mc->result & MEMCHECK_LOG);
m_ui.chkEnable->setChecked(m_mc->result & MEMCHECK_BREAK);
m_ui.chkChange->setChecked(m_mc->cond & MEMCHECK_WRITE_ONCHANGE);
m_ui.chkRead->setChecked(m_mc->cond & MEMCHECK_READ);
m_ui.chkWrite->setChecked(m_mc->cond & MEMCHECK_WRITE);
if (bp->hasCond)
m_ui.txtCondition->setText(QString::fromLocal8Bit(bp->cond.expressionString));
}
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
{
m_ui.rdoMemory->setChecked(true);
connect(m_ui.rdoExecute, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
connect(m_ui.rdoMemory, &QRadioButton::toggled, this, &BreakpointDialog::onRdoButtonToggled);
m_ui.rdoMemory->toggle();
m_ui.txtAddress->setText(QtUtils::FilledQStringFromValue(mc->start, 16));
m_ui.txtSize->setText(QtUtils::FilledQStringFromValue(mc->end - mc->start, 16));
m_ui.chkRead->setChecked(mc->cond & MEMCHECK_READ);
m_ui.chkWrite->setChecked(mc->cond & MEMCHECK_WRITE);
m_ui.chkChange->setChecked(mc->cond & MEMCHECK_WRITE_ONCHANGE);
m_ui.chkEnable->setChecked(mc->result & MEMCHECK_BREAK);
m_ui.chkLog->setChecked(mc->result & MEMCHECK_LOG);
}
}
BreakpointDialog::~BreakpointDialog()
@@ -90,48 +90,70 @@ void BreakpointDialog::onRdoButtonToggled()
m_ui.chkLog->setEnabled(!isExecute);
}
// When we are creating a breakpoint, use m_bp or m_mc only as a place to store information for the new breakpoint
// When we are modifying a breakpoint, m_bp or m_mc is a pointer to the breakpoint we are updating
void BreakpointDialog::accept()
{
if (m_purpose == BPDIALOG_PURPOSE::CREATE)
if (m_purpose == PURPOSE::CREATE)
{
if (m_ui.rdoExecute->isChecked())
{
m_bp = new BreakPoint;
m_bp->cpu = m_cpu->getCpuType();
m_bp->cond.debug = m_cpu;
}
else
{
m_mc = new MemCheck;
m_mc->cpu = m_cpu->getCpuType();
}
m_bp_mc = BreakPoint();
else if (m_ui.rdoMemory->isChecked())
m_bp_mc = MemCheck();
}
PostfixExpression expression;
// Validate the address
u64 address;
if (!m_cpu->initExpression(m_ui.txtAddress->text().toLocal8Bit(), expression) || !m_cpu->parseExpression(expression, address))
if (auto* bp = std::get_if<BreakPoint>(&m_bp_mc))
{
QMessageBox::warning(this, tr("Error"), tr("Invalid address \"%1\"").arg(m_ui.txtAddress->text()));
return;
PostfixExpression expr;
u64 address;
if (!m_cpu->initExpression(m_ui.txtAddress->text().toLocal8Bit().constData(), expr) ||
!m_cpu->parseExpression(expr, address))
{
QMessageBox::warning(this, tr("Error"), tr("Invalid address \"%1\"").arg(m_ui.txtAddress->text()));
return;
}
bp->addr = address;
bp->enabled = m_ui.chkEnable->isChecked();
if (!m_ui.txtCondition->text().isEmpty())
{
bp->hasCond = true;
bp->cond.debug = m_cpu;
if (!m_cpu->initExpression(m_ui.txtCondition->text().toLocal8Bit().constData(), expr))
{
QMessageBox::warning(this, tr("Error"), tr("Invalid condition \"%1\"").arg(getExpressionError()));
return;
}
bp->cond.expression = expr;
strncpy(&bp->cond.expressionString[0], m_ui.txtCondition->text().toLocal8Bit().constData(),
sizeof(bp->cond.expressionString));
}
}
u64 size;
if (m_ui.rdoMemory->isChecked())
if (auto* mc = std::get_if<MemCheck>(&m_bp_mc))
{
if (!m_cpu->initExpression(m_ui.txtSize->text().toLocal8Bit(), expression) || !m_cpu->parseExpression(expression, size) || !size)
PostfixExpression expr;
u64 startAddress;
if (!m_cpu->initExpression(m_ui.txtAddress->text().toLocal8Bit().constData(), expr) ||
!m_cpu->parseExpression(expr, startAddress))
{
QMessageBox::warning(this, tr("Error"), tr("Invalid address \"%1\"").arg(m_ui.txtAddress->text()));
return;
}
u64 size;
if (!m_cpu->initExpression(m_ui.txtSize->text().toLocal8Bit(), expr) ||
!m_cpu->parseExpression(expr, size) || !size)
{
QMessageBox::warning(this, tr("Error"), tr("Invalid size \"%1\"").arg(m_ui.txtSize->text()));
return;
}
m_mc->start = address;
const bool changedSize = m_mc->end != (m_mc->start + size);
const u32 prevEnd = m_mc->end;
m_mc->end = m_mc->start + size;
mc->start = startAddress;
mc->end = startAddress + size;
int condition = 0;
if (m_ui.chkRead->isChecked())
@@ -141,68 +163,24 @@ void BreakpointDialog::accept()
if (m_ui.chkChange->isChecked())
condition |= MEMCHECK_WRITE_ONCHANGE;
mc->cond = static_cast<MemCheckCondition>(condition);
int result = 0;
if (m_ui.chkEnable->isChecked())
result |= MEMCHECK_BREAK;
if (m_ui.chkLog->isChecked())
result |= MEMCHECK_LOG;
if (m_purpose == BPDIALOG_PURPOSE::CREATE)
{
Host::RunOnCPUThread([this, condition, result] {
CBreakPoints::AddMemCheck(m_cpu->getCpuType(), m_mc->start, m_mc->end, (MemCheckCondition)condition, (MemCheckResult)result);
delete m_mc;
});
}
else
{
Host::RunOnCPUThread([this, mc = *m_mc, condition, result, prevEnd, changedSize] {
if (changedSize)
{
CBreakPoints::RemoveMemCheck(m_cpu->getCpuType(), mc.start, prevEnd);
CBreakPoints::AddMemCheck(m_cpu->getCpuType(), mc.start, mc.end, static_cast<MemCheckCondition>(condition), static_cast<MemCheckResult>(result));
}
else
{
CBreakPoints::ChangeMemCheck(m_cpu->getCpuType(), mc.start, mc.end, static_cast<MemCheckCondition>(condition), static_cast<MemCheckResult>(result));
}
});
}
mc->result = static_cast<MemCheckResult>(result);
}
else
if (m_purpose == PURPOSE::EDIT)
{
if (m_purpose == BPDIALOG_PURPOSE::CREATE)
Host::RunOnCPUThread([this, address] {
CBreakPoints::AddBreakPoint(m_cpu->getCpuType(), address);
});
// Validate the condition
// TODO: Expression management in the core should be updated to make this prettier
if (!m_ui.txtCondition->text().isEmpty())
{
auto strData = m_ui.txtCondition->text().toLocal8Bit();
expression.clear();
if (!m_cpu->initExpression(strData.constData(), expression))
{
QMessageBox::warning(this, tr("Error"), tr("Invalid condition \"%1\"").arg(strData));
return;
}
m_bp->cond.expression = expression;
strncpy(&m_bp->cond.expressionString[0], strData.constData(), sizeof(m_bp->cond.expressionString));
Host::RunOnCPUThread([this, address] {
CBreakPoints::ChangeBreakPointAddCond(m_cpu->getCpuType(), address, m_bp->cond);
});
}
else
{
Host::RunOnCPUThread([this, address] { CBreakPoints::ChangeBreakPointRemoveCond(m_cpu->getCpuType(), address); });
}
Host::RunOnCPUThread([this, address] { CBreakPoints::ChangeBreakPoint(m_cpu->getCpuType(), address, m_ui.chkEnable->isChecked()); });
m_bp->addr = address;
m_bpModel.removeRows(m_rowIndex, 1);
}
m_bpModel.insertBreakpointRows(0, 1, {m_bp_mc});
QDialog::accept();
}
+11 -11
View File
@@ -19,6 +19,8 @@
#include "DebugTools/Breakpoints.h"
#include "Models/BreakpointModel.h"
#include <QtWidgets/QDialog>
class BreakpointDialog final : public QDialog
@@ -26,28 +28,26 @@ class BreakpointDialog final : public QDialog
Q_OBJECT
public:
BreakpointDialog(QWidget* parent, DebugInterface* cpu);
BreakpointDialog(QWidget* parent, DebugInterface* cpu, BreakPoint* bp);
BreakpointDialog(QWidget* parent, DebugInterface* cpu, MemCheck* mc);
BreakpointDialog(QWidget* parent, DebugInterface* cpu, BreakpointModel& model);
BreakpointDialog(QWidget* parent, DebugInterface* cpu, BreakpointModel& model, BreakpointMemcheck bpmc, int rowIndex);
~BreakpointDialog();
public slots:
void onRdoButtonToggled();
void accept() override;
private:
enum class BPDIALOG_PURPOSE
enum class PURPOSE
{
CREATE,
EDIT_BP,
EDIT_MC
EDIT
};
Ui::BreakpointDialog m_ui;
DebugInterface* m_cpu;
const BPDIALOG_PURPOSE m_purpose;
BreakPoint* m_bp = nullptr;
MemCheck* m_mc = nullptr;
};
const PURPOSE m_purpose;
BreakpointModel& m_bpModel;
BreakpointMemcheck m_bp_mc;
int m_rowIndex;
};
+105 -445
View File
@@ -19,6 +19,8 @@
#include "DisassemblyWidget.h"
#include "BreakpointDialog.h"
#include "Models/BreakpointModel.h"
#include "Models/ThreadModel.h"
#include "DebugTools/DebugInterface.h"
#include "DebugTools/Breakpoints.h"
@@ -27,7 +29,6 @@
#include "common/BitCast.h"
#include "QtUtils.h"
#include <QtWidgets/QHeaderView>
#include <QtGui/QClipboard>
#include <QtWidgets/QMessageBox>
#include <QtConcurrent/QtConcurrent>
@@ -40,6 +41,9 @@ using namespace MipsStackWalk;
CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
: m_cpu(cpu)
, m_bpModel(cpu)
, m_threadModel(cpu)
, m_stackModel(cpu)
{
m_ui.setupUi(this);
@@ -55,18 +59,23 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
connect(m_ui.registerWidget, &RegisterWidget::VMUpdate, this, &CpuWidget::reloadCPUWidgets);
connect(m_ui.disassemblyWidget, &DisassemblyWidget::VMUpdate, this, &CpuWidget::reloadCPUWidgets);
connect(m_ui.tabWidget, &QTabWidget::currentChanged, [this] { fixBPListColumnSize(); });
connect(m_ui.breakpointList, &QTableWidget::customContextMenuRequested, this, &CpuWidget::onBPListContextMenu);
connect(m_ui.breakpointList, &QTableWidget::itemChanged, this, &CpuWidget::onBPListItemChange);
connect(m_ui.breakpointList, &QTableView::customContextMenuRequested, this, &CpuWidget::onBPListContextMenu);
connect(m_ui.breakpointList, &QTableView::doubleClicked, this, &CpuWidget::onBPListDoubleClicked);
connect(m_ui.threadList, &QTableWidget::customContextMenuRequested, this, &CpuWidget::onThreadListContextMenu);
connect(m_ui.threadList, &QTableWidget::cellDoubleClicked, this, &CpuWidget::onThreadListDoubleClick);
m_ui.breakpointList->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_ui.breakpointList->setModel(&m_bpModel);
connect(m_ui.threadList, &QTableWidget::customContextMenuRequested, this, &CpuWidget::onThreadListContextMenu);
connect(m_ui.threadList, &QTableWidget::cellDoubleClicked, this, &CpuWidget::onThreadListDoubleClick);
connect(m_ui.threadList, &QTableView::customContextMenuRequested, this, &CpuWidget::onThreadListContextMenu);
connect(m_ui.threadList, &QTableView::doubleClicked, this, &CpuWidget::onThreadListDoubleClick);
connect(m_ui.stackframeList, &QTableWidget::customContextMenuRequested, this, &CpuWidget::onStackListContextMenu);
connect(m_ui.stackframeList, &QTableWidget::cellDoubleClicked, this, &CpuWidget::onStackListDoubleClick);
m_ui.threadList->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_ui.threadList->setModel(&m_threadModel);
connect(m_ui.stackList, &QTableView::customContextMenuRequested, this, &CpuWidget::onStackListContextMenu);
connect(m_ui.stackList, &QTableView::doubleClicked, this, &CpuWidget::onStackListDoubleClick);
m_ui.stackList->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_ui.stackList->setModel(&m_stackModel);
connect(m_ui.tabWidgetRegFunc, &QTabWidget::currentChanged, [this](int i) {if(i == 1){updateFunctionList(true);} });
connect(m_ui.listFunctions, &QListWidget::customContextMenuRequested, this, &CpuWidget::onFuncListContextMenu);
@@ -86,9 +95,6 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
m_ui.registerWidget->SetCpu(&cpu);
m_ui.memoryviewWidget->SetCpu(&cpu);
if (m_cpu.getCpuType() == BREAKPOINT_EE)
CBreakPoints::SetUpdateHandler(std::bind(&CpuWidget::reloadCPUWidgets, this));
this->repaint();
}
@@ -101,11 +107,6 @@ void CpuWidget::paintEvent(QPaintEvent* event)
m_ui.memoryviewWidget->update();
}
void CpuWidget::resizeEvent(QResizeEvent* event)
{
fixBPListColumnSize();
}
// The cpu shouldn't be alive when these are called
// But make sure it isn't just in case
void CpuWidget::onStepInto()
@@ -159,11 +160,11 @@ void CpuWidget::onStepOut()
// Allow the cpu to skip this pc if it is a breakpoint
CBreakPoints::SetSkipFirst(m_cpu.getCpuType(), m_cpu.getPC());
if (m_stacklistObjects.size() < 2)
if (m_stackModel.rowCount() < 2)
return;
Host::RunOnCPUThread([&] {
CBreakPoints::AddBreakPoint(m_cpu.getCpuType(), m_stacklistObjects.at(1).pc, true);
CBreakPoints::AddBreakPoint(m_cpu.getCpuType(), m_stackModel.data(m_stackModel.index(1, StackModel::PC), Qt::UserRole).toUInt(), true);
m_cpu.resumeCpu();
});
@@ -234,145 +235,18 @@ void CpuWidget::onVMPaused()
void CpuWidget::updateBreakpoints()
{
m_ui.breakpointList->blockSignals(true);
m_ui.breakpointList->setRowCount(0);
m_bplistObjects.clear();
int iter = 0;
for (const auto& breakpoint : CBreakPoints::GetBreakpoints())
{
if (breakpoint.cpu != m_cpu.getCpuType())
continue;
if (breakpoint.temporary)
continue;
m_ui.breakpointList->insertRow(iter);
BreakpointObject obj;
obj.bp = std::make_shared<BreakPoint>(breakpoint);
m_bplistObjects.push_back(obj);
// Type (R/O)
QTableWidgetItem* typeItem = new QTableWidgetItem();
typeItem->setText(tr("Execute"));
typeItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable);
m_ui.breakpointList->setItem(iter, 0, typeItem);
// Offset (R/O), possibly allow changing offset???
QTableWidgetItem* offsetItem = new QTableWidgetItem();
offsetItem->setText(FilledQStringFromValue(breakpoint.addr, 16));
offsetItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable);
m_ui.breakpointList->setItem(iter, 1, offsetItem);
// Size & Label (R/O)
QTableWidgetItem* sizeLabelItem = new QTableWidgetItem();
sizeLabelItem->setText(m_cpu.GetSymbolMap().GetLabelString(breakpoint.addr).c_str());
sizeLabelItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable);
m_ui.breakpointList->setItem(iter, 2, sizeLabelItem);
// Opcode (R/O)
QTableWidgetItem* opcodeItem = new QTableWidgetItem();
opcodeItem->setText(m_ui.disassemblyWidget->GetLineDisasm(breakpoint.addr));
opcodeItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable);
m_ui.breakpointList->setItem(iter, 3, opcodeItem);
// Condition (R/W)
QTableWidgetItem* conditionItem = new QTableWidgetItem();
conditionItem->setText(breakpoint.hasCond ? QString::fromLocal8Bit(breakpoint.cond.expressionString) : "");
conditionItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEditable);
m_ui.breakpointList->setItem(iter, 4, conditionItem);
// Hits (R/O) (Disabled for execute bp)
QTableWidgetItem* hitsItem = new QTableWidgetItem();
hitsItem->setText("N/A");
hitsItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable);
m_ui.breakpointList->setItem(iter, 5, hitsItem);
// Enabled (R/W)
QTableWidgetItem* enabledItem = new QTableWidgetItem();
enabledItem->setCheckState(breakpoint.enabled ? Qt::Checked : Qt::Unchecked);
enabledItem->setFlags(Qt::ItemFlag::ItemIsUserCheckable | Qt::ItemFlag::ItemIsEnabled);
m_ui.breakpointList->setItem(iter, 6, enabledItem);
iter++;
}
for (const auto& memcheck : CBreakPoints::GetMemChecks())
{
if (memcheck.cpu != m_cpu.getCpuType())
continue;
m_ui.breakpointList->insertRow(iter);
BreakpointObject obj;
obj.mc = std::make_shared<MemCheck>(memcheck);
m_bplistObjects.push_back(obj);
// Type (R/O)
QTableWidgetItem* typeItem = new QTableWidgetItem();
QString type("");
type += (memcheck.cond & MEMCHECK_READ) ? tr("Read") : "";
type += ((memcheck.cond & MEMCHECK_BOTH) == MEMCHECK_BOTH) ? ", " : " ";
type += (memcheck.cond & MEMCHECK_WRITE) ? (memcheck.cond & MEMCHECK_WRITE_ONCHANGE) ? tr("Write(C)") : tr("Write") : "";
typeItem->setText(type);
typeItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable);
m_ui.breakpointList->setItem(iter, 0, typeItem);
// Offset (R/O), possibly allow changing offset?
QTableWidgetItem* offsetItem = new QTableWidgetItem();
offsetItem->setText(FilledQStringFromValue(memcheck.start, 16));
offsetItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable);
m_ui.breakpointList->setItem(iter, 1, offsetItem);
// Size & Label (R/O)
QTableWidgetItem* sizeLabelItem = new QTableWidgetItem();
sizeLabelItem->setText(QString::number(memcheck.end - memcheck.start, 16));
sizeLabelItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEditable);
m_ui.breakpointList->setItem(iter, 2, sizeLabelItem);
// Opcode (R/O)
QTableWidgetItem* opcodeItem = new QTableWidgetItem();
opcodeItem->setText(m_ui.disassemblyWidget->GetLineDisasm(memcheck.start));
opcodeItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable);
m_ui.breakpointList->setItem(iter, 3, opcodeItem);
// Condition (R/W) (Disabled for memchecks)
QTableWidgetItem* conditionItem = new QTableWidgetItem();
conditionItem->setText("N/A");
conditionItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable);
m_ui.breakpointList->setItem(iter, 4, conditionItem);
// Hits (R/O)
QTableWidgetItem* hitsItem = new QTableWidgetItem();
hitsItem->setText(QString::number(memcheck.numHits));
hitsItem->setFlags(Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable);
m_ui.breakpointList->setItem(iter, 5, hitsItem);
// Enabled (R/W)
QTableWidgetItem* enabledItem = new QTableWidgetItem();
enabledItem->setCheckState((memcheck.result & MEMCHECK_BREAK) ? Qt::Checked : Qt::Unchecked);
enabledItem->setFlags(Qt::ItemFlag::ItemIsUserCheckable | Qt::ItemFlag::ItemIsEnabled);
m_ui.breakpointList->setItem(iter, 6, enabledItem);
iter++;
}
m_ui.breakpointList->blockSignals(false);
m_bpModel.refreshData();
}
void CpuWidget::fixBPListColumnSize()
void CpuWidget::onBPListDoubleClicked(const QModelIndex& index)
{
m_ui.breakpointList->horizontalHeader()->resizeSection(0, 90);
m_ui.breakpointList->horizontalHeader()->resizeSection(1, 65);
m_ui.breakpointList->horizontalHeader()->resizeSection(5, 40);
m_ui.breakpointList->horizontalHeader()->resizeSection(6, 60);
constexpr int currentWidthTotal = 90 + 65 + 40 + 60;
const int sectionWidth = (m_ui.breakpointList->width() - currentWidthTotal) / 3.0f;
m_ui.breakpointList->horizontalHeader()->resizeSection(2, sectionWidth);
m_ui.breakpointList->horizontalHeader()->resizeSection(3, sectionWidth);
m_ui.breakpointList->horizontalHeader()->resizeSection(4, sectionWidth);
if (index.isValid())
{
if (index.column() == BreakpointModel::OFFSET)
{
m_ui.disassemblyWidget->gotoAddress(m_bpModel.data(index, Qt::UserRole).toUInt());
}
}
}
void CpuWidget::onBPListContextMenu(QPoint pos)
@@ -380,14 +254,11 @@ void CpuWidget::onBPListContextMenu(QPoint pos)
if (!m_cpu.isAlive())
return;
if (m_bplistContextMenu)
delete m_bplistContextMenu;
m_bplistContextMenu = new QMenu(m_ui.breakpointList);
QMenu* contextMenu = new QMenu(tr("Breakpoint List Context Menu"), m_ui.breakpointList);
QAction* newAction = new QAction(tr("New"), m_ui.breakpointList);
connect(newAction, &QAction::triggered, this, &CpuWidget::contextBPListNew);
m_bplistContextMenu->addAction(newAction);
contextMenu->addAction(newAction);
const QItemSelectionModel* selModel = m_ui.breakpointList->selectionModel();
@@ -395,98 +266,21 @@ void CpuWidget::onBPListContextMenu(QPoint pos)
{
QAction* editAction = new QAction(tr("Edit"), m_ui.breakpointList);
connect(editAction, &QAction::triggered, this, &CpuWidget::contextBPListEdit);
m_bplistContextMenu->addAction(editAction);
contextMenu->addAction(editAction);
// Only copy when one column is selected
// Shouldn't be trivial to support cross column copy
if (selModel->selectedIndexes().count() == 1)
{
QAction* copyAction = new QAction(tr("Copy"), m_ui.breakpointList);
connect(copyAction, &QAction::triggered, this, &CpuWidget::contextBPListCopy);
m_bplistContextMenu->addAction(copyAction);
contextMenu->addAction(copyAction);
}
QAction* deleteAction = new QAction(tr("Delete"), m_ui.breakpointList);
connect(deleteAction, &QAction::triggered, this, &CpuWidget::contextBPListDelete);
m_bplistContextMenu->addAction(deleteAction);
contextMenu->addAction(deleteAction);
}
m_bplistContextMenu->popup(m_ui.breakpointList->mapToGlobal(pos));
}
void CpuWidget::onBPListItemChange(QTableWidgetItem* item)
{
if (item->column() == 2 && m_bplistObjects.at(item->row()).mc) // Size / Label column. Size is editable for memchecks
{
const auto& mc = m_bplistObjects.at(item->row()).mc;
bool ok;
u32 val = item->text().toUInt(&ok, 16);
if (!ok)
{
QMessageBox::warning(this, tr("Error"), tr("Invalid size \"%1\"").arg(item->text()));
item->setText(QString::number((mc->end - mc->start), 16));
return;
}
if (val == (mc->end - mc->start))
{
return;
}
Host::RunOnCPUThread([this, val, mc] {
CBreakPoints::RemoveMemCheck(m_cpu.getCpuType(), mc->start, mc->end);
CBreakPoints::AddMemCheck(m_cpu.getCpuType(), mc->start, mc->start + val, mc->cond, mc->result);
});
updateBreakpoints();
}
else if (item->column() == 4 && m_bplistObjects.at(item->row()).bp) // Condition column. Only editable for breakpoints
{
const auto& bp = m_bplistObjects.at(item->row()).bp;
if (item->text().isEmpty() && bp->hasCond)
{
Host::RunOnCPUThread([this, bp] {
CBreakPoints::ChangeBreakPointRemoveCond(m_cpu.getCpuType(), bp->addr);
});
updateBreakpoints();
}
else if (item->text() != QString::fromLocal8Bit(&bp->cond.expressionString[0]))
{
PostfixExpression expression;
if (!m_cpu.initExpression(item->text().toLocal8Bit().constData(), expression))
{
QMessageBox::warning(this, tr("Error"), tr("Invalid condition \"%1\"").arg(item->text()));
item->setText(QString::fromLocal8Bit(&bp->cond.expressionString[0]));
return;
}
BreakPointCond cond;
cond.debug = &m_cpu;
cond.expression = expression;
strcpy(&cond.expressionString[0], item->text().toLocal8Bit().constData());
Host::RunOnCPUThread([this, bp, cond] {
CBreakPoints::ChangeBreakPointAddCond(m_cpu.getCpuType(), bp->addr, cond);
});
updateBreakpoints();
}
}
else if (item->column() == 6)
{
auto bpmc = m_bplistObjects.at(item->row());
Host::RunOnCPUThread([this, bpmc, checked = item->checkState()] {
if (bpmc.bp)
{
CBreakPoints::ChangeBreakPoint(m_cpu.getCpuType(), bpmc.bp->addr, checked);
}
else
{
CBreakPoints::ChangeMemCheck(m_cpu.getCpuType(), bpmc.mc->start, bpmc.mc->end, bpmc.mc->cond, MemCheckResult(bpmc.mc->result ^ MEMCHECK_BREAK));
}
});
}
contextMenu->popup(m_ui.breakpointList->mapToGlobal(pos));
}
void CpuWidget::contextBPListCopy()
@@ -496,7 +290,7 @@ void CpuWidget::contextBPListCopy()
if (!selModel->hasSelection())
return;
QGuiApplication::clipboard()->setText(m_ui.breakpointList->selectedItems().first()->text());
QGuiApplication::clipboard()->setText(m_bpModel.data(selModel->currentIndex()).toString());
}
void CpuWidget::contextBPListDelete()
@@ -506,34 +300,21 @@ void CpuWidget::contextBPListDelete()
if (!selModel->hasSelection())
return;
int last_row = -1;
for (auto& index : selModel->selectedIndexes())
QModelIndexList rows = selModel->selectedIndexes();
std::sort(rows.begin(), rows.end(), [](const QModelIndex& a, const QModelIndex& b) {
return a.row() > b.row();
});
for (const QModelIndex& index : rows)
{
if (index.row() == last_row) // If the next index is in the same row, don't delete that breakpoint twice!
continue;
auto& bpObject = m_bplistObjects.at(index.row());
Host::RunOnCPUThread([&] {
if (bpObject.bp)
{
CBreakPoints::RemoveBreakPoint(m_cpu.getCpuType(), bpObject.bp->addr);
}
else
{
CBreakPoints::RemoveMemCheck(m_cpu.getCpuType(), bpObject.mc->start, bpObject.mc->end);
}
});
last_row = index.row();
m_bpModel.removeRows(index.row(), 1);
}
updateBreakpoints();
}
void CpuWidget::contextBPListNew()
{
BreakpointDialog* bpDialog = new BreakpointDialog(this, &m_cpu);
connect(bpDialog, &BreakpointDialog::accepted, this, &CpuWidget::updateBreakpoints);
BreakpointDialog* bpDialog = new BreakpointDialog(this, &m_cpu, m_bpModel);
bpDialog->show();
}
@@ -544,20 +325,11 @@ void CpuWidget::contextBPListEdit()
if (!selModel->hasSelection())
return;
auto& bpObject = m_bplistObjects.at(selModel->selectedIndexes().first().row());
const int selectedRow = selModel->selectedIndexes().first().row();
BreakpointDialog* bpDialog;
auto bpObject = m_bpModel.at(selectedRow);
if (bpObject.bp)
{
bpDialog = new BreakpointDialog(this, &m_cpu, bpObject.bp.get());
}
else
{
bpDialog = new BreakpointDialog(this, &m_cpu, bpObject.mc.get());
}
connect(bpDialog, &BreakpointDialog::accepted, this, &CpuWidget::updateBreakpoints);
BreakpointDialog* bpDialog = new BreakpointDialog(this, &m_cpu, m_bpModel, bpObject, selectedRow);
bpDialog->show();
}
@@ -601,127 +373,41 @@ void CpuWidget::updateFunctionList(bool whenEmpty)
void CpuWidget::updateThreads()
{
m_ui.threadList->setRowCount(0);
if (m_cpu.getCpuType() == BREAKPOINT_EE)
m_threadlistObjects = getEEThreads();
for (size_t i = 0; i < m_threadlistObjects.size(); i++)
{
m_ui.threadList->insertRow(i);
const auto& thread = m_threadlistObjects[i];
if (thread.data.status == THS_RUN)
m_activeThread = thread;
QTableWidgetItem* idItem = new QTableWidgetItem();
idItem->setText(QString::number(thread.tid));
idItem->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.threadList->setItem(i, 0, idItem);
QTableWidgetItem* pcItem = new QTableWidgetItem();
if (thread.data.status == THS_RUN)
pcItem->setText(FilledQStringFromValue(m_cpu.getPC(), 16));
else
pcItem->setText(FilledQStringFromValue(thread.data.entry, 16));
pcItem->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.threadList->setItem(i, 1, pcItem);
QTableWidgetItem* entryItem = new QTableWidgetItem();
entryItem->setText(FilledQStringFromValue(thread.data.entry_init, 16));
entryItem->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.threadList->setItem(i, 2, entryItem);
QTableWidgetItem* priorityItem = new QTableWidgetItem();
priorityItem->setText(QString::number(thread.data.currentPriority));
priorityItem->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.threadList->setItem(i, 3, priorityItem);
QString statusString;
switch (thread.data.status)
{
case THS_BAD:
statusString = tr("Bad");
break;
case THS_RUN:
statusString = tr("Running");
break;
case THS_READY:
statusString = tr("Ready");
break;
case THS_WAIT:
statusString = tr("Waiting");
break;
case THS_SUSPEND:
statusString = tr("Suspended");
break;
case THS_WAIT_SUSPEND:
statusString = tr("Waiting/Suspended");
break;
case THS_DORMANT:
statusString = tr("Dormant");
break;
}
QTableWidgetItem* statusItem = new QTableWidgetItem();
statusItem->setText(statusString);
statusItem->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.threadList->setItem(i, 4, statusItem);
QString waitTypeString;
switch (thread.data.waitType)
{
case WAIT_NONE:
waitTypeString = tr("None");
break;
case WAIT_WAKEUP_REQ:
waitTypeString = tr("Wakeup request");
break;
case WAIT_SEMA:
waitTypeString = tr("Semaphore");
break;
}
QTableWidgetItem* waitItem = new QTableWidgetItem();
waitItem->setText(waitTypeString);
waitItem->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.threadList->setItem(i, 5, waitItem);
}
m_threadModel.refreshData();
}
void CpuWidget::onThreadListContextMenu(QPoint pos)
{
if (!m_threadlistContextMenu)
{
m_threadlistContextMenu = new QMenu(m_ui.threadList);
if (!m_ui.threadList->selectionModel()->hasSelection())
return;
QAction* copyAction = new QAction(tr("Copy"), m_ui.threadList);
connect(copyAction, &QAction::triggered, [this] {
const auto& items = m_ui.threadList->selectedItems();
if (!items.size())
return;
QApplication::clipboard()->setText(items.first()->text());
});
m_threadlistContextMenu->addAction(copyAction);
}
QMenu* contextMenu = new QMenu(tr("Thread List Context Menu"), m_ui.threadList);
m_threadlistContextMenu->exec(m_ui.threadList->mapToGlobal(pos));
QAction* actionCopy = new QAction(tr("Copy"), m_ui.threadList);
connect(actionCopy, &QAction::triggered, [this]() {
const auto* selModel = m_ui.threadList->selectionModel();
if (!selModel->hasSelection())
return;
QGuiApplication::clipboard()->setText(m_ui.threadList->model()->data(selModel->currentIndex()).toString());
});
contextMenu->addAction(actionCopy);
contextMenu->popup(m_ui.threadList->mapToGlobal(pos));
}
void CpuWidget::onThreadListDoubleClick(int row, int column)
void CpuWidget::onThreadListDoubleClick(const QModelIndex& index)
{
const auto& entry = m_threadlistObjects.at(row);
if (column == 1) // PC
switch (index.column())
{
if (entry.data.status == THS_RUN)
m_ui.disassemblyWidget->gotoAddress(m_cpu.getPC());
else
m_ui.disassemblyWidget->gotoAddress(entry.data.entry);
}
else if (column == 2) // Entry Point
{
m_ui.disassemblyWidget->gotoAddress(entry.data.entry_init);
case ThreadModel::ThreadColumns::ENTRY:
m_ui.memoryviewWidget->gotoAddress(m_ui.threadList->model()->data(index, Qt::UserRole).toUInt());
m_ui.tabWidget->setCurrentWidget(m_ui.tab_memory);
break;
default: // Default to PC
m_ui.disassemblyWidget->gotoAddress(m_ui.threadList->model()->data(m_ui.threadList->model()->index(index.row(), ThreadModel::ThreadColumns::PC), Qt::UserRole).toUInt());
break;
}
}
@@ -789,72 +475,46 @@ void CpuWidget::onFuncListDoubleClick(QListWidgetItem* item)
void CpuWidget::updateStackFrames()
{
m_ui.stackframeList->setRowCount(0);
m_stacklistObjects = MipsStackWalk::Walk(&m_cpu, m_cpu.getPC(), m_cpu.getRegister(0, 31), m_cpu.getRegister(0, 29),
m_activeThread.data.entry_init, m_activeThread.data.stack);
for (size_t i = 0; i < m_stacklistObjects.size(); i++)
{
m_ui.stackframeList->insertRow(i);
const auto& stackFrame = m_stacklistObjects.at(i);
QTableWidgetItem* entryItem = new QTableWidgetItem();
entryItem->setText(FilledQStringFromValue(stackFrame.entry, 16));
entryItem->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.stackframeList->setItem(i, 0, entryItem);
QTableWidgetItem* entryName = new QTableWidgetItem();
entryName->setText(m_cpu.GetSymbolMap().GetLabelString(stackFrame.entry).c_str());
entryName->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.stackframeList->setItem(i, 1, entryName);
QTableWidgetItem* entryPC = new QTableWidgetItem();
entryPC->setText(FilledQStringFromValue(stackFrame.pc, 16));
entryPC->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.stackframeList->setItem(i, 2, entryPC);
QTableWidgetItem* entryOpcode = new QTableWidgetItem();
entryOpcode->setText(m_ui.disassemblyWidget->GetLineDisasm(stackFrame.pc));
entryOpcode->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.stackframeList->setItem(i, 3, entryOpcode);
QTableWidgetItem* entrySP = new QTableWidgetItem();
entrySP->setText(FilledQStringFromValue(stackFrame.sp, 16));
entrySP->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.stackframeList->setItem(i, 4, entrySP);
QTableWidgetItem* entryStackSize = new QTableWidgetItem();
entryStackSize->setText(QString::number(stackFrame.stackSize));
entryStackSize->setFlags(Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEnabled);
m_ui.stackframeList->setItem(i, 5, entryStackSize);
}
m_stackModel.refreshData();
}
void CpuWidget::onStackListContextMenu(QPoint pos)
{
if (!m_stacklistContextMenu)
{
m_stacklistContextMenu = new QMenu(m_ui.stackframeList);
if (!m_ui.stackList->selectionModel()->hasSelection())
return;
QAction* copyAction = new QAction(tr("Copy"), m_ui.stackframeList);
connect(copyAction, &QAction::triggered, [this] {
const auto& items = m_ui.stackframeList->selectedItems();
if (!items.size())
return;
QApplication::clipboard()->setText(items.first()->text());
});
m_stacklistContextMenu->addAction(copyAction);
}
QMenu* contextMenu = new QMenu(tr("Stack List Context Menu"), m_ui.stackList);
m_stacklistContextMenu->exec(m_ui.stackframeList->mapToGlobal(pos));
QAction* actionCopy = new QAction(tr("Copy"), m_ui.stackList);
connect(actionCopy, &QAction::triggered, [this]() {
const auto* selModel = m_ui.stackList->selectionModel();
if (!selModel->hasSelection())
return;
QGuiApplication::clipboard()->setText(m_ui.stackList->model()->data(selModel->currentIndex()).toString());
});
contextMenu->addAction(actionCopy);
contextMenu->popup(m_ui.stackList->mapToGlobal(pos));
}
void CpuWidget::onStackListDoubleClick(int row, int column)
void CpuWidget::onStackListDoubleClick(const QModelIndex& index)
{
const auto& entry = m_stacklistObjects.at(row);
m_ui.disassemblyWidget->gotoAddress(entry.pc);
switch (index.column())
{
case StackModel::StackModel::ENTRY:
case StackModel::StackModel::ENTRY_LABEL:
m_ui.disassemblyWidget->gotoAddress(m_ui.stackList->model()->data(m_ui.stackList->model()->index(index.row(), StackModel::StackColumns::ENTRY), Qt::UserRole).toUInt());
break;
case StackModel::StackModel::SP:
m_ui.memoryviewWidget->gotoAddress(m_ui.stackList->model()->data(index, Qt::UserRole).toUInt());
m_ui.tabWidget->setCurrentWidget(m_ui.tab_memory);
break;
default: // Default to PC
m_ui.disassemblyWidget->gotoAddress(m_ui.stackList->model()->data(m_ui.stackList->model()->index(index.row(), StackModel::StackColumns::PC), Qt::UserRole).toUInt());
break;
}
}
template <typename T>
+10 -21
View File
@@ -22,6 +22,10 @@
#include "DebugTools/BiosDebugData.h"
#include "DebugTools/MipsStackWalk.h"
#include "Models/BreakpointModel.h"
#include "Models/ThreadModel.h"
#include "Models/StackModel.h"
#include "QtHost.h"
#include <QtWidgets/QWidget>
#include <QtWidgets/QTableWidget>
@@ -39,7 +43,6 @@ public:
~CpuWidget();
public slots:
void resizeEvent(QResizeEvent* event);
void paintEvent(QPaintEvent* event);
void onStepInto();
@@ -49,10 +52,8 @@ public slots:
void onVMPaused();
void updateBreakpoints();
void fixBPListColumnSize();
void onBPListDoubleClicked(const QModelIndex& index);
void onBPListContextMenu(QPoint pos);
void onBPListItemChange(QTableWidgetItem* item);
void contextBPListCopy();
void contextBPListDelete();
@@ -60,12 +61,12 @@ public slots:
void contextBPListEdit();
void updateThreads();
void onThreadListDoubleClick(const QModelIndex& index);
void onThreadListContextMenu(QPoint pos);
void onThreadListDoubleClick(int row, int column);
void updateStackFrames();
void onStackListContextMenu(QPoint pos);
void onStackListDoubleClick(int row, int column);
void onStackListDoubleClick(const QModelIndex& index);
void updateFunctionList(bool whenEmpty = false);
void onFuncListContextMenu(QPoint pos);
@@ -82,7 +83,6 @@ public slots:
updateBreakpoints();
updateThreads();
updateStackFrames();
updateFunctionList();
m_ui.registerWidget->update();
m_ui.disassemblyWidget->update();
@@ -94,8 +94,6 @@ public slots:
private:
std::vector<QTableWidget*> m_registerTableViews;
QMenu* m_bplistContextMenu = 0;
QMenu* m_threadlistContextMenu = 0;
QMenu* m_stacklistContextMenu = 0;
QMenu* m_funclistContextMenu = 0;
@@ -103,18 +101,9 @@ private:
DebugInterface& m_cpu;
// Poor mans variant
// Allows us to map row index to breakpoint / memcheck objects
struct BreakpointObject
{
std::shared_ptr<BreakPoint> bp;
std::shared_ptr<MemCheck> mc;
};
std::vector<BreakpointObject> m_bplistObjects;
std::vector<EEThread> m_threadlistObjects;
EEThread m_activeThread;
std::vector<StackFrame> m_stacklistObjects;
BreakpointModel m_bpModel;
ThreadModel m_threadModel;
StackModel m_stackModel;
bool m_demangleFunctions = true;
};
+4 -141
View File
@@ -403,7 +403,7 @@
<number>0</number>
</property>
<item>
<widget class="QTableWidget" name="breakpointList">
<widget class="QTableView" name="breakpointList">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
@@ -413,59 +413,6 @@
<property name="gridStyle">
<enum>Qt::NoPen</enum>
</property>
<property name="rowCount">
<number>0</number>
</property>
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderDefaultSectionSize">
<number>75</number>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderCascadingSectionResizes">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column>
<property name="text">
<string>Offset</string>
</property>
</column>
<column>
<property name="text">
<string>Size / Label</string>
</property>
</column>
<column>
<property name="text">
<string>Opcode</string>
</property>
</column>
<column>
<property name="text">
<string>Condition</string>
</property>
</column>
<column>
<property name="text">
<string>Hits</string>
</property>
</column>
<column>
<property name="text">
<string>Enabled</string>
</property>
</column>
</widget>
</item>
</layout>
@@ -491,7 +438,7 @@
<number>0</number>
</property>
<item>
<widget class="QTableWidget" name="threadList">
<widget class="QTableView" name="threadList">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
@@ -504,55 +451,13 @@
<property name="cornerButtonEnabled">
<bool>false</bool>
</property>
<property name="rowCount">
<number>0</number>
</property>
<property name="columnCount">
<number>6</number>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>ID</string>
</property>
</column>
<column>
<property name="text">
<string>PC</string>
</property>
</column>
<column>
<property name="text">
<string>Entry Point</string>
</property>
</column>
<column>
<property name="text">
<string>Priority</string>
</property>
</column>
<column>
<property name="text">
<string>State</string>
</property>
</column>
<column>
<property name="text">
<string>Wait Type</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_callstack">
<attribute name="title">
<string>Call Stack</string>
<string>Active Call Stack</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="spacing">
@@ -571,7 +476,7 @@
<number>0</number>
</property>
<item>
<widget class="QTableWidget" name="stackframeList">
<widget class="QTableView" name="stackList">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
@@ -590,48 +495,6 @@
<property name="cornerButtonEnabled">
<bool>false</bool>
</property>
<property name="rowCount">
<number>0</number>
</property>
<property name="columnCount">
<number>6</number>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>Entry</string>
</property>
</column>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>PC</string>
</property>
</column>
<column>
<property name="text">
<string>Opcode</string>
</property>
</column>
<column>
<property name="text">
<string>SP</string>
</property>
</column>
<column>
<property name="text">
<string>Frame Size</string>
</property>
</column>
</widget>
</item>
</layout>
+21 -10
View File
@@ -61,6 +61,9 @@ DebuggerWindow::DebuggerWindow(QWidget* parent)
m_ui.cpuTabs->addTab(m_cpuWidget_r5900, "R5900");
m_ui.cpuTabs->addTab(m_cpuWidget_r3000, "R3000");
CBreakPoints::SetUpdateHandler(std::bind(&DebuggerWindow::onBreakpointsChanged, this));
return;
}
@@ -85,16 +88,18 @@ void DebuggerWindow::onVMStateChanged()
m_actionStepInto->setEnabled(true);
m_actionStepOver->setEnabled(true);
m_actionStepOut->setEnabled(true);
CBreakPoints::ClearTemporaryBreakPoints();
if (CBreakPoints::GetBreakpointTriggered())
{
CBreakPoints::SetBreakpointTriggered(false);
// Our current PC is on a breakpoint.
// When we run the core again, we want to skip this breakpoint and run
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, r5900Debug.getPC());
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, r3000Debug.getPC());
}
Host::RunOnCPUThread([] {
if (CBreakPoints::GetBreakpointTriggered())
{
CBreakPoints::ClearTemporaryBreakPoints();
CBreakPoints::SetBreakpointTriggered(false);
// Our current PC is on a breakpoint.
// When we run the core again, we want to skip this breakpoint and run
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, r5900Debug.getPC());
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, r3000Debug.getPC());
}
});
}
return;
}
@@ -121,3 +126,9 @@ void DebuggerWindow::onStepOut()
CpuWidget* currentCpu = static_cast<CpuWidget*>(m_ui.cpuTabs->currentWidget());
currentCpu->onStepOut();
}
void DebuggerWindow::onBreakpointsChanged()
{
m_cpuWidget_r5900->reloadCPUWidgets();
m_cpuWidget_r3000->reloadCPUWidgets();
}
+1
View File
@@ -33,6 +33,7 @@ public slots:
void onStepInto();
void onStepOver();
void onStepOut();
void onBreakpointsChanged();
private:
Ui::DebuggerWindow m_ui;
+3 -2
View File
@@ -487,7 +487,7 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event)
void DisassemblyWidget::mousePressEvent(QMouseEvent* event)
{
const u32 selectedAddress = (event->y() / m_rowHeight * 4) + m_visibleStart;
const u32 selectedAddress = (static_cast<int>(event->position().y()) / m_rowHeight * 4) + m_visibleStart;
if (event->buttons() & Qt::LeftButton)
{
if (event->modifiers() & Qt::ShiftModifier)
@@ -523,7 +523,7 @@ void DisassemblyWidget::mouseDoubleClickEvent(QMouseEvent* event)
if (!m_cpu->isAlive())
return;
const u32 selectedAddress = (event->y() / m_rowHeight * 4) + m_visibleStart;
const u32 selectedAddress = (static_cast<int>(event->position().y()) / m_rowHeight * 4) + m_visibleStart;
if (CBreakPoints::IsAddressBreakPoint(m_cpu->getCpuType(), selectedAddress))
{
Host::RunOnCPUThread([&] { CBreakPoints::RemoveBreakPoint(m_cpu->getCpuType(), selectedAddress); });
@@ -734,4 +734,5 @@ void DisassemblyWidget::gotoAddress(u32 address)
m_selectedAddressEnd = destAddress;
this->repaint();
this->setFocus();
}
+1
View File
@@ -500,4 +500,5 @@ void MemoryViewWidget::gotoAddress(u32 address)
m_table.UpdateStartAddress(address & ~0xF);
m_table.selectedAddress = address;
this->repaint();
this->setFocus();
}
@@ -0,0 +1,360 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "BreakpointModel.h"
#include "DebugTools/DebugInterface.h"
#include "DebugTools/Breakpoints.h"
#include "DebugTools/DisassemblyManager.h"
#include "QtHost.h"
#include "QtUtils.h"
#include <QtWidgets/QMessageBox>
#include <algorithm>
BreakpointModel::BreakpointModel(DebugInterface& cpu, QObject* parent)
: QAbstractTableModel(parent)
, m_cpu(cpu)
{
}
int BreakpointModel::rowCount(const QModelIndex&) const
{
return m_breakpoints.size();
}
int BreakpointModel::columnCount(const QModelIndex&) const
{
return BreakpointColumns::COLUMN_COUNT;
}
QVariant BreakpointModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::DisplayRole)
{
auto bp_mc = m_breakpoints.at(index.row());
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
{
switch (index.column())
{
case BreakpointColumns::TYPE:
return tr("Execute");
case BreakpointColumns::OFFSET:
return QtUtils::FilledQStringFromValue(bp->addr, 16);
case BreakpointColumns::SIZE_LABEL:
return m_cpu.GetSymbolMap().GetLabelString(bp->addr).c_str();
case BreakpointColumns::OPCODE:
// Note: Fix up the disassemblymanager so we can use it here, instead of calling a function through the disassemblyview (yuck)
return m_cpu.disasm(bp->addr, true).c_str();
case BreakpointColumns::CONDITION:
return bp->hasCond ? QString::fromLocal8Bit(bp->cond.expressionString) : tr("No Condition");
case BreakpointColumns::HITS:
return tr("--");
case BreakpointColumns::ENABLED:
return bp->enabled ? tr("Enabled") : tr("Disabled");
}
}
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
{
switch (index.column())
{
case BreakpointColumns::TYPE:
{
QString type("");
type += (mc->cond & MEMCHECK_READ) ? tr("Read") : "";
type += ((mc->cond & MEMCHECK_BOTH) == MEMCHECK_BOTH) ? ", " : " ";
type += (mc->cond & MEMCHECK_WRITE) ? (mc->cond & MEMCHECK_WRITE_ONCHANGE) ? tr("Write(C)") : tr("Write") : "";
return type;
}
case BreakpointColumns::OFFSET:
return QtUtils::FilledQStringFromValue(mc->start, 16);
case BreakpointColumns::SIZE_LABEL:
return QString::number(mc->end - mc->start, 16);
case BreakpointColumns::OPCODE:
return tr("--"); // Our address is going to point to memory, no purpose in printing the op
case BreakpointColumns::CONDITION:
return tr("--"); // No condition on memchecks
case BreakpointColumns::HITS:
return QString::number(mc->numHits);
case BreakpointColumns::ENABLED:
return (mc->result & MEMCHECK_BREAK) ? tr("Enabled") : tr("Disabled");
}
}
}
else if (role == Qt::UserRole)
{
auto bp_mc = m_breakpoints.at(index.row());
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
{
switch (index.column())
{
case BreakpointColumns::TYPE:
return 0;
case BreakpointColumns::OFFSET:
return bp->addr;
case BreakpointColumns::SIZE_LABEL:
return m_cpu.GetSymbolMap().GetLabelString(bp->addr).c_str();
case BreakpointColumns::OPCODE:
// Note: Fix up the disassemblymanager so we can use it here, instead of calling a function through the disassemblyview (yuck)
return m_cpu.disasm(bp->addr, true).c_str();
case BreakpointColumns::CONDITION:
return bp->hasCond ? QString::fromLocal8Bit(bp->cond.expressionString) : tr("");
case BreakpointColumns::HITS:
return 0;
case BreakpointColumns::ENABLED:
return bp->enabled;
}
}
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
{
switch (index.column())
{
case BreakpointColumns::TYPE:
return mc->cond;
case BreakpointColumns::OFFSET:
return mc->start;
case BreakpointColumns::SIZE_LABEL:
return mc->end - mc->start;
case BreakpointColumns::OPCODE:
return "";
case BreakpointColumns::CONDITION:
return "";
case BreakpointColumns::HITS:
return mc->numHits;
case BreakpointColumns::ENABLED:
return (mc->result & MEMCHECK_BREAK);
}
}
}
else if (role == Qt::CheckStateRole)
{
if (index.column() == 6)
{
auto bp_mc = m_breakpoints.at(index.row());
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
{
return bp->enabled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked;
}
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
{
return (mc->result & MEMCHECK_BREAK) ? Qt::CheckState::Checked : Qt::CheckState::Unchecked;
}
}
}
return QVariant();
}
QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
switch (section)
{
case BreakpointColumns::TYPE:
return tr("TYPE");
case BreakpointColumns::OFFSET:
return tr("OFFSET");
case BreakpointColumns::SIZE_LABEL:
return tr("SIZE / LABEL");
case BreakpointColumns::OPCODE:
return tr("INSTRUCTION");
case BreakpointColumns::CONDITION:
return tr("CONDITION");
case BreakpointColumns::HITS:
return tr("HITS");
case BreakpointColumns::ENABLED:
return tr("ENABLED");
default:
return QVariant();
}
}
return QVariant();
}
Qt::ItemFlags BreakpointModel::flags(const QModelIndex& index) const
{
volatile const int row = index.row();
bool is_breakpoint = std::holds_alternative<BreakPoint>(m_breakpoints.at(row));
switch (index.column())
{
case BreakpointColumns::CONDITION:
if (is_breakpoint)
return Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable | Qt::ItemFlag::ItemIsEditable;
[[fallthrough]];
case BreakpointColumns::TYPE:
case BreakpointColumns::OPCODE:
case BreakpointColumns::HITS:
case BreakpointColumns::OFFSET:
case BreakpointColumns::SIZE_LABEL:
return Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable;
case BreakpointColumns::ENABLED:
return Qt::ItemFlag::ItemIsUserCheckable | Qt::ItemFlag::ItemIsEnabled | Qt::ItemFlag::ItemIsSelectable;
}
return index.flags();
}
bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (role == Qt::CheckStateRole && index.column() == BreakpointColumns::ENABLED)
{
auto bp_mc = m_breakpoints.at(index.row());
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
{
Host::RunOnCPUThread([cpu = this->m_cpu.getCpuType(), bp = *bp, enabled = value.toBool()] {
CBreakPoints::ChangeBreakPoint(cpu, bp.addr, enabled);
});
}
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
{
Host::RunOnCPUThread([cpu = this->m_cpu.getCpuType(), mc = *mc] {
CBreakPoints::ChangeMemCheck(cpu, mc.start, mc.end, mc.cond,
MemCheckResult(mc.result ^ MEMCHECK_BREAK));
});
}
return true;
}
else if (role == Qt::EditRole && index.column() == BreakpointColumns::CONDITION)
{
auto bp_mc = m_breakpoints.at(index.row());
if (std::holds_alternative<MemCheck>(bp_mc))
return false;
const auto bp = std::get<BreakPoint>(bp_mc);
const QString condValue = value.toString();
if (condValue.isEmpty())
{
if (bp.hasCond)
{
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), bp] {
CBreakPoints::ChangeBreakPointRemoveCond(cpu, bp.addr);
});
}
}
else
{
PostfixExpression expr;
if (!m_cpu.initExpression(condValue.toLocal8Bit().constData(), expr))
{
QMessageBox::warning(nullptr, "Condition Error", QString(getExpressionError()));
return false;
}
BreakPointCond cond;
cond.debug = &m_cpu;
cond.expression = expr;
strcpy(&cond.expressionString[0], condValue.toLocal8Bit().constData());
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), bp, cond] {
CBreakPoints::ChangeBreakPointAddCond(cpu, bp.addr, cond);
});
return true;
}
}
return false;
}
bool BreakpointModel::removeRows(int row, int count, const QModelIndex& index)
{
beginRemoveRows(index, row, row + count);
for (int i = row; i < row + count; i++)
{
auto bp_mc = m_breakpoints.at(i);
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
{
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), addr = bp->addr] {
CBreakPoints::RemoveBreakPoint(cpu, addr);
});
}
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
{
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), start = mc->start, end = mc->end] {
CBreakPoints::RemoveMemCheck(cpu, start, end);
});
}
}
endRemoveRows();
return true;
}
bool BreakpointModel::insertBreakpointRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index)
{
if (breakpoints.size() != static_cast<size_t>(count))
return false;
beginInsertRows(index, row, row + count);
for (const auto& bp_mc : breakpoints)
{
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
{
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), bp = *bp] {
CBreakPoints::AddBreakPoint(cpu, bp.addr);
if (bp.hasCond)
{
CBreakPoints::ChangeBreakPointAddCond(cpu, bp.addr, bp.cond);
}
});
}
else if (const auto* mc = std::get_if<MemCheck>(&bp_mc))
{
Host::RunOnCPUThread([cpu = m_cpu.getCpuType(), mc = *mc] {
CBreakPoints::AddMemCheck(cpu, mc.start, mc.end, mc.cond, mc.result);
});
}
}
endInsertRows();
return true;
}
void BreakpointModel::refreshData()
{
beginResetModel();
m_breakpoints.clear();
auto breakpoints = CBreakPoints::GetBreakpoints(m_cpu.getCpuType(), false);
for (const auto& bp : breakpoints)
{
m_breakpoints.push_back(bp);
}
auto memchecks = CBreakPoints::GetMemChecks(m_cpu.getCpuType());
for (const auto& mc : memchecks)
{
m_breakpoints.push_back(mc);
}
endResetModel();
}
@@ -0,0 +1,59 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtCore/QAbstractTableModel>
#include "DebugTools/DebugInterface.h"
#include "DebugTools/Breakpoints.h"
using BreakpointMemcheck = std::variant<BreakPoint, MemCheck>;
class BreakpointModel : public QAbstractTableModel
{
Q_OBJECT
public:
enum BreakpointColumns : int
{
TYPE = 0,
OFFSET,
SIZE_LABEL,
OPCODE,
CONDITION,
HITS,
ENABLED,
COLUMN_COUNT
};
explicit BreakpointModel(DebugInterface& cpu, QObject* parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
Qt::ItemFlags flags(const QModelIndex& index) const override;
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
bool removeRows(int row, int count, const QModelIndex& index = QModelIndex()) override;
bool insertBreakpointRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index = QModelIndex());
BreakpointMemcheck at(int row) const { return m_breakpoints.at(row); };
void refreshData();
private:
DebugInterface& m_cpu;
std::vector<BreakpointMemcheck> m_breakpoints;
};
+123
View File
@@ -0,0 +1,123 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "StackModel.h"
#include "DebugTools/MipsStackWalk.h"
#include "DebugTools/BiosDebugData.h"
#include "QtUtils.h"
StackModel::StackModel(DebugInterface& cpu, QObject* parent)
: QAbstractTableModel(parent)
, m_cpu(cpu)
{
}
int StackModel::rowCount(const QModelIndex&) const
{
return m_stackFrames.size();
}
int StackModel::columnCount(const QModelIndex&) const
{
return StackModel::COLUMN_COUNT;
}
QVariant StackModel::data(const QModelIndex& index, int role) const
{
if (role == Qt::DisplayRole)
{
const auto& stackFrame = m_stackFrames.at(index.row());
switch (index.column())
{
case StackModel::ENTRY:
return QtUtils::FilledQStringFromValue(stackFrame.entry, 16);
case StackModel::ENTRY_LABEL:
return m_cpu.GetSymbolMap().GetLabelString(stackFrame.entry).c_str();
case StackModel::PC:
return QtUtils::FilledQStringFromValue(stackFrame.pc, 16);
case StackModel::PC_OPCODE:
return m_cpu.disasm(stackFrame.pc, true).c_str();
case StackModel::SP:
return QtUtils::FilledQStringFromValue(stackFrame.sp, 16);
case StackModel::SIZE:
return QString::number(stackFrame.stackSize);
}
}
else if (role == Qt::UserRole)
{
const auto& stackFrame = m_stackFrames.at(index.row());
switch (index.column())
{
case StackModel::ENTRY:
return stackFrame.entry;
case StackModel::ENTRY_LABEL:
return m_cpu.GetSymbolMap().GetLabelString(stackFrame.entry).c_str();
case StackModel::PC:
return stackFrame.pc;
case StackModel::PC_OPCODE:
return m_cpu.disasm(stackFrame.pc, true).c_str();
case StackModel::SP:
return stackFrame.sp;
case StackModel::SIZE:
return stackFrame.stackSize;
}
}
return QVariant();
}
QVariant StackModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
switch (section)
{
case StackColumns::ENTRY:
return tr("ENTRY");
case StackColumns::ENTRY_LABEL:
return tr("LABEL");
case StackColumns::PC:
return tr("PC");
case StackColumns::PC_OPCODE:
return tr("INSTRUCTION");
case StackColumns::SP:
return tr("STACK POINTER");
case StackColumns::SIZE:
return tr("SIZE");
default:
return QVariant();
}
}
return QVariant();
}
void StackModel::refreshData()
{
// Hopefully in the near future we can get a stack frame for
// each thread
beginResetModel();
for (const auto& thread : m_cpu.GetThreadList())
{
if (thread->Status() == ThreadStatus::THS_RUN)
{
m_stackFrames = MipsStackWalk::Walk(&m_cpu, m_cpu.getPC(), m_cpu.getRegister(0, 31), m_cpu.getRegister(0, 29),
thread->EntryPoint(), thread->StackTop());
break;
}
}
endResetModel();
}
+51
View File
@@ -0,0 +1,51 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtCore/QAbstractTableModel>
#include "DebugTools/DebugInterface.h"
#include "DebugTools/MipsStackWalk.h"
class StackModel : public QAbstractTableModel
{
Q_OBJECT
public:
enum StackColumns : int
{
ENTRY = 0,
ENTRY_LABEL,
PC,
PC_OPCODE,
SP,
SIZE,
COLUMN_COUNT
};
explicit StackModel(DebugInterface& cpu, QObject* parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
void refreshData();
private:
DebugInterface& m_cpu;
std::vector<MipsStackWalk::StackFrame> m_stackFrames;
};
+135
View File
@@ -0,0 +1,135 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "ThreadModel.h"
#include "QtUtils.h"
ThreadModel::ThreadModel(DebugInterface& cpu, QObject* parent)
: QAbstractTableModel(parent)
, m_cpu(cpu)
{
}
int ThreadModel::rowCount(const QModelIndex&) const
{
return m_cpu.GetThreadList().size();
}
int ThreadModel::columnCount(const QModelIndex&) const
{
return ThreadModel::COLUMN_COUNT;
}
QVariant ThreadModel::data(const QModelIndex& index, int role) const
{
const auto threads = m_cpu.GetThreadList();
auto* const thread = threads.at(index.row()).get();
if (role == Qt::DisplayRole)
{
switch (index.column())
{
case ThreadModel::ID:
return thread->TID();
case ThreadModel::PC:
{
if (thread->Status() == ThreadStatus::THS_RUN)
return QtUtils::FilledQStringFromValue(m_cpu.getPC(), 16);
return QtUtils::FilledQStringFromValue(thread->PC(), 16);
}
case ThreadModel::ENTRY:
return QtUtils::FilledQStringFromValue(thread->EntryPoint(), 16);
case ThreadModel::PRIORITY:
return QString::number(thread->Priority());
case ThreadModel::STATE:
{
const auto& state = ThreadStateStrings.find(thread->Status());
if (state != ThreadStateStrings.end())
return state->second;
return tr("INVALID");
}
case ThreadModel::WAIT_TYPE:
{
const auto& waitType = ThreadWaitStrings.find(thread->Wait());
if (waitType != ThreadWaitStrings.end())
return waitType->second;
return tr("INVALID");
}
}
}
else if (role == Qt::UserRole)
{
switch (index.column())
{
case ThreadModel::ID:
return thread->TID();
case ThreadModel::PC:
{
if (thread->Status() == ThreadStatus::THS_RUN)
return m_cpu.getPC();
return thread->PC();
}
case ThreadModel::ENTRY:
return thread->EntryPoint();
case ThreadModel::PRIORITY:
return thread->Priority();
case ThreadModel::STATE:
return static_cast<u32>(thread->Status());
case ThreadModel::WAIT_TYPE:
return static_cast<u32>(thread->Wait());
default:
return QVariant();
}
}
return QVariant();
}
QVariant ThreadModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
switch (section)
{
case ThreadColumns::ID:
return tr("ID");
case ThreadColumns::PC:
return tr("PC");
case ThreadColumns::ENTRY:
return tr("ENTRY");
case ThreadColumns::PRIORITY:
return tr("PRIORITY");
case ThreadColumns::STATE:
return tr("STATE");
case ThreadColumns::WAIT_TYPE:
return tr("WAIT TYPE");
default:
return QVariant();
}
}
return QVariant();
}
void ThreadModel::refreshData()
{
beginResetModel();
endResetModel();
}
+74
View File
@@ -0,0 +1,74 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QtCore/QAbstractTableModel>
#include "DebugTools/DebugInterface.h"
#include "DebugTools/BiosDebugData.h"
#include <map>
class ThreadModel : public QAbstractTableModel
{
Q_OBJECT
public:
enum ThreadColumns : int
{
ID = 0,
PC,
ENTRY,
PRIORITY,
STATE,
WAIT_TYPE,
COLUMN_COUNT
};
explicit ThreadModel(DebugInterface& cpu, QObject* parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
void refreshData();
private:
const std::map<ThreadStatus, QString> ThreadStateStrings{
{ThreadStatus::THS_BAD, tr("BAD")},
{ThreadStatus::THS_RUN, tr("RUN")},
{ThreadStatus::THS_READY, tr("READY")},
{ThreadStatus::THS_WAIT, tr("WAIT")},
{ThreadStatus::THS_SUSPEND, tr("SUSPEND")},
{ThreadStatus::THS_WAIT_SUSPEND, tr("WAIT SUSPEND")},
{ThreadStatus::THS_DORMANT, tr("DORMANT")},
};
const std::map<WaitState, QString> ThreadWaitStrings{
{WaitState::NONE, tr("NONE")},
{WaitState::WAKEUP_REQ, tr("WAKEUP REQUEST")},
{WaitState::SEMA, tr("SEMAPHORE")},
{WaitState::SLEEP, tr("SLEEP")},
{WaitState::DELAY, tr("DELAY")},
{WaitState::EVENTFLAG, tr("EVENTFLAG")},
{WaitState::MBOX, tr("MBOX")},
{WaitState::VPOOL, tr("VPOOL")},
{WaitState::FIXPOOL, tr("FIXPOOL")},
};
DebugInterface& m_cpu;
};
+1 -1
View File
@@ -156,7 +156,7 @@ void DisplayWidget::handleCloseEvent(QCloseEvent* event)
}
else
{
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit);
QMetaObject::invokeMethod(g_main_window, "requestExit", Q_ARG(bool, true));
}
// Cancel the event from closing the window.
+1 -1
View File
@@ -488,7 +488,7 @@ void GameListWidget::resizeTableViewColumnsToFit()
80, // last played
80, // size
60, // region
100 // compatibility
120 // compatibility
});
}
+75 -77
View File
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -157,7 +157,7 @@ void MainWindow::initialize()
restoreStateFromConfig();
switchToGameListView();
updateWindowTitle();
updateSaveStateMenus(QString(), QString(), 0);
updateSaveStateMenusEnableState(false);
#ifdef _WIN32
registerForDeviceNotifications();
@@ -346,7 +346,7 @@ void MainWindow::connectSignals()
connect(m_ui.actionDiscordServer, &QAction::triggered, this, &MainWindow::onDiscordServerActionTriggered);
connect(m_ui.actionAboutQt, &QAction::triggered, qApp, &QApplication::aboutQt);
connect(m_ui.actionAbout, &QAction::triggered, this, &MainWindow::onAboutActionTriggered);
connect(m_ui.actionCheckForUpdates, &QAction::triggered, this, &MainWindow::onCheckForUpdatesActionTriggered);
connect(m_ui.actionCheckForUpdates, &QAction::triggered, this, [this]() { checkForUpdates(true, true); });
connect(m_ui.actionOpenDataDirectory, &QAction::triggered, this, &MainWindow::onToolsOpenDataDirectoryTriggered);
connect(m_ui.actionCoverDownloader, &QAction::triggered, this, &MainWindow::onToolsCoverDownloaderTriggered);
connect(m_ui.actionGridViewShowTitles, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowCoverTitles);
@@ -521,7 +521,7 @@ void MainWindow::setStyleFromSettings()
qApp->setStyleSheet(QString());
qApp->setStyle(QStyleFactory::create("Fusion"));
}
else if (theme == "darkfusion")
else if (theme == "darkfusion")
{
// adapted from https://gist.github.com/QuantumCD/6245215
qApp->setStyle(QStyleFactory::create("Fusion"));
@@ -742,7 +742,7 @@ else if (theme == "darkfusion")
// Custom palette by RedDevilus, Blue as main color and Purple as complimentary.
// Alternative dark theme.
qApp->setStyle(QStyleFactory::create("Fusion"));
const QColor blackishblue(50, 25, 70);
const QColor darkerPurple(90, 30, 105);
const QColor nauticalPurple(110, 30, 125);
@@ -963,10 +963,10 @@ void MainWindow::onToolsVideoCaptureToggled(bool checked)
}
const QString container(QString::fromStdString(
Host::GetStringSettingValue("EmuCore/GS", "VideoCaptureContainer", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_CONTAINER)));
Host::GetStringSettingValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER)));
const QString filter(tr("%1 Files (*.%2)").arg(container.toUpper()).arg(container));
QString path(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseSnapshotFilename())).arg(container));
QString path(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseVideoFilename())).arg(container));
path = QFileDialog::getSaveFileName(this, tr("Video Capture"), path, filter);
if (path.isEmpty())
{
@@ -1259,11 +1259,6 @@ void MainWindow::cancelGameListRefresh()
m_game_list_widget->cancelRefresh();
}
void MainWindow::invalidateSaveStateCache()
{
m_save_states_invalidated = true;
}
void MainWindow::reportError(const QString& title, const QString& message)
{
QMessageBox::critical(this, title, message);
@@ -1280,8 +1275,7 @@ void MainWindow::runOnUIThread(const std::function<void()>& func)
func();
}
bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_save_to_state /* = true */,
bool default_save_to_state /* = true */, bool block_until_done /* = false */)
bool MainWindow::requestShutdown(bool allow_confirm, bool allow_save_to_state, bool default_save_to_state)
{
if (!s_vm_valid)
return true;
@@ -1326,34 +1320,21 @@ bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_sav
// Now we can actually shut down the VM.
g_emu_thread->shutdownVM(save_state);
if (block_until_done || m_is_closing || QtHost::InBatchMode())
{
// We need to yield here, since the display gets destroyed.
while (VMManager::GetState() != VMState::Shutdown)
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
}
if (!m_is_closing && QtHost::InBatchMode())
{
// If we don't set the closing flag here, the VM shutdown may not complete by the time closeEvent() is called,
// leading to a confirm.
m_is_closing = true;
QGuiApplication::quit();
}
return true;
}
void MainWindow::requestExit()
void MainWindow::requestExit(bool allow_confirm)
{
// this is block, because otherwise closeEvent() will also prompt
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown, true))
if (!requestShutdown(allow_confirm, true, EmuConfig.SaveStateOnShutdown))
return;
// We could use close here, but if we're not visible (e.g. quitting from fullscreen), closing the window
// doesn't quit the application.
QGuiApplication::quit();
// VM stopped signal won't have fired yet, so queue an exit if we still have one.
// Otherwise, immediately exit, because there's no VM to exit us later.
if (QtHost::IsVMValid())
m_is_closing = true;
else
QGuiApplication::quit();
}
void MainWindow::checkForSettingChanges()
@@ -1374,11 +1355,6 @@ std::optional<WindowInfo> MainWindow::getWindowInfo()
return std::nullopt;
}
void Host::InvalidateSaveStateCache()
{
QMetaObject::invokeMethod(g_main_window, &MainWindow::invalidateSaveStateCache, Qt::QueuedConnection);
}
void MainWindow::onGameListRefreshProgress(const QString& status, int current, int total)
{
m_ui.statusBar->showMessage(status);
@@ -1387,6 +1363,7 @@ void MainWindow::onGameListRefreshProgress(const QString& status, int current, i
void MainWindow::onGameListRefreshComplete()
{
m_ui.statusBar->clearMessage();
clearProgressBar();
}
@@ -1487,8 +1464,8 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
if (m_ui.menuDebug->menuAction()->isVisible())
{
// TODO: Hook this up once it's implemented.
action = menu.addAction(tr("Boot and Debug"));
connect(action, &QAction::triggered, [this, entry]() { DebugInterface::setPauseOnEntry(true); startGameListEntry(entry); getDebuggerWindow()->show(); });
}
menu.addSeparator();
@@ -1580,14 +1557,16 @@ void MainWindow::onChangeDiscMenuAboutToHide()
void MainWindow::onLoadStateMenuAboutToShow()
{
if (m_save_states_invalidated)
updateSaveStateMenus(m_current_disc_path, m_current_game_serial, m_current_game_crc);
m_ui.menuLoadState->clear();
updateSaveStateMenusEnableState(!m_current_game_serial.isEmpty());
populateLoadStateMenu(m_ui.menuLoadState, m_current_disc_path, m_current_game_serial, m_current_game_crc);
}
void MainWindow::onSaveStateMenuAboutToShow()
{
if (m_save_states_invalidated)
updateSaveStateMenus(m_current_disc_path, m_current_game_serial, m_current_game_crc);
m_ui.menuSaveState->clear();
updateSaveStateMenusEnableState(!m_current_game_serial.isEmpty());
populateSaveStateMenu(m_ui.menuSaveState, m_current_game_serial, m_current_game_crc);
}
void MainWindow::onViewToolbarActionToggled(bool checked)
@@ -1640,7 +1619,7 @@ void MainWindow::onViewGamePropertiesActionTriggered()
auto lock = GameList::GetLock();
const GameList::Entry* entry = m_current_elf_override.isEmpty() ?
GameList::GetEntryForPath(m_current_disc_path.toUtf8().constData()) :
GameList::GetEntryForPath(m_current_elf_override.toUtf8().constData());
GameList::GetEntryForPath(m_current_elf_override.toUtf8().constData());
if (entry)
{
SettingsDialog::openGamePropertiesDialog(
@@ -1675,15 +1654,7 @@ void MainWindow::onAboutActionTriggered()
about.exec();
}
void MainWindow::onCheckForUpdatesActionTriggered()
{
// Wipe out the last version, that way it displays the update if we've previously skipped it.
Host::RemoveBaseSettingValue("AutoUpdater", "LastVersion");
Host::CommitBaseSettingChanges();
checkForUpdates(true);
}
void MainWindow::checkForUpdates(bool display_message)
void MainWindow::checkForUpdates(bool display_message, bool force_check)
{
if (!AutoUpdaterDialog::isSupported())
{
@@ -1714,6 +1685,13 @@ void MainWindow::checkForUpdates(bool display_message)
if (m_auto_updater_dialog)
return;
if (force_check)
{
// Wipe out the last version, that way it displays the update if we've previously skipped it.
Host::RemoveBaseSettingValue("AutoUpdater", "LastVersion");
Host::CommitBaseSettingChanges();
}
m_auto_updater_dialog = new AutoUpdaterDialog(this);
connect(m_auto_updater_dialog, &AutoUpdaterDialog::updateCheckCompleted, this, &MainWindow::onUpdateCheckComplete);
m_auto_updater_dialog->queueUpdateCheck(display_message);
@@ -1733,7 +1711,7 @@ void MainWindow::startupUpdateCheck()
if (!Host::GetBaseBoolSettingValue("AutoUpdater", "CheckAtStartup", true))
return;
checkForUpdates(false);
checkForUpdates(false, false);
}
void MainWindow::onToolsOpenDataDirectoryTriggered()
@@ -1889,7 +1867,7 @@ void MainWindow::onVMStarting()
updateWindowTitle();
// prevent loading state until we're fully initialized
updateSaveStateMenus(QString(), QString(), 0);
updateSaveStateMenusEnableState(false);
}
void MainWindow::onVMStarted()
@@ -1951,6 +1929,14 @@ void MainWindow::onVMStopped()
updateStatusBarWidgetVisibility();
updateInputRecordingActions(false);
// If we're closing or in batch mode, quit the whole application now.
if (m_is_closing || QtHost::InBatchMode())
{
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
QCoreApplication::quit();
return;
}
if (m_display_widget)
updateDisplayWidgetCursor();
else
@@ -1969,7 +1955,7 @@ void MainWindow::onGameChanged(const QString& path, const QString& elf_override,
m_current_game_name = name;
m_current_game_crc = crc;
updateWindowTitle();
updateSaveStateMenus(path, serial, crc);
updateSaveStateMenusEnableState(!serial.isEmpty());
}
void MainWindow::showEvent(QShowEvent* event)
@@ -1990,16 +1976,24 @@ void MainWindow::showEvent(QShowEvent* event)
void MainWindow::closeEvent(QCloseEvent* event)
{
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown, true))
// If there's no VM, we can just exit as normal.
if (!s_vm_valid)
{
event->ignore();
QMainWindow::closeEvent(event);
return;
}
// But if there is, we have to cancel the action, regardless of whether we ended exiting
// or not. The window still needs to be visible while GS is shutting down.
event->ignore();
// Exit cancelled?
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown))
return;
// Application will be exited in VM stopped handler.
saveStateToConfig();
m_is_closing = true;
QMainWindow::closeEvent(event);
}
static QString getFilenameFromMimeData(const QMimeData* md)
@@ -2264,7 +2258,12 @@ void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main, bool
// Don't risk doing this on Wayland, it really doesn't like window state changes,
// and positioning has no effect anyway.
if (!s_use_central_widget)
restoreDisplayWindowGeometryFromConfig();
{
if (isVisible() && g_emu_thread->shouldRenderToMain())
container->move(pos());
else
restoreDisplayWindowGeometryFromConfig();
}
if (!is_exclusive_fullscreen)
container->showFullScreen();
@@ -2825,21 +2824,14 @@ void MainWindow::populateSaveStateMenu(QMenu* menu, const QString& serial, quint
}
}
void MainWindow::updateSaveStateMenus(const QString& filename, const QString& serial, quint32 crc)
void MainWindow::updateSaveStateMenusEnableState(bool enable)
{
const bool load_enabled = !serial.isEmpty();
const bool save_enabled = !serial.isEmpty() && s_vm_valid;
m_ui.menuLoadState->clear();
const bool load_enabled = enable;
const bool save_enabled = enable && s_vm_valid;
m_ui.menuLoadState->setEnabled(load_enabled);
m_ui.actionLoadState->setEnabled(load_enabled);
m_ui.menuSaveState->clear();
m_ui.menuSaveState->setEnabled(save_enabled);
m_ui.actionSaveState->setEnabled(save_enabled);
m_save_states_invalidated = false;
if (load_enabled)
populateLoadStateMenu(m_ui.menuLoadState, filename, serial, crc);
if (save_enabled)
populateSaveStateMenu(m_ui.menuSaveState, serial, crc);
}
void MainWindow::doStartFile(std::optional<CDVD_SourceType> source, const QString& path)
@@ -2869,11 +2861,17 @@ void MainWindow::doDiscChange(CDVD_SourceType source, const QString& path)
bool reset_system = false;
if (!m_was_disc_change_request)
{
const int choice = QMessageBox::question(this, tr("Confirm Disc Change"),
tr("Do you want to swap discs or boot the new image (via system reset)?"), tr("Swap Disc"), tr("Reset"), tr("Cancel"), 0, 2);
if (choice == 2)
QMessageBox message(QMessageBox::Question, tr("Confirm Disc Change"),
tr("Do you want to swap discs or boot the new image (via system reset)?"));
message.addButton(tr("Swap Disc"), QMessageBox::ActionRole);
QPushButton* reset_button = message.addButton(tr("Reset"), QMessageBox::ActionRole);
QPushButton* cancel_button = message.addButton(QMessageBox::Cancel);
message.setDefaultButton(cancel_button);
message.exec();
if (message.clickedButton() == cancel_button)
return;
reset_system = (choice != 0);
reset_system = (message.clickedButton() == reset_button);
}
switchToEmulationView();
+6 -9
View File
@@ -110,17 +110,17 @@ public:
/// Rescans a single file. NOTE: Happens on UI thread.
void rescanFile(const std::string& path);
void openDebugger();
public Q_SLOTS:
void checkForUpdates(bool display_message);
void checkForUpdates(bool display_message, bool force_check);
void refreshGameList(bool invalidate_cache);
void cancelGameListRefresh();
void invalidateSaveStateCache();
void reportError(const QString& title, const QString& message);
bool confirmMessage(const QString& title, const QString& message);
void runOnUIThread(const std::function<void()>& func);
bool requestShutdown(
bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true, bool block_until_done = false);
void requestExit();
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true);
void requestExit(bool allow_confirm = true);
void checkForSettingChanges();
std::optional<WindowInfo> getWindowInfo();
@@ -162,7 +162,6 @@ private Q_SLOTS:
void onSupportForumsActionTriggered();
void onDiscordServerActionTriggered();
void onAboutActionTriggered();
void onCheckForUpdatesActionTriggered();
void onToolsOpenDataDirectoryTriggered();
void onToolsCoverDownloaderTriggered();
void updateTheme();
@@ -244,7 +243,6 @@ private:
void updateInputRecordingActions(bool started);
DebuggerWindow* getDebuggerWindow();
void openDebugger();
ControllerSettingsDialog* getControllerSettingsDialog();
void doControllerSettings(ControllerSettingsDialog::Category category = ControllerSettingsDialog::Category::Count);
@@ -261,7 +259,7 @@ private:
void loadSaveStateFile(const QString& filename, const QString& state_filename);
void populateLoadStateMenu(QMenu* menu, const QString& filename, const QString& serial, quint32 crc);
void populateSaveStateMenu(QMenu* menu, const QString& serial, quint32 crc);
void updateSaveStateMenus(const QString& filename, const QString& serial, quint32 crc);
void updateSaveStateMenusEnableState(bool enable);
void doStartFile(std::optional<CDVD_SourceType> source, const QString& path);
void doDiscChange(CDVD_SourceType source, const QString& path);
@@ -293,7 +291,6 @@ private:
bool m_display_created = false;
bool m_relative_mouse_mode = false;
bool m_save_states_invalidated = false;
bool m_was_paused_on_surface_loss = false;
bool m_was_disc_change_request = false;
bool m_is_closing = false;
+43 -11
View File
@@ -96,6 +96,7 @@ static bool s_nogui_mode = false;
static bool s_start_fullscreen_ui = false;
static bool s_start_fullscreen_ui_fullscreen = false;
static bool s_test_config_and_exit = false;
static bool s_boot_and_debug = false;
//////////////////////////////////////////////////////////////////////////
// CPU Thread
@@ -429,6 +430,10 @@ void EmuThread::executeVM()
VMManager::Execute();
continue;
case VMState::Resetting:
VMManager::Reset();
continue;
case VMState::Stopping:
destroyVM();
m_event_loop->processEvents(QEventLoop::AllEvents);
@@ -861,6 +866,10 @@ void EmuThread::beginCapture(const QString& path)
GetMTGS().RunOnGSThread([path = path.toStdString()]() {
GSBeginCapture(std::move(path));
});
// Sync GS thread. We want to start adding audio at the same time as video.
// TODO: This could be up to 64 frames behind... use the pts to adjust it.
GetMTGS().WaitGS(false, false, false);
}
void EmuThread::endCapture()
@@ -1220,12 +1229,9 @@ void Host::CancelGameListRefresh()
QMetaObject::invokeMethod(g_main_window, "cancelGameListRefresh", Qt::BlockingQueuedConnection);
}
void Host::RequestExit(bool save_state_if_running)
void Host::RequestExit(bool allow_confirm)
{
if (VMManager::HasValidVM())
g_emu_thread->shutdownVM(save_state_if_running);
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection);
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, allow_confirm));
}
void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool default_save_state)
@@ -1233,9 +1239,25 @@ void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool def
if (!VMManager::HasValidVM())
return;
// Run it on the host thread, that way we get the confirm prompt (if enabled).
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection, Q_ARG(bool, allow_confirm),
Q_ARG(bool, allow_save_state), Q_ARG(bool, default_save_state), Q_ARG(bool, false));
// This is a bit messy here - we want to shut down immediately (in case it was requested by the game),
// but we also need to exit-on-shutdown for batch mode. So, if we're running on the CPU thread, destroy
// the VM, then request the main window to exit.
if (allow_confirm || !g_emu_thread->isOnEmuThread())
{
// Run it on the host thread, that way we get the confirm prompt (if enabled).
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection, Q_ARG(bool, allow_confirm),
Q_ARG(bool, allow_save_state), Q_ARG(bool, default_save_state));
}
else
{
// Change state to stopping -> return -> shut down VM.
g_emu_thread->shutdownVM(allow_save_state && default_save_state);
// This will probably call shutdownVM() again, but by the time it runs, we'll have already shut down
// and it'll be a noop.
if (QtHost::InBatchMode())
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, false));
}
}
bool Host::IsFullscreen()
@@ -1543,7 +1565,7 @@ static void SignalHandler(int signal)
graceful_shutdown_attempted = true;
// This could be a bit risky invoking from a signal handler... hopefully it's okay.
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit, Qt::QueuedConnection);
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, false));
return;
}
@@ -1600,6 +1622,7 @@ void QtHost::PrintCommandLineHelp(const std::string_view& progname)
std::fprintf(stderr, " -nofullscreen: Prevents fullscreen mode from triggering if enabled.\n");
std::fprintf(stderr, " -earlyconsolelog: Forces logging of early console messages to console.\n");
std::fprintf(stderr, " -testconfig: Initializes configuration and checks version, then exits.\n");
std::fprintf(stderr, " -debugger: Open debugger and break on entry point.\n");
#ifdef ENABLE_RAINTEGRATION
std::fprintf(stderr, " -raintegration: Use RAIntegration instead of built-in achievement support.\n");
#endif
@@ -1722,6 +1745,11 @@ bool QtHost::ParseCommandLineOptions(const QStringList& args, std::shared_ptr<VM
s_test_config_and_exit = true;
continue;
}
else if (CHECK_ARG(QStringLiteral("-debugger")))
{
s_boot_and_debug = true;
continue;
}
#ifdef ENABLE_RAINTEGRATION
else if (CHECK_ARG(QStringLiteral("-raintegration")))
{
@@ -1812,8 +1840,6 @@ int main(int argc, char* argv[])
{
CrashHandler::Install();
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
RegisterTypes();
@@ -1861,6 +1887,12 @@ int main(int argc, char* argv[])
if (s_start_fullscreen_ui)
g_emu_thread->startFullscreenUI(s_start_fullscreen_ui_fullscreen);
if (s_boot_and_debug)
{
DebugInterface::setPauseOnEntry(true);
main_window->openDebugger();
}
// Skip the update check if we're booting a game directly.
if (autoboot)
g_emu_thread->startVM(std::move(autoboot));
+14 -14
View File
@@ -595,7 +595,7 @@ namespace SettingWidgetBinder
/// Binds a widget's value to a setting, updating it when the value changes.
template <typename WidgetType>
static void BindWidgetToBoolSetting(
static inline void BindWidgetToBoolSetting(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, bool default_value)
{
using Accessor = SettingAccessor<WidgetType>;
@@ -636,7 +636,7 @@ namespace SettingWidgetBinder
}
template <typename WidgetType>
static void BindWidgetToIntSetting(
static inline void BindWidgetToIntSetting(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, int default_value, int option_offset = 0)
{
using Accessor = SettingAccessor<WidgetType>;
@@ -677,7 +677,7 @@ namespace SettingWidgetBinder
}
template <typename WidgetType>
static void BindWidgetToFloatSetting(
static inline void BindWidgetToFloatSetting(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value)
{
using Accessor = SettingAccessor<WidgetType>;
@@ -718,7 +718,7 @@ namespace SettingWidgetBinder
}
template <typename WidgetType>
static void BindWidgetToNormalizedSetting(
static inline void BindWidgetToNormalizedSetting(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float range, float default_value)
{
using Accessor = SettingAccessor<WidgetType>;
@@ -759,7 +759,7 @@ namespace SettingWidgetBinder
}
template <typename WidgetType>
static void BindWidgetToStringSetting(
static inline void BindWidgetToStringSetting(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, std::string default_value = std::string())
{
using Accessor = SettingAccessor<WidgetType>;
@@ -804,7 +804,7 @@ namespace SettingWidgetBinder
}
template <typename WidgetType, typename DataType>
static void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
static inline void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
std::optional<DataType> (*from_string_function)(const char* str), const char* (*to_string_function)(DataType value),
DataType default_value)
{
@@ -866,7 +866,7 @@ namespace SettingWidgetBinder
}
template <typename WidgetType, typename DataType>
static void BindWidgetToEnumSetting(
static inline void BindWidgetToEnumSetting(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, const char** enum_names, DataType default_value)
{
using Accessor = SettingAccessor<WidgetType>;
@@ -928,7 +928,7 @@ namespace SettingWidgetBinder
}
template <typename WidgetType>
static void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
static inline void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
const char** enum_names, const char** enum_values, const char* default_value)
{
using Accessor = SettingAccessor<WidgetType>;
@@ -992,7 +992,7 @@ namespace SettingWidgetBinder
}
template <typename WidgetType>
static void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget, QAbstractButton* browse_button,
static inline void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget, QAbstractButton* browse_button,
QAbstractButton* open_button, QAbstractButton* reset_button, std::string section, std::string key, std::string default_value,
bool use_relative = true)
{
@@ -1068,7 +1068,7 @@ namespace SettingWidgetBinder
}
}
static void BindSliderToIntSetting(SettingsInterface* sif, QSlider* slider, QLabel* label, const QString& label_suffix,
static inline void BindSliderToIntSetting(SettingsInterface* sif, QSlider* slider, QLabel* label, const QString& label_suffix,
std::string section, std::string key, s32 default_value)
{
const s32 global_value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value);
@@ -1093,7 +1093,7 @@ namespace SettingWidgetBinder
[sif, slider, label, label_suffix, orig_font = std::move(orig_font), section, key, default_value](const QPoint& pt) {
QMenu menu(slider);
slider->connect(menu.addAction(qApp->translate("SettingWidgetBinder", "Reset")), &QAction::triggered, slider,
[sif, slider, label, label_suffix, orig_font, section, key, default_value]() {
[sif, label, label_suffix, orig_font, section, key, default_value]() {
const s32 global_value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value);
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix));
label->setFont(orig_font);
@@ -1109,8 +1109,8 @@ namespace SettingWidgetBinder
});
slider->connect(slider, &QSlider::valueChanged, slider,
[sif, label, label_suffix, section = std::move(section), key = std::move(key), default_value,
orig_font = std::move(orig_font), bold_font = std::move(bold_font)](int value) {
[sif, label, label_suffix, section = std::move(section), key = std::move(key), orig_font = std::move(orig_font),
bold_font = std::move(bold_font)](int value) {
label->setText(QStringLiteral("%1%2").arg(value).arg(label_suffix));
if (label->font() != bold_font)
@@ -1126,7 +1126,7 @@ namespace SettingWidgetBinder
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix));
slider->connect(slider, &QSlider::valueChanged, slider,
[sif, label, label_suffix, section = std::move(section), key = std::move(key), default_value](int value) {
[label, label_suffix, section = std::move(section), key = std::move(key)](int value) {
label->setText(QStringLiteral("%1%2").arg(value).arg(label_suffix));
Host::SetBaseIntSettingValue(section.c_str(), key.c_str(), value);
Host::CommitBaseSettingChanges();
@@ -105,14 +105,13 @@ void AchievementSettingsWidget::updateEnableState()
{
const bool enabled = m_dialog->getEffectiveBoolValue("Achievements", "Enabled", false);
const bool challenge = m_dialog->getEffectiveBoolValue("Achievements", "ChallengeMode", false);
const bool notifications = m_dialog->getEffectiveBoolValue("Achievements", "Notifications", true);
m_ui.testMode->setEnabled(enabled);
m_ui.unofficialTestMode->setEnabled(enabled);
m_ui.richPresence->setEnabled(enabled);
m_ui.challengeMode->setEnabled(enabled);
m_ui.leaderboards->setEnabled(enabled && challenge);
m_ui.notifications->setEnabled(enabled);
m_ui.soundEffects->setEnabled(enabled && notifications);
m_ui.soundEffects->setEnabled(enabled);
m_ui.primedIndicators->setEnabled(enabled);
}
@@ -37,6 +37,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeINTCSpinDetection, "EmuCore/Speedhacks", "IntcStat", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeWaitLoopDetection, "EmuCore/Speedhacks", "WaitLoop", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeFastmem, "EmuCore/CPU/Recompiler", "EnableFastmem", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnTLBMiss, "EmuCore/CPU/Recompiler", "PauseOnTLBMiss", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vu0Recompiler, "EmuCore/CPU/Recompiler", "EnableVU0", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vu1Recompiler, "EmuCore/CPU/Recompiler", "EnableVU1", true);
@@ -84,6 +85,11 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.eeFastmem, tr("Enable Fast Memory Access"), tr("Checked"),
tr("Uses backpatching to avoid register flushing on every memory access."));
dialog->registerWidgetHelp(m_ui.pauseOnTLBMiss, tr("Pause On TLB Miss"), tr("Unchecked"),
tr("Pauses the virtual machine when a TLB miss occurs, instead of ignoring it and continuing. Note the the VM will pause after the "
"end of the block, not on the instruction which caused the exception. Refer to the console to see the address where the invalid "
"access occurred."));
dialog->registerWidgetHelp(m_ui.vu0RoundingMode, tr("Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
dialog->registerWidgetHelp(m_ui.vu1RoundingMode, tr("Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
@@ -165,6 +165,13 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="pauseOnTLBMiss">
<property name="text">
<string>Pause On TLB Miss</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
+5 -8
View File
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -28,12 +28,11 @@
#include "SettingWidgetBinder.h"
#include "SettingsDialog.h"
static constexpr s32 DEFAULT_INTERPOLATION_MODE = 5;
static constexpr s32 DEFAULT_SYNCHRONIZATION_MODE = 0;
static constexpr s32 DEFAULT_EXPANSION_MODE = 0;
static constexpr s32 DEFAULT_DPL_DECODING_LEVEL = 0;
static const char* DEFAULT_OUTPUT_MODULE = "cubeb";
static constexpr s32 DEFAULT_TARGET_LATENCY = 100;
static constexpr s32 DEFAULT_TARGET_LATENCY = 60;
static constexpr s32 DEFAULT_OUTPUT_LATENCY = 20;
static constexpr s32 DEFAULT_VOLUME = 100;
static constexpr s32 DEFAULT_SOUNDTOUCH_SEQUENCE_LENGTH = 30;
@@ -60,7 +59,6 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
m_ui.setupUi(this);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.interpolation, "SPU2/Mixing", "Interpolation", DEFAULT_INTERPOLATION_MODE);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.syncMode, "SPU2/Output", "SynchMode", DEFAULT_SYNCHRONIZATION_MODE);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.expansionMode, "SPU2/Output", "SpeakerConfiguration", DEFAULT_EXPANSION_MODE);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.dplLevel, "SPU2/Output", "DplDecodingLevel", DEFAULT_DPL_DECODING_LEVEL);
@@ -110,9 +108,8 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
onMinimalOutputLatencyStateChanged();
updateLatencyLabels();
dialog->registerWidgetHelp(m_ui.interpolation, tr("Interpolation"), tr("Gaussian (PS2-like / great sound)"), tr(""));
dialog->registerWidgetHelp(m_ui.syncMode, tr("Synchronization"), tr("TimeStretch (Recommended)"), tr(""));
dialog->registerWidgetHelp(m_ui.syncMode, tr("Synchronization"), tr("TimeStretch (Recommended)"),
tr("When running outside of 100% speed, adjusts the tempo on audio instead of dropping frames. Produces much nicer fast forward/slowdown audio."));
dialog->registerWidgetHelp(m_ui.expansionMode, tr("Expansion"), tr("Stereo (None, Default)"), tr(""));
@@ -120,7 +117,7 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
dialog->registerWidgetHelp(m_ui.backend, tr("Output Backend"), tr("Default"), tr(""));
dialog->registerWidgetHelp(m_ui.targetLatency, tr("Target Latency"), tr("100 ms"),
dialog->registerWidgetHelp(m_ui.targetLatency, tr("Target Latency"), tr("60 ms"),
tr("Determines the buffer size which the time stretcher will try to keep filled. It effectively selects the average latency, as "
"audio will be stretched/shrunk to keep the buffer size within check."));
dialog->registerWidgetHelp(m_ui.outputLatency, tr("Output Latency"), tr("20 ms"),
+23 -52
View File
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>754</width>
<height>464</height>
<height>485</height>
</rect>
</property>
<property name="windowTitle">
@@ -49,6 +49,9 @@
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>30</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -63,7 +66,7 @@
<item>
<widget class="QLabel" name="sequenceLengthLabel">
<property name="text">
<string>100</string>
<string>30</string>
</property>
</widget>
</item>
@@ -86,6 +89,9 @@
<property name="maximum">
<number>30</number>
</property>
<property name="value">
<number>20</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -100,7 +106,7 @@
<item>
<widget class="QLabel" name="seekWindowSizeLabel">
<property name="text">
<string>100</string>
<string>20</string>
</property>
</widget>
</item>
@@ -123,6 +129,9 @@
<property name="maximum">
<number>15</number>
</property>
<property name="value">
<number>10</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -137,7 +146,7 @@
<item>
<widget class="QLabel" name="overlapLabel">
<property name="text">
<string>100</string>
<string>10</string>
</property>
</widget>
</item>
@@ -201,6 +210,9 @@
<property name="maximum">
<number>200</number>
</property>
<property name="value">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@@ -267,53 +279,12 @@
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Interpolation:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="interpolation">
<item>
<property name="text">
<string>Nearest (Fastest / worst quality)</string>
</property>
</item>
<item>
<property name="text">
<string>Linear (Simple / okay sound)</string>
</property>
</item>
<item>
<property name="text">
<string>Cubic (Fake highs / okay sound)</string>
</property>
</item>
<item>
<property name="text">
<string>Hermite (Better highs / okay sound)</string>
</property>
</item>
<item>
<property name="text">
<string>Catmull-Rom (PS2-like / good sound)</string>
</property>
</item>
<item>
<property name="text">
<string>Gaussian (PS2-like / great sound)</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Synchronization:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="0" column="1">
<widget class="QComboBox" name="syncMode">
<item>
<property name="text">
@@ -332,14 +303,14 @@
</item>
</widget>
</item>
<item row="2" column="0">
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Expansion:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="1" column="1">
<widget class="QComboBox" name="expansionMode">
<item>
<property name="text">
@@ -407,7 +378,7 @@
<number>200</number>
</property>
<property name="value">
<number>100</number>
<number>60</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -423,7 +394,7 @@
<item>
<widget class="QLabel" name="targetLatencyLabel">
<property name="text">
<string>100 ms</string>
<string>60 ms</string>
</property>
</widget>
</item>
@@ -466,7 +437,7 @@
<number>200</number>
</property>
<property name="value">
<number>100</number>
<number>20</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -482,7 +453,7 @@
<item>
<widget class="QLabel" name="outputLatencyLabel">
<property name="text">
<string>100 ms</string>
<string>20 ms</string>
</property>
</widget>
</item>
+47 -38
View File
@@ -42,10 +42,12 @@
ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
: QWidget(parent)
, m_dialog(dialog)
, m_config_section(StringUtil::StdStringFromFormat("Pad%u", port + 1u))
, m_config_section(fmt::format("Pad{}", port + 1))
, m_port_number(port)
{
m_ui.setupUi(this);
m_ui.groupBox->setTitle(tr("Controller Port %1").arg(port + 1));
populateControllerTypes();
onTypeChanged();
@@ -113,10 +115,9 @@ void ControllerBindingWidget::onTypeChanged()
if (has_settings)
{
const QString settings_title(tr("%1 Settings").arg(qApp->translate("PAD", cinfo->display_name)));
const gsl::span<const SettingInfo> settings(cinfo->settings, cinfo->num_settings);
m_settings_widget = new ControllerCustomSettingsWidget(
settings, m_config_section, std::string(), settings_title, cinfo->name, getDialog(), m_ui.stackedWidget);
m_settings_widget =
new ControllerCustomSettingsWidget(settings, m_config_section, std::string(), cinfo->name, getDialog(), m_ui.stackedWidget);
m_ui.stackedWidget->addWidget(m_settings_widget);
}
@@ -458,8 +459,7 @@ void ControllerMacroEditWidget::updateBinds()
//////////////////////////////////////////////////////////////////////////
ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(gsl::span<const SettingInfo> settings, std::string config_section,
std::string config_prefix, const QString& group_title, const char* translation_ctx, ControllerSettingsDialog* dialog,
QWidget* parent_widget)
std::string config_prefix, const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget)
: QWidget(parent_widget)
, m_settings(settings)
, m_config_section(std::move(config_section))
@@ -469,22 +469,19 @@ ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(gsl::span<const S
if (settings.empty())
return;
QGroupBox* gbox = new QGroupBox(group_title, this);
QGridLayout* gbox_layout = new QGridLayout(gbox);
createSettingWidgets(translation_ctx, gbox, gbox_layout);
QScrollArea* sarea = new QScrollArea(this);
QWidget* swidget = new QWidget(sarea);
sarea->setWidget(swidget);
sarea->setWidgetResizable(true);
sarea->setFrameShape(QFrame::StyledPanel);
sarea->setFrameShadow(QFrame::Sunken);
QGridLayout* swidget_layout = new QGridLayout(swidget);
createSettingWidgets(translation_ctx, swidget, swidget_layout);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(gbox);
QHBoxLayout* bottom_hlayout = new QHBoxLayout();
QPushButton* restore_defaults = new QPushButton(tr("Restore Default Settings"), this);
restore_defaults->setIcon(QIcon::fromTheme(QStringLiteral("restart-line")));
connect(restore_defaults, &QPushButton::clicked, this, &ControllerCustomSettingsWidget::restoreDefaults);
bottom_hlayout->addStretch(1);
bottom_hlayout->addWidget(restore_defaults);
layout->addLayout(bottom_hlayout);
layout->addStretch(1);
layout->addWidget(sarea);
}
ControllerCustomSettingsWidget::~ControllerCustomSettingsWidget() = default;
@@ -503,8 +500,6 @@ static std::tuple<QString, QString> getPrefixAndSuffixForIntFormat(const QString
return std::tie(prefix, suffix);
}
#if 0
// Unused until we handle multiplier below.
static std::tuple<QString, QString, int> getPrefixAndSuffixForFloatFormat(const QString& format)
{
QString prefix, suffix;
@@ -532,7 +527,6 @@ static std::tuple<QString, QString, int> getPrefixAndSuffixForFloatFormat(const
return std::tie(prefix, suffix, decimals);
}
#endif
void ControllerCustomSettingsWidget::createSettingWidgets(const char* translation_ctx, QWidget* widget_parent, QGridLayout* layout)
{
@@ -569,7 +563,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
sb->setPrefix(prefix);
sb->setSuffix(suffix);
}
SettingWidgetBinder::BindWidgetToIntSetting(sif, sb, m_config_section, std::move(key_name), si.IntegerDefaultValue());
ControllerSettingWidgetBinder::BindWidgetToInputProfileInt(
sif, sb, m_config_section, std::move(key_name), si.IntegerDefaultValue());
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
layout->addWidget(sb, current_row, 1, 1, 3);
current_row++;
@@ -582,7 +577,7 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
cb->setObjectName(QString::fromUtf8(si.name));
for (u32 i = 0; si.options[i] != nullptr; i++)
cb->addItem(qApp->translate(translation_ctx, si.options[i]));
SettingWidgetBinder::BindWidgetToIntSetting(
ControllerSettingWidgetBinder::BindWidgetToInputProfileInt(
sif, cb, m_config_section, std::move(key_name), si.IntegerDefaultValue(), si.IntegerMinValue());
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
layout->addWidget(cb, current_row, 1, 1, 3);
@@ -594,11 +589,10 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
{
QDoubleSpinBox* sb = new QDoubleSpinBox(widget_parent);
sb->setObjectName(QString::fromUtf8(si.name));
sb->setMinimum(si.FloatMinValue());
sb->setMaximum(si.FloatMaxValue());
sb->setSingleStep(si.FloatStepValue());
#if 0
// We can't use this until we handle multiplier.
sb->setMinimum(si.FloatMinValue() * si.multiplier);
sb->setMaximum(si.FloatMaxValue() * si.multiplier);
sb->setSingleStep(si.FloatStepValue() * si.multiplier);
if (si.format)
{
const auto [prefix, suffix, decimals] = getPrefixAndSuffixForFloatFormat(QString::fromUtf8(si.format));
@@ -607,8 +601,9 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
sb->setDecimals(decimals);
sb->setSuffix(suffix);
}
#endif
SettingWidgetBinder::BindWidgetToFloatSetting(sif, sb, m_config_section, std::move(key_name), si.FloatDefaultValue());
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(
sif, sb, m_config_section, std::move(key_name), si.FloatDefaultValue(), si.multiplier);
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
layout->addWidget(sb, current_row, 1, 1, 3);
current_row++;
@@ -619,7 +614,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
{
QLineEdit* le = new QLineEdit(widget_parent);
le->setObjectName(QString::fromUtf8(si.name));
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
layout->addWidget(le, current_row, 1, 1, 3);
current_row++;
@@ -641,7 +637,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
for (u32 i = 0; si.options[i] != nullptr; i++)
cb->addItem(qApp->translate(translation_ctx, si.options[i]), QString::fromUtf8(si.options[i]));
}
SettingWidgetBinder::BindWidgetToStringSetting(sif, cb, m_config_section, std::move(key_name), si.StringDefaultValue());
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
sif, cb, m_config_section, std::move(key_name), si.StringDefaultValue());
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
layout->addWidget(cb, current_row, 1, 1, 3);
current_row++;
@@ -653,7 +650,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
QLineEdit* le = new QLineEdit(widget_parent);
le->setObjectName(QString::fromUtf8(si.name));
QPushButton* browse_button = new QPushButton(tr("Browse..."), widget_parent);
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
connect(browse_button, &QPushButton::clicked, [this, le]() {
const QString path(QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Select File"))));
if (!path.isEmpty())
@@ -677,6 +675,16 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
layout->addItem(new QSpacerItem(1, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), current_row++, 0, 1, 4);
}
QHBoxLayout* bottom_hlayout = new QHBoxLayout();
QPushButton* restore_defaults = new QPushButton(tr("Restore Default Settings"), this);
restore_defaults->setIcon(QIcon::fromTheme(QStringLiteral("restart-line")));
connect(restore_defaults, &QPushButton::clicked, this, &ControllerCustomSettingsWidget::restoreDefaults);
bottom_hlayout->addStretch(1);
bottom_hlayout->addWidget(restore_defaults);
layout->addLayout(bottom_hlayout, current_row++, 0, 1, 4);
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding), current_row++, 0, 1, 4);
}
void ControllerCustomSettingsWidget::restoreDefaults()
@@ -715,7 +723,7 @@ void ControllerCustomSettingsWidget::restoreDefaults()
{
QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QString::fromStdString(si.name));
if (widget)
widget->setValue(si.FloatDefaultValue());
widget->setValue(si.FloatDefaultValue() * si.multiplier);
}
break;
@@ -851,10 +859,12 @@ ControllerBindingWidget_Base* ControllerBindingWidget_DualShock2::createInstance
USBDeviceWidget::USBDeviceWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
: QWidget(parent)
, m_dialog(dialog)
, m_config_section(StringUtil::StdStringFromFormat("USB%u", port + 1u))
, m_config_section(fmt::format("USB{}", port + 1))
, m_port_number(port)
{
m_ui.setupUi(this);
m_ui.groupBox->setTitle(tr("USB Port %1").arg(port + 1));
populateDeviceTypes();
populatePages();
@@ -926,9 +936,8 @@ void USBDeviceWidget::populatePages()
if (!settings.empty())
{
const QString settings_title(tr("Device Settings"));
m_settings_widget = new ControllerCustomSettingsWidget(
settings, m_config_section, m_device_type + "_", settings_title, m_device_type.c_str(), m_dialog, m_ui.stackedWidget);
settings, m_config_section, m_device_type + "_", m_device_type.c_str(), m_dialog, m_ui.stackedWidget);
m_ui.stackedWidget->addWidget(m_settings_widget);
}
+1 -1
View File
@@ -139,7 +139,7 @@ class ControllerCustomSettingsWidget : public QWidget
public:
ControllerCustomSettingsWidget(gsl::span<const SettingInfo> settings, std::string config_section, std::string config_prefix,
const QString& group_title, const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget);
const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget);
~ControllerCustomSettingsWidget();
private Q_SLOTS:
@@ -22,6 +22,10 @@
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
#ifdef SDL_BUILD
#include "pcsx2/Frontend/SDLInputSource.h"
#endif
ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent, ControllerSettingsDialog* dialog)
: QWidget(parent)
, m_dialog(dialog)
@@ -30,8 +34,16 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
SettingsInterface* sif = dialog->getProfileSettingsInterface();
#ifdef SDL_BUILD
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", false);
connect(m_ui.enableSDLSource, &QCheckBox::stateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
connect(m_ui.ledSettings, &QToolButton::clicked, this, &ControllerGlobalSettingsWidget::ledSettingsClicked);
#else
m_ui.enableSDLSource->setEnabled(false);
m_ui.ledSettings->setEnabled(false);
#endif
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableMouseMapping, "UI", "EnableMouseMapping", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.multitapPort1, "Pad", "MultitapPort1", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.multitapPort2, "Pad", "MultitapPort2", false);
@@ -66,12 +78,13 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
m_ui.profileSettings = nullptr;
}
connect(m_ui.enableSDLSource, &QCheckBox::stateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
for (QCheckBox* cb : {m_ui.multitapPort1, m_ui.multitapPort2})
connect(cb, &QCheckBox::stateChanged, this, [this]() { emit bindingSetupChanged(); });
connect(m_ui.pointerXScale, &QSlider::valueChanged, this, [this](int value) { m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(value)); });
connect(m_ui.pointerYScale, &QSlider::valueChanged, this, [this](int value) { m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(value)); });
connect(m_ui.pointerXScale, &QSlider::valueChanged, this,
[this](int value) { m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(value)); });
connect(m_ui.pointerYScale, &QSlider::valueChanged, this,
[this](int value) { m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(value)); });
m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerXScale->value()));
m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerYScale->value()));
@@ -106,4 +119,40 @@ void ControllerGlobalSettingsWidget::updateSDLOptionsEnabled()
{
const bool enabled = m_ui.enableSDLSource->isChecked();
m_ui.enableSDLEnhancedMode->setEnabled(enabled);
m_ui.ledSettings->setEnabled(enabled);
}
void ControllerGlobalSettingsWidget::ledSettingsClicked()
{
ControllerLEDSettingsDialog dialog(this, m_dialog);
dialog.exec();
}
ControllerLEDSettingsDialog::ControllerLEDSettingsDialog(QWidget* parent, ControllerSettingsDialog* dialog)
: QDialog(parent)
, m_dialog(dialog)
{
m_ui.setupUi(this);
linkButton(m_ui.SDL0LED, 0);
linkButton(m_ui.SDL1LED, 1);
linkButton(m_ui.SDL2LED, 2);
linkButton(m_ui.SDL3LED, 3);
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
}
ControllerLEDSettingsDialog::~ControllerLEDSettingsDialog() = default;
void ControllerLEDSettingsDialog::linkButton(ColorPickerButton* button, u32 player_id)
{
#ifdef SDL_BUILD
std::string key(fmt::format("Player{}LED", player_id));
const u32 current_value = SDLInputSource::ParseRGBForPlayerId(m_dialog->getStringValue("SDLExtra", key.c_str(), ""), player_id);
button->setColor(current_value);
connect(button, &ColorPickerButton::colorChanged, this, [this, key = std::move(key)](u32 new_rgb) {
m_dialog->setStringValue("SDLExtra", key.c_str(), fmt::format("{:06X}", new_rgb).c_str());
});
#endif
}
@@ -20,7 +20,10 @@
#include <array>
#include <vector>
#include "ColorPickerButton.h"
#include "ui_ControllerGlobalSettingsWidget.h"
#include "ui_ControllerLEDSettingsDialog.h"
class ControllerSettingsDialog;
@@ -38,9 +41,26 @@ public:
Q_SIGNALS:
void bindingSetupChanged();
private:
private Q_SLOTS:
void updateSDLOptionsEnabled();
void ledSettingsClicked();
private:
Ui::ControllerGlobalSettingsWidget m_ui;
ControllerSettingsDialog* m_dialog;
};
class ControllerLEDSettingsDialog : public QDialog
{
Q_OBJECT
public:
ControllerLEDSettingsDialog(QWidget* parent, ControllerSettingsDialog* dialog);
~ControllerLEDSettingsDialog();
private:
void linkButton(ColorPickerButton* button, u32 player_id);
Ui::ControllerLEDSettingsDialog m_ui;
ControllerSettingsDialog* m_dialog;
};
@@ -50,11 +50,27 @@
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="enableSDLEnhancedMode">
<property name="text">
<string>DualShock 4 / DualSense Enhanced Mode</string>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="enableSDLEnhancedMode">
<property name="text">
<string>DualShock 4 / DualSense Enhanced Mode</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="ledSettings">
<property name="toolTip">
<string>Controller LED Settings</string>
</property>
<property name="icon">
<iconset theme="lightbulb-line">
<normaloff>.</normaloff>.
</iconset>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ControllerLEDSettingsDialog</class>
<widget class="QDialog" name="ControllerLEDSettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>501</width>
<height>108</height>
</rect>
</property>
<property name="windowTitle">
<string>Controller LED Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>SDL-0 LED</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="ColorPickerButton" name="SDL0LED"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>SDL-1 LED</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="ColorPickerButton" name="SDL1LED"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="2">
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>SDL-2 LED</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="ColorPickerButton" name="SDL2LED"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="3">
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>SDL-3 LED</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="ColorPickerButton" name="SDL3LED"/>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ColorPickerButton</class>
<extends>QPushButton</extends>
<header>ColorPickerButton.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -38,7 +38,8 @@ namespace ControllerSettingWidgetBinder
{
/// Interface specific method of BindWidgetToBoolSetting().
template <typename WidgetType>
static void BindWidgetToInputProfileBool(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, bool default_value)
static inline void BindWidgetToInputProfileBool(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, bool default_value)
{
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
@@ -68,19 +69,53 @@ namespace ControllerSettingWidgetBinder
}
}
/// Interface specific method of BindWidgetToIntSetting().
template <typename WidgetType>
static inline void BindWidgetToInputProfileInt(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, s32 default_value, s32 option_offset = 0)
{
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
if (sif)
{
const s32 value = sif->GetIntValue(section.c_str(), key.c_str(), default_value);
Accessor::setIntValue(widget, value - option_offset);
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key), option_offset]() {
const float new_value = Accessor::getIntValue(widget);
sif->SetIntValue(section.c_str(), key.c_str(), new_value + option_offset);
sif->Save();
g_emu_thread->reloadGameSettings();
});
}
else
{
const s32 value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value);
Accessor::setIntValue(widget, value - option_offset);
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), option_offset]() {
const s32 new_value = Accessor::getIntValue(widget);
Host::SetBaseIntSettingValue(section.c_str(), key.c_str(), new_value + option_offset);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
});
}
}
/// Interface specific method of BindWidgetToFloatSetting().
template <typename WidgetType>
static void BindWidgetToInputProfileFloat(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value)
static inline void BindWidgetToInputProfileFloat(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value, float multiplier = 1.0f)
{
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
if (sif)
{
const float value = sif->GetFloatValue(section.c_str(), key.c_str(), default_value);
Accessor::setFloatValue(widget, value);
Accessor::setFloatValue(widget, value * multiplier);
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key)]() {
const float new_value = Accessor::getFloatValue(widget);
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key), multiplier]() {
const float new_value = Accessor::getFloatValue(widget) / multiplier;
sif->SetFloatValue(section.c_str(), key.c_str(), new_value);
sif->Save();
g_emu_thread->reloadGameSettings();
@@ -89,10 +124,10 @@ namespace ControllerSettingWidgetBinder
else
{
const float value = Host::GetBaseFloatSettingValue(section.c_str(), key.c_str(), default_value);
Accessor::setFloatValue(widget, value);
Accessor::setFloatValue(widget, value * multiplier);
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
const float new_value = Accessor::getFloatValue(widget);
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), multiplier]() {
const float new_value = Accessor::getFloatValue(widget) / multiplier;
Host::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
@@ -102,12 +137,11 @@ namespace ControllerSettingWidgetBinder
/// Interface specific method of BindWidgetToNormalizedSetting().
template <typename WidgetType>
static void BindWidgetToInputProfileNormalized(
static inline void BindWidgetToInputProfileNormalized(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float range, float default_value)
{
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
if (sif)
{
const float value = sif->GetFloatValue(section.c_str(), key.c_str(), default_value);
@@ -136,7 +170,7 @@ namespace ControllerSettingWidgetBinder
/// Interface specific method of BindWidgetToStringSetting().
template <typename WidgetType>
static void BindWidgetToInputProfileString(
static inline void BindWidgetToInputProfileString(
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, std::string default_value = std::string())
{
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
@@ -160,7 +194,8 @@ namespace ControllerSettingWidgetBinder
}
else
{
const QString value(QString::fromStdString(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str())));
const QString value(
QString::fromStdString(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str())));
Accessor::setStringValue(widget, value);
@@ -447,7 +447,7 @@ void ControllerSettingsDialog::updateListDescription(u32 global_slot, Controller
{
QListWidgetItem* item = m_ui.settingsCategory->item(i);
const QVariant data(item->data(Qt::UserRole));
if (data.type() == QVariant::UInt && data.toUInt() == global_slot)
if (data.metaType().id() == QMetaType::UInt && data.toUInt() == global_slot)
{
const auto [port, slot] = sioConvertPadToPortAndSlot(global_slot);
const bool mtap_enabled = getBoolValue("Pad", (port == 0) ? "MultitapPort1" : "MultitapPort2", false);
@@ -469,7 +469,7 @@ void ControllerSettingsDialog::updateListDescription(u32 port, USBDeviceWidget*
{
QListWidgetItem* item = m_ui.settingsCategory->item(i);
const QVariant data(item->data(Qt::UserRole));
if (data.type() == QVariant::UInt && data.toUInt() == (MAX_PORTS + port))
if (data.metaType().id() == QMetaType::UInt && data.toUInt() == (MAX_PORTS + port))
{
const std::string dtype(getStringValue(fmt::format("USB{}", port + 1).c_str(), "Type", "None"));
const QString display_name(qApp->translate("USB", USB::GetDeviceName(dtype)));
+71 -25
View File
@@ -260,9 +260,13 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsDialog* dialog, QWidget* parent)
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hddEnabled, "DEV9/Hdd", "HddEnable", false);
connect(m_ui.hddFile, &QLineEdit::editingFinished, this, &DEV9SettingsWidget::onHddFileEdit);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.hddFile, "DEV9/Hdd", "HddFile", "DEV9hdd.raw");
if (m_dialog->isPerGameSettings())
{
m_ui.hddFile->setText(QString::fromUtf8(m_dialog->getStringValue("DEV9/Hdd", "HddFile", "").value().c_str()));
m_ui.hddFile->setPlaceholderText(QString::fromUtf8(Host::GetBaseStringSettingValue("DEV9/Hdd", "HddFile", "DEV9hdd.raw")));
}
else
m_ui.hddFile->setText(QString::fromUtf8(m_dialog->getStringValue("DEV9/Hdd", "HddFile", "DEV9hdd.raw").value().c_str()));
connect(m_ui.hddBrowseFile, &QPushButton::clicked, this, &DEV9SettingsWidget::onHddBrowseFileClicked);
//TODO: need a getUintValue for if 48bit support occurs
@@ -270,18 +274,27 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsDialog* dialog, QWidget* parent)
if (m_dialog->isPerGameSettings())
{
std::optional<int> sizeOpt = std::nullopt;
if (size > 0)
sizeOpt = size;
const int sizeGlobal = (u64)Host::GetBaseIntSettingValue("DEV9/Hdd", "HddSizeSectors", 0) * 512 / (1024 * 1024 * 1024);
m_ui.hddSizeSpinBox->setMinimum(39);
m_ui.hddSizeSpinBox->setSpecialValueText(tr("Global [%1]").arg(sizeGlobal));
SettingWidgetBinder::SettingAccessor<QSpinBox>::makeNullableInt(m_ui.hddSizeSpinBox, sizeGlobal);
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, sizeOpt);
m_ui.hddSizeSlider->setValue(sizeOpt.value_or(sizeGlobal));
m_ui.hddSizeSlider->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_ui.hddSizeSlider, &QSlider::customContextMenuRequested, this, &DEV9SettingsWidget::onHddSizeSliderContext);
}
else
{
m_ui.hddSizeSlider->setValue(size);
SettingWidgetBinder::SettingAccessor<QSpinBox>::setIntValue(m_ui.hddSizeSpinBox, size);
}
// clang-format off
m_ui.hddSizeSlider ->setValue(size);
m_ui.hddSizeSpinBox->setValue(size);
connect(m_ui.hddSizeSlider, QOverload<int>::of(&QSlider ::valueChanged), this, &DEV9SettingsWidget::onHddSizeSlide);
connect(m_ui.hddSizeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &DEV9SettingsWidget::onHddSizeSpin );
// clang-format on
connect(m_ui.hddSizeSlider, QOverload<int>::of(&QSlider::valueChanged), this, &DEV9SettingsWidget::onHddSizeSlide);
SettingWidgetBinder::SettingAccessor<QSpinBox>::connectValueChanged(m_ui.hddSizeSpinBox, [&]() { onHddSizeAccessorSpin(); });
connect(m_ui.hddCreate, &QPushButton::clicked, this, &DEV9SettingsWidget::onHddCreateClicked);
}
@@ -682,7 +695,7 @@ void DEV9SettingsWidget::onEthHostEdit(QStandardItem* item)
void DEV9SettingsWidget::onHddEnabledChanged(int state)
{
const bool enabled = state == Qt::CheckState::PartiallyChecked ? m_dialog->getEffectiveBoolValue("DEV9/Hdd", "HddEnable", false) : state;
const bool enabled = state == Qt::CheckState::PartiallyChecked ? Host::GetBaseBoolSettingValue("DEV9/Hdd", "HddEnable", false) : state;
m_ui.hddFile->setEnabled(enabled);
m_ui.hddFileLabel->setEnabled(enabled);
@@ -699,8 +712,8 @@ void DEV9SettingsWidget::onHddBrowseFileClicked()
{
QString path =
QDir::toNativeSeparators(QFileDialog::getSaveFileName(QtUtils::GetRootWidget(this), tr("HDD Image File"),
!m_ui.hddFile->text().isEmpty() ? m_ui.hddFile->text() : "DEV9hdd.raw", tr("HDD (*.raw)"), nullptr,
QFileDialog::DontConfirmOverwrite));
!m_ui.hddFile->text().isEmpty() ? m_ui.hddFile->text() : (!m_ui.hddFile->placeholderText().isEmpty() ? m_ui.hddFile->placeholderText() : "DEV9hdd.raw"),
tr("HDD (*.raw)"), nullptr, QFileDialog::DontConfirmOverwrite));
if (path.isEmpty())
return;
@@ -711,10 +724,16 @@ void DEV9SettingsWidget::onHddBrowseFileClicked()
void DEV9SettingsWidget::onHddFileEdit()
{
//Check if file exists, if so set HddSize to correct value
// Check if file exists, if so set HddSize to correct value.
// Also save the hddPath setting
std::string hddPath(m_ui.hddFile->text().toStdString());
if (hddPath.empty())
{
m_dialog->setStringSettingValue("DEV9/Hdd", "HddFile", std::nullopt);
return;
}
else
m_dialog->setStringSettingValue("DEV9/Hdd", "HddFile", hddPath.c_str());
if (!Path::IsAbsolute(hddPath))
hddPath = Path::Combine(EmuFolders::Settings, hddPath);
@@ -739,22 +758,49 @@ void DEV9SettingsWidget::onHddFileEdit()
void DEV9SettingsWidget::onHddSizeSlide(int i)
{
// We have to call onHddSizeAccessorSpin() ourself, as the value could still be considered null when the valueChanged signal is fired
QSignalBlocker sb(m_ui.hddSizeSpinBox);
m_ui.hddSizeSpinBox->setValue(i);
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", (int)((s64)i * 1024 * 1024 * 1024 / 512));
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, i);
onHddSizeAccessorSpin();
}
void DEV9SettingsWidget::onHddSizeSpin(int i)
void DEV9SettingsWidget::onHddSizeSliderContext(const QPoint& pt)
{
QSignalBlocker sb(m_ui.hddSizeSlider);
m_ui.hddSizeSlider->setValue(i);
QMenu menu(m_ui.hddSizeSlider);
connect(menu.addAction(qApp->translate("SettingWidgetBinder", "Reset")), &QAction::triggered, this, &DEV9SettingsWidget::onHddSizeSliderReset);
menu.exec(m_ui.hddSizeSlider->mapToGlobal(pt));
}
//TODO: need a setUintSettingValue for if 48bit support occurs
if (i == 39)
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", std::nullopt);
void DEV9SettingsWidget::onHddSizeSliderReset([[maybe_unused]] bool checked)
{
// We have to call onHddSizeAccessorSpin() ourself, as the value could still be considered non-null when the valueChanged signal is fired
QSignalBlocker sb(m_ui.hddSizeSpinBox);
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, std::nullopt);
onHddSizeAccessorSpin();
}
void DEV9SettingsWidget::onHddSizeAccessorSpin()
{
//TODO: need a getUintValue for if 48bit support occurs
QSignalBlocker sb(m_ui.hddSizeSlider);
if (m_dialog->isPerGameSettings())
{
std::optional<int> new_value = SettingWidgetBinder::SettingAccessor<QSpinBox>::getNullableIntValue(m_ui.hddSizeSpinBox);
const int sizeGlobal = (u64)Host::GetBaseIntSettingValue("DEV9/Hdd", "HddSizeSectors", 0) * 512 / (1024 * 1024 * 1024);
m_ui.hddSizeSlider->setValue(new_value.value_or(sizeGlobal));
if (new_value.has_value())
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", new_value.value() * (1024 * 1024 * 1024 / 512));
else
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", std::nullopt);
}
else
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", i * (1024 * 1024 * 1024 / 512));
{
const int new_value = SettingWidgetBinder::SettingAccessor<QSpinBox>::getIntValue(m_ui.hddSizeSpinBox);
m_ui.hddSizeSlider->setValue(new_value);
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", new_value * (1024 * 1024 * 1024 / 512));
}
}
void DEV9SettingsWidget::onHddCreateClicked()
@@ -774,7 +820,7 @@ void DEV9SettingsWidget::onHddCreateClicked()
if (!Path::IsAbsolute(hddPath))
hddPath = Path::Combine(EmuFolders::Settings, hddPath);
if (!FileSystem::FileExists(hddPath.c_str()))
if (FileSystem::FileExists(hddPath.c_str()))
{
//GHC uses UTF8 on all platforms
QMessageBox::StandardButton selection =
+5 -1
View File
@@ -49,7 +49,11 @@ private Q_SLOTS:
void onHddBrowseFileClicked();
void onHddFileEdit();
void onHddSizeSlide(int i);
void onHddSizeSpin(int i);
// Per game only.
void onHddSizeSliderContext(const QPoint& pt);
void onHddSizeSliderReset(bool checked = false);
//
void onHddSizeAccessorSpin();
void onHddCreateClicked();
public:
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -100,9 +100,12 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget
dialog->registerWidgetHelp(m_ui.eeCycleRate, tr("Cycle Rate"), tr("100% (Normal Speed)"),
tr("Higher values may increase internal framerate in games, but will increase CPU requirements substantially. "
"Lower values will reduce the CPU load allowing lightweight games to run full speed on weaker CPUs."));
dialog->registerWidgetHelp(m_ui.eeCycleSkipping, tr("Cycle Skip"), tr("None"),
dialog->registerWidgetHelp(m_ui.eeCycleSkipping, tr("Cycle Skip"), tr("Disabled"),
tr("Makes the emulated Emotion Engine skip cycles. "
"Helps a small subset of games like SOTC. Most of the time it's harmful to performance."));
dialog->registerWidgetHelp(m_ui.affinityControl, tr("Affinity Control"), tr("Disabled"),
tr("Sets the priority for specific threads in a specific order ignoring the system scheduler. "
"May help CPUs with big (P) and little (E) cores (e.g. Intel 12th or newer generation CPUs from Intel or other vendors such as AMD)"));
dialog->registerWidgetHelp(m_ui.MTVU, tr("MTVU (Multi-threaded VU1)"), tr("Checked"),
tr("Generally a speedup on CPUs with 3 or more threads. "
"Safe for most games, but a few are incompatible and may hang."));
+5
View File
@@ -346,6 +346,11 @@
<string>In-Game</string>
</property>
</item>
<item>
<property name="text">
<string>Playable</string>
</property>
</item>
<item>
<property name="text">
<string>Perfect</string>
+200 -107
View File
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -97,7 +97,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.fmvAspectRatio, "EmuCore/GS", "FMVAspectRatioSwitch",
Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames, FMVAspectRatioSwitchType::Off);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.interlacing, "EmuCore/GS", "deinterlace_mode", DEFAULT_INTERLACE_MODE);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.bilinearFiltering, "EmuCore/GS", "linear_present_mode", static_cast<int>(GSPostBilinearMode::BilinearSmooth));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.bilinearFiltering, "EmuCore/GS", "linear_present_mode", static_cast<int>(GSPostBilinearMode::BilinearSmooth));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.widescreenPatches, "EmuCore", "EnableWideScreenPatches", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.noInterlacingPatches, "EmuCore", "EnableNoInterlacingPatches", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.integerScaling, "EmuCore/GS", "IntegerScaling", false);
@@ -105,8 +106,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCOverscan, "EmuCore/GS", "pcrtc_overscan", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCAntiBlur, "EmuCore/GS", "pcrtc_antiblur", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.DisableInterlaceOffset, "EmuCore/GS", "disable_interlace_offset", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotSize, "EmuCore/GS", "ScreenshotSize", static_cast<int>(GSScreenshotSize::WindowResolution));
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotFormat, "EmuCore/GS", "ScreenshotFormat", static_cast<int>(GSScreenshotFormat::PNG));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.screenshotSize, "EmuCore/GS", "ScreenshotSize", static_cast<int>(GSScreenshotSize::WindowResolution));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.screenshotFormat, "EmuCore/GS", "ScreenshotFormat", static_cast<int>(GSScreenshotFormat::PNG));
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotQuality, "EmuCore/GS", "ScreenshotQuality", 50);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.stretchY, "EmuCore/GS", "StretchY", 100.0f);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropLeft, "EmuCore/GS", "CropLeft", 0);
@@ -114,7 +117,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropRight, "EmuCore/GS", "CropRight", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropBottom, "EmuCore/GS", "CropBottom", 0);
connect(m_ui.fullscreenModes, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onFullscreenModeChanged);
connect(
m_ui.fullscreenModes, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onFullscreenModeChanged);
//////////////////////////////////////////////////////////////////////////
// OSD Settings
@@ -147,55 +151,33 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
//////////////////////////////////////////////////////////////////////////
// HW Settings
//////////////////////////////////////////////////////////////////////////
static const char* upscale_entries[] = {
"Native (PS2) (Default)",
"1.25x Native",
"1.5x Native",
"1.75x Native",
"2x Native (~720p)",
"2.25x Native",
"2.5x Native",
"2.75x Native",
"3x Native (~1080p)",
"3.5x Native",
"4x Native (~1440p/2K)",
"5x Native (~1620p)",
"6x Native (~2160p/4K)",
"7x Native (~2520p)",
"8x Native (~2880p/5K)",
nullptr};
static const char* upscale_entries[] = {"Native (PS2) (Default)", "1.25x Native", "1.5x Native", "1.75x Native", "2x Native (~720p)",
"2.25x Native", "2.5x Native", "2.75x Native", "3x Native (~1080p)", "3.5x Native", "4x Native (~1440p/2K)", "5x Native (~1620p)",
"6x Native (~2160p/4K)", "7x Native (~2520p)", "8x Native (~2880p/5K)", nullptr};
static const char* upscale_values[] = {
"1",
"1.25",
"1.5",
"1.75",
"2",
"2.25",
"2.5",
"2.75",
"3",
"3.5",
"4",
"5",
"6",
"7",
"8",
nullptr };
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.upscaleMultiplier, "EmuCore/GS", "upscale_multiplier", upscale_entries, upscale_values, "1.0");
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureFiltering, "EmuCore/GS", "filter", static_cast<int>(BiFiltering::PS2));
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.trilinearFiltering, "EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic), -1);
"1", "1.25", "1.5", "1.75", "2", "2.25", "2.5", "2.75", "3", "3.5", "4", "5", "6", "7", "8", nullptr};
SettingWidgetBinder::BindWidgetToEnumSetting(
sif, m_ui.anisotropicFiltering, "EmuCore/GS", "MaxAnisotropy", s_anisotropic_filtering_entries, s_anisotropic_filtering_values, "0");
sif, m_ui.upscaleMultiplier, "EmuCore/GS", "upscale_multiplier", upscale_entries, upscale_values, "1.0");
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureFiltering, "EmuCore/GS", "filter", static_cast<int>(BiFiltering::PS2));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.trilinearFiltering, "EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic), -1);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.anisotropicFiltering, "EmuCore/GS", "MaxAnisotropy",
s_anisotropic_filtering_entries, s_anisotropic_filtering_values, "0");
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.dithering, "EmuCore/GS", "dithering_ps2", 2);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.mipmapping, "EmuCore/GS", "mipmap_hw", static_cast<int>(HWMipmapLevel::Automatic), -1);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), -1);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.mipmapping, "EmuCore/GS", "mipmap_hw", static_cast<int>(HWMipmapLevel::Automatic), -1);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), -1);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading",
static_cast<int>(TexturePreloadingLevel::Off));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading", static_cast<int>(TexturePreloadingLevel::Off));
connect(m_ui.trilinearFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onTrilinearFilteringChanged);
connect(m_ui.gpuPaletteConversion, QOverload<int>::of(&QCheckBox::stateChanged), this, &GraphicsSettingsWidget::onGpuPaletteConversionChanged);
connect(m_ui.trilinearFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&GraphicsSettingsWidget::onTrilinearFilteringChanged);
connect(m_ui.gpuPaletteConversion, QOverload<int>::of(&QCheckBox::stateChanged), this,
&GraphicsSettingsWidget::onGpuPaletteConversionChanged);
onTrilinearFilteringChanged();
onGpuPaletteConversionChanged(m_ui.gpuPaletteConversion->checkState());
@@ -205,6 +187,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.halfScreenFix, "EmuCore/GS", "UserHacks_Half_Bottom_Override", -1, -1);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuSpriteRenderBW, "EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuCLUTRender, "EmuCore/GS", "UserHacks_CPUCLUTRender", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gpuTargetCLUTMode, "EmuCore/GS", "UserHacks_GPUTargetCLUTMode", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawStart, "EmuCore/GS", "UserHacks_SkipDraw_Start", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawEnd, "EmuCore/GS", "UserHacks_SkipDraw_End", 0);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hwAutoFlush, "EmuCore/GS", "UserHacks_AutoFlush", false);
@@ -212,7 +195,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDepthEmulation, "EmuCore/GS", "UserHacks_DisableDepthSupport", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableSafeFeatures, "EmuCore/GS", "UserHacks_Disable_Safe_Features", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.preloadFrameData, "EmuCore/GS", "preload_frame_with_gs_data", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disablePartialInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
SettingWidgetBinder::BindWidgetToBoolSetting(
sif, m_ui.disablePartialInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.textureInsideRt, "EmuCore/GS", "UserHacks_TextureInsideRt", false);
//////////////////////////////////////////////////////////////////////////
@@ -233,7 +217,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.dumpReplaceableMipmaps, "EmuCore/GS", "DumpReplaceableMipmaps", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.dumpTexturesWithFMVActive, "EmuCore/GS", "DumpTexturesWithFMVActive", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.loadTextureReplacements, "EmuCore/GS", "LoadTextureReplacements", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.loadTextureReplacementsAsync, "EmuCore/GS", "LoadTextureReplacementsAsync", true);
SettingWidgetBinder::BindWidgetToBoolSetting(
sif, m_ui.loadTextureReplacementsAsync, "EmuCore/GS", "LoadTextureReplacementsAsync", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.precacheTextureReplacements, "EmuCore/GS", "PrecacheTextureReplacements", false);
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.texturesDirectory, m_ui.texturesBrowse, m_ui.texturesOpen, m_ui.texturesReset,
"Folders", "Textures", Path::Combine(EmuFolders::DataRoot, "textures"));
@@ -247,10 +232,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.threadedPresentation, "EmuCore/GS", "DisableThreadedPresentation", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.overrideTextureBarriers, "EmuCore/GS", "OverrideTextureBarriers", -1, -1);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.overrideGeometryShader, "EmuCore/GS", "OverrideGeometryShaders", -1, -1);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gsDumpCompression, "EmuCore/GS", "GSDumpCompression", static_cast<int>(GSDumpCompressionMethod::Zstandard));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.gsDumpCompression, "EmuCore/GS", "GSDumpCompression", static_cast<int>(GSDumpCompressionMethod::Zstandard));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableFramebufferFetch, "EmuCore/GS", "DisableFramebufferFetch", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDualSource, "EmuCore/GS", "DisableDualSourceBlend", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gsDownloadMode, "EmuCore/GS", "HWDownloadMode", static_cast<int>(GSHardwareDownloadMode::Enabled));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.gsDownloadMode, "EmuCore/GS", "HWDownloadMode", static_cast<int>(GSHardwareDownloadMode::Enabled));
//////////////////////////////////////////////////////////////////////////
// SW Settings
@@ -314,19 +301,53 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
// Capture settings
{
for (const char** container = Pcsx2Config::GSOptions::VideoCaptureContainers; *container; container++)
for (const char** container = Pcsx2Config::GSOptions::CaptureContainers; *container; container++)
{
const QString name(QString::fromUtf8(*container));
m_ui.videoCaptureContainer->addItem(name.toUpper(), name);
m_ui.captureContainer->addItem(name.toUpper(), name);
}
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureContainer, "EmuCore/GS", "VideoCaptureContainer");
connect(m_ui.videoCaptureContainer, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onVideoCaptureContainerChanged);
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.videoDumpingDirectory, m_ui.videoDumpingDirectoryBrowse,
m_ui.videoDumpingDirectoryOpen, m_ui.videoDumpingDirectoryReset, "Folders", "Videos",
Path::Combine(EmuFolders::DataRoot, "videos"));
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.captureContainer, "EmuCore/GS", "CaptureContainer");
connect(m_ui.captureContainer, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onCaptureContainerChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCapture, "EmuCore/GS", "EnableVideoCapture", true);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.videoCaptureBitrate, "EmuCore/GS", "VideoCaptureBitrate", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_BITRATE);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.videoCaptureWidth, "EmuCore/GS", "VideoCaptureWidth", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_WIDTH);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.videoCaptureHeight, "EmuCore/GS", "VideoCaptureHeight", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_HEIGHT);
SettingWidgetBinder::BindWidgetToBoolSetting(
sif, m_ui.videoCaptureResolutionAuto, "EmuCore/GS", "VideoCaptureAutoResolution", true);
SettingWidgetBinder::BindWidgetToBoolSetting(
sif, m_ui.enableVideoCaptureArguments, "EmuCore/GS", "EnableVideoCaptureParameters", false);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureArguments, "EmuCore/GS", "VideoCaptureParameters");
connect(m_ui.enableVideoCapture, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onEnableVideoCaptureChanged);
connect(
m_ui.videoCaptureResolutionAuto, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onVideoCaptureAutoResolutionChanged);
connect(m_ui.enableVideoCaptureArguments, &QCheckBox::stateChanged, this,
&GraphicsSettingsWidget::onEnableVideoCaptureArgumentsChanged);
onVideoCaptureContainerChanged();
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableAudioCapture, "EmuCore/GS", "EnableAudioCapture", true);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.audioCaptureBitrate, "EmuCore/GS", "AudioCaptureBitrate", Pcsx2Config::GSOptions::DEFAULT_AUDIO_CAPTURE_BITRATE);
SettingWidgetBinder::BindWidgetToBoolSetting(
sif, m_ui.enableAudioCaptureArguments, "EmuCore/GS", "EnableAudioCaptureParameters", false);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.audioCaptureArguments, "EmuCore/GS", "AudioCaptureParameters");
connect(m_ui.enableAudioCapture, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onEnableAudioCaptureChanged);
connect(m_ui.enableAudioCaptureArguments, &QCheckBox::stateChanged, this,
&GraphicsSettingsWidget::onEnableAudioCaptureArgumentsChanged);
onCaptureContainerChanged();
onEnableVideoCaptureChanged();
onEnableVideoCaptureArgumentsChanged();
onVideoCaptureAutoResolutionChanged();
onEnableAudioCaptureChanged();
onEnableAudioCaptureArgumentsChanged();
}
// Display tab
@@ -341,42 +362,50 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
tr("Disables interlacing offset which may reduce blurring in some situations."));
dialog->registerWidgetHelp(m_ui.bilinearFiltering, tr("Bilinear Filtering"), tr("Bilinear (Smooth)"),
tr("Enables bilinear post processing filter. Smooths the overall picture as it is displayed on the screen. Corrects positioning between pixels."));
tr("Enables bilinear post processing filter. Smooths the overall picture as it is displayed on the screen. Corrects "
"positioning between pixels."));
dialog->registerWidgetHelp(m_ui.PCRTCOffsets, tr("Screen Offsets"), tr("Unchecked"),
tr("Enables PCRTC Offsets which position the screen as the game requests. Useful for some games such as WipEout Fusion for its screen shake effect, but can make the picture blurry."));
tr("Enables PCRTC Offsets which position the screen as the game requests. Useful for some games such as WipEout Fusion for its "
"screen shake effect, but can make the picture blurry."));
dialog->registerWidgetHelp(m_ui.PCRTCOverscan, tr("Show Overscan"), tr("Unchecked"),
tr("Enables the option to show the overscan area on games which draw more than the safe area of the screen."));
dialog->registerWidgetHelp(m_ui.fmvAspectRatio, tr("FMV Aspect Ratio"), tr("Off (Default)"),
tr("Overrides the FMV aspect ratio."));
dialog->registerWidgetHelp(m_ui.fmvAspectRatio, tr("FMV Aspect Ratio"), tr("Off (Default)"), tr("Overrides the FMV aspect ratio."));
dialog->registerWidgetHelp(m_ui.PCRTCAntiBlur, tr("Anti-Blur"), tr("Checked"),
tr("Enables internal Anti-Blur hacks. Less accurate to PS2 rendering but will make a lot of games look less blurry."));
dialog->registerWidgetHelp(m_ui.vsync, tr("VSync"), tr("Unchecked"),
tr("Enable this option to match PCSX2's refresh rate with your current monitor or screen. VSync is automatically disabled when it is not possible (eg. running at non-100% speed)."));
tr("Enable this option to match PCSX2's refresh rate with your current monitor or screen. VSync is automatically disabled when "
"it is not possible (eg. running at non-100% speed)."));
dialog->registerWidgetHelp(m_ui.integerScaling, tr("Integer Scaling"), tr("Unchecked"),
tr("Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an integer number. May result in a sharper image in some 2D games."));
dialog->registerWidgetHelp(m_ui.aspectRatio, tr("Aspect Ratio"), tr("Auto Standard (4:3/3:2 Progressive)"), tr(""));
tr("Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an "
"integer number. May result in a sharper image in some 2D games."));
dialog->registerWidgetHelp(m_ui.aspectRatio, tr("Aspect Ratio"), tr("Auto Standard (4:3/3:2 Progressive)"),
tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto Standard (4:3/3:2 "
"Progressive) which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era."));
dialog->registerWidgetHelp(m_ui.interlacing, tr("Deinterlacing"), tr("Automatic (Default)"), tr(""));
dialog->registerWidgetHelp(m_ui.screenshotSize, tr("Screenshot Size"), tr("Screen Resolution"),
tr("Determines the resolution at which screenshots will be saved. Internal resolutions preserve more detail at the cost of file size."));
tr("Determines the resolution at which screenshots will be saved. Internal resolutions preserve more detail at the cost of "
"file size."));
dialog->registerWidgetHelp(m_ui.screenshotFormat, tr("Screenshot Format"), tr("PNG"),
tr("Selects the format which will be used to save screenshots. JPEG produces smaller files, but loses detail."));
dialog->registerWidgetHelp(m_ui.screenshotQuality, tr("Screenshot Quality"), tr("50%"),
tr("Selects the quality at which screenshots will be compressed. Higher values preserve more detail for JPEG, and reduce file size for PNG."));
tr("Selects the quality at which screenshots will be compressed. Higher values preserve more detail for JPEG, and reduce file "
"size for PNG."));
dialog->registerWidgetHelp(m_ui.stretchY, tr("Stretch Height"), tr("100%"), tr(""));
dialog->registerWidgetHelp(m_ui.fullscreenModes, tr("Fullscreen Mode"), tr("Borderless Fullscreen"), tr(""));
dialog->registerWidgetHelp(m_ui.fullscreenModes, tr("Fullscreen Mode"), tr("Borderless Fullscreen"),
tr("Chooses the fullscreen resolution and frequency."));
dialog->registerWidgetHelp(m_ui.cropLeft, tr("Left"), tr("0px"), tr(""));
@@ -392,11 +421,11 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
// Hardware
dialog->registerWidgetHelp(m_ui.upscaleMultiplier, tr("Internal Resolution"), tr("Native (PS2) (Default)"), tr(""));
dialog->registerWidgetHelp(m_ui.mipmapping, tr("Mipmapping"), tr("Automatic (Default)"),
tr("Control the accuracy level of the mipmapping emulation."));
dialog->registerWidgetHelp(
m_ui.mipmapping, tr("Mipmapping"), tr("Automatic (Default)"), tr("Control the accuracy level of the mipmapping emulation."));
dialog->registerWidgetHelp(m_ui.textureFiltering, tr("Texture Filtering"), tr("Bilinear (PS2)"),
tr("Control the texture filtering of the emulation."));
dialog->registerWidgetHelp(
m_ui.textureFiltering, tr("Texture Filtering"), tr("Bilinear (PS2)"), tr("Control the texture filtering of the emulation."));
dialog->registerWidgetHelp(m_ui.trilinearFiltering, tr("Trilinear Filtering"), tr("Automatic (Default)"),
tr("Control the texture tri-filtering of the emulation."));
@@ -414,8 +443,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
tr("Control the number of Auto-CRC fixes and hacks applied to games."));
dialog->registerWidgetHelp(m_ui.blending, tr("Blending Accuracy"), tr("Basic (Recommended)"),
tr("Control the accuracy level of the GS blending unit emulation. "
"The higher the setting, the more blending is emulated in the shader accurately, and the higher the speed penalty will be. "
tr("Control the accuracy level of the GS blending unit emulation.<br> "
"The higher the setting, the more blending is emulated in the shader accurately, and the higher the speed penalty will "
"be.<br> "
"Do note that Direct3D's blending is reduced in capability compared to OpenGL/Vulkan"));
dialog->registerWidgetHelp(m_ui.texturePreloading, tr("Texture Preloading"), tr("Full (Hash Cache)"),
@@ -442,15 +472,16 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
// Software
dialog->registerWidgetHelp(m_ui.extraSWThreads, tr("Extra Rendering Threads"), tr("2 threads"),
tr("Number of rendering threads: 0 for single thread, 2 or more for multithread (1 is for debugging). "
"If you have 4 threads on your CPU pick 2 or 3. You can calculate how to get the best performance (amount of CPU threads - 2). "
"If you have 4 threads on your CPU pick 2 or 3. You can calculate how to get the best performance (amount of CPU threads - "
"2). "
"7+ threads will not give much more performance and could perhaps even lower it."));
dialog->registerWidgetHelp(m_ui.swAutoFlush, tr("Auto Flush"), tr("Checked"),
tr("Force a primitive flush when a framebuffer is also an input texture. "
"Fixes some processing effects such as the shadows in the Jak series and radiosity in GTA:SA."));
dialog->registerWidgetHelp(m_ui.swMipmap, tr("Mipmapping"), tr("Checked"),
tr("Enables mipmapping, which some games require to render correctly."));
dialog->registerWidgetHelp(
m_ui.swMipmap, tr("Mipmapping"), tr("Checked"), tr("Enables mipmapping, which some games require to render correctly."));
}
// Hardware Fixes tab
@@ -479,7 +510,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.disableSafeFeatures, tr("Disable Safe Features"), tr("Unchecked"),
tr("This option disables multiple safe features. "
"Disables accurate Unscale Point and Line rendering which can help Xenosaga games. "
"Disables accurate GS Memory Clearing to be done on the CPU, and let the GPU handle it, which can help Kingdom Hearts games."));
"Disables accurate GS Memory Clearing to be done on the CPU, and let the GPU handle it, which can help Kingdom Hearts "
"games."));
dialog->registerWidgetHelp(m_ui.disablePartialInvalidation, tr("Disable Partial Invalidation"), tr("Unchecked"),
tr("By default, the texture cache handles partial invalidations. Unfortunately it is very costly to compute CPU wise. "
@@ -505,13 +537,16 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.roundSprite, tr("Round Sprite"), tr("Off (Default)"),
tr("Corrects the sampling of 2D sprite textures when upscaling. "
"Fixes lines in sprites of games like Ar tonelico when upscaling. Half option is for flat sprites, Full is for all sprites."));
"Fixes lines in sprites of games like Ar tonelico when upscaling. Half option is for flat sprites, Full is for all "
"sprites."));
dialog->registerWidgetHelp(m_ui.textureOffsetX, tr("Texture Offsets X"), tr("0"),
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment too."));
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment "
"too."));
dialog->registerWidgetHelp(m_ui.textureOffsetY, tr("Texture Offsets Y"), tr("0"),
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment too."));
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment "
"too."));
dialog->registerWidgetHelp(m_ui.alignSprite, tr("Align Sprite"), tr("Unchecked"),
tr("Fixes issues with upscaling(vertical lines) in Namco games like Ace Combat, Tekken, Soul Calibur, etc."));
@@ -545,10 +580,11 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.casSharpness, tr("Sharpness"), tr("50%"), tr(""));
dialog->registerWidgetHelp(m_ui.shadeBoost, tr("Shade Boost"), tr("Unchecked"),
tr("Enables saturation, contrast, and brightness to be adjusted. Values of brightness, saturation, and contrast are at default 50."));
tr("Enables saturation, contrast, and brightness to be adjusted. Values of brightness, saturation, and contrast are at default "
"50."));
dialog->registerWidgetHelp(m_ui.fxaa, tr("FXAA"), tr("Unchecked"),
tr("Applies the FXAA anti-aliasing algorithm to improve the visual quality of games."));
dialog->registerWidgetHelp(
m_ui.fxaa, tr("FXAA"), tr("Unchecked"), tr("Applies the FXAA anti-aliasing algorithm to improve the visual quality of games."));
dialog->registerWidgetHelp(m_ui.shadeBoostBrightness, tr("Brightness"), tr("50"), tr(""));
@@ -561,7 +597,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
// OSD tab
{
dialog->registerWidgetHelp(m_ui.osdScale, tr("OSD Scale"), tr("100%"), tr(""));
dialog->registerWidgetHelp(
m_ui.osdScale, tr("OSD Scale"), tr("100%"), tr("Scales the size of the onscreen OSD from 100% to 500%."));
dialog->registerWidgetHelp(m_ui.osdShowMessages, tr("Show OSD Messages"), tr("Checked"),
tr("Shows on-screen-display messages when events occur such as save states being "
@@ -576,11 +613,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.osdShowResolution, tr("Show Resolution"), tr("Unchecked"),
tr("Shows the resolution of the game in the top-right corner of the display."));
dialog->registerWidgetHelp(m_ui.osdShowCPU, tr("Show CPU Usage"), tr("Unchecked"),
tr("Shows host's CPU utilization."));
dialog->registerWidgetHelp(m_ui.osdShowCPU, tr("Show CPU Usage"), tr("Unchecked"), tr("Shows host's CPU utilization."));
dialog->registerWidgetHelp(m_ui.osdShowGPU, tr("Show GPU Usage"), tr("Unchecked"),
tr("Shows host's GPU utilization."));
dialog->registerWidgetHelp(m_ui.osdShowGPU, tr("Show GPU Usage"), tr("Unchecked"), tr("Shows host's GPU utilization."));
dialog->registerWidgetHelp(m_ui.osdShowGSStats, tr("Show Statistics"), tr("Unchecked"),
tr("Shows counters for internal graphical utilization, useful for debugging."));
@@ -588,14 +623,27 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.osdShowIndicators, tr("Show Indicators"), tr("Unchecked"),
tr("Shows OSD icon indicators for emulation states such as Pausing, Turbo, Fast Forward, and Slow Motion."));
dialog->registerWidgetHelp(m_ui.osdShowSettings, tr("Show Settings"), tr("Unchecked"), tr(""));
dialog->registerWidgetHelp(m_ui.osdShowSettings, tr("Show Settings"), tr("Unchecked"),
tr("Displays various settings and the current values of those settings, useful for debugging."));
dialog->registerWidgetHelp(m_ui.osdShowInputs, tr("Show Inputs"), tr("Unchecked"), tr(""));
dialog->registerWidgetHelp(m_ui.osdShowInputs, tr("Show Inputs"), tr("Unchecked"),
tr("Shows the current controler state of the system in the bottom left corner of the display."));
dialog->registerWidgetHelp(m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"), tr(""));
dialog->registerWidgetHelp(
m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"), tr("Displays a graph showing the average frametimes."));
dialog->registerWidgetHelp(m_ui.warnAboutUnsafeSettings, tr("Warn About Unsafe Settings"),
tr("Checked"), tr("Displays warnings when settings are enabled which may break games."));
dialog->registerWidgetHelp(m_ui.warnAboutUnsafeSettings, tr("Warn About Unsafe Settings"), tr("Checked"),
tr("Displays warnings when settings are enabled which may break games."));
}
// Recording tab
{
dialog->registerWidgetHelp(m_ui.enableVideoCaptureArguments, tr("Enable Extra Arguments"), tr("Unchecked"), tr(""));
dialog->registerWidgetHelp(m_ui.videoCaptureArguments, tr("Extra Arguments"), tr("Leave It Blank"),
tr("Parameters passed to selected video codec.<br> "
"You must use '=' to separate key from value and ':' to separate two pairs from each other.<br> "
"For example: \"crf = 21 : preset = veryfast\""));
}
// Advanced tab
@@ -620,8 +668,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.disableFramebufferFetch, tr("Disable Frame Buffer Fetch"), tr("Unchecked"), tr(""));
dialog->registerWidgetHelp(m_ui.skipPresentingDuplicateFrames, tr("Skip Presenting Duplicate Frames"), tr("Unchecked"),
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still rendered, it just means "
"the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time fluctuations when the CPU/GPU are near maximum "
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still "
"rendered, it just means "
"the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time fluctuations when the CPU/GPU "
"are near maximum "
"utilization, but makes frame pacing more inconsistent and can increase input lag."));
dialog->registerWidgetHelp(m_ui.threadedPresentation, tr("Disable Threaded Presentation"), tr("Unchecked"),
@@ -700,9 +750,8 @@ void GraphicsSettingsWidget::onFullscreenModeChanged(int index)
void GraphicsSettingsWidget::onTrilinearFilteringChanged()
{
const bool forced_bilinear =
(m_dialog->getEffectiveIntValue("EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic))
>= static_cast<int>(TriFiltering::Forced));
const bool forced_bilinear = (m_dialog->getEffectiveIntValue("EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic)) >=
static_cast<int>(TriFiltering::Forced));
m_ui.textureFiltering->setDisabled(forced_bilinear);
}
@@ -714,16 +763,15 @@ void GraphicsSettingsWidget::onShadeBoostChanged()
m_ui.shadeBoostSaturation->setEnabled(enabled);
}
void GraphicsSettingsWidget::onVideoCaptureContainerChanged()
void GraphicsSettingsWidget::onCaptureContainerChanged()
{
const std::string container(
m_dialog->getEffectiveStringValue("EmuCore/GS", "VideoCaptureContainer", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_CONTAINER));
m_dialog->getEffectiveStringValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER));
m_ui.videoCaptureCodec->disconnect();
m_ui.videoCaptureCodec->clear();
const std::vector<std::pair<std::string, std::string>> vcapture_formats(GSCapture::GetVideoCodecList(container.c_str()));
m_ui.videoCaptureCodec->addItem(tr("Default"), QString());
for (const auto& [format, name] : vcapture_formats)
for (const auto& [format, name] : GSCapture::GetVideoCodecList(container.c_str()))
{
const QString qformat(QString::fromStdString(format));
const QString qname(QString::fromStdString(name));
@@ -732,6 +780,50 @@ void GraphicsSettingsWidget::onVideoCaptureContainerChanged()
SettingWidgetBinder::BindWidgetToStringSetting(
m_dialog->getSettingsInterface(), m_ui.videoCaptureCodec, "EmuCore/GS", "VideoCaptureCodec");
m_ui.audioCaptureCodec->disconnect();
m_ui.audioCaptureCodec->clear();
m_ui.audioCaptureCodec->addItem(tr("Default"), QString());
for (const auto& [format, name] : GSCapture::GetAudioCodecList(container.c_str()))
{
const QString qformat(QString::fromStdString(format));
const QString qname(QString::fromStdString(name));
m_ui.audioCaptureCodec->addItem(QStringLiteral("%1 [%2]").arg(qformat).arg(qname), qformat);
}
SettingWidgetBinder::BindWidgetToStringSetting(
m_dialog->getSettingsInterface(), m_ui.audioCaptureCodec, "EmuCore/GS", "AudioCaptureCodec");
}
void GraphicsSettingsWidget::onEnableVideoCaptureChanged()
{
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableVideoCapture", true);
m_ui.videoCaptureOptions->setEnabled(enabled);
}
void GraphicsSettingsWidget::onEnableVideoCaptureArgumentsChanged()
{
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableVideoCaptureParameters", false);
m_ui.videoCaptureArguments->setEnabled(enabled);
}
void GraphicsSettingsWidget::onVideoCaptureAutoResolutionChanged()
{
const bool enabled = !m_dialog->getEffectiveBoolValue("EmuCore/GS", "VideoCaptureAutoResolution", true);
m_ui.videoCaptureWidth->setEnabled(enabled);
m_ui.videoCaptureHeight->setEnabled(enabled);
}
void GraphicsSettingsWidget::onEnableAudioCaptureChanged()
{
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableAudioCapture", true);
m_ui.audioCaptureOptions->setEnabled(enabled);
}
void GraphicsSettingsWidget::onEnableAudioCaptureArgumentsChanged()
{
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableAudioCaptureParameters", false);
m_ui.audioCaptureArguments->setEnabled(enabled);
}
void GraphicsSettingsWidget::onGpuPaletteConversionChanged(int state)
@@ -760,7 +852,8 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
const bool is_sw_dx = false;
#endif
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::DX12 || type == GSRendererType::OGL || type == GSRendererType::VK || type == GSRendererType::Metal);
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::DX12 || type == GSRendererType::OGL ||
type == GSRendererType::VK || type == GSRendererType::Metal);
const bool is_software = (type == GSRendererType::SW);
const bool hw_fixes = (is_hardware && m_ui.enableHWFixes->checkState() == Qt::Checked);
const int prev_tab = m_ui.tabs->currentIndex();
+7 -2
View File
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -43,7 +43,12 @@ private Q_SLOTS:
void onGpuPaletteConversionChanged(int state);
void onFullscreenModeChanged(int index);
void onShadeBoostChanged();
void onVideoCaptureContainerChanged();
void onCaptureContainerChanged();
void onEnableVideoCaptureChanged();
void onEnableVideoCaptureArgumentsChanged();
void onVideoCaptureAutoResolutionChanged();
void onEnableAudioCaptureChanged();
void onEnableAudioCaptureArgumentsChanged();
private:
GSRendererType getEffectiveRenderer() const;
+310 -45
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>861</width>
<height>501</height>
<width>720</width>
<height>466</height>
</rect>
</property>
<property name="windowTitle">
@@ -920,14 +920,14 @@
</item>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Skipdraw Range:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QSpinBox" name="skipDrawStart">
@@ -945,7 +945,7 @@
</item>
</layout>
</item>
<item row="4" column="0" colspan="2">
<item row="5" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="hwAutoFlush">
@@ -1030,6 +1030,32 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_47">
<property name="text">
<string>GPU Target CLUT:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="gpuTargetCLUTMode">
<item>
<property name="text">
<string>Disabled (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Enabled (Exact Match)</string>
</property>
</item>
<item>
<property name="text">
<string>Enabled (Check Inside Target)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="upscalingFixesTab">
@@ -1623,6 +1649,285 @@
</item>
</layout>
</widget>
<widget class="QGroupBox" name="recordingTab">
<attribute name="title">
<string>Recording</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QGroupBox" name="videoDumpDirectory">
<property name="title">
<string>Video Dumping Directory</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLineEdit" name="videoDumpingDirectory"/>
</item>
<item>
<widget class="QPushButton" name="videoDumpingDirectoryBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="videoDumpingDirectoryOpen">
<property name="text">
<string>Open...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="videoDumpingDirectoryReset">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Capture Setup</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="captureContainerLabel">
<property name="text">
<string>Container:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="captureContainer"/>
</item>
<item row="1" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_10" columnstretch="1,1">
<property name="horizontalSpacing">
<number>20</number>
</property>
<property name="verticalSpacing">
<number>10</number>
</property>
<item row="1" column="1">
<widget class="QWidget" name="audioCaptureOptions" native="true">
<layout class="QFormLayout" name="formLayout_10">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="audioCaptureCodecLabel">
<property name="text">
<string>Codec:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="audioCaptureCodec"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="audioCaptureBitrateLabel">
<property name="text">
<string>Bitrate:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="audioCaptureBitrate">
<property name="suffix">
<string> kbps</string>
</property>
<property name="minimum">
<number>16</number>
</property>
<property name="maximum">
<number>2048</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="enableAudioCaptureArguments">
<property name="text">
<string>Extra Arguments</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QLineEdit" name="audioCaptureArguments"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="enableAudioCapture">
<property name="text">
<string>Capture Audio</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QWidget" name="videoCaptureOptions" native="true">
<layout class="QFormLayout" name="formLayout_6">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="videoCaptureCodecLabel">
<property name="text">
<string>Codec:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="videoCaptureCodec"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="videoCaptureBitrateLabel">
<property name="text">
<string>Bitrate:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="videoCaptureBitrate">
<property name="suffix">
<string> kbps</string>
</property>
<property name="minimum">
<number>100</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="videoCaptureResolutionLabel">
<property name="text">
<string>Resolution:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_10" stretch="1,0,1,0">
<item>
<widget class="QSpinBox" name="videoCaptureWidth">
<property name="minimum">
<number>320</number>
</property>
<property name="maximum">
<number>32768</number>
</property>
<property name="singleStep">
<number>16</number>
</property>
<property name="value">
<number>640</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_46">
<property name="text">
<string>x</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="videoCaptureHeight">
<property name="minimum">
<number>240</number>
</property>
<property name="maximum">
<number>32768</number>
</property>
<property name="singleStep">
<number>16</number>
</property>
<property name="value">
<number>240</number>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="videoCaptureResolutionAuto">
<property name="text">
<string>Auto</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="enableVideoCaptureArguments">
<property name="text">
<string>Extra Arguments</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<widget class="QLineEdit" name="videoCaptureArguments"/>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="enableVideoCapture">
<property name="text">
<string>Capture Video</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="advancedTab">
<attribute name="title">
<string>Advanced</string>
@@ -1716,46 +2021,6 @@
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_45">
<property name="text">
<string>Video Capture Codec:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0,0,0">
<item>
<widget class="QComboBox" name="videoCaptureCodec"/>
</item>
<item>
<widget class="QComboBox" name="videoCaptureContainer"/>
</item>
<item>
<widget class="QLabel" name="label_46">
<property name="text">
<string>Bitrate:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="videoCaptureBitrate">
<property name="suffix">
<string> kbps</string>
</property>
<property name="minimum">
<number>100</number>
</property>
<property name="maximum">
<number>100000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
+34 -1
View File
@@ -17,6 +17,7 @@
#include "QtHost.h"
#include "QtUtils.h"
#include "Settings/ControllerSettingWidgetBinder.h"
#include "Settings/InputBindingDialog.h"
#include "Settings/InputBindingWidget.h"
#include <QtCore/QTimer>
@@ -24,6 +25,8 @@
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include "fmt/format.h"
// _BitScanForward()
#include "pcsx2/GS/GSIntrin.h"
@@ -45,6 +48,26 @@ InputBindingDialog::InputBindingDialog(SettingsInterface* sif, InputBindingInfo:
connect(m_ui.clearBindings, &QPushButton::clicked, this, &InputBindingDialog::onClearBindingsButtonClicked);
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, [this]() { done(0); });
updateList();
// Only show the sensitivity controls for binds where it's applicable.
if (bind_type == InputBindingInfo::Type::Button || bind_type == InputBindingInfo::Type::Axis ||
bind_type == InputBindingInfo::Type::HalfAxis)
{
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
sif, m_ui.sensitivity, m_section_name, fmt::format("{}Scale", m_key_name), 100.0f, 1.0f);
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
sif, m_ui.deadzone, m_section_name, fmt::format("{}Deadzone", m_key_name), 100.0f, 0.0f);
connect(m_ui.sensitivity, &QSlider::valueChanged, this, &InputBindingDialog::onSensitivityChanged);
connect(m_ui.deadzone, &QSlider::valueChanged, this, &InputBindingDialog::onDeadzoneChanged);
onSensitivityChanged(m_ui.sensitivity->value());
onDeadzoneChanged(m_ui.deadzone->value());
}
else
{
m_ui.verticalLayout->removeWidget(m_ui.sensitivityWidget);
}
}
InputBindingDialog::~InputBindingDialog()
@@ -109,7 +132,7 @@ bool InputBindingDialog::eventFilter(QObject* watched, QEvent* event)
// if we've moved more than a decent distance from the center of the widget, bind it.
// this is so we don't accidentally bind to the mouse if you bump it while reaching for your pad.
static constexpr const s32 THRESHOLD = 50;
const QPoint diff(static_cast<QMouseEvent*>(event)->globalPos() - m_input_listen_start_position);
const QPoint diff(static_cast<QMouseEvent*>(event)->globalPosition().toPoint() - m_input_listen_start_position);
bool has_one = false;
if (std::abs(diff.x()) >= THRESHOLD)
@@ -318,6 +341,16 @@ void InputBindingDialog::inputManagerHookCallback(InputBindingKey key, float val
}
}
void InputBindingDialog::onSensitivityChanged(int value)
{
m_ui.sensitivityValue->setText(tr("%1%").arg(value));
}
void InputBindingDialog::onDeadzoneChanged(int value)
{
m_ui.deadzoneValue->setText(tr("%1%").arg(value));
}
void InputBindingDialog::hookInputManager()
{
InputManager::SetHook([this](InputBindingKey key, float value) {
+3
View File
@@ -41,6 +41,9 @@ protected Q_SLOTS:
void onInputListenTimerTimeout();
void inputManagerHookCallback(InputBindingKey key, float value);
void onSensitivityChanged(int value);
void onDeadzoneChanged(int value);
protected:
enum : u32
{
+88 -1
View File
@@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>533</width>
<height>283</height>
<height>266</height>
</rect>
</property>
<property name="windowTitle">
@@ -30,6 +30,93 @@
<item>
<widget class="QListWidget" name="bindingList"/>
</item>
<item>
<widget class="QWidget" name="sensitivityWidget" native="true">
<layout class="QGridLayout" name="sensitivityLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="sensitivityLabel">
<property name="text">
<string>Sensitivity:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="sensitivity">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="value">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="sensitivityValue">
<property name="text">
<string>100%</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="deadzoneLabel">
<property name="text">
<string>Deadzone:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="deadzone">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>5</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="deadzoneValue">
<property name="text">
<string>100%</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="status">
<property name="text">
+1 -1
View File
@@ -166,7 +166,7 @@ bool InputBindingWidget::eventFilter(QObject* watched, QEvent* event)
// if we've moved more than a decent distance from the center of the widget, bind it.
// this is so we don't accidentally bind to the mouse if you bump it while reaching for your pad.
static constexpr const s32 THRESHOLD = 50;
const QPoint diff(static_cast<QMouseEvent*>(event)->globalPos() - m_input_listen_start_position);
const QPoint diff(static_cast<QMouseEvent*>(event)->globalPosition().toPoint() - m_input_listen_start_position);
bool has_one = false;
if (std::abs(diff.x()) >= THRESHOLD)
@@ -98,7 +98,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
AutoUpdaterDialog::getDefaultTag());
m_ui.autoUpdateCurrentVersion->setText(tr("%1 (%2)").arg(AutoUpdaterDialog::getCurrentVersion()).arg(AutoUpdaterDialog::getCurrentVersionDate()));
connect(m_ui.checkForUpdates, &QPushButton::clicked, this, []() { g_main_window->checkForUpdates(true); });
connect(m_ui.checkForUpdates, &QPushButton::clicked, this, []() { g_main_window->checkForUpdates(true, true); });
}
else
{
+1 -1
View File
@@ -191,7 +191,7 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
m_ui.settingsContainer->setCurrentIndex(0);
m_ui.helpText->setText(m_category_help_text[0]);
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &SettingsDialog::onCategoryCurrentRowChanged);
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::accept);
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::close);
connect(m_ui.restoreDefaultsButton, &QPushButton::clicked, this, &SettingsDialog::onRestoreDefaultsClicked);
}
File diff suppressed because it is too large Load Diff
+20 -2
View File
@@ -46,9 +46,10 @@
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\lzma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\demangler\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src\c4\ext\fast_float\include;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\sdl2\include;$(SolutionDir)3rdparty\sdl2\SDL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)pcsx2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<!-- Needed for moc pch -->
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(ProjectDir)\Settings;$(ProjectDir)\GameList;$(ProjectDir)\Tools\InputRecording;$(ProjectDir)\Debugger</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(ProjectDir)\Settings;$(ProjectDir)\GameList;$(ProjectDir)\Tools\InputRecording;$(ProjectDir)\Debugger;$(ProjectDir)\Debugger\Models</AdditionalIncludeDirectories>
<ExceptionHandling>Async</ExceptionHandling>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
@@ -70,6 +71,8 @@
<FloatingPointModel>Precise</FloatingPointModel>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ConformanceMode>true</ConformanceMode>
<!-- Current Qt debug builds assert on RTTI. Remove this once we next build Qt. -->
<RuntimeTypeInfo Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(Debug))">true</RuntimeTypeInfo>
<AdditionalOptions>/Zc:__cplusplus /Zo /utf-8%(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
@@ -135,6 +138,7 @@
<Manifest Include="..\pcsx2\windows\PCSX2.manifest" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="ColorPickerButton.cpp" />
<ClCompile Include="EarlyHardwareCheck.cpp" />
<ClCompile Include="QtProgressCallback.cpp" />
<ClCompile Include="Settings\DebugSettingsWidget.cpp" />
@@ -148,6 +152,9 @@
<ClCompile Include="Debugger\MemoryViewWidget.cpp" />
<ClCompile Include="Debugger\RegisterWidget.cpp" />
<ClCompile Include="Debugger\BreakpointDialog.cpp" />
<ClCompile Include="Debugger\Models\BreakpointModel.cpp" />
<ClCompile Include="Debugger\Models\ThreadModel.cpp" />
<ClCompile Include="Debugger\Models\StackModel.cpp" />
<ClCompile Include="Settings\BIOSSettingsWidget.cpp" />
<ClCompile Include="Settings\ControllerBindingWidgets.cpp" />
<ClCompile Include="Settings\ControllerGlobalSettingsWidget.cpp" />
@@ -208,6 +215,7 @@
<QtMoc Include="Settings\DEV9SettingsWidget.h" />
<QtMoc Include="Settings\DEV9UiCommon.h" />
<QtMoc Include="QtProgressCallback.h" />
<QtMoc Include="ColorPickerButton.h" />
<ClInclude Include="Settings\ControllerSettingWidgetBinder.h" />
<QtMoc Include="Settings\FolderSettingsWidget.h" />
<QtMoc Include="Settings\DebugSettingsWidget.h" />
@@ -228,6 +236,9 @@
<QtMoc Include="Debugger\MemoryViewWidget.h" />
<QtMoc Include="Debugger\RegisterWidget.h" />
<QtMoc Include="Debugger\BreakpointDialog.h" />
<QtMoc Include="Debugger\Models\BreakpointModel.h" />
<QtMoc Include="Debugger\Models\ThreadModel.h" />
<QtMoc Include="Debugger\Models\StackModel.h" />
<QtMoc Include="Settings\ControllerBindingWidgets.h" />
<QtMoc Include="Settings\ControllerGlobalSettingsWidget.h" />
<ClInclude Include="Settings\MemoryCardConvertWorker.h" />
@@ -278,11 +289,15 @@
<ClCompile Include="$(IntDir)Debugger\moc_RegisterWidget.cpp" />
<ClCompile Include="$(IntDir)Debugger\moc_MemoryViewWidget.cpp" />
<ClCompile Include="$(IntDir)Debugger\moc_BreakpointDialog.cpp" />
<ClCompile Include="$(IntDir)Debugger\Models\moc_BreakpointModel.cpp" />
<ClCompile Include="$(IntDir)Debugger\Models\moc_ThreadModel.cpp" />
<ClCompile Include="$(IntDir)Debugger\Models\moc_StackModel.cpp" />
<ClCompile Include="$(IntDir)GameList\moc_GameListModel.cpp" />
<ClCompile Include="$(IntDir)GameList\moc_GameListRefreshThread.cpp" />
<ClCompile Include="$(IntDir)GameList\moc_GameListWidget.cpp" />
<ClCompile Include="$(IntDir)moc_AboutDialog.cpp" />
<ClCompile Include="$(IntDir)moc_AutoUpdaterDialog.cpp" />
<ClCompile Include="$(IntDir)moc_ColorPickerButton.cpp" />
<ClCompile Include="$(IntDir)moc_CoverDownloadDialog.cpp" />
<ClCompile Include="$(IntDir)moc_DisplayWidget.cpp" />
<ClCompile Include="$(IntDir)moc_MainWindow.cpp" />
@@ -405,6 +420,9 @@
<QtUi Include="Settings\DebugSettingsWidget.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\ControllerLEDSettingsDialog.ui">
<FileType>Document</FileType>
</QtUi>
<None Include="Settings\USBBindingWidget_DrivingForce.ui" />
<None Include="Settings\USBBindingWidget_GTForce.ui" />
<QtUi Include="Settings\USBDeviceWidget.ui">
@@ -421,4 +439,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(SolutionDir)common\vsprops\QtCompile.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
</Project>
+39 -3
View File
@@ -22,11 +22,12 @@
<Filter Include="Debugger">
<UniqueIdentifier>{ddb40cc4-9996-4ade-b647-eb549063553c}</UniqueIdentifier>
</Filter>
<Filter Include="Debugger\Models">
<UniqueIdentifier>{f4084ca0-d9d5-4584-b9d2-063db9f67de2}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\pcsx2\PCSX2.rc">
<Filter>Resources</Filter>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\windows\PCSX2.rc" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="PrecompiledHeader.cpp" />
@@ -274,6 +275,15 @@
<ClCompile Include="Debugger\BreakpointDialog.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\Models\BreakpointModel.cpp">
<Filter>Debugger\Models</Filter>
</ClCompile>
<ClCompile Include="Debugger\Models\ThreadModel.cpp">
<Filter>Debugger\Models</Filter>
</ClCompile>
<ClCompile Include="Debugger\Models\StackModel.cpp">
<Filter>Debugger\Models</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\moc_CpuWidget.cpp">
<Filter>moc</Filter>
</ClCompile>
@@ -292,6 +302,19 @@
<ClCompile Include="$(IntDir)Debugger\moc_BreakpointDialog.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\Models\moc_BreakpointModel.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\Models\moc_ThreadModel.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\Models\moc_StackModel.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="ColorPickerButton.cpp" />
<ClCompile Include="$(IntDir)moc_ColorPickerButton.cpp">
<Filter>moc</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
@@ -429,6 +452,16 @@
<QtMoc Include="Debugger\BreakpointDialog.h">
<Filter>Debugger</Filter>
</QtMoc>
<QtMoc Include="Debugger\Models\BreakpointModel.h">
<Filter>Debugger\Models</Filter>
</QtMoc>
<QtMoc Include="Debugger\Models\ThreadModel.h">
<Filter>Debugger\Models</Filter>
</QtMoc>
<QtMoc Include="Debugger\Models\StackModel.h">
<Filter>Debugger\Models</Filter>
</QtMoc>
<QtMoc Include="ColorPickerButton.h" />
</ItemGroup>
<ItemGroup>
<QtResource Include="resources\resources.qrc">
@@ -547,6 +580,9 @@
<QtUi Include="Debugger\BreakpointDialog.ui">
<Filter>Debugger</Filter>
</QtUi>
<QtUi Include="Settings\ControllerLEDSettingsDialog.ui">
<Filter>Settings</Filter>
</QtUi>
</ItemGroup>
<ItemGroup>
<None Include="Settings\FolderSettingsWidget.ui">
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M9.973 18H11v-5h2v5h1.027c.132-1.202.745-2.194 1.74-3.277.113-.122.832-.867.917-.973a6 6 0 1 0-9.37-.002c.086.107.807.853.918.974.996 1.084 1.609 2.076 1.741 3.278zM10 20v1h4v-1h-4zm-4.246-5a8 8 0 1 1 12.49.002C17.624 15.774 16 17 16 18.5V21a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-2.5C8 17 6.375 15.774 5.754 15z" fill="#000000"/></svg>

After

Width:  |  Height:  |  Size: 458 B

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M9.973 18H11v-5h2v5h1.027c.132-1.202.745-2.194 1.74-3.277.113-.122.832-.867.917-.973a6 6 0 1 0-9.37-.002c.086.107.807.853.918.974.996 1.084 1.609 2.076 1.741 3.278zM10 20v1h4v-1h-4zm-4.246-5a8 8 0 1 1 12.49.002C17.624 15.774 16 17 16 18.5V21a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-2.5C8 17 6.375 15.774 5.754 15z" fill="#ffffff"/></svg>

After

Width:  |  Height:  |  Size: 458 B

+2
View File
@@ -37,6 +37,7 @@
<file>icons/black/svg/image-fill.svg</file>
<file>icons/black/svg/keyboard-line.svg</file>
<file>icons/black/svg/layout-grid-line.svg</file>
<file>icons/black/svg/lightbulb-line.svg</file>
<file>icons/black/svg/list-check.svg</file>
<file>icons/black/svg/login-box-line.svg</file>
<file>icons/black/svg/pause-line.svg</file>
@@ -96,6 +97,7 @@
<file>icons/white/svg/image-fill.svg</file>
<file>icons/white/svg/keyboard-line.svg</file>
<file>icons/white/svg/layout-grid-line.svg</file>
<file>icons/white/svg/lightbulb-line.svg</file>
<file>icons/white/svg/list-check.svg</file>
<file>icons/white/svg/login-box-line.svg</file>
<file>icons/white/svg/pause-line.svg</file>
+3 -3
View File
@@ -37,7 +37,7 @@
#include "Elfheader.h"
#include "ps2/BiosTools.h"
#include "Recording/InputRecording.h"
#include "VMManager.h"
#include "Host.h"
// This typically reflects the Sony-assigned serial code for the Disc, if one exists.
// (examples: SLUS-2113, etc).
@@ -2440,8 +2440,8 @@ static void cdvdWrite16(u8 rt) // SCOMMAND
case 0x0F: // sceCdPowerOff (0:1)- Call74 from Xcdvdman
Console.WriteLn(Color_StrongBlack, "sceCdPowerOff called. Resetting VM.");
VMManager::Reset();
Console.WriteLn(Color_StrongBlack, "sceCdPowerOff called. Shutting down VM.");
Host::RequestVMShutdown(false, false, false);
break;
case 0x12: // sceCdReadILinkId (0:9)

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