Compare commits

...

261 Commits

Author SHA1 Message Date
refractionpcsx2
d2202a4e33 sadfs 2023-02-10 20:05:39 +00:00
Stenzek
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
Stenzek
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
Stenzek
1b0c03d892 GS/HW: Fix fixed/invalid TEX0 case in TimeSplitters 2 2023-02-10 03:43:10 +00:00
Ziemas
bca49184e7 Debugger: Fix missing return path. (#8094) 2023-02-09 19:48:54 +00:00
Stenzek
26d6c33163 GSRunner: Clear bindings and disable game settings 2023-02-09 17:29:47 +01:00
Ziemas
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
Stenzek
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
Stenzek
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
Stenzek
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
Stenzek
d6099dd263 GS/Vulkan: Use Bresenham line rasterization when supported 2023-02-09 13:42:05 +00:00
Stenzek
a1bc39141e PAD: Fix trigger deadzone/scale setting 2023-02-09 12:30:20 +00:00
Connor McLaughlin
13ed41d077 GS/DX11: Disable multisampling in rasterizer state 2023-02-09 11:13:42 +00:00
Stenzek
8a0a8f718f GameDB: Remove preloading disable for a bunch of games
These are fine now.
2023-02-09 10:51:06 +00:00
Stenzek
7d08a54ad9 GS/HW: Optimize TC source size based on CLAMP 2023-02-09 10:51:06 +00:00
Stenzek
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
Berylskid
892d3a370d GameDB: Fix texture flickers of Armored Core Nexus 2023-02-09 09:37:17 +00:00
Stenzek
6af7ca9867 PAD: Fix invert in deadzone computation 2023-02-09 10:03:55 +01:00
Stenzek
c3c354f794 PAD: Add trigger deadzone/sensitivity settings 2023-02-09 10:03:55 +01:00
Stenzek
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
Stenzek
79daed63ee Qt: Handle multiplier in controller settings 2023-02-09 10:03:55 +01:00
Stenzek
21d3ad86d4 Qt: Make controller settings page scrollable 2023-02-09 10:03:55 +01:00
Stenzek
31ebe842e8 Qt: Add per-bind sensitivity/deadzone controls (shift-click) 2023-02-09 10:03:55 +01:00
eyfix
88487de72f USB: Add values to GunCon2 config. (#8078) 2023-02-09 09:55:23 +01:00
Haruka
616da8c99d CDVD: simplify code 2023-02-09 09:52:00 +01:00
Haruka
ec8712cceb CDVD: use DevCon logging instead of stdout / stderr 2023-02-09 09:52:00 +01:00
Haruka
3d6923b2a1 CDVD: implement SetSpindleSpeed on macOS 2023-02-09 09:52:00 +01:00
Haruka
f04337becf CDVD: fix macOS CD reading 2023-02-09 09:52:00 +01:00
Haruka
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
Stenzek
330061a6e7 GS/OGL: Fix offseted downloads not being offset
Fixes background screen effect in Gradius V.
2023-02-09 07:04:50 +01:00
Stenzek
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
Berylskid
52f034a513 GameDB: Add missing quatation marks in memcardFilters for Armored Core Last Raven 2023-02-08 17:32:49 +01:00
Stenzek
25e05388ba Qt: Open fullscreen window on same display as main 2023-02-08 17:29:59 +01:00
JordanTheToaster
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
JordanTheToaster
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
eyfix
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
JordanTheToaster
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
JordanTheToaster
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 Bot
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
KamFretoZ
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
JordanTheToaster
a287c2caac GameDB: Add Align Sprite to Football Kingdom
Fixes vertical lines.
2023-02-05 14:42:58 +00:00
Stenzek
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
Stenzek
d10621c201 GS/DX11: Use annotations for debug messages 2023-02-04 12:30:24 +00:00
Ziemas
e1d6dfc324 Add command line boot and debug option 2023-02-04 12:30:07 +00:00
Stenzek
130ea2a7ca PAD: Fix pressure getting set to 1 after modifier 2023-02-04 12:29:53 +00:00
Stenzek
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
Stenzek
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
Mrlinkwii
e8d43f53d9 GameDB: fixes for 'Tom & Jerry - War of the Whiskers' & 'Brave - The Search for Spirit Dancer'' 2023-02-03 18:19:42 +00:00
RedDevilus
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
Stenzek
7c2a1f0f37 GS: Vectorize CLUT rect update 2023-02-03 14:36:37 +00:00
Stenzek
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
TheLastRar
3586a12c46 DEV9: Remove pcap dumper
Never worked in Qt
2023-02-02 21:13:52 +00:00
TheLastRar
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
TheLastRar
dc9f61e70a DEV9: Add classes for editing packets and make PCAP use them 2023-02-02 21:13:52 +00:00
TheLastRar
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
TheLastRar
42511ce8d8 DEV9: Remove unneeded headers
by providing a typedef for Adapter
2023-02-02 21:13:52 +00:00
RedDevilus
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
JordanTheToaster
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
Mrlinkwii
b48fb0d4da Misc : label & comment fixes
Misc : remove old comments
labeler: Add labels for Translations
2023-02-01 10:22:12 +00:00
RedDevilus
7a6470a19d CI: Add RetroAchievements/Rcheevos labels for PRs
Beats doing it manually labels for Rcheevos.
2023-02-01 09:39:30 +00:00
Silent
bfd8fc771a Qt: Clear the status text after gamelist scanning
Improves UI parity with DuckStation.
2023-02-01 09:38:46 +00:00
Connor McLaughlin
f96ca4ac1f GS/OGL: Fix syntax error in fragment shader 2023-02-01 09:04:52 +01:00
TheLastRar
937bfce68e DEV9: Better match HDD size per-game UI to rest of settings 2023-01-31 21:23:05 +00:00
TheLastRar
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
TheLastRar
8d3325e6cd DEV9: Fix HDD file overwrite check 2023-01-31 21:23:05 +00:00
TheLastRar
4badb5b975 DEV9: Fix HddEnable not enabling UI correctly in per-game settings 2023-01-31 21:23:05 +00:00
TheLastRar
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
TheLastRar
1c3379f082 Qt: Connect close instead of accept for the close button 2023-01-31 02:06:09 +00:00
Mrlinkwii
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
Goatman13
f1e80c466d IPU: Reset threshold on IPU reset. 2023-01-30 19:13:50 +00:00
Mrlinkwii
9a542bcb20 GameDB: fixes for Simple 2000 Series Vol. 48 2023-01-30 17:31:00 +00:00
JordanTheToaster
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
Mrlinkwii
517ccd5e40 GameDB:fixes for Dragon Quest VIII - Journey of the Cursed King 2023-01-29 17:14:17 +00:00
JordanTheToaster
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
TellowKrinkle
ca25a31d79 GS: Display output ignores TEXA 2023-01-29 10:39:33 +00:00
RedDevilus
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
Stenzek
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
Stenzek
c596a51593 VMManager: Exit the CPU rec immediately on stopping 2023-01-28 13:40:55 +00:00
Stenzek
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
Stenzek
1b40e4aaca Qt: Fix -nogui/-batch closing 2023-01-28 02:51:02 +00:00
Stenzek
84d7fe550b GSDumpReplayer: Fix frame limiting 2023-01-28 02:51:02 +00:00
TheLastRar
e68d507659 DEV9: Unify GetAdapter method definitions
by providing a typedef for Adapter
2023-01-27 18:52:29 +00:00
TheLastRar
2db1e8fb81 DEV9: Move logic for getting MAC address into AdapterUtils 2023-01-27 18:52:29 +00:00
JordanTheToaster
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
Silent
21dcda147c Host: Fix a context menu regression from #7960 2023-01-27 18:46:20 +00:00
JordanTheToaster
201d5ba219 Docs: Update sponsors in README 2023-01-27 17:59:01 +00:00
JordanTheToaster
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
Silent
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
Silent
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 Wilding
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
Toastarrr
20de162a55 OSD: Fix invisible inputs
OSD: Show all button inputs and their pressure when available
2023-01-27 11:10:47 +00:00
TheLastRar
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
TheLastRar
ccc1874a4b DEV9: Correct a few socket logs 2023-01-27 11:02:29 +00:00
Stenzek
4fec896378 Qt: Make behavior between both update checks consistent 2023-01-27 10:37:00 +00:00
Stenzek
d485fcb3ee GameList: Fix double CDVD open 2023-01-26 18:26:32 +00:00
Stenzek
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
Stenzek
62fffaf56f GzippedFileReader: Fix freeing potentially-invalid pointer 2023-01-26 18:26:32 +00:00
Stenzek
553a5cc455 CDVD: Remove exceptions 2023-01-26 11:11:36 +00:00
Stenzek
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
Stenzek
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
Stenzek
d12fa690c0 R5900: Remove exceptions 2023-01-26 11:11:36 +00:00
Stenzek
94226e83ba Common: Purge EventSource 2023-01-26 11:11:36 +00:00
Stenzek
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
icup321
1b86a6e6f8 GameDB: Fixes for Incredibles - ROTU 2023-01-26 09:44:59 +00:00
Stenzek
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
Stenzek
39dde85d03 Qt: Fix -Wunused-lambda-capture warning 2023-01-26 09:28:13 +00:00
Stenzek
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
TellowKrinkle
2cd5ce6aea GHActions: Update release pipeline for MultiISA 2023-01-25 18:27:06 -06:00
Florin9doi
64fbaff82b DInput: Support for up to 128 buttons 2023-01-25 20:46:44 +00:00
Stenzek
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
Stenzek
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
Silent
6a40959f3a DInputSource: Use wil on m_dinput_module 2023-01-25 13:21:51 +00:00
Mrlinkwii
c4bf297f42 GameDB: clean up comments 2023-01-25 13:15:58 +00:00
Stenzek
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
Stenzek
91c3e3b684 GS/SW: Use rip-relative addressing for constants 2023-01-25 13:15:17 +00:00
Stenzek
609a44aaf2 GS/SW: Move code buffer into main memory map 2023-01-25 13:15:17 +00:00
Stenzek
3d84443bcf GS/SW: Share JIT code between all threads 2023-01-25 13:15:17 +00:00
Stenzek
56046d4db8 GS/SW: Move scanline local data to rasterizer 2023-01-25 13:15:17 +00:00
Stenzek
90fc037833 GS/SW: Share global data between threads 2023-01-25 13:15:17 +00:00
Stenzek
ee4eadf7a6 GS/SW: Make local a function parameter to DrawScanline 2023-01-25 13:15:17 +00:00
Stenzek
3292121e67 GS/SW: Make local a function parameter to SetupPrim
.. and associated 32-bit removal.
2023-01-25 13:15:17 +00:00
Stenzek
c8416b820b GS/SW: Combine IDrawScanline and GSDrawScanline 2023-01-25 13:15:17 +00:00
Stenzek
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
pgert
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
JordanTheToaster
bf2ba3c4d1 GameDB: Add missing demos
Adds some missing PAL demos to the DB.
2023-01-24 18:31:36 +00:00
Stenzek
9d50d44c99 GS: Show VRAM usage in statistics 2023-01-24 10:38:03 +00:00
Stenzek
e76afee12d GS/TextureCache: Only expand target on write on TBW match 2023-01-24 10:20:42 +00:00
TheLastRar
06ef51db2e DEV9: Move NetLib functions into header and mark as inline 2023-01-23 18:47:28 +00:00
TheLastRar
a85a2a3cc5 DEV9: Make use of MAC_Address struct 2023-01-23 18:47:28 +00:00
TheLastRar
8fbecbcdd7 DEV9: Add MAC_Address struct 2023-01-23 18:47:28 +00:00
TheLastRar
b386f78d68 DEV9: Make use of WriteIPAddress 2023-01-23 18:47:28 +00:00
TheLastRar
095757044a DEV9: Add IP_Address helpers to NetLib 2023-01-23 18:47:28 +00:00
PCSX2 Bot
9b3b8aa4de PAD: Update to latest controller database. 2023-01-23 17:05:04 +01:00
Connor McLaughlin
4932834441 GSRunner: Release globals on shutdown 2023-01-23 16:49:24 +01:00
refractionpcsx2
8773ebf64b VM: Queue shutdown message when called from inside emulation. 2023-01-23 16:45:58 +01:00
Connor McLaughlin
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
JordanTheToaster
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
Berylskid
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
JordanTheToaster
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
KFZ
e79fc72950 GameDB: Fixes for SpongeBob - The Movie (#7936) 2023-01-22 15:51:22 +00:00
JordanTheToaster
bcda41120e GameDB: Add Autoflush to Dynasty Warriors 5 Xtreme
Autoflush fixes the missing sun luminosity.
2023-01-22 15:01:54 +00:00
Mrlinkwii
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
lightningterror
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
Stenzek
88c1f00b62 GS: Add audio capture and custom resolution 2023-01-21 16:56:57 +00:00
Stenzek
6834367a3e GS: Move video capture encoding onto its own thread 2023-01-21 16:56:57 +00:00
Stenzek
dedcf21a37 GSCapture: Make readback for capture asynchronous 2023-01-21 16:56:57 +00:00
Stenzek
a747a5f9fa SPU2: Make SndOut.h compile in isolation 2023-01-21 16:56:57 +00:00
Stenzek
fcfb9865df GS: Add GSDownloadTexture (so we can download more than one at once) 2023-01-21 16:56:57 +00:00
JordanTheToaster
aa1e9cc9fa GameDB: Add AutoFlush to Battle For Volcano Island
Adds autoflush to fix texture corruptions.
2023-01-21 16:02:08 +00:00
Silent
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
Leyo
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
JordanTheToaster
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
Oymat
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
Mrlinkwii
536a4162c4 GameDB: upscaling fixes for 'TOCA Race Driver' 2023-01-19 21:47:36 +00:00
TheLastRar
41a47f99f7 DEV9: Use unique_ptr via typedef for ifadddrs buffer 2023-01-19 14:56:18 +01:00
TheLastRar
31fa1ea21e DEV9: AdapterUtils formatting 2023-01-19 14:56:18 +01:00
Stenzek
fb49c71118 SPU2: Clean up some unused/conditionally used functions 2023-01-19 11:02:13 +00:00
Stenzek
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
Stenzek
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
Tokman5
d94e861a78 GS: Add video folder and support additional arguments for video dumping 2023-01-19 10:39:22 +00:00
Oymat
d9b537d334 GameDB: Add SoftwareRendererFMVHack to Onimusha: Warlords (#7916)
close https://github.com/PCSX2/pcsx2/issues/7787
2023-01-18 19:15:43 +00:00
Stenzek
93c2081d3f USB: Remove readerwriterqueue
Not used anymore, apparently forgot to remove this in the USB refactor.
2023-01-18 10:08:46 +00:00
Leyo
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
Mrlinkwii
1f4416a77a GameDB: upscale fixes for 'Lord of the Rings, The - The Two Towers' 2023-01-17 19:26:13 +00:00
Mrlinkwii
e9d4dba64b GameDB: fixes for 'Dreamworks Madagascar' 2023-01-17 11:15:42 +00:00
lightningterror
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
Stenzek
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
JordanTheToaster
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 Bot
bc0fdc49e0 PAD: Update to latest controller database. 2023-01-16 17:18:26 +01:00
Stenzek
43ccb63eb5 Qt: Add DS4/DS5 LED settings 2023-01-16 14:08:01 +01:00
Ty Lamontagne
a0000a8547 Debugger: Implement boot and debug
Creates a breakpoint automatically on the ELF entry point
2023-01-15 17:05:35 +00:00
Stenzek
a37ff0c4f2 GS/Vulkan: Fix incorrect clamp in CreateSurface() 2023-01-15 17:40:15 +01:00
Stenzek
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
Stenzek
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
Stenzek
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
Stenzek
a342f4c7e9 GS/HW: Adjust Burnout CRC hack to stop hash cache spiking 2023-01-15 16:20:40 +00:00
JordanTheToaster
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
Stenzek
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
pgert
2740785df5 UI: Correct Error-messages: "SSE4.1" not "SSE4" (#7890) 2023-01-14 23:06:56 +00:00
Stenzek
613a9964a1 FullscreenUI: Fix descriptor use-after-free when deleting state 2023-01-14 14:07:30 +00:00
Ty Lamontagne
2ef2f5db1d Debugger: Fix step out 2023-01-14 12:51:14 +01:00
Ty Lamontagne
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
Mrlinkwii
58ff3e6c0d GameDB: add missing serial 2023-01-13 23:57:13 +00:00
Stenzek
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 McLaughlin
be76092195 USB: Correct Keyboardmania binding list 2023-01-13 09:31:27 +00:00
Stenzek
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
arcum42
8c21765c0f cmake: Turn back on some warnings that no longer need to be turned off. 2023-01-13 09:27:29 +00:00
TellowKrinkle
a2e3522862 GS:MTL: Implement clut shaders 2023-01-13 00:43:47 -04:00
Mrlinkwii
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 McLaughlin
0bca1aab74 Misc: Latest round of warning cleanups 2023-01-12 11:04:29 +01:00
Connor McLaughlin
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
Stenzek
7ef46eaa29 GameDB: Swap some CPU CLUT games for GPU CLUT
Burnout series, NFS Most Wanted.
2023-01-11 23:37:43 +00:00
Stenzek
38957625ad GameDatabase: Add GPUTargetCLUT 2023-01-11 23:37:43 +00:00
Stenzek
d30e076dbd GS: Add GPU Target CLUT 2023-01-11 23:37:43 +00:00
Stenzek
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
Stenzek
3ffa5eb613 GS: Add const to GSDirtyRect functions 2023-01-11 23:37:43 +00:00
Mrlinkwii
c60583c6bb GameDB: fixes for Battle for Volcano Island 2023-01-11 23:10:14 +00:00
Stenzek
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
RedDevilus
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
RedDevilus
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
arcum42
0a90765ed0 build: -Wno-maybe-uninitialized is a gcc only warning. 2023-01-11 00:55:21 +01:00
arcum42
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
Mrlinkwii
5be05853c6 GameDB: fixes for Hawk Kawasaki Racing 2023-01-10 21:00:43 +00:00
JordanTheToaster
0f569ac5cb Format: Clang format System.cpp 2023-01-10 16:18:26 +01:00
JordanTheToaster
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
JordanTheToaster
4d418d1bb5 Emitter: Remove old unused code
Irrelevant and outdated code that is no longer needed.
2023-01-10 16:18:26 +01:00
303 changed files with 22270 additions and 12505 deletions

24
.github/labeler.yml vendored
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/**/*'

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

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:

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 }}

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

View File

@@ -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}"

View File

@@ -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
.github/workflows/scripts/linux/functions.sh vendored Executable file
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
}

View File

@@ -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[@]}"

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

View File

@@ -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 Saturn Adapter,a:b0,b:b1,x:b3,y:b4,start:b9,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b7,righttrigger:b2,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,
@@ -882,7 +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,x:b6,y:b8,start:b18,leftshoulder:b10,rightshoulder:b12,dpup:b24,dpdown:b28,dpleft:b30,dpright:b26,lefttrigger:b14,righttrigger:b4,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,
@@ -899,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,
@@ -945,6 +946,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
@@ -1131,6 +1133,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
@@ -1241,10 +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,x:b3,y:b4,start:b9,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b7,righttrigger:b2,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,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,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,
@@ -1327,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,
@@ -1385,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,
@@ -1416,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,
@@ -1445,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,

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;

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
@@ -36,13 +38,13 @@
#define PS_POINT_SAMPLER 0
#define PS_SHUFFLE 0
#define PS_READ_BA 0
#define PS_SWAP_GA 0
#define PS_DFMT 0
#define PS_DEPTH_FMT 0
#define PS_PAL_FMT 0
#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 +132,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 +160,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 +185,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 +221,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 +248,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 +262,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 +273,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 +292,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 +302,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 +363,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 +483,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 +500,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 +517,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 +686,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
@@ -865,28 +876,37 @@ PS_OUTPUT ps_main(PS_INPUT input)
if (PS_SHUFFLE)
{
uint4 denorm_c = uint4(C);
uint2 denorm_TA = uint2(float2(TA.xy) * 255.0f + 0.5f);
// Mask will take care of the correct destination
if (PS_READ_BA)
C.rb = C.bb;
else
C.rb = C.rr;
if (PS_READ_BA)
if(PS_SWAP_GA)
{
if (denorm_c.a & 0x80u)
C.ga = (float2)(float((denorm_c.a & 0x7Fu) | (denorm_TA.y & 0x80u)));
else
C.ga = (float2)(float((denorm_c.a & 0x7Fu) | (denorm_TA.x & 0x80u)));
float4 RT = trunc(RtTexture.Load(int3(input.p.xy, 0)) * 255.0f + 0.1f);
C.a = C.g;
C.g = C.a;
}
else
{
if (denorm_c.g & 0x80u)
C.ga = (float2)(float((denorm_c.g & 0x7Fu) | (denorm_TA.y & 0x80u)));
uint4 denorm_c = uint4(C);
uint2 denorm_TA = uint2(float2(TA.xy) * 255.0f + 0.5f);
// Mask will take care of the correct destination
if (PS_READ_BA)
C.rb = C.bb;
else
C.ga = (float2)(float((denorm_c.g & 0x7Fu) | (denorm_TA.x & 0x80u)));
C.rb = C.rr;
if (PS_READ_BA)
{
if (denorm_c.a & 0x80u)
C.ga = (float2)(float((denorm_c.a & 0x7Fu) | (denorm_TA.y & 0x80u)));
else
C.ga = (float2)(float((denorm_c.a & 0x7Fu) | (denorm_TA.x & 0x80u)));
}
else
{
if (denorm_c.g & 0x80u)
C.ga = (float2)(float((denorm_c.g & 0x7Fu) | (denorm_TA.y & 0x80u)));
else
C.ga = (float2)(float((denorm_c.g & 0x7Fu) | (denorm_TA.x & 0x80u)));
}
}
}

View File

@@ -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
//////////////////////////////////////////////////////////////////////

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;

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

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
{

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
@@ -346,6 +347,7 @@ void main()
#define PS_ZCLAMP 0
#define PS_FEEDBACK_LOOP 0
#define PS_TEX_IS_FB 0
#define PS_SWAP_GA 0
#endif
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
@@ -361,10 +363,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 +392,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 +422,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 +458,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 +485,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 +500,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 +512,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 +533,7 @@ mat4 sample_4c(vec4 uv)
return c;
}
vec4 sample_4_index(vec4 uv)
uvec4 sample_4_index(vec4 uv)
{
vec4 c;
@@ -529,22 +543,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 +599,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 +722,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 +736,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 +750,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 +916,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
@@ -1165,26 +1174,32 @@ void main()
vec4 C = ps_color();
#if PS_SHUFFLE
uvec4 denorm_c = uvec4(C);
uvec2 denorm_TA = uvec2(vec2(TA.xy) * 255.0f + 0.5f);
// Mask will take care of the correct destination
#if PS_READ_BA
C.rb = C.bb;
#if PS_SWAP_GA
vec4 RT = trunc(subpassLoad(RtSampler) * 255.0f + 0.1f);
C.a = RT.g;
C.g = RT.a;
#else
C.rb = C.rr;
#endif
uvec4 denorm_c = uvec4(C);
uvec2 denorm_TA = uvec2(vec2(TA.xy) * 255.0f + 0.5f);
#if PS_READ_BA
if ((denorm_c.a & 0x80u) != 0u)
C.ga = vec2(float((denorm_c.a & 0x7Fu) | (denorm_TA.y & 0x80u)));
else
C.ga = vec2(float((denorm_c.a & 0x7Fu) | (denorm_TA.x & 0x80u)));
#else
if ((denorm_c.g & 0x80u) != 0u)
C.ga = vec2(float((denorm_c.g & 0x7Fu) | (denorm_TA.y & 0x80u)));
else
C.ga = vec2(float((denorm_c.g & 0x7Fu) | (denorm_TA.x & 0x80u)));
// Mask will take care of the correct destination
#if PS_READ_BA
C.rb = C.bb;
#else
C.rb = C.rr;
#endif
#if PS_READ_BA
if ((denorm_c.a & 0x80u) != 0u)
C.ga = vec2(float((denorm_c.a & 0x7Fu) | (denorm_TA.y & 0x80u)));
else
C.ga = vec2(float((denorm_c.a & 0x7Fu) | (denorm_TA.x & 0x80u)));
#else
if ((denorm_c.g & 0x80u) != 0u)
C.ga = vec2(float((denorm_c.g & 0x7Fu) | (denorm_TA.y & 0x80u)));
else
C.ga = vec2(float((denorm_c.g & 0x7Fu) | (denorm_TA.x & 0x80u)));
#endif
#endif
#endif

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()

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

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;
};

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);
}

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. :)

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);

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;
}

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

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
}

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)
{

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

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",

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;

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;
}

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

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;

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" />

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>

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};

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
crowdin.yml Normal file
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'

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();

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)

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);
}

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

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);
}

View File

@@ -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;
};

View File

@@ -112,11 +112,14 @@ void BreakpointDialog::accept()
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))
{
@@ -177,7 +180,7 @@ void BreakpointDialog::accept()
m_bpModel.removeRows(m_rowIndex, 1);
}
m_bpModel.insertRows(0, 1, {m_bp_mc});
m_bpModel.insertBreakpointRows(0, 1, {m_bp_mc});
QDialog::accept();
}

View File

@@ -160,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();
});

View File

@@ -105,8 +105,5 @@ private:
ThreadModel m_threadModel;
StackModel m_stackModel;
std::vector<EEThread> m_threadlistObjects;
std::vector<StackFrame> m_stacklistObjects;
bool m_demangleFunctions = true;
};

View File

@@ -88,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;
}

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); });

View File

@@ -306,9 +306,9 @@ bool BreakpointModel::removeRows(int row, int count, const QModelIndex& index)
return true;
}
bool BreakpointModel::insertRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index)
bool BreakpointModel::insertBreakpointRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index)
{
if (breakpoints.size() != count)
if (breakpoints.size() != static_cast<size_t>(count))
return false;
beginInsertRows(index, row, row + count);

View File

@@ -47,7 +47,7 @@ public:
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 insertRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index = QModelIndex());
bool insertBreakpointRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index = QModelIndex());
BreakpointMemcheck at(int row) const { return m_breakpoints.at(row); };

View File

@@ -107,18 +107,15 @@ QVariant StackModel::headerData(int section, Qt::Orientation orientation, int ro
void StackModel::refreshData()
{
if (m_cpu.getCpuType() == BREAKPOINT_IOP)
return;
// Hopefully in the near future we can get a stack frame for
// each thread
beginResetModel();
for (const auto& thread : getEEThreads())
for (const auto& thread : m_cpu.GetThreadList())
{
if (thread.data.status == THS_RUN)
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.data.entry_init, thread.data.stack);
thread->EntryPoint(), thread->StackTop());
break;
}
}

View File

@@ -27,10 +27,7 @@ ThreadModel::ThreadModel(DebugInterface& cpu, QObject* parent)
int ThreadModel::rowCount(const QModelIndex&) const
{
if (m_cpu.getCpuType() == BREAKPOINT_EE)
return getEEThreads().size();
else
return 0;
return m_cpu.GetThreadList().size();
}
int ThreadModel::columnCount(const QModelIndex&) const
@@ -40,66 +37,65 @@ int ThreadModel::columnCount(const QModelIndex&) const
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)
{
const auto thread = getEEThreads().at(index.row());
switch (index.column())
{
case ThreadModel::ID:
return thread.tid;
return thread->TID();
case ThreadModel::PC:
{
if (thread.data.status == THS_RUN)
if (thread->Status() == ThreadStatus::THS_RUN)
return QtUtils::FilledQStringFromValue(m_cpu.getPC(), 16);
else
return QtUtils::FilledQStringFromValue(thread.data.entry, 16);
return QtUtils::FilledQStringFromValue(thread->PC(), 16);
}
case ThreadModel::ENTRY:
return QtUtils::FilledQStringFromValue(thread.data.entry_init, 16);
return QtUtils::FilledQStringFromValue(thread->EntryPoint(), 16);
case ThreadModel::PRIORITY:
return QString::number(thread.data.currentPriority);
return QString::number(thread->Priority());
case ThreadModel::STATE:
{
const auto& state = ThreadStateStrings.find(thread.data.status);
const auto& state = ThreadStateStrings.find(thread->Status());
if (state != ThreadStateStrings.end())
return state->second;
else
return tr("INVALID");
return tr("INVALID");
}
case ThreadModel::WAIT_TYPE:
{
const auto& waitType = ThreadWaitStrings.find(thread.data.waitType);
const auto& waitType = ThreadWaitStrings.find(thread->Wait());
if (waitType != ThreadWaitStrings.end())
return waitType->second;
else
return tr("INVALID");
return tr("INVALID");
}
}
}
else if (role == Qt::UserRole)
{
const auto& thread = getEEThreads().at(index.row());
switch (index.column())
{
case ThreadModel::ID:
return thread.tid;
return thread->TID();
case ThreadModel::PC:
{
if (thread.data.status == THS_RUN)
if (thread->Status() == ThreadStatus::THS_RUN)
return m_cpu.getPC();
else
return thread.data.entry;
return thread->PC();
}
case ThreadModel::ENTRY:
return thread.data.entry_init;
return thread->EntryPoint();
case ThreadModel::PRIORITY:
return thread.data.currentPriority;
return thread->Priority();
case ThreadModel::STATE:
return thread.data.status;
return static_cast<u32>(thread->Status());
case ThreadModel::WAIT_TYPE:
return thread.data.waitType;
return static_cast<u32>(thread->Wait());
default:
return QVariant();
}

View File

@@ -48,19 +48,27 @@ public:
void refreshData();
private:
const std::map<int, QString> ThreadStateStrings{
{THS_BAD, tr("BAD")},
{THS_RUN, tr("RUN")},
{THS_READY, tr("READY")},
{THS_WAIT, tr("WAIT")},
{THS_SUSPEND, tr("SUSPEND")},
{THS_WAIT_SUSPEND, tr("WAIT SUSPEND")},
{THS_DORMANT, tr("DORMANT")}};
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<int, QString> ThreadWaitStrings{
{WAIT_NONE, tr("NONE")},
{WAIT_WAKEUP_REQ, tr("WAKEUP REQUEST")},
{WAIT_SEMA, tr("SEMAPHORE")}};
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;
};

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.

View File

@@ -488,7 +488,7 @@ void GameListWidget::resizeTableViewColumnsToFit()
80, // last played
80, // size
60, // region
100 // compatibility
120 // compatibility
});
}

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();

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;

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));

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();

View File

@@ -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);
}

View File

@@ -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(""));

View File

@@ -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>

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;
@@ -109,7 +108,8 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
onMinimalOutputLatencyStateChanged();
updateLatencyLabels();
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(""));
@@ -117,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"),

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>
@@ -366,7 +378,7 @@
<number>200</number>
</property>
<property name="value">
<number>100</number>
<number>60</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -382,7 +394,7 @@
<item>
<widget class="QLabel" name="targetLatencyLabel">
<property name="text">
<string>100 ms</string>
<string>60 ms</string>
</property>
</widget>
</item>
@@ -425,7 +437,7 @@
<number>200</number>
</property>
<property name="value">
<number>100</number>
<number>20</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -441,7 +453,7 @@
<item>
<widget class="QLabel" name="outputLatencyLabel">
<property name="text">
<string>100 ms</string>
<string>20 ms</string>
</property>
</widget>
</item>

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);
}

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:

View File

@@ -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
}

View File

@@ -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;
};

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);

View File

@@ -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)));

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 =

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:

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-
@@ -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."));

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>

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();

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;

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>

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) {

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
{

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">

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)

View File

@@ -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
{

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

View File

@@ -46,6 +46,7 @@
<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;$(ProjectDir)\Debugger\Models</AdditionalIncludeDirectories>
@@ -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" />
@@ -211,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" />
@@ -292,6 +297,7 @@
<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" />
@@ -414,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">
@@ -430,4 +439,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<Import Project="$(SolutionDir)common\vsprops\QtCompile.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
</Project>

View File

@@ -27,9 +27,7 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\pcsx2\PCSX2.rc">
<Filter>Resources</Filter>
</ResourceCompile>
<ResourceCompile Include="..\pcsx2\windows\PCSX2.rc" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="PrecompiledHeader.cpp" />
@@ -313,6 +311,10 @@
<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">
@@ -459,6 +461,7 @@
<QtMoc Include="Debugger\Models\StackModel.h">
<Filter>Debugger\Models</Filter>
</QtMoc>
<QtMoc Include="ColorPickerButton.h" />
</ItemGroup>
<ItemGroup>
<QtResource Include="resources\resources.qrc">
@@ -577,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">

View File

@@ -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

View File

@@ -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

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>

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)

View File

@@ -430,9 +430,7 @@ bool DoCDVDopen()
Host::AddKeyedOSDMessage("BlockDumpCreate", fmt::format("Saving CDVD block dump to '{}'.", temp), Host::OSD_INFO_DURATION);
blockDumpFile.Create(std::move(temp), 2);
if (blockDumpFile.IsOpened())
if (blockDumpFile.Create(std::move(temp), 2))
{
int blockofs = 0;
uint blocksize = CD_FRAMESIZE_RAW;

View File

@@ -51,15 +51,8 @@ s32 CALLBACK ISOopen(const char* pTitle)
return -1;
}
try
{
iso.Open(pTitle);
}
catch (BaseException& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
if (!iso.Open(pTitle))
return -1;
}
switch (iso.GetType())
{

View File

@@ -0,0 +1,115 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 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 "CDVD/CDVDdiscReader.h"
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/storage/IOMedia.h>
#include <IOKit/storage/IOCDMedia.h>
#include <IOKit/storage/IODVDMedia.h>
#include <IOKit/IOBSD.h>
#include <IOKit/IOKitLib.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#ifdef __APPLE__
std::vector<std::string> GetDriveListFromClasses(CFMutableDictionaryRef classes)
{
io_iterator_t iterator = IO_OBJECT_NULL;
kern_return_t result;
std::vector<std::string> drives;
CFDictionarySetValue(classes, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue);
result = IOServiceGetMatchingServices(kIOMasterPortDefault, classes, &iterator);
if (result != KERN_SUCCESS)
return drives;
while (io_object_t media = IOIteratorNext(iterator))
{
CFTypeRef path_cfstr = IORegistryEntryCreateCFProperty(media, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
if (path_cfstr)
{
char path[PATH_MAX] = {0};
strlcpy(path, "/dev/r", PATH_MAX);
size_t path_prefix_len = strnlen(path, PATH_MAX);
result = CFStringGetCString((CFStringRef)path_cfstr, path + path_prefix_len, PATH_MAX - path_prefix_len, kCFStringEncodingUTF8);
if (result)
{
drives.emplace_back(path);
}
CFRelease(path_cfstr);
}
IOObjectRelease(media);
}
IOObjectRelease(iterator);
return drives;
}
#endif
std::vector<std::string> GetOpticalDriveList()
{
#ifdef __APPLE__
std::vector<std::string> drives;
if (CFMutableDictionaryRef cd_classes = IOServiceMatching(kIOCDMediaClass))
{
std::vector<std::string> cd = GetDriveListFromClasses(cd_classes);
drives.insert(drives.end(), cd.begin(), cd.end());
}
if (CFMutableDictionaryRef dvd_classes = IOServiceMatching(kIODVDMediaClass))
{
std::vector<std::string> dvd = GetDriveListFromClasses(dvd_classes);
drives.insert(drives.end(), dvd.begin(), dvd.end());
}
return drives;
#else
return {};
#endif
}
void GetValidDrive(std::string& drive)
{
if (!drive.empty())
{
#ifdef __APPLE__
int fd = open(drive.c_str(), O_RDONLY | O_NONBLOCK);
if (fd != -1)
{
close(fd);
}
else
{
drive.clear();
}
#else
drive.clear();
#endif
}
if (drive.empty())
{
auto drives = GetOpticalDriveList();
if (!drives.empty())
drive = drives.front();
}
if (!drive.empty())
DevCon.WriteLn("CDVD: Opening drive '%s'...", drive.c_str());
}

View File

@@ -0,0 +1,263 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 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 "CDVD/CDVDdiscReader.h"
#include "CDVD/CDVD.h"
#ifdef __APPLE__
#include <IOKit/storage/IOCDMediaBSDClient.h>
#include <IOKit/storage/IODVDMediaBSDClient.h>
#endif
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
IOCtlSrc::IOCtlSrc(decltype(m_filename) filename)
: m_filename(filename)
{
if (!Reopen())
throw std::runtime_error(" * CDVD: Error opening source.\n");
}
IOCtlSrc::~IOCtlSrc()
{
if (m_device != -1)
{
SetSpindleSpeed(true);
close(m_device);
}
}
bool IOCtlSrc::Reopen()
{
if (m_device != -1)
close(m_device);
// O_NONBLOCK allows a valid file descriptor to be returned even if the
// drive is empty. Probably does other things too.
m_device = open(m_filename.c_str(), O_RDONLY | O_NONBLOCK);
if (m_device == -1)
return false;
// DVD detection MUST be first on Linux - The TOC ioctls work for both
// CDs and DVDs.
if (ReadDVDInfo() || ReadCDInfo())
SetSpindleSpeed(false);
return true;
}
void IOCtlSrc::SetSpindleSpeed(bool restore_defaults) const
{
u16 speed = restore_defaults ? 0xFFFF : m_media_type >= 0 ? 5540 :
3600;
int ioctl_code = m_media_type >= 0 ? DKIOCDVDSETSPEED : DKIOCCDSETSPEED;
if (ioctl(m_device, ioctl_code, &speed) == -1)
{
DevCon.Warning("CDVD: Failed to set spindle speed: %s", strerror(errno));
}
else if (!restore_defaults)
{
DevCon.WriteLn("CDVD: Spindle speed set to %d", speed);
}
}
u32 IOCtlSrc::GetSectorCount() const
{
return m_sectors;
}
u32 IOCtlSrc::GetLayerBreakAddress() const
{
return m_layer_break;
}
s32 IOCtlSrc::GetMediaType() const
{
return m_media_type;
}
const std::vector<toc_entry>& IOCtlSrc::ReadTOC() const
{
return m_toc;
}
bool IOCtlSrc::ReadSectors2048(u32 sector, u32 count, u8* buffer) const
{
const ssize_t bytes_to_read = 2048 * count;
ssize_t bytes_read = pread(m_device, buffer, bytes_to_read, sector * 2048ULL);
if (bytes_read == bytes_to_read)
return true;
if (bytes_read == -1)
DevCon.Warning("CDVD: read sectors %u-%u failed: %s",
sector, sector + count - 1, strerror(errno));
else
DevCon.Warning("CDVD: read sectors %u-%u: %zd bytes read, %zd bytes expected",
sector, sector + count - 1, bytes_read, bytes_to_read);
return false;
}
bool IOCtlSrc::ReadSectors2352(u32 sector, u32 count, u8* buffer) const
{
#ifdef __APPLE__
dk_cd_read_t desc;
memset(&desc, 0, sizeof(dk_cd_read_t));
desc.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader | kCDSectorAreaSubHeader | kCDSectorAreaUser | kCDSectorAreaAuxiliary;
desc.sectorType = kCDSectorTypeUnknown;
for (u32 i = 0; i < count; ++i)
{
desc.offset = (sector + i) * 2352ULL;
desc.buffer = buffer + i * 2352;
desc.bufferLength = 2352;
if (ioctl(m_device, DKIOCCDREAD, &desc) == -1)
{
DevCon.Warning("CDVD: DKIOCCDREAD sector %u failed: %s",
sector + i, strerror(errno));
return false;
}
}
return true;
#else
return false;
#endif
}
bool IOCtlSrc::ReadDVDInfo()
{
#ifdef __APPLE__
dk_dvd_read_structure_t dvdrs;
memset(&dvdrs, 0, sizeof(dk_dvd_read_structure_t));
dvdrs.format = kDVDStructureFormatPhysicalFormatInfo;
dvdrs.layer = 0;
DVDPhysicalFormatInfo layer0;
dvdrs.buffer = &layer0;
dvdrs.bufferLength = sizeof(DVDPhysicalFormatInfo);
int ret = ioctl(m_device, DKIOCDVDREADSTRUCTURE, &dvdrs);
if (ret == -1)
{
return false;
}
u32 start_sector = *(u32*)layer0.startingPhysicalSectorNumberOfDataArea;
u32 end_sector = *(u32*)layer0.endPhysicalSectorNumberOfDataArea;
if (layer0.numberOfLayers == 0)
{
// Single layer
m_media_type = 0;
m_layer_break = 0;
m_sectors = end_sector - start_sector + 1;
}
else if (layer0.trackPath == 0)
{
// Dual layer, Parallel Track Path
DVDPhysicalFormatInfo layer1;
dvdrs.layer = 1;
dvdrs.buffer = &layer1;
dvdrs.bufferLength = sizeof(DVDPhysicalFormatInfo);
ret = ioctl(m_device, DKIOCDVDREADSTRUCTURE, &dvdrs);
if (ret == -1)
return false;
u32 layer1_start_sector = *(u32*)layer1.startingPhysicalSectorNumberOfDataArea;
u32 layer1_end_sector = *(u32*)layer1.endPhysicalSectorNumberOfDataArea;
m_media_type = 1;
m_layer_break = end_sector - start_sector;
m_sectors = end_sector - start_sector + 1 + layer1_end_sector - layer1_start_sector + 1;
}
else
{
// Dual layer, Opposite Track Path
u32 end_sector_layer0 = *(u32*)layer0.endSectorNumberInLayerZero;
m_media_type = 2;
m_layer_break = end_sector_layer0 - start_sector;
m_sectors = end_sector_layer0 - start_sector + 1 + end_sector - (~end_sector_layer0 & 0xFFFFFFU) + 1;
}
return true;
#else
return false;
#endif
}
bool IOCtlSrc::ReadCDInfo()
{
#ifdef __APPLE__
u8* buffer = (u8*)malloc(2048);
dk_cd_read_toc_t cdrt;
memset(&cdrt, 0, sizeof(dk_cd_read_toc_t));
cdrt.format = kCDTOCFormatTOC;
cdrt.formatAsTime = 1;
cdrt.address.track = 0;
cdrt.buffer = buffer;
cdrt.bufferLength = 2048;
memset(buffer, 0, 2048);
if (ioctl(m_device, DKIOCCDREADTOC, &cdrt) == -1)
{
DevCon.Warning("CDVD: DKIOCCDREADTOC failed: %s\n", strerror(errno));
return false;
}
CDTOC* toc = (CDTOC*)buffer;
u32 desc_count = CDTOCGetDescriptorCount(toc);
for (u32 i = 0; i < desc_count; ++i)
{
CDTOCDescriptor desc = toc->descriptors[i];
if (desc.point < 0xa0 && desc.adr == 1)
{
u32 lba = CDConvertMSFToLBA(desc.p);
m_toc.push_back({lba, desc.point, desc.adr, desc.control});
}
else if (desc.point == 0xa2) // lead out, use to get total sector count
{
m_sectors = CDConvertMSFToLBA(desc.p);
}
}
m_media_type = -1;
free(buffer);
return true;
#else
return false;
#endif
}
bool IOCtlSrc::DiscReady()
{
#ifdef __APPLE__
if (m_device == -1)
return false;
if (!m_sectors)
{
Reopen();
}
return !!m_sectors;
#else
return false;
#endif
}

View File

@@ -293,7 +293,7 @@ bool GzippedFileReader::OkIndex()
Console.Warning("This may take a while (but only once). Scanning compressed file to generate a quick access index...");
const s64 prevoffset = FileSystem::FTell64(m_src);
Access* index;
Access* index = nullptr;
int len = build_index(m_src, GZFILE_SPAN_DEFAULT, &index);
printf("\n"); // build_index prints progress without \n's
FileSystem::FSeek64(m_src, prevoffset, SEEK_SET);

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