Compare commits

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

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

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

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

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

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

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

Fixes Burnout 3 crashing in clang builds.
2023-01-16 20:13:46 +00:00
JordanTheToasterandrefractionpcsx2 f6cb7ca01d GameDB: Add HPO Normal to WWE 2008 and 2009
Fixes slight blur on people and depth bleed that happens on the right hand side.
2023-01-16 18:19:27 +00:00
PCSX2 Botandlightningterror bc0fdc49e0 PAD: Update to latest controller database. 2023-01-16 17:18:26 +01:00
256 changed files with 20421 additions and 11412 deletions
+18 -6
View File
@@ -32,6 +32,8 @@
- '**/GameIndex.*'
'Installer | Package':
- 'build.sh'
'Translations':
- 'pcsx2-qt/Translations/*'
# Tools / Features
'Debugger':
@@ -45,6 +47,9 @@
'TAS Functionality':
- 'pcsx2/Recording/*'
- 'pcsx2/Recording/**/*'
'RetroAchievements':
- 'pcsx2/Frontend/Achievements.*'
- 'pcsx2/Achievements.*'
# Emulation Components
'Counters':
@@ -64,21 +69,31 @@
'GS':
- 'pcsx2/GS/*'
- 'pcsx2/GS/**/*'
- 'bin/resources/shaders/*'
- 'bin/resources/shaders/**/*'
'GS: Direct3D 11':
- 'pcsx2/GS/Renderers/DX11/*'
- 'pcsx2/GS/Renderers/DX11/**/*'
- 'bin/resources/shaders/dx11/*'
- 'bin/resources/shaders/dx11/**/*'
'GS: Direct3D 12':
- 'pcsx2/GS/Renderers/DX12/*'
- 'pcsx2/GS/Renderers/DX12/**/*'
- 'bin/resources/shaders/dx11/*'
- 'bin/resources/shaders/dx11/**/*'
'GS: Hardware':
- 'pcsx2/GS/Renderers/HW/*'
- 'pcsx2/GS/Renderers/HW/**/*'
'GS: OpenGL':
- 'pcsx2/GS/Renderers/OpenGL/*'
- 'pcsx2/GS/Renderers/OpenGL/**/*'
- 'bin/resources/shaders/opengl/*'
- 'bin/resources/shaders/opengl/**/*'
'GS: Vulkan':
- 'pcsx2/GS/Renderers/Vulkan/*'
- 'pcsx2/GS/Renderers/Vulkan/**/*'
- 'bin/resources/shaders/vulkan/*'
- 'bin/resources/shaders/vulkan/**/*'
'GS: Metal':
- 'pcsx2/GS/Renderers/Metal/*'
- 'pcsx2/GS/Renderers/Metal/**/*'
@@ -102,12 +117,9 @@
'Memory Card':
- 'pcsx2/gui/MemoryCard*'
- 'pcsx2/gui/**/MemoryCard*'
'PAD: Linux/Mac':
- 'pcsx2/PAD/Linux/*'
- 'pcsx2/PAD/Linux/**/*'
'PAD: Windows':
- 'pcsx2/PAD/Windows/*'
- 'pcsx2/PAD/Windows/**/*'
'PAD':
- 'pcsx2/PAD/*'
- 'pcsx2/PAD/**/*'
'SPU2':
- 'pcsx2/SPU2/*'
- 'pcsx2/SPU2/**/*'
+2 -15
View File
@@ -9,25 +9,12 @@ on:
- master
jobs:
build_linux_qt_sse4:
build_linux_qt:
name: "AppImage"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt SSE4"
jobName: "Qt"
compiler: clang
cmakeflags: ""
simd: "SSE4"
buildAppImage: true
secrets: inherit
build_linux_qt_avx2:
name: "AppImage"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt AVX2"
detail: ""
compiler: clang
cmakeflags: "-DARCH_FLAG=-march=haswell"
simd: "AVX2"
buildAppImage: true
secrets: inherit
+2 -7
View File
@@ -28,10 +28,6 @@ on:
required: false
type: string
default: ""
simd:
required: false
type: string
default: ""
cheats_url:
required: false
type: string
@@ -63,7 +59,6 @@ jobs:
OS: linux
GUI_FRAMEWORK: QT
ARCH: ${{ inputs.platform }}
SIMD: ${{ inputs.simd }}
EVENT_NAME: ${{ github.event_name }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_NUM: ${{ github.event.pull_request.number }}
@@ -79,8 +74,8 @@ jobs:
uses: actions/cache@v3
with:
path: .ccache
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.simd }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.simd }} ${{ inputs.detail }} ccache
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache
- name: Install Packages
env:
-1
View File
@@ -49,7 +49,6 @@ jobs:
OS: macos
GUI_FRAMEWORK: ${{ inputs.gui }}
ARCH: ${{ inputs.platform }}
SIMD: ''
EVENT_NAME: ${{ github.event_name }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_NUM: ${{ github.event.pull_request.number }}
+14 -18
View File
@@ -8,32 +8,28 @@ on:
jobs:
# Build Everything
# Linux
build_linux_qt_sse4:
build_linux_qt:
if: github.repository == 'PCSX2/pcsx2'
name: "Linux - AppImage SSE4"
name: "Linux"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt"
compiler: clang
cmakeflags: ""
simd: "SSE4"
buildAppImage: true
secrets: inherit
build_linux_qt_avx2:
if: github.repository == 'PCSX2/pcsx2'
name: "Linux - AppImage AVX2"
uses: ./.github/workflows/linux_build_qt.yml
with:
jobName: "Qt"
detail: ""
compiler: clang
cmakeflags: "-DARCH_FLAG=-march=haswell"
simd: "AVX2"
buildAppImage: true
secrets: inherit
# Windows
build_windows_qt:
if: github.repository == 'PCSX2/pcsx2'
name: "Windows"
uses: ./.github/workflows/windows_build_qt.yml
with:
jobName: Qt
configuration: CMake
buildSystem: cmake
secrets: inherit
build_qt_sse4:
if: github.repository == 'PCSX2/pcsx2'
name: "Windows - SSE4"
@@ -67,8 +63,8 @@ jobs:
upload_artifacts:
if: github.repository == 'PCSX2/pcsx2'
needs:
- build_linux_qt_sse4
- build_linux_qt_avx2
- build_linux_qt
- build_windows_qt
- build_qt_sse4
- build_qt_avx2
- build_macos_qt
@@ -21,7 +21,7 @@ NAME=""
if [ "${OS}" == "macos" ]; then
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}"
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") || ("$OS" == "linux" && "$GUI_FRAMEWORK" == "QT") ]]; then
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") ]]; then
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}-${SIMD}"
else
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}"
File diff suppressed because it is too large Load Diff
+15 -10
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,
+22 -17
View File
@@ -21,6 +21,8 @@
#define PS_FST 0
#define PS_WMS 0
#define PS_WMT 0
#define PS_ADJS 0
#define PS_ADJT 0
#define PS_AEM_FMT FMT_32
#define PS_AEM 0
#define PS_TFX 0
@@ -42,7 +44,6 @@
#define PS_CHANNEL_FETCH 0
#define PS_TALES_OF_ABYSS_HLE 0
#define PS_URBAN_CHAOS_HLE 0
#define PS_INVALID_TEX0 0
#define PS_SCALE_FACTOR 1.0
#define PS_HDR 0
#define PS_COLCLIP 0
@@ -158,10 +159,10 @@ cbuffer cb1
float2 TA;
float MaxDepthPS;
float Af;
uint4 MskFix;
uint4 FbMask;
float4 HalfTexel;
float4 MinMax;
float4 STRange;
int4 ChannelShuffle;
float2 TC_OffsetHack;
float2 STScale;
@@ -183,7 +184,20 @@ float4 sample_c(float2 uv, float uv_w)
// As of 2018 this issue is still present.
uv = (trunc(uv * WH.zw) + float2(0.5, 0.5)) / WH.zw;
}
#if !PS_ADJS && !PS_ADJT
uv *= STScale;
#else
#if PS_ADJS
uv.x = (uv.x - STRange.x) * STRange.z;
#else
uv.x = uv.x * STScale.x;
#endif
#if PS_ADJT
uv.y = (uv.y - STRange.y) * STRange.w;
#else
uv.y = uv.y * STScale.y;
#endif
#endif
#if PS_AUTOMATIC_LOD == 1
return Texture.Sample(TextureSampler, uv);
@@ -218,12 +232,7 @@ float4 sample_p_norm(float u)
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)
{
@@ -238,7 +247,7 @@ float4 clamp_wrap_uv(float4 uv)
// textures. Fixes Xenosaga's hair issue.
uv = frac(uv);
#endif
uv = (float4)(((uint4)(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
uv = (float4)(((uint4)(uv * tex_size) & asuint(MinMax.xyxy)) | asuint(MinMax.zwzw)) / tex_size;
}
}
else
@@ -252,7 +261,7 @@ float4 clamp_wrap_uv(float4 uv)
#if PS_FST == 0
uv.xz = frac(uv.xz);
#endif
uv.xz = (float2)(((uint2)(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
uv.xz = (float2)(((uint2)(uv.xz * tex_size.xx) & asuint(MinMax.xx)) | asuint(MinMax.zz)) / tex_size.xx;
}
if(PS_WMT == 2)
{
@@ -263,7 +272,7 @@ float4 clamp_wrap_uv(float4 uv)
#if PS_FST == 0
uv.yw = frac(uv.yw);
#endif
uv.yw = (float2)(((uint2)(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
uv.yw = (float2)(((uint2)(uv.yw * tex_size.yy) & asuint(MinMax.yy)) | asuint(MinMax.ww)) / tex_size.yy;
}
}
@@ -353,7 +362,7 @@ float4 fetch_c(int2 uv)
int2 clamp_wrap_uv_depth(int2 uv)
{
int4 mask = (int4)MskFix << 4;
int4 mask = asint(MinMax) << 4;
if (PS_WMS == PS_WMT)
{
if (PS_WMS == 2)
@@ -676,11 +685,7 @@ float4 fog(float4 c, float f)
float4 ps_color(PS_INPUT input)
{
#if PS_FST == 0 && PS_INVALID_TEX0 == 1
// Re-normalize coordinate from invalid GS to corrected texture size
float2 st = (input.t.xy * WH.xy) / (input.t.w * WH.zw);
float2 st_int = (input.ti.zw * WH.xy) / (input.t.w * WH.zw);
#elif PS_FST == 0
#if PS_FST == 0
float2 st = input.t.xy / input.t.w;
float2 st_int = input.ti.zw / input.t.w;
#else
@@ -75,13 +75,12 @@ layout(std140, binding = 0) uniform cb21
float MaxDepthPS;
float Af;
uvec4 MskFix;
uvec4 FbMask;
vec4 HalfTexel;
vec4 MinMax;
vec4 STRange;
ivec4 ChannelShuffle;
@@ -92,11 +91,6 @@ layout(std140, binding = 0) uniform cb21
};
#endif
//layout(std140, binding = 22) uniform cb22
//{
// vec4 rt_size;
//};
//////////////////////////////////////////////////////////////////////
// Default Sampler
//////////////////////////////////////////////////////////////////////
+20 -15
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);
@@ -146,11 +159,7 @@ vec4 sample_p_norm(float u)
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
@@ -162,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
@@ -174,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
@@ -185,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
@@ -227,7 +236,7 @@ uvec4 sample_4_index(vec4 uv)
#if PS_PAL_FMT == 1
// 4HL
return i & 0xFu
return i & 0xFu;
#elif PS_PAL_FMT == 2
// 4HH
return i >> 4u;
@@ -288,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
@@ -591,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
+25 -21
View File
@@ -312,6 +312,8 @@ void main()
#define PS_FST 0
#define PS_WMS 0
#define PS_WMT 0
#define PS_ADJS 0
#define PS_ADJT 0
#define PS_FMT FMT_32
#define PS_AEM 0
#define PS_TFX 0
@@ -332,7 +334,6 @@ void main()
#define PS_CHANNEL_FETCH 0
#define PS_TALES_OF_ABYSS_HLE 0
#define PS_URBAN_CHAOS_HLE 0
#define PS_INVALID_TEX0 0
#define PS_SCALE_FACTOR 1.0
#define PS_HDR 0
#define PS_COLCLIP 0
@@ -361,10 +362,10 @@ layout(std140, set = 0, binding = 1) uniform cb1
vec2 TA;
float MaxDepthPS;
float Af;
uvec4 MskFix;
uvec4 FbMask;
vec4 HalfTexel;
vec4 MinMax;
vec4 STRange;
ivec4 ChannelShuffle;
vec2 TC_OffsetHack;
vec2 STScale;
@@ -420,7 +421,20 @@ vec4 sample_c(vec2 uv)
// As of 2018 this issue is still present.
uv = (trunc(uv * WH.zw) + vec2(0.5, 0.5)) / WH.zw;
#endif
#if !PS_ADJS && !PS_ADJT
uv *= STScale;
#else
#if PS_ADJS
uv.x = (uv.x - STRange.x) * STRange.z;
#else
uv.x = uv.x * STScale.x;
#endif
#if PS_ADJT
uv.y = (uv.y - STRange.y) * STRange.w;
#else
uv.y = uv.y * STScale.y;
#endif
#endif
#if PS_AUTOMATIC_LOD == 1
return texture(Texture, uv);
@@ -455,13 +469,7 @@ vec4 sample_p_norm(float u)
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
{
@@ -476,7 +484,7 @@ vec4 clamp_wrap_uv(vec4 uv)
// textures. Fixes Xenosaga's hair issue.
uv = fract(uv);
#endif
uv = vec4((uvec4(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
uv = vec4((uvec4(uv * tex_size) & floatBitsToUint(MinMax.xyxy)) | floatBitsToUint(MinMax.zwzw)) / tex_size;
}
#endif
}
@@ -491,7 +499,7 @@ vec4 clamp_wrap_uv(vec4 uv)
#if PS_FST == 0
uv.xz = fract(uv.xz);
#endif
uv.xz = vec2((uvec2(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
uv.xz = vec2((uvec2(uv.xz * tex_size.xx) & floatBitsToUint(MinMax.xx)) | floatBitsToUint(MinMax.zz)) / tex_size.xx;
}
#endif
#if PS_WMT == 2
@@ -503,7 +511,7 @@ vec4 clamp_wrap_uv(vec4 uv)
#if PS_FST == 0
uv.yw = fract(uv.yw);
#endif
uv.yw = vec2((uvec2(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
uv.yw = vec2((uvec2(uv.yw * tex_size.yy) & floatBitsToUint(MinMax.yy)) | floatBitsToUint(MinMax.ww)) / tex_size.yy;
}
#endif
}
@@ -534,14 +542,14 @@ uvec4 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 = i & 0xFu;
return i & 0xFu;
#elif PS_PAL_FMT == 2
// 4HH
c = i >> 4u;
return i >> 4u;
#else
// 8
return i;
@@ -590,7 +598,7 @@ vec4 fetch_c(ivec2 uv)
ivec2 clamp_wrap_uv_depth(ivec2 uv)
{
ivec4 mask = ivec4(MskFix << 4);
ivec4 mask = floatBitsToInt(MinMax) << 4;
#if (PS_WMS == PS_WMT)
{
#if (PS_WMS == 2)
@@ -907,11 +915,7 @@ vec4 fog(vec4 c, float f)
vec4 ps_color()
{
#if PS_FST == 0 && PS_INVALID_TEX0 == 1
// Re-normalize coordinate from invalid GS to corrected texture size
vec2 st = (vsIn.t.xy * WH.xy) / (vsIn.t.w * WH.zw);
vec2 st_int = (vsIn.ti.zw * WH.xy) / (vsIn.t.w * WH.zw);
#elif PS_FST == 0
#if PS_FST == 0
vec2 st = vsIn.t.xy / vsIn.t.w;
vec2 st_int = vsIn.ti.zw / vsIn.t.w;
#else
+1 -5
View File
@@ -10,16 +10,14 @@ add_library(common)
# x86emitter sources
target_sources(common PRIVATE
AlignedMalloc.cpp
VirtualMemory.cpp
EventSource.inl
SafeArray.inl
Console.cpp
CrashHandler.cpp
DynamicLibrary.cpp
EventSource.cpp
Exceptions.cpp
FastJmp.cpp
FileSystem.cpp
General.cpp
Image.cpp
HTTPDownloader.cpp
MemorySettingsInterface.cpp
@@ -71,7 +69,6 @@ target_sources(common PRIVATE
DynamicLibrary.h
Easing.h
EnumOps.h
EventSource.h
Exceptions.h
FastJmp.h
FileSystem.h
@@ -88,7 +85,6 @@ target_sources(common PRIVATE
MD5Digest.h
MRCHelpers.h
Path.h
PageFaultSource.h
PrecompiledHeader.h
ProgressCallback.h
ReadbackSpinManager.h
-94
View File
@@ -1,94 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <list>
#include <mutex>
// --------------------------------------------------------------------------------------
// EventSource< template EvtType >
// --------------------------------------------------------------------------------------
template <typename ListenerType>
class EventSource
{
public:
typedef typename ListenerType::EvtParams EvtParams;
typedef typename std::list<ListenerType*> ListenerList;
typedef typename ListenerList::iterator ListenerIterator;
protected:
typedef typename ListenerList::const_iterator ConstIterator;
ListenerList m_listeners;
// This is a cached copy of the listener list used to handle standard dispatching, which
// allows for self-modification of the EventSource's listener list by the listeners.
// Translation: The dispatcher uses this copy instead, to avoid iterator invalidation.
ListenerList m_cache_copy;
bool m_cache_valid;
std::mutex m_listeners_lock;
public:
EventSource()
{
m_cache_valid = false;
}
virtual ~EventSource() = default;
virtual ListenerIterator Add(ListenerType& listener);
virtual void Remove(ListenerType& listener);
virtual void Remove(const ListenerIterator& listenerHandle);
void Add(ListenerType* listener)
{
if (listener == NULL)
return;
Add(*listener);
}
void Remove(ListenerType* listener)
{
if (listener == NULL)
return;
Remove(*listener);
}
void Dispatch(const EvtParams& params);
protected:
virtual ListenerIterator _AddFast_without_lock(ListenerType& listener);
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& params);
};
// --------------------------------------------------------------------------------------
// IEventDispatcher
// --------------------------------------------------------------------------------------
// This class is used as a base interface for EventListeners. It allows the listeners to do
// customized dispatching of several event types into "user friendly" function overrides.
//
template <typename EvtParams>
class IEventDispatcher
{
protected:
IEventDispatcher() {}
public:
virtual ~IEventDispatcher() = default;
virtual void DispatchEvent(const EvtParams& params) = 0;
};
-110
View File
@@ -1,110 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/Exceptions.h"
#include "common/Console.h"
template <typename ListenerType>
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType& listener)
{
std::unique_lock locker(m_listeners_lock);
// Check for duplicates before adding the event.
if (IsDebugBuild)
{
ListenerIterator iter = m_listeners.begin();
while (iter != m_listeners.end())
{
if ((*iter) == &listener)
return iter;
++iter;
}
}
return _AddFast_without_lock(listener);
}
template <typename ListenerType>
void EventSource<ListenerType>::Remove(ListenerType& listener)
{
std::unique_lock locker(m_listeners_lock);
m_cache_valid = false;
m_listeners.remove(&listener);
}
template <typename ListenerType>
void EventSource<ListenerType>::Remove(const ListenerIterator& listenerHandle)
{
std::unique_lock locker(m_listeners_lock);
m_cache_valid = false;
m_listeners.erase(listenerHandle);
}
template <typename ListenerType>
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock(ListenerType& listener)
{
m_cache_valid = false;
m_listeners.push_front(&listener);
return m_listeners.begin();
}
template <typename ListenerType>
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& evtparams)
{
while (iter != iend)
{
try
{
(*iter)->DispatchEvent(evtparams);
}
catch (Exception::RuntimeError& ex)
{
if (IsDevBuild)
{
pxFailDev(("Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage()).c_str());
}
else
{
Console.Error("Ignoring runtime error thrown from event listener: %s", ex.FormatDiagnosticMessage().c_str());
}
}
catch (BaseException& ex)
{
if (IsDevBuild)
{
ex.DiagMsg() = "Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
throw;
}
Console.Error("Ignoring non-runtime BaseException thrown from event listener: %s", ex.FormatDiagnosticMessage().c_str());
}
++iter;
}
}
template <typename ListenerType>
void EventSource<ListenerType>::Dispatch(const EvtParams& evtparams)
{
if (!m_cache_valid)
{
m_cache_copy = m_listeners;
m_cache_valid = true;
}
if (m_cache_copy.empty())
return;
_DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams);
}
-27
View File
@@ -74,33 +74,6 @@ namespace Exception
virtual BaseException* Clone() const = 0;
};
// --------------------------------------------------------------------------------------
// Ps2Generic Exception
// --------------------------------------------------------------------------------------
// This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
//
// Implementation note: does not derive from BaseException, so that we can use different
// catch block hierarchies to handle them (if needed).
//
// Translation Note: Currently these exceptions are never translated. English/diagnostic
// format only. :)
//
class Ps2Generic
{
protected:
std::string m_message; // a "detailed" message of what disastrous thing has occurred!
public:
virtual ~Ps2Generic() = default;
virtual u32 GetPc() const = 0;
virtual bool IsDelaySlot() const = 0;
virtual std::string& Message() { return m_message; }
virtual void Rethrow() const = 0;
virtual Ps2Generic* Clone() const = 0;
};
// Some helper macros for defining the standard constructors of internationalized constructors
// Parameters:
// classname - Yeah, the name of this class being defined. :)
+4 -1
View File
@@ -60,7 +60,10 @@ namespace GL
GLint info_log_length = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
if (status == GL_FALSE || info_log_length > 0)
// Log will create a new line when there are no warnings so let's set a minimum log length of 1.
constexpr int info_log_min_length = 1;
if (status == GL_FALSE || info_log_length > info_log_min_length)
{
std::string info_log;
info_log.resize(info_log_length + 1);
+23 -4
View File
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -14,7 +14,26 @@
*/
#include "PrecompiledHeader.h"
#include "EventSource.h"
#include "EventSource.inl"
#include "General.h"
//template class EventSource< int >;
// --------------------------------------------------------------------------------------
// PageProtectionMode (implementations)
// --------------------------------------------------------------------------------------
std::string PageProtectionMode::ToString() const
{
std::string modeStr;
if (m_read)
modeStr += "Read";
if (m_write)
modeStr += "Write";
if (m_exec)
modeStr += "Exec";
if (modeStr.empty())
return "NoAccess";
if (modeStr.length() <= 5)
modeStr += "Only";
return modeStr;
}
+14
View File
@@ -116,6 +116,14 @@ static __fi PageProtectionMode PageAccess_Any()
return PageProtectionMode().All();
}
struct PageFaultInfo
{
uptr pc;
uptr addr;
};
using PageFaultHandler = bool(*)(const PageFaultInfo& info);
// --------------------------------------------------------------------------------------
// HostSys
// --------------------------------------------------------------------------------------
@@ -141,6 +149,12 @@ namespace HostSys
extern void DestroySharedMemory(void* ptr);
extern void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode);
extern void UnmapSharedMemory(void* baseaddr, size_t size);
/// Installs the specified page fault handler. Only one handler can be active at once.
bool InstallPageFaultHandler(PageFaultHandler handler);
/// Removes the page fault handler. handler is only specified to check against the active callback.
void RemovePageFaultHandler(PageFaultHandler handler);
}
class SharedMemoryMappingArea
+90 -38
View File
@@ -21,13 +21,15 @@
#include <fcntl.h>
#include <unistd.h>
#include <mutex>
#include "fmt/core.h"
#include "common/Align.h"
#include "common/PageFaultSource.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/Exceptions.h"
#include "common/General.h"
// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean
// the same thing.
@@ -44,34 +46,57 @@
#include <ucontext.h>
#endif
extern void SignalExit(int sig);
static std::recursive_mutex s_exception_handler_mutex;
static PageFaultHandler s_exception_handler_callback;
static bool s_in_exception_handler;
static const uptr m_pagemask = getpagesize() - 1;
#if defined(__APPLE__)
#ifdef __APPLE__
static struct sigaction s_old_sigbus_action;
#else
static struct sigaction s_old_sigsegv_action;
#endif
static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
{
#ifdef __APPLE__
const struct sigaction& sa = s_old_sigbus_action;
#else
const struct sigaction& sa = s_old_sigsegv_action;
#endif
if (sa.sa_flags & SA_SIGINFO)
{
sa.sa_sigaction(signal, siginfo, ctx);
}
else if (sa.sa_handler == SIG_DFL)
{
// Re-raising the signal would just queue it, and since we'd restore the handler back to us,
// we'd end up right back here again. So just abort, because that's probably what it'd do anyway.
abort();
}
else if (sa.sa_handler != SIG_IGN)
{
sa.sa_handler(signal);
}
}
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
{
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
// for page fault handling. On linux, there is a single signal handler for the whole
// process, but the handler is executed by the thread that caused the exception.
// Executing the handler concurrently from multiple threads wouldn't go down well.
std::unique_lock lock(s_exception_handler_mutex);
// Prevent recursive exception filtering.
if (s_in_exception_handler)
{
CallExistingSignalHandler(signal, siginfo, ctx);
return;
}
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
// from the context of the current thread and stackframe. So long as the thread is not
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
// be safe even on the main thread.
// (in other words, stdio limitations only really apply to process-level asynchronous
// signals)
// Note: Use of stdio functions isn't safe here. Avoid console logs,
// assertions, file logs, or just about anything else useful.
// Note: Use of stdio functions isn't safe here. Avoid console logs, assertions, file logs,
// or just about anything else useful. However, that's really only a concern if the signal
// occurred within those functions. The logging which we do only happens when the exception
// occurred within JIT code.
#if defined(__APPLE__) && defined(__x86_64__)
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__rip);
@@ -81,35 +106,62 @@ static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
void* const exception_pc = nullptr;
#endif
// Note: This signal can be accessed by the EE or MTVU thread
// Source_PageFault is a global variable with its own state information
// so for now we lock this exception code unless someone can fix this better...
std::unique_lock lock(PageFault_Mutex);
const PageFaultInfo pfi{(uptr)exception_pc, (uptr)siginfo->si_addr & ~__pagemask};
Source_PageFault->Dispatch(PageFaultInfo((uptr)exception_pc, (uptr)siginfo->si_addr & ~m_pagemask));
s_in_exception_handler = true;
// resumes execution right where we left off (re-executes instruction that
// caused the SIGSEGV).
if (Source_PageFault->WasHandled())
const bool handled = s_exception_handler_callback(pfi);
s_in_exception_handler = false;
// Resumes execution right where we left off (re-executes instruction that caused the SIGSEGV).
if (handled)
return;
std::fprintf(stderr, "Unhandled page fault @ 0x%08x", siginfo->si_addr);
pxFailRel("Unhandled page fault");
// Call old signal handler, which will likely dump core.
CallExistingSignalHandler(signal, siginfo, ctx);
}
void _platform_InstallSignalHandler()
bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
{
Console.WriteLn("Installing POSIX SIGSEGV handler...");
struct sigaction sa;
std::unique_lock lock(s_exception_handler_mutex);
pxAssertRel(!s_exception_handler_callback, "A page fault handler is already registered.");
if (!s_exception_handler_callback)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SysPageFaultSignalFilter;
#if defined(__APPLE__)
// MacOS uses SIGBUS for memory permission violations
sigaction(SIGBUS, &sa, &s_old_sigbus_action);
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = SysPageFaultSignalFilter;
#ifdef __APPLE__
// MacOS uses SIGBUS for memory permission violations
if (sigaction(SIGBUS, &sa, &s_old_sigbus_action) != 0)
return false;
#else
sigaction(SIGSEGV, &sa, &s_old_sigsegv_action);
if (sigaction(SIGSEGV, &sa, &s_old_sigsegv_action) != 0)
return false;
#endif
}
s_exception_handler_callback = handler;
return true;
}
void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
{
std::unique_lock lock(s_exception_handler_mutex);
pxAssertRel(!s_exception_handler_callback || s_exception_handler_callback == handler,
"Not removing the same handler previously registered.");
if (!s_exception_handler_callback)
return;
s_exception_handler_callback = nullptr;
struct sigaction sa;
#ifdef __APPLE__
sigaction(SIGBUS, &s_old_sigbus_action, &sa);
#else
sigaction(SIGSEGV, &s_old_sigsegv_action, &sa);
#endif
}
+14 -1
View File
@@ -153,6 +153,9 @@ namespace Vulkan
m_provoking_vertex = {};
m_provoking_vertex.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT;
m_line_rasterization_state = {};
m_line_rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
// set defaults
SetNoCullRasterizationState();
SetNoDepthTestState();
@@ -255,7 +258,17 @@ namespace Vulkan
m_ci.pRasterizationState = &m_rasterization_state;
}
void GraphicsPipelineBuilder::SetLineWidth(float width) { m_rasterization_state.lineWidth = width; }
void GraphicsPipelineBuilder::SetLineWidth(float width)
{
m_rasterization_state.lineWidth = width;
}
void GraphicsPipelineBuilder::SetLineRasterizationMode(VkLineRasterizationModeEXT mode)
{
Util::AddPointerToChain(&m_rasterization_state, &m_line_rasterization_state);
m_line_rasterization_state.lineRasterizationMode = mode;
}
void GraphicsPipelineBuilder::SetMultisamples(u32 multisamples, bool per_sample_shading)
{
+2
View File
@@ -96,6 +96,7 @@ namespace Vulkan
void SetRasterizationState(VkPolygonMode polygon_mode, VkCullModeFlags cull_mode, VkFrontFace front_face);
void SetLineWidth(float width);
void SetLineRasterizationMode(VkLineRasterizationModeEXT mode);
void SetMultisamples(u32 multisamples, bool per_sample_shading);
void SetNoCullRasterizationState();
@@ -157,6 +158,7 @@ namespace Vulkan
VkPipelineMultisampleStateCreateInfo m_multisample_state;
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT m_provoking_vertex;
VkPipelineRasterizationLineStateCreateInfoEXT m_line_rasterization_state;
};
class ComputePipelineBuilder
+16
View File
@@ -458,6 +458,8 @@ namespace Vulkan
SupportsExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, false);
m_optional_extensions.vk_ext_calibrated_timestamps =
SupportsExtension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, false);
m_optional_extensions.vk_ext_line_rasterization =
SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
m_optional_extensions.vk_khr_driver_properties =
SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
m_optional_extensions.vk_arm_rasterization_order_attachment_access =
@@ -654,12 +656,19 @@ namespace Vulkan
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
if (m_optional_extensions.vk_ext_provoking_vertex)
{
provoking_vertex_feature.provokingVertexLast = VK_TRUE;
Util::AddPointerToChain(&device_info, &provoking_vertex_feature);
}
if (m_optional_extensions.vk_ext_line_rasterization)
{
line_rasterization_feature.bresenhamLines = VK_TRUE;
Util::AddPointerToChain(&device_info, &line_rasterization_feature);
}
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
{
rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess = VK_TRUE;
@@ -724,12 +733,16 @@ namespace Vulkan
VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
// add in optional feature structs
if (m_optional_extensions.vk_ext_provoking_vertex)
Util::AddPointerToChain(&features2, &provoking_vertex_features);
if (m_optional_extensions.vk_ext_line_rasterization)
Util::AddPointerToChain(&features2, &line_rasterization_feature);
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
Util::AddPointerToChain(&features2, &rasterization_order_access_feature);
@@ -739,6 +752,7 @@ namespace Vulkan
// confirm we actually support it
m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE);
m_optional_extensions.vk_arm_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
m_optional_extensions.vk_ext_line_rasterization &= (line_rasterization_feature.bresenhamLines == VK_TRUE);
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
void** pNext = &properties2.pNext;
@@ -789,6 +803,8 @@ namespace Vulkan
Console.WriteLn("VK_EXT_provoking_vertex is %s",
m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_line_rasterization is %s",
m_optional_extensions.vk_ext_line_rasterization ? "supported" : "NOT supported");
Console.WriteLn("VK_EXT_calibrated_timestamps is %s",
m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported");
Console.WriteLn("VK_ARM_rasterization_order_attachment_access is %s",
+1
View File
@@ -52,6 +52,7 @@ namespace Vulkan
bool vk_ext_provoking_vertex : 1;
bool vk_ext_memory_budget : 1;
bool vk_ext_calibrated_timestamps : 1;
bool vk_ext_line_rasterization : 1;
bool vk_khr_driver_properties : 1;
bool vk_arm_rasterization_order_attachment_access : 1;
bool vk_khr_fragment_shader_barycentric : 1;
+57 -39
View File
@@ -17,60 +17,78 @@
#include "common/Align.h"
#include "common/RedtapeWindows.h"
#include "common/PageFaultSource.h"
#include "common/Console.h"
#include "common/General.h"
#include "common/Exceptions.h"
#include "common/StringUtil.h"
#include "common/AlignedMalloc.h"
#include "fmt/core.h"
#include "common/Assertions.h"
#include "fmt/core.h"
#include "fmt/format.h"
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
{
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
#include <mutex>
#if defined(_M_AMD64)
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Rip);
#else
void* const exception_pc = nullptr;
#endif
// Note: This exception can be accessed by the EE or MTVU thread
// Source_PageFault is a global variable with its own state information
// so for now we lock this exception code unless someone can fix this better...
std::unique_lock lock(PageFault_Mutex);
Source_PageFault->Dispatch(PageFaultInfo((uptr)exception_pc, (uptr)eps->ExceptionRecord->ExceptionInformation[1]));
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
}
static std::recursive_mutex s_exception_handler_mutex;
static PageFaultHandler s_exception_handler_callback;
static void* s_exception_handler_handle;
static bool s_in_exception_handler;
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
{
// Prevent recursive exception filtering by catching the exception from the filter here.
// In the event that the filter causes an access violation (happened during shutdown
// because Source_PageFault was deallocated), this will allow the debugger to catch the
// exception.
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
// work but I don't fully understand why some do and some don't.
__try
{
return DoSysPageFaultExceptionFilter(eps);
}
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Executing the handler concurrently from multiple threads wouldn't go down well.
std::unique_lock lock(s_exception_handler_mutex);
// Prevent recursive exception filtering.
if (s_in_exception_handler)
return EXCEPTION_CONTINUE_SEARCH;
// Only interested in page faults.
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
return EXCEPTION_CONTINUE_SEARCH;
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Rip);
const PageFaultInfo pfi{(uptr)exception_pc, (uptr)eps->ExceptionRecord->ExceptionInformation[1]};
s_in_exception_handler = true;
const bool handled = s_exception_handler_callback(pfi);
s_in_exception_handler = false;
return handled ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
}
bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
{
std::unique_lock lock(s_exception_handler_mutex);
pxAssertRel(!s_exception_handler_callback, "A page fault handler is already registered.");
if (!s_exception_handler_handle)
{
s_exception_handler_handle = AddVectoredExceptionHandler(TRUE, SysPageFaultExceptionFilter);
if (!s_exception_handler_handle)
return false;
}
s_exception_handler_callback = handler;
return true;
}
void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
{
std::unique_lock lock(s_exception_handler_mutex);
pxAssertRel(!s_exception_handler_callback || s_exception_handler_callback == handler,
"Not removing the same handler previously registered.");
s_exception_handler_callback = nullptr;
if (s_exception_handler_handle)
{
RemoveVectoredExceptionHandler(s_exception_handler_handle);
s_exception_handler_handle = {};
}
}
void _platform_InstallSignalHandler()
{
#ifdef _WIN64 // We don't handle SEH properly on Win64 so use a vectored exception handler instead
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
#endif
}
static DWORD ConvertToWinApi(const PageProtectionMode& mode)
{
DWORD winmode = PAGE_NOACCESS;
+1 -3
View File
@@ -70,6 +70,7 @@
<ClCompile Include="FastJmp.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="General.cpp" />
<ClCompile Include="GL\Context.cpp" />
<ClCompile Include="GL\ContextWGL.cpp" />
<ClCompile Include="GL\Program.cpp" />
@@ -90,7 +91,6 @@
<ClCompile Include="StringUtil.cpp" />
<ClCompile Include="SettingsWrapper.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="VirtualMemory.cpp" />
<ClCompile Include="Vulkan\vk_mem_alloc.cpp" />
<ClCompile Include="Vulkan\Builders.cpp" />
<ClCompile Include="Vulkan\Context.cpp" />
@@ -130,7 +130,6 @@
<ClCompile Include="emitter\WinCpuDetect.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="EventSource.inl" />
<MASM Include="FastJmp.asm" />
<None Include="Vulkan\EntryPoints.inl" />
</ItemGroup>
@@ -178,7 +177,6 @@
<ClInclude Include="SettingsWrapper.h" />
<ClInclude Include="Assertions.h" />
<ClInclude Include="Console.h" />
<ClInclude Include="EventSource.h" />
<ClInclude Include="Exceptions.h" />
<ClInclude Include="General.h" />
<ClInclude Include="MathUtils.h" />
+1 -9
View File
@@ -67,9 +67,6 @@
<ClCompile Include="emitter\simd.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VirtualMemory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="emitter\WinCpuDetect.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -211,6 +208,7 @@
<ClCompile Include="WAVWriter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="General.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlignedMalloc.h">
@@ -234,9 +232,6 @@
<ClInclude Include="emitter\implement\dwshift.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="EventSource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Exceptions.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -532,9 +527,6 @@
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="EventSource.inl">
<Filter>Source Files</Filter>
</None>
<None Include="Vulkan\EntryPoints.inl">
<Filter>Source Files\Vulkan</Filter>
</None>
+6
View File
@@ -16,6 +16,12 @@
#include "common/emitter/internal.h"
#include "common/emitter/tools.h"
// warning: suggest braces around initialization of subobject [-Wmissing-braces]
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-braces"
#endif
namespace x86Emitter
{
const xImplAVX_Move xVMOVAPS = {0x00, 0x28, 0x29};
+3
View File
@@ -0,0 +1,3 @@
files:
- source: pcsx2-qt/Translations/pcsx2-qt_en.ts
translation: '/pcsx2-qt/Translations/pcsx2-qt_%two_letters_code%.ts'
+44 -11
View File
@@ -48,6 +48,7 @@
#include "pcsx2/HostDisplay.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/INISettingsInterface.h"
#include "pcsx2/PAD/Host/PAD.h"
#include "pcsx2/PerformanceMetrics.h"
#include "pcsx2/VMManager.h"
@@ -79,6 +80,7 @@ static std::optional<bool> s_use_window;
// Owned by the GS thread.
static u32 s_dump_frame_number = 0;
static u32 s_loop_number = s_loop_count;
bool GSRunner::InitializeConfig()
{
@@ -102,6 +104,13 @@ bool GSRunner::InitializeConfig()
// we don't need any sound output
si.SetStringValue("SPU2/Output", "OutputModule", "nullout");
// none of the bindings are going to resolve to anything
PAD::ClearPortBindings(si, 0);
si.ClearSection("Hotkeys");
// make sure any gamesettings inis in your tree don't get loaded
si.SetBoolValue("EmuCore", "EnablePerGameSettings", false);
// force logging
si.SetBoolValue("Logging", "EnableSystemConsole", true);
si.SetBoolValue("Logging", "EnableTimestamps", true);
@@ -273,13 +282,15 @@ void Host::ReleaseHostDisplay(bool clear_state)
bool Host::BeginPresentFrame(bool frame_skip)
{
// when we wrap around, don't race other files
GSJoinSnapshotThreads();
// queue dumping of this frame
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
GSQueueSnapshot(dump_path);
if (s_loop_number == 0)
{
// when we wrap around, don't race other files
GSJoinSnapshotThreads();
// queue dumping of this frame
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
GSQueueSnapshot(dump_path);
}
if (g_host_display->BeginPresent(frame_skip))
return true;
@@ -351,10 +362,6 @@ void Host::OnSaveStateSaved(const std::string_view& filename)
{
}
void Host::InvalidateSaveStateCache()
{
}
void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false */)
{
pxFailRel("Not implemented");
@@ -377,7 +384,7 @@ void Host::SetFullscreen(bool enabled)
{
}
void Host::RequestExit(bool save_state_if_running)
void Host::RequestExit(bool allow_confirm)
{
}
@@ -523,6 +530,29 @@ static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& param
s_settings_interface.SetIntValue("EmuCore/GS", "Renderer", static_cast<int>(type));
continue;
}
else if (CHECK_ARG_PARAM("-renderhacks"))
{
std::string str(argv[++i]);
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks", true);
if(str.find("af") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_AutoFlush", true);
if (str.find("cpufb") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_CPU_FB_Conversion", true);
if (str.find("dds") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisableDepthSupport", true);
if (str.find("dpi") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisablePartialInvalidation", true);
if (str.find("dsf") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisableSafeFeatures", true);
if (str.find("tinrt") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_TextureInsideRt", true);
if (str.find("plf") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "preload_frame_with_gs_data", true);
continue;
}
else if (CHECK_ARG_PARAM("-logfile"))
{
const char* logfile = argv[++i];
@@ -631,6 +661,7 @@ int main(int argc, char* argv[])
// apply new settings (e.g. pick up renderer change)
VMManager::ApplySettings();
GSDumpReplayer::SetIsDumpRunner(true);
if (VMManager::Initialize(params))
{
@@ -644,6 +675,7 @@ int main(int argc, char* argv[])
InputManager::CloseSources();
VMManager::Internal::ReleaseMemory();
VMManager::Internal::ReleaseGlobals();
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
GSRunner::DestroyPlatformWindow();
@@ -654,6 +686,7 @@ void Host::CPUThreadVSync()
{
// update GS thread copy of frame number
GetMTGS().RunOnGSThread([frame_number = GSDumpReplayer::GetFrameNumber()]() { s_dump_frame_number = frame_number; });
GetMTGS().RunOnGSThread([loop_number = GSDumpReplayer::GetLoopCount()]() { s_loop_number = loop_number; });
// process any window messages (but we shouldn't really have any)
GSRunner::PumpPlatformMessages();
+10 -5
View File
@@ -16,7 +16,7 @@ def is_gs_path(path):
return False
def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
def run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, gspath):
args = [runner]
gsname = Path(gspath).name
while gsname.rfind('.') >= 0:
@@ -28,6 +28,10 @@ def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
if renderer is not None:
args.extend(["-renderer", renderer])
if renderhacks is not None:
args.extend(["-renderhacks", renderhacks])
args.extend(["-dumpdir", real_dumpdir])
args.extend(["-logfile", os.path.join(real_dumpdir, "emulog.txt")])
@@ -46,7 +50,7 @@ def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
subprocess.run(args)
def run_regression_tests(runner, gsdir, dumpdir, renderer, parallel=1):
def run_regression_tests(runner, gsdir, dumpdir, renderer, renderhacks, parallel=1):
paths = glob.glob(gsdir + "/*.*", recursive=True)
gamepaths = list(filter(is_gs_path, paths))
@@ -57,10 +61,10 @@ def run_regression_tests(runner, gsdir, dumpdir, renderer, parallel=1):
if parallel <= 1:
for game in gamepaths:
run_regression_test(runner, dumpdir, renderer, parallel, game)
run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, game)
else:
print("Processing %u games on %u processors" % (len(gamepaths), parallel))
func = partial(run_regression_test, runner, dumpdir, renderer, parallel)
func = partial(run_regression_test, runner, dumpdir, renderer, parallel, renderhacks)
pool = multiprocessing.Pool(parallel)
pool.map(func, gamepaths)
pool.close()
@@ -76,10 +80,11 @@ if __name__ == "__main__":
parser.add_argument("-dumpdir", action="store", required=True, help="Base directory to dump frames to")
parser.add_argument("-renderer", action="store", required=False, help="Renderer to use")
parser.add_argument("-parallel", action="store", type=int, default=1, help="Number of proceeses to run")
parser.add_argument("-renderhacks", action="store", required=False, help="Enable HW Renering hacks")
args = parser.parse_args()
if not run_regression_tests(args.runner, os.path.realpath(args.gsdir), os.path.realpath(args.dumpdir), args.renderer, args.parallel):
if not run_regression_tests(args.runner, os.path.realpath(args.gsdir), os.path.realpath(args.dumpdir), args.renderer, args.renderhacks, args.parallel):
sys.exit(1)
else:
sys.exit(0)
+1 -1
View File
@@ -465,7 +465,7 @@ void AutoUpdaterDialog::downloadUpdateClicked()
else if (result == 1)
{
// updater started. since we're a modal on the main window, we have to queue this.
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit, Qt::QueuedConnection);
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, true));
done(0);
}
+3 -6
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;
}
}
+24 -28
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();
}
+20 -12
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;
};
+1 -1
View File
@@ -156,7 +156,7 @@ void DisplayWidget::handleCloseEvent(QCloseEvent* event)
}
else
{
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit);
QMetaObject::invokeMethod(g_main_window, "requestExit", Q_ARG(bool, true));
}
// Cancel the event from closing the window.
+1 -1
View File
@@ -488,7 +488,7 @@ void GameListWidget::resizeTableViewColumnsToFit()
80, // last played
80, // size
60, // region
100 // compatibility
120 // compatibility
});
}
+61 -70
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);
@@ -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,7 +1464,6 @@ 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(); });
}
@@ -1581,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)
@@ -1676,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())
{
@@ -1715,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);
@@ -1734,7 +1711,7 @@ void MainWindow::startupUpdateCheck()
if (!Host::GetBaseBoolSettingValue("AutoUpdater", "CheckAtStartup", true))
return;
checkForUpdates(false);
checkForUpdates(false, false);
}
void MainWindow::onToolsOpenDataDirectoryTriggered()
@@ -1890,7 +1867,7 @@ void MainWindow::onVMStarting()
updateWindowTitle();
// prevent loading state until we're fully initialized
updateSaveStateMenus(QString(), QString(), 0);
updateSaveStateMenusEnableState(false);
}
void MainWindow::onVMStarted()
@@ -1952,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
@@ -1970,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)
@@ -1991,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)
@@ -2265,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();
@@ -2826,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)
+6 -9
View File
@@ -110,17 +110,17 @@ public:
/// Rescans a single file. NOTE: Happens on UI thread.
void rescanFile(const std::string& path);
void openDebugger();
public Q_SLOTS:
void checkForUpdates(bool display_message);
void checkForUpdates(bool display_message, bool force_check);
void refreshGameList(bool invalidate_cache);
void cancelGameListRefresh();
void invalidateSaveStateCache();
void reportError(const QString& title, const QString& message);
bool confirmMessage(const QString& title, const QString& message);
void runOnUIThread(const std::function<void()>& func);
bool requestShutdown(
bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true, bool block_until_done = false);
void requestExit();
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true);
void requestExit(bool allow_confirm = true);
void checkForSettingChanges();
std::optional<WindowInfo> getWindowInfo();
@@ -162,7 +162,6 @@ private Q_SLOTS:
void onSupportForumsActionTriggered();
void onDiscordServerActionTriggered();
void onAboutActionTriggered();
void onCheckForUpdatesActionTriggered();
void onToolsOpenDataDirectoryTriggered();
void onToolsCoverDownloaderTriggered();
void updateTheme();
@@ -244,7 +243,6 @@ private:
void updateInputRecordingActions(bool started);
DebuggerWindow* getDebuggerWindow();
void openDebugger();
ControllerSettingsDialog* getControllerSettingsDialog();
void doControllerSettings(ControllerSettingsDialog::Category category = ControllerSettingsDialog::Category::Count);
@@ -261,7 +259,7 @@ private:
void loadSaveStateFile(const QString& filename, const QString& state_filename);
void populateLoadStateMenu(QMenu* menu, const QString& filename, const QString& serial, quint32 crc);
void populateSaveStateMenu(QMenu* menu, const QString& serial, quint32 crc);
void updateSaveStateMenus(const QString& filename, const QString& serial, quint32 crc);
void updateSaveStateMenusEnableState(bool enable);
void doStartFile(std::optional<CDVD_SourceType> source, const QString& path);
void doDiscChange(CDVD_SourceType source, const QString& path);
@@ -293,7 +291,6 @@ private:
bool m_display_created = false;
bool m_relative_mouse_mode = false;
bool m_save_states_invalidated = false;
bool m_was_paused_on_surface_loss = false;
bool m_was_disc_change_request = false;
bool m_is_closing = false;
+43 -9
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")))
{
@@ -1859,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));
+12 -12
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
}
}
[[maybe_unused]] 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);
@@ -1109,8 +1109,8 @@ namespace SettingWidgetBinder
});
slider->connect(slider, &QSlider::valueChanged, slider,
[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) {
[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)
@@ -105,14 +105,13 @@ void AchievementSettingsWidget::updateEnableState()
{
const bool enabled = m_dialog->getEffectiveBoolValue("Achievements", "Enabled", false);
const bool challenge = m_dialog->getEffectiveBoolValue("Achievements", "ChallengeMode", false);
const bool notifications = m_dialog->getEffectiveBoolValue("Achievements", "Notifications", true);
m_ui.testMode->setEnabled(enabled);
m_ui.unofficialTestMode->setEnabled(enabled);
m_ui.richPresence->setEnabled(enabled);
m_ui.challengeMode->setEnabled(enabled);
m_ui.leaderboards->setEnabled(enabled && challenge);
m_ui.notifications->setEnabled(enabled);
m_ui.soundEffects->setEnabled(enabled && notifications);
m_ui.soundEffects->setEnabled(enabled);
m_ui.primedIndicators->setEnabled(enabled);
}
@@ -37,6 +37,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeINTCSpinDetection, "EmuCore/Speedhacks", "IntcStat", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeWaitLoopDetection, "EmuCore/Speedhacks", "WaitLoop", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeFastmem, "EmuCore/CPU/Recompiler", "EnableFastmem", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnTLBMiss, "EmuCore/CPU/Recompiler", "PauseOnTLBMiss", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vu0Recompiler, "EmuCore/CPU/Recompiler", "EnableVU0", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vu1Recompiler, "EmuCore/CPU/Recompiler", "EnableVU1", true);
@@ -84,6 +85,11 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.eeFastmem, tr("Enable Fast Memory Access"), tr("Checked"),
tr("Uses backpatching to avoid register flushing on every memory access."));
dialog->registerWidgetHelp(m_ui.pauseOnTLBMiss, tr("Pause On TLB Miss"), tr("Unchecked"),
tr("Pauses the virtual machine when a TLB miss occurs, instead of ignoring it and continuing. Note the the VM will pause after the "
"end of the block, not on the instruction which caused the exception. Refer to the console to see the address where the invalid "
"access occurred."));
dialog->registerWidgetHelp(m_ui.vu0RoundingMode, tr("Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
dialog->registerWidgetHelp(m_ui.vu1RoundingMode, tr("Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
@@ -165,6 +165,13 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="pauseOnTLBMiss">
<property name="text">
<string>Pause On TLB Miss</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
+47 -38
View File
@@ -42,10 +42,12 @@
ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
: QWidget(parent)
, m_dialog(dialog)
, m_config_section(StringUtil::StdStringFromFormat("Pad%u", port + 1u))
, m_config_section(fmt::format("Pad{}", port + 1))
, m_port_number(port)
{
m_ui.setupUi(this);
m_ui.groupBox->setTitle(tr("Controller Port %1").arg(port + 1));
populateControllerTypes();
onTypeChanged();
@@ -113,10 +115,9 @@ void ControllerBindingWidget::onTypeChanged()
if (has_settings)
{
const QString settings_title(tr("%1 Settings").arg(qApp->translate("PAD", cinfo->display_name)));
const gsl::span<const SettingInfo> settings(cinfo->settings, cinfo->num_settings);
m_settings_widget = new ControllerCustomSettingsWidget(
settings, m_config_section, std::string(), settings_title, cinfo->name, getDialog(), m_ui.stackedWidget);
m_settings_widget =
new ControllerCustomSettingsWidget(settings, m_config_section, std::string(), cinfo->name, getDialog(), m_ui.stackedWidget);
m_ui.stackedWidget->addWidget(m_settings_widget);
}
@@ -458,8 +459,7 @@ void ControllerMacroEditWidget::updateBinds()
//////////////////////////////////////////////////////////////////////////
ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(gsl::span<const SettingInfo> settings, std::string config_section,
std::string config_prefix, const QString& group_title, const char* translation_ctx, ControllerSettingsDialog* dialog,
QWidget* parent_widget)
std::string config_prefix, const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget)
: QWidget(parent_widget)
, m_settings(settings)
, m_config_section(std::move(config_section))
@@ -469,22 +469,19 @@ ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(gsl::span<const S
if (settings.empty())
return;
QGroupBox* gbox = new QGroupBox(group_title, this);
QGridLayout* gbox_layout = new QGridLayout(gbox);
createSettingWidgets(translation_ctx, gbox, gbox_layout);
QScrollArea* sarea = new QScrollArea(this);
QWidget* swidget = new QWidget(sarea);
sarea->setWidget(swidget);
sarea->setWidgetResizable(true);
sarea->setFrameShape(QFrame::StyledPanel);
sarea->setFrameShadow(QFrame::Sunken);
QGridLayout* swidget_layout = new QGridLayout(swidget);
createSettingWidgets(translation_ctx, swidget, swidget_layout);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(gbox);
QHBoxLayout* bottom_hlayout = new QHBoxLayout();
QPushButton* restore_defaults = new QPushButton(tr("Restore Default Settings"), this);
restore_defaults->setIcon(QIcon::fromTheme(QStringLiteral("restart-line")));
connect(restore_defaults, &QPushButton::clicked, this, &ControllerCustomSettingsWidget::restoreDefaults);
bottom_hlayout->addStretch(1);
bottom_hlayout->addWidget(restore_defaults);
layout->addLayout(bottom_hlayout);
layout->addStretch(1);
layout->addWidget(sarea);
}
ControllerCustomSettingsWidget::~ControllerCustomSettingsWidget() = default;
@@ -503,8 +500,6 @@ static std::tuple<QString, QString> getPrefixAndSuffixForIntFormat(const QString
return std::tie(prefix, suffix);
}
#if 0
// Unused until we handle multiplier below.
static std::tuple<QString, QString, int> getPrefixAndSuffixForFloatFormat(const QString& format)
{
QString prefix, suffix;
@@ -532,7 +527,6 @@ static std::tuple<QString, QString, int> getPrefixAndSuffixForFloatFormat(const
return std::tie(prefix, suffix, decimals);
}
#endif
void ControllerCustomSettingsWidget::createSettingWidgets(const char* translation_ctx, QWidget* widget_parent, QGridLayout* layout)
{
@@ -569,7 +563,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
sb->setPrefix(prefix);
sb->setSuffix(suffix);
}
SettingWidgetBinder::BindWidgetToIntSetting(sif, sb, m_config_section, std::move(key_name), si.IntegerDefaultValue());
ControllerSettingWidgetBinder::BindWidgetToInputProfileInt(
sif, sb, m_config_section, std::move(key_name), si.IntegerDefaultValue());
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
layout->addWidget(sb, current_row, 1, 1, 3);
current_row++;
@@ -582,7 +577,7 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
cb->setObjectName(QString::fromUtf8(si.name));
for (u32 i = 0; si.options[i] != nullptr; i++)
cb->addItem(qApp->translate(translation_ctx, si.options[i]));
SettingWidgetBinder::BindWidgetToIntSetting(
ControllerSettingWidgetBinder::BindWidgetToInputProfileInt(
sif, cb, m_config_section, std::move(key_name), si.IntegerDefaultValue(), si.IntegerMinValue());
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
layout->addWidget(cb, current_row, 1, 1, 3);
@@ -594,11 +589,10 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
{
QDoubleSpinBox* sb = new QDoubleSpinBox(widget_parent);
sb->setObjectName(QString::fromUtf8(si.name));
sb->setMinimum(si.FloatMinValue());
sb->setMaximum(si.FloatMaxValue());
sb->setSingleStep(si.FloatStepValue());
#if 0
// We can't use this until we handle multiplier.
sb->setMinimum(si.FloatMinValue() * si.multiplier);
sb->setMaximum(si.FloatMaxValue() * si.multiplier);
sb->setSingleStep(si.FloatStepValue() * si.multiplier);
if (si.format)
{
const auto [prefix, suffix, decimals] = getPrefixAndSuffixForFloatFormat(QString::fromUtf8(si.format));
@@ -607,8 +601,9 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
sb->setDecimals(decimals);
sb->setSuffix(suffix);
}
#endif
SettingWidgetBinder::BindWidgetToFloatSetting(sif, sb, m_config_section, std::move(key_name), si.FloatDefaultValue());
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(
sif, sb, m_config_section, std::move(key_name), si.FloatDefaultValue(), si.multiplier);
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
layout->addWidget(sb, current_row, 1, 1, 3);
current_row++;
@@ -619,7 +614,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
{
QLineEdit* le = new QLineEdit(widget_parent);
le->setObjectName(QString::fromUtf8(si.name));
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
layout->addWidget(le, current_row, 1, 1, 3);
current_row++;
@@ -641,7 +637,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
for (u32 i = 0; si.options[i] != nullptr; i++)
cb->addItem(qApp->translate(translation_ctx, si.options[i]), QString::fromUtf8(si.options[i]));
}
SettingWidgetBinder::BindWidgetToStringSetting(sif, cb, m_config_section, std::move(key_name), si.StringDefaultValue());
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
sif, cb, m_config_section, std::move(key_name), si.StringDefaultValue());
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
layout->addWidget(cb, current_row, 1, 1, 3);
current_row++;
@@ -653,7 +650,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
QLineEdit* le = new QLineEdit(widget_parent);
le->setObjectName(QString::fromUtf8(si.name));
QPushButton* browse_button = new QPushButton(tr("Browse..."), widget_parent);
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
connect(browse_button, &QPushButton::clicked, [this, le]() {
const QString path(QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Select File"))));
if (!path.isEmpty())
@@ -677,6 +675,16 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
layout->addItem(new QSpacerItem(1, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), current_row++, 0, 1, 4);
}
QHBoxLayout* bottom_hlayout = new QHBoxLayout();
QPushButton* restore_defaults = new QPushButton(tr("Restore Default Settings"), this);
restore_defaults->setIcon(QIcon::fromTheme(QStringLiteral("restart-line")));
connect(restore_defaults, &QPushButton::clicked, this, &ControllerCustomSettingsWidget::restoreDefaults);
bottom_hlayout->addStretch(1);
bottom_hlayout->addWidget(restore_defaults);
layout->addLayout(bottom_hlayout, current_row++, 0, 1, 4);
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding), current_row++, 0, 1, 4);
}
void ControllerCustomSettingsWidget::restoreDefaults()
@@ -715,7 +723,7 @@ void ControllerCustomSettingsWidget::restoreDefaults()
{
QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QString::fromStdString(si.name));
if (widget)
widget->setValue(si.FloatDefaultValue());
widget->setValue(si.FloatDefaultValue() * si.multiplier);
}
break;
@@ -851,10 +859,12 @@ ControllerBindingWidget_Base* ControllerBindingWidget_DualShock2::createInstance
USBDeviceWidget::USBDeviceWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
: QWidget(parent)
, m_dialog(dialog)
, m_config_section(StringUtil::StdStringFromFormat("USB%u", port + 1u))
, m_config_section(fmt::format("USB{}", port + 1))
, m_port_number(port)
{
m_ui.setupUi(this);
m_ui.groupBox->setTitle(tr("USB Port %1").arg(port + 1));
populateDeviceTypes();
populatePages();
@@ -926,9 +936,8 @@ void USBDeviceWidget::populatePages()
if (!settings.empty())
{
const QString settings_title(tr("Device Settings"));
m_settings_widget = new ControllerCustomSettingsWidget(
settings, m_config_section, m_device_type + "_", settings_title, m_device_type.c_str(), m_dialog, m_ui.stackedWidget);
settings, m_config_section, m_device_type + "_", m_device_type.c_str(), m_dialog, m_ui.stackedWidget);
m_ui.stackedWidget->addWidget(m_settings_widget);
}
+1 -1
View File
@@ -139,7 +139,7 @@ class ControllerCustomSettingsWidget : public QWidget
public:
ControllerCustomSettingsWidget(gsl::span<const SettingInfo> settings, std::string config_section, std::string config_prefix,
const QString& group_title, const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget);
const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget);
~ControllerCustomSettingsWidget();
private Q_SLOTS:
@@ -151,7 +151,7 @@ void ControllerLEDSettingsDialog::linkButton(ColorPickerButton* button, u32 play
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, player_id, key = std::move(key)](u32 new_rgb) {
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
@@ -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);
+71 -25
View File
@@ -260,9 +260,13 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsDialog* dialog, QWidget* parent)
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hddEnabled, "DEV9/Hdd", "HddEnable", false);
connect(m_ui.hddFile, &QLineEdit::editingFinished, this, &DEV9SettingsWidget::onHddFileEdit);
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.hddFile, "DEV9/Hdd", "HddFile", "DEV9hdd.raw");
if (m_dialog->isPerGameSettings())
{
m_ui.hddFile->setText(QString::fromUtf8(m_dialog->getStringValue("DEV9/Hdd", "HddFile", "").value().c_str()));
m_ui.hddFile->setPlaceholderText(QString::fromUtf8(Host::GetBaseStringSettingValue("DEV9/Hdd", "HddFile", "DEV9hdd.raw")));
}
else
m_ui.hddFile->setText(QString::fromUtf8(m_dialog->getStringValue("DEV9/Hdd", "HddFile", "DEV9hdd.raw").value().c_str()));
connect(m_ui.hddBrowseFile, &QPushButton::clicked, this, &DEV9SettingsWidget::onHddBrowseFileClicked);
//TODO: need a getUintValue for if 48bit support occurs
@@ -270,18 +274,27 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsDialog* dialog, QWidget* parent)
if (m_dialog->isPerGameSettings())
{
std::optional<int> sizeOpt = std::nullopt;
if (size > 0)
sizeOpt = size;
const int sizeGlobal = (u64)Host::GetBaseIntSettingValue("DEV9/Hdd", "HddSizeSectors", 0) * 512 / (1024 * 1024 * 1024);
m_ui.hddSizeSpinBox->setMinimum(39);
m_ui.hddSizeSpinBox->setSpecialValueText(tr("Global [%1]").arg(sizeGlobal));
SettingWidgetBinder::SettingAccessor<QSpinBox>::makeNullableInt(m_ui.hddSizeSpinBox, sizeGlobal);
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, sizeOpt);
m_ui.hddSizeSlider->setValue(sizeOpt.value_or(sizeGlobal));
m_ui.hddSizeSlider->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_ui.hddSizeSlider, &QSlider::customContextMenuRequested, this, &DEV9SettingsWidget::onHddSizeSliderContext);
}
else
{
m_ui.hddSizeSlider->setValue(size);
SettingWidgetBinder::SettingAccessor<QSpinBox>::setIntValue(m_ui.hddSizeSpinBox, size);
}
// clang-format off
m_ui.hddSizeSlider ->setValue(size);
m_ui.hddSizeSpinBox->setValue(size);
connect(m_ui.hddSizeSlider, QOverload<int>::of(&QSlider ::valueChanged), this, &DEV9SettingsWidget::onHddSizeSlide);
connect(m_ui.hddSizeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &DEV9SettingsWidget::onHddSizeSpin );
// clang-format on
connect(m_ui.hddSizeSlider, QOverload<int>::of(&QSlider::valueChanged), this, &DEV9SettingsWidget::onHddSizeSlide);
SettingWidgetBinder::SettingAccessor<QSpinBox>::connectValueChanged(m_ui.hddSizeSpinBox, [&]() { onHddSizeAccessorSpin(); });
connect(m_ui.hddCreate, &QPushButton::clicked, this, &DEV9SettingsWidget::onHddCreateClicked);
}
@@ -682,7 +695,7 @@ void DEV9SettingsWidget::onEthHostEdit(QStandardItem* item)
void DEV9SettingsWidget::onHddEnabledChanged(int state)
{
const bool enabled = state == Qt::CheckState::PartiallyChecked ? m_dialog->getEffectiveBoolValue("DEV9/Hdd", "HddEnable", false) : state;
const bool enabled = state == Qt::CheckState::PartiallyChecked ? Host::GetBaseBoolSettingValue("DEV9/Hdd", "HddEnable", false) : state;
m_ui.hddFile->setEnabled(enabled);
m_ui.hddFileLabel->setEnabled(enabled);
@@ -699,8 +712,8 @@ void DEV9SettingsWidget::onHddBrowseFileClicked()
{
QString path =
QDir::toNativeSeparators(QFileDialog::getSaveFileName(QtUtils::GetRootWidget(this), tr("HDD Image File"),
!m_ui.hddFile->text().isEmpty() ? m_ui.hddFile->text() : "DEV9hdd.raw", tr("HDD (*.raw)"), nullptr,
QFileDialog::DontConfirmOverwrite));
!m_ui.hddFile->text().isEmpty() ? m_ui.hddFile->text() : (!m_ui.hddFile->placeholderText().isEmpty() ? m_ui.hddFile->placeholderText() : "DEV9hdd.raw"),
tr("HDD (*.raw)"), nullptr, QFileDialog::DontConfirmOverwrite));
if (path.isEmpty())
return;
@@ -711,10 +724,16 @@ void DEV9SettingsWidget::onHddBrowseFileClicked()
void DEV9SettingsWidget::onHddFileEdit()
{
//Check if file exists, if so set HddSize to correct value
// Check if file exists, if so set HddSize to correct value.
// Also save the hddPath setting
std::string hddPath(m_ui.hddFile->text().toStdString());
if (hddPath.empty())
{
m_dialog->setStringSettingValue("DEV9/Hdd", "HddFile", std::nullopt);
return;
}
else
m_dialog->setStringSettingValue("DEV9/Hdd", "HddFile", hddPath.c_str());
if (!Path::IsAbsolute(hddPath))
hddPath = Path::Combine(EmuFolders::Settings, hddPath);
@@ -739,22 +758,49 @@ void DEV9SettingsWidget::onHddFileEdit()
void DEV9SettingsWidget::onHddSizeSlide(int i)
{
// We have to call onHddSizeAccessorSpin() ourself, as the value could still be considered null when the valueChanged signal is fired
QSignalBlocker sb(m_ui.hddSizeSpinBox);
m_ui.hddSizeSpinBox->setValue(i);
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", (int)((s64)i * 1024 * 1024 * 1024 / 512));
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, i);
onHddSizeAccessorSpin();
}
void DEV9SettingsWidget::onHddSizeSpin(int i)
void DEV9SettingsWidget::onHddSizeSliderContext(const QPoint& pt)
{
QSignalBlocker sb(m_ui.hddSizeSlider);
m_ui.hddSizeSlider->setValue(i);
QMenu menu(m_ui.hddSizeSlider);
connect(menu.addAction(qApp->translate("SettingWidgetBinder", "Reset")), &QAction::triggered, this, &DEV9SettingsWidget::onHddSizeSliderReset);
menu.exec(m_ui.hddSizeSlider->mapToGlobal(pt));
}
//TODO: need a setUintSettingValue for if 48bit support occurs
if (i == 39)
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", std::nullopt);
void DEV9SettingsWidget::onHddSizeSliderReset([[maybe_unused]] bool checked)
{
// We have to call onHddSizeAccessorSpin() ourself, as the value could still be considered non-null when the valueChanged signal is fired
QSignalBlocker sb(m_ui.hddSizeSpinBox);
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, std::nullopt);
onHddSizeAccessorSpin();
}
void DEV9SettingsWidget::onHddSizeAccessorSpin()
{
//TODO: need a getUintValue for if 48bit support occurs
QSignalBlocker sb(m_ui.hddSizeSlider);
if (m_dialog->isPerGameSettings())
{
std::optional<int> new_value = SettingWidgetBinder::SettingAccessor<QSpinBox>::getNullableIntValue(m_ui.hddSizeSpinBox);
const int sizeGlobal = (u64)Host::GetBaseIntSettingValue("DEV9/Hdd", "HddSizeSectors", 0) * 512 / (1024 * 1024 * 1024);
m_ui.hddSizeSlider->setValue(new_value.value_or(sizeGlobal));
if (new_value.has_value())
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", new_value.value() * (1024 * 1024 * 1024 / 512));
else
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", std::nullopt);
}
else
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", i * (1024 * 1024 * 1024 / 512));
{
const int new_value = SettingWidgetBinder::SettingAccessor<QSpinBox>::getIntValue(m_ui.hddSizeSpinBox);
m_ui.hddSizeSlider->setValue(new_value);
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", new_value * (1024 * 1024 * 1024 / 512));
}
}
void DEV9SettingsWidget::onHddCreateClicked()
@@ -774,7 +820,7 @@ void DEV9SettingsWidget::onHddCreateClicked()
if (!Path::IsAbsolute(hddPath))
hddPath = Path::Combine(EmuFolders::Settings, hddPath);
if (!FileSystem::FileExists(hddPath.c_str()))
if (FileSystem::FileExists(hddPath.c_str()))
{
//GHC uses UTF8 on all platforms
QMessageBox::StandardButton selection =
+5 -1
View File
@@ -49,7 +49,11 @@ private Q_SLOTS:
void onHddBrowseFileClicked();
void onHddFileEdit();
void onHddSizeSlide(int i);
void onHddSizeSpin(int i);
// Per game only.
void onHddSizeSliderContext(const QPoint& pt);
void onHddSizeSliderReset(bool checked = false);
//
void onHddSizeAccessorSpin();
void onHddCreateClicked();
public:
+5
View File
@@ -346,6 +346,11 @@
<string>In-Game</string>
</property>
</item>
<item>
<property name="text">
<string>Playable</string>
</property>
</item>
<item>
<property name="text">
<string>Perfect</string>
+194 -108
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());
@@ -213,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);
//////////////////////////////////////////////////////////////////////////
@@ -234,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"));
@@ -248,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
@@ -315,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
@@ -342,39 +362,45 @@ 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."));
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."));
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(""));
@@ -395,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."));
@@ -417,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)"),
@@ -445,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
@@ -482,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. "
@@ -508,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."));
@@ -548,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(""));
@@ -564,8 +597,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
// OSD tab
{
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.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 "
@@ -580,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."));
@@ -593,16 +624,26 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
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("Displays various settings and the current values of those settings, useful for debugging."));
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("Shows the current controler state of the system in the bottom left corner of the display."));
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("Displays a graph showing the average frametimes."));
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
@@ -627,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"),
@@ -707,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);
}
@@ -721,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));
@@ -739,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)
@@ -767,7 +852,8 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
const bool is_sw_dx = false;
#endif
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::DX12 || type == GSRendererType::OGL || type == GSRendererType::VK || type == GSRendererType::Metal);
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::DX12 || type == GSRendererType::OGL ||
type == GSRendererType::VK || type == GSRendererType::Metal);
const bool is_software = (type == GSRendererType::SW);
const bool hw_fixes = (is_hardware && m_ui.enableHWFixes->checkState() == Qt::Checked);
const int prev_tab = m_ui.tabs->currentIndex();
+7 -2
View File
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -43,7 +43,12 @@ private Q_SLOTS:
void onGpuPaletteConversionChanged(int state);
void onFullscreenModeChanged(int index);
void onShadeBoostChanged();
void onVideoCaptureContainerChanged();
void onCaptureContainerChanged();
void onEnableVideoCaptureChanged();
void onEnableVideoCaptureArgumentsChanged();
void onVideoCaptureAutoResolutionChanged();
void onEnableAudioCaptureChanged();
void onEnableAudioCaptureArgumentsChanged();
private:
GSRendererType getEffectiveRenderer() const;
+281 -42
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">
@@ -1649,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>
@@ -1742,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>
+33
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()
@@ -318,6 +341,16 @@ void InputBindingDialog::inputManagerHookCallback(InputBindingKey key, float val
}
}
void InputBindingDialog::onSensitivityChanged(int value)
{
m_ui.sensitivityValue->setText(tr("%1%").arg(value));
}
void InputBindingDialog::onDeadzoneChanged(int value)
{
m_ui.deadzoneValue->setText(tr("%1%").arg(value));
}
void InputBindingDialog::hookInputManager()
{
InputManager::SetHook([this](InputBindingKey key, float value) {
+3
View File
@@ -41,6 +41,9 @@ protected Q_SLOTS:
void onInputListenTimerTimeout();
void inputManagerHookCallback(InputBindingKey key, float value);
void onSensitivityChanged(int value);
void onDeadzoneChanged(int value);
protected:
enum : u32
{
+88 -1
View File
@@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>533</width>
<height>283</height>
<height>266</height>
</rect>
</property>
<property name="windowTitle">
@@ -30,6 +30,93 @@
<item>
<widget class="QListWidget" name="bindingList"/>
</item>
<item>
<widget class="QWidget" name="sensitivityWidget" native="true">
<layout class="QGridLayout" name="sensitivityLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="sensitivityLabel">
<property name="text">
<string>Sensitivity:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="sensitivity">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>200</number>
</property>
<property name="value">
<number>100</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="sensitivityValue">
<property name="text">
<string>100%</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="deadzoneLabel">
<property name="text">
<string>Deadzone:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="deadzone">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>5</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="deadzoneValue">
<property name="text">
<string>100%</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="status">
<property name="text">
@@ -98,7 +98,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
AutoUpdaterDialog::getDefaultTag());
m_ui.autoUpdateCurrentVersion->setText(tr("%1 (%2)").arg(AutoUpdaterDialog::getCurrentVersion()).arg(AutoUpdaterDialog::getCurrentVersionDate()));
connect(m_ui.checkForUpdates, &QPushButton::clicked, this, []() { g_main_window->checkForUpdates(true); });
connect(m_ui.checkForUpdates, &QPushButton::clicked, this, []() { g_main_window->checkForUpdates(true, true); });
}
else
{
+1 -1
View File
@@ -191,7 +191,7 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
m_ui.settingsContainer->setCurrentIndex(0);
m_ui.helpText->setText(m_category_help_text[0]);
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &SettingsDialog::onCategoryCurrentRowChanged);
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::accept);
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::close);
connect(m_ui.restoreDefaultsButton, &QPushButton::clicked, this, &SettingsDialog::onRestoreDefaultsClicked);
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -71,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>
+3 -3
View File
@@ -37,7 +37,7 @@
#include "Elfheader.h"
#include "ps2/BiosTools.h"
#include "Recording/InputRecording.h"
#include "VMManager.h"
#include "Host.h"
// This typically reflects the Sony-assigned serial code for the Disc, if one exists.
// (examples: SLUS-2113, etc).
@@ -2440,8 +2440,8 @@ static void cdvdWrite16(u8 rt) // SCOMMAND
case 0x0F: // sceCdPowerOff (0:1)- Call74 from Xcdvdman
Console.WriteLn(Color_StrongBlack, "sceCdPowerOff called. Resetting VM.");
VMManager::Reset();
Console.WriteLn(Color_StrongBlack, "sceCdPowerOff called. Shutting down VM.");
Host::RequestVMShutdown(false, false, false);
break;
case 0x12: // sceCdReadILinkId (0:9)
+1 -3
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;
+1 -8
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())
{
+115
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());
}
+263
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
}
+1 -1
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);
+13 -8
View File
@@ -15,14 +15,14 @@
#include "PrecompiledHeader.h"
#include "IsoFileFormats.h"
#include "common/Assertions.h"
#include "common/Exceptions.h"
#include "CDVD/IsoFileFormats.h"
#include "Config.h"
#include "Host.h"
#include "fmt/core.h"
#include "common/Assertions.h"
#include <errno.h>
#include "fmt/format.h"
static const char* nameFromType(int type)
{
@@ -246,12 +246,17 @@ bool InputIsoFile::Open(std::string srcfile, bool testOnly)
bool detected = Detect();
if (testOnly)
{
Close();
return detected;
}
if (!detected)
throw Exception::BadStream()
.SetUserMsg("Unrecognized ISO image file format.")
.SetDiagMsg("ISO mounting failed: PCSX2 is unable to identify the ISO image type.");
{
Console.Error(fmt::format("Unable to identify the ISO image type for '{}'", srcfile));
Close();
return false;
}
if (!isBlockdump && !isCompressed)
{
+1 -1
View File
@@ -130,7 +130,7 @@ public:
return m_filename;
}
void Create(std::string filename, int mode);
bool Create(std::string filename, int mode);
void Close();
void WriteHeader(int blockofs, uint blocksize, uint blocks);
-11
View File
@@ -16,18 +16,14 @@
#include "PrecompiledHeader.h"
#include "CDVD/CDVDdiscReader.h"
#ifdef __linux__
#include <libudev.h>
#include <linux/cdrom.h>
#endif
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
std::vector<std::string> GetOpticalDriveList()
{
#ifdef __linux__
udev* udev_context = udev_new();
if (!udev_context)
return {};
@@ -56,16 +52,12 @@ std::vector<std::string> GetOpticalDriveList()
udev_unref(udev_context);
return drives;
#else
return {};
#endif
}
void GetValidDrive(std::string& drive)
{
if (!drive.empty())
{
#ifdef __linux__
int fd = open(drive.c_str(), O_RDONLY | O_NONBLOCK);
if (fd != -1)
{
@@ -77,9 +69,6 @@ void GetValidDrive(std::string& drive)
{
drive.clear();
}
#else
drive.clear();
#endif
}
if (drive.empty())
{
-19
View File
@@ -17,10 +17,7 @@
#include "CDVD/CDVDdiscReader.h"
#include "CDVD/CDVD.h"
#ifdef __linux__
#include <linux/cdrom.h>
#endif
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
@@ -108,7 +105,6 @@ bool IOCtlSrc::ReadSectors2048(u32 sector, u32 count, u8* buffer) const
bool IOCtlSrc::ReadSectors2352(u32 sector, u32 count, u8* buffer) const
{
#ifdef __linux__
union
{
cdrom_msf msf;
@@ -130,14 +126,10 @@ bool IOCtlSrc::ReadSectors2352(u32 sector, u32 count, u8* buffer) const
}
return true;
#else
return false;
#endif
}
bool IOCtlSrc::ReadDVDInfo()
{
#ifdef __linux__
dvd_struct dvdrs;
dvdrs.type = DVD_STRUCT_PHYSICAL;
dvdrs.physical.layer_num = 0;
@@ -180,14 +172,10 @@ bool IOCtlSrc::ReadDVDInfo()
}
return true;
#else
return false;
#endif
}
bool IOCtlSrc::ReadCDInfo()
{
#ifdef __linux__
cdrom_tochdr header;
if (ioctl(m_device, CDROMREADTOCHDR, &header) == -1)
@@ -214,14 +202,10 @@ bool IOCtlSrc::ReadCDInfo()
m_media_type = -1;
return true;
#else
return false;
#endif
}
bool IOCtlSrc::DiscReady()
{
#ifdef __linux__
if (m_device == -1)
return false;
@@ -239,7 +223,4 @@ bool IOCtlSrc::DiscReady()
}
return !!m_sectors;
#else
return false;
#endif
}
+10 -14
View File
@@ -15,7 +15,9 @@
#include "PrecompiledHeader.h"
#include "IsoFileFormats.h"
#include "CDVD/IsoFileFormats.h"
#include "Host.h"
#include "common/Exceptions.h"
#include "common/FileSystem.h"
#include "common/StringUtil.h"
@@ -44,7 +46,7 @@ void OutputIsoFile::_init()
m_blocks = 0;
}
void OutputIsoFile::Create(std::string filename, int version)
bool OutputIsoFile::Create(std::string filename, int version)
{
Close();
m_filename = std::move(filename);
@@ -57,11 +59,13 @@ void OutputIsoFile::Create(std::string filename, int version)
m_outstream = FileSystem::OpenCFile(m_filename.c_str(), "wb");
if (!m_outstream)
{
Console.Error("(OutputIsoFile::Create) Unable to open the file '%s' for writing: %d", m_filename.c_str(), errno);
Exception::FromErrno(filename, errno)->Rethrow();
Console.Error(fmt::format("(OutputIsoFile::Create) Unable to open the file '{}' for writing: {}", m_filename, errno));
_init();
return false;
}
Console.WriteLn("isoFile create ok: %s ", m_filename.c_str());
return true;
}
// Generates format header information for blockdumps.
@@ -122,16 +126,8 @@ void OutputIsoFile::WriteBuffer(const void* src, size_t size)
{
if (std::fwrite(src, size, 1, m_outstream) != 1)
{
int err = errno;
if (!err)
{
throw Exception::BadStream(m_filename)
.SetDiagMsg(fmt::format("An error occurred while writing {} bytes to file", size));
}
std::unique_ptr<BaseException> ex(Exception::FromErrno(m_filename, err));
ex->SetDiagMsg(fmt::format("An error occurred while writing {} bytes to file: {}", size, ex->DiagMsg()));
ex->Rethrow();
Host::ReportErrorAsync("Write Error", fmt::format("errno {} when trying to write {} bytes to block dump file.\n\nClosing file."));
Close();
}
}
+12 -20
View File
@@ -150,6 +150,7 @@ set(pcsx2Sources
Vif_Codes.cpp
Vif_Transfer.cpp
Vif_Unpack.cpp
VirtualMemory.cpp
vtlb.cpp
VU0.cpp
VUmicro.cpp
@@ -201,7 +202,6 @@ set(pcsx2Headers
PerformanceMetrics.h
PrecompiledHeader.h
R3000A.h
R5900Exceptions.h
R5900.h
R5900OpcodeTables.h
SaveState.h
@@ -217,6 +217,7 @@ set(pcsx2Headers
Vif_Dma.h
Vif.h
Vif_Unpack.h
VirtualMemory.h
vtlb.h
VUflags.h
VUmicro.h
@@ -328,6 +329,7 @@ set(pcsx2DEV9Sources
DEV9/InternalServers/DNS_Logger.cpp
DEV9/InternalServers/DNS_Server.cpp
DEV9/PacketReader/ARP/ARP_Packet.cpp
DEV9/PacketReader/ARP/ARP_PacketEditor.cpp
DEV9/PacketReader/IP/ICMP/ICMP_Packet.cpp
DEV9/PacketReader/IP/TCP/TCP_Options.cpp
DEV9/PacketReader/IP/TCP/TCP_Packet.cpp
@@ -339,7 +341,7 @@ set(pcsx2DEV9Sources
DEV9/PacketReader/IP/IP_Options.cpp
DEV9/PacketReader/IP/IP_Packet.cpp
DEV9/PacketReader/EthernetFrame.cpp
DEV9/PacketReader/NetLib.cpp
DEV9/PacketReader/EthernetFrameEditor.cpp
DEV9/Sessions/BaseSession.cpp
DEV9/Sessions/ICMP_Session/ICMP_Session.cpp
DEV9/Sessions/TCP_Session/TCP_Session.cpp
@@ -366,6 +368,7 @@ set(pcsx2DEV9Headers
DEV9/InternalServers/DNS_Server.h
DEV9/net.h
DEV9/PacketReader/ARP/ARP_Packet.h
DEV9/PacketReader/ARP/ARP_PacketEditor.h
DEV9/PacketReader/IP/ICMP/ICMP_Packet.h
DEV9/PacketReader/IP/TCP/TCP_Options.h
DEV9/PacketReader/IP/TCP/TCP_Packet.h
@@ -380,6 +383,8 @@ set(pcsx2DEV9Headers
DEV9/PacketReader/IP/IP_Packet.h
DEV9/PacketReader/IP/IP_Payload.h
DEV9/PacketReader/EthernetFrame.h
DEV9/PacketReader/EthernetFrameEditor.h
DEV9/PacketReader/MAC_Address.h
DEV9/PacketReader/NetLib.h
DEV9/PacketReader/Payload.h
DEV9/pcap_io.h
@@ -431,8 +436,6 @@ set(pcsx2USBHeaders
USB/qemu-usb/input-keymap.h
USB/qemu-usb/queue.h
USB/qemu-usb/qusb.h
USB/readerwriterqueue/atomicops.h
USB/readerwriterqueue/readerwriterqueue.h
USB/shared/ringbuffer.h
USB/usb-eyetoy/jo_mpeg.h
USB/usb-eyetoy/ov519.h
@@ -496,7 +499,6 @@ set(pcsx2GSSources
GS/GSAlignedClass.cpp
GS/GSCapture.cpp
GS/GSClut.cpp
GS/GSCodeBuffer.cpp
GS/GSCrc.cpp
GS/GSDrawingContext.cpp
GS/GSDump.cpp
@@ -531,12 +533,10 @@ set(pcsx2GSSources
# GS headers
set(pcsx2GSHeaders
GS/config.h
GS/GSAlignedClass.h
GS/GSBlock.h
GS/GSCapture.h
GS/GSClut.h
GS/GSCodeBuffer.h
GS/GSCrc.h
GS/GSDrawingContext.h
GS/GSDrawingEnvironment.h
@@ -687,8 +687,6 @@ set(pcsx2IPUSources
set(pcsx2IPUSourcesUnshared
IPU/IPU_MultiISA.cpp
IPU/IPUdither.cpp
IPU/mpeg2lib/Idct.cpp
IPU/mpeg2lib/Mpeg.cpp
IPU/yuv2rgb.cpp
)
@@ -698,8 +696,7 @@ set(pcsx2IPUHeaders
IPU/IPU_Fifo.h
IPU/IPU_MultiISA.h
IPU/IPUdma.h
IPU/mpeg2lib/Mpeg.h
IPU/mpeg2lib/Vlc.h
IPU/mpeg2_vlc.h
IPU/yuv2rgb.h
)
@@ -919,14 +916,14 @@ set(pcsx2LinuxSources
)
set(pcsx2OSXSources
CDVD/Linux/DriveUtility.cpp
CDVD/Linux/IOCtlSrc.cpp
CDVD/Darwin/DriveUtility.cpp
CDVD/Darwin/IOCtlSrc.cpp
Darwin/DarwinFlatFileReader.cpp
)
set(pcsx2FreeBSDSources
CDVD/Linux/DriveUtility.cpp
CDVD/Linux/IOCtlSrc.cpp
CDVD/Darwin/DriveUtility.cpp
CDVD/Darwin/IOCtlSrc.cpp
Darwin/DarwinFlatFileReader.cpp
)
@@ -990,10 +987,6 @@ set(pcsx2RecordingHeaders
${rec_src}/Utilities/InputRecordingLogger.h
)
# System headers
set(pcsx2SystemHeaders
System/RecTypes.h)
# Windows sources
set(pcsx2WindowsSources
CDVD/Windows/DriveUtility.cpp
@@ -1119,7 +1112,6 @@ target_sources(PCSX2 PRIVATE
${pcsx2FrontendHeaders}
${pcsx2ps2Sources}
${pcsx2ps2Headers}
${pcsx2SystemHeaders}
)
# platform sources
+23 -6
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-
@@ -537,6 +537,8 @@ struct Pcsx2Config
EnableEECache : 1;
bool
EnableFastmem : 1;
bool
PauseOnTLBMiss : 1;
BITFIELD_END
RecompilerOptions();
@@ -605,15 +607,18 @@ struct Pcsx2Config
{
static const char* AspectRatioNames[];
static const char* FMVAspectRatioSwitchNames[];
static const char* VideoCaptureContainers[];
static const char* CaptureContainers[];
static const char* GetRendererName(GSRendererType type);
static constexpr float DEFAULT_FRAME_RATE_NTSC = 59.94f;
static constexpr float DEFAULT_FRAME_RATE_PAL = 50.00f;
static constexpr u32 DEFAULT_VIDEO_CAPTURE_BITRATE = 6000;
static const char* DEFAULT_VIDEO_CAPTURE_CONTAINER;
static constexpr int DEFAULT_VIDEO_CAPTURE_BITRATE = 6000;
static constexpr int DEFAULT_VIDEO_CAPTURE_WIDTH = 640;
static constexpr int DEFAULT_VIDEO_CAPTURE_HEIGHT = 480;
static constexpr int DEFAULT_AUDIO_CAPTURE_BITRATE = 160;
static const char* DEFAULT_CAPTURE_CONTAINER;
union
{
@@ -679,7 +684,12 @@ struct Pcsx2Config
DumpPaletteTextures : 1,
LoadTextureReplacements : 1,
LoadTextureReplacementsAsync : 1,
PrecacheTextureReplacements : 1;
PrecacheTextureReplacements : 1,
EnableVideoCapture : 1,
EnableVideoCaptureParameters : 1,
VideoCaptureAutoResolution : 1,
EnableAudioCapture : 1,
EnableAudioCaptureParameters : 1;
};
};
@@ -752,9 +762,15 @@ struct Pcsx2Config
GSScreenshotFormat ScreenshotFormat{GSScreenshotFormat::PNG};
int ScreenshotQuality{50};
std::string VideoCaptureContainer{DEFAULT_VIDEO_CAPTURE_CONTAINER};
std::string CaptureContainer{DEFAULT_CAPTURE_CONTAINER};
std::string VideoCaptureCodec;
std::string VideoCaptureParameters;
std::string AudioCaptureCodec;
std::string AudioCaptureParameters;
int VideoCaptureBitrate{DEFAULT_VIDEO_CAPTURE_BITRATE};
int VideoCaptureWidth{DEFAULT_VIDEO_CAPTURE_WIDTH};
int VideoCaptureHeight{DEFAULT_VIDEO_CAPTURE_HEIGHT};
int AudioCaptureBitrate{DEFAULT_AUDIO_CAPTURE_BITRATE};
std::string Adapter;
std::string HWDumpDirectory;
@@ -1309,6 +1325,7 @@ namespace EmuFolders
extern std::string GameSettings;
extern std::string Textures;
extern std::string InputProfiles;
extern std::string Videos;
// Assumes that AppRoot and DataRoot have been initialized.
void SetDefaults(SettingsInterface& si);
+7 -1
View File
@@ -445,6 +445,10 @@ u32 UpdateVSyncRate()
if (vSyncInfo.Framerate != frames_per_second || vSyncInfo.VideoMode != gsVideoMode)
{
// NBA Jam 2004 PAL will fail to display 3D on the menu if this value isn't correct on reset.
if (video_mode_initialized && vSyncInfo.VideoMode != gsVideoMode)
CSRreg.FIELD = 1;
vSyncInfo.VideoMode = gsVideoMode;
vSyncInfoCalc(&vSyncInfo, frames_per_second, total_scanlines);
@@ -457,7 +461,9 @@ u32 UpdateVSyncRate()
hsyncCounter.CycleT = vSyncInfo.hRender; // Amount of cycles before the counter will be updated
vsyncCounter.CycleT = vSyncInfo.Render; // Amount of cycles before the counter will be updated
hsyncCounter.sCycle = cpuRegs.cycle;
vsyncCounter.sCycle = cpuRegs.cycle;
vsyncCounter.Mode = MODE_VRENDER;
cpuRcntSet();
}
-2
View File
@@ -62,8 +62,6 @@ struct EECNT_MODE
u32 OverflowReached:1;
};
// fixme: Cycle and sCycleT members are unused.
// But they can't be removed without making a new savestate version.
struct Counter
{
u32 count;
+101 -60
View File
@@ -15,21 +15,24 @@
#include "PrecompiledHeader.h"
#include <algorithm>
#ifdef __POSIX__
#include <vector>
#include <fstream>
#include <net/if.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "common/StringUtil.h"
#ifdef __linux__
#include <unistd.h>
#include <sys/ioctl.h>
#endif
#if defined(__FreeBSD__) || (__APPLE__)
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/route.h>
#include "common/Assertions.h"
@@ -39,13 +42,14 @@
#include "AdapterUtils.h"
using namespace PacketReader;
using namespace PacketReader::IP;
#ifdef _WIN32
bool AdapterUtils::GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer)
bool AdapterUtils::GetAdapter(const std::string& name, Adapter* adapter, AdapterBuffer* buffer)
{
int neededSize = 128;
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> adapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
PIP_ADAPTER_ADDRESSES pAdapterInfo;
@@ -54,14 +58,14 @@ bool AdapterUtils::GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSE
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
NULL,
AdapterInfo.get(),
adapterInfo.get(),
&dwBufLen);
if (dwStatus == ERROR_BUFFER_OVERFLOW)
{
DevCon.WriteLn("DEV9: GetWin32Adapter() buffer too small, resizing");
neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1;
AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
adapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
DevCon.WriteLn("DEV9: New size %i", neededSize);
@@ -69,31 +73,32 @@ bool AdapterUtils::GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSE
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
NULL,
AdapterInfo.get(),
adapterInfo.get(),
&dwBufLen);
}
if (dwStatus != ERROR_SUCCESS)
return false;
pAdapterInfo = AdapterInfo.get();
pAdapterInfo = adapterInfo.get();
do
{
if (strcmp(pAdapterInfo->AdapterName, name.c_str()) == 0)
{
*adapter = *pAdapterInfo;
buffer->swap(AdapterInfo);
buffer->swap(adapterInfo);
return true;
}
pAdapterInfo = pAdapterInfo->Next;
} while (pAdapterInfo);
return false;
}
bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer)
bool AdapterUtils::GetAdapterAuto(Adapter* adapter, AdapterBuffer* buffer)
{
int neededSize = 128;
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> adapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
PIP_ADAPTER_ADDRESSES pAdapter;
@@ -102,7 +107,7 @@ bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::uniqu
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
NULL,
AdapterInfo.get(),
adapterInfo.get(),
&dwBufLen);
if (dwStatus == ERROR_BUFFER_OVERFLOW)
@@ -110,7 +115,7 @@ bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::uniqu
DevCon.WriteLn("DEV9: PCAPGetWin32Adapter() buffer too small, resizing");
//
neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1;
AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
adapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
DevCon.WriteLn("DEV9: New size %i", neededSize);
@@ -118,45 +123,45 @@ bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::uniqu
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
NULL,
AdapterInfo.get(),
adapterInfo.get(),
&dwBufLen);
}
if (dwStatus != ERROR_SUCCESS)
return 0;
pAdapter = AdapterInfo.get();
pAdapter = adapterInfo.get();
do
{
if (pAdapter->IfType != IF_TYPE_SOFTWARE_LOOPBACK &&
pAdapter->OperStatus == IfOperStatusUp)
{
//Search for an adapter with;
//IPv4 Address
//DNS
//Gateway
// Search for an adapter with;
// IPv4 Address,
// DNS,
// Gateway.
bool hasIPv4 = false;
bool hasDNS = false;
bool hasGateway = false;
//IPv4
// IPv4.
if (GetAdapterIP(pAdapter).has_value())
hasIPv4 = true;
//DNS
// DNS.
if (GetDNS(pAdapter).size() > 0)
hasDNS = true;
//Gateway
// Gateway.
if (GetGateways(pAdapter).size() > 0)
hasGateway = true;
if (hasIPv4 && hasDNS && hasGateway)
{
*adapter = *pAdapter;
buffer->swap(AdapterInfo);
buffer->swap(adapterInfo);
return true;
}
}
@@ -167,16 +172,18 @@ bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::uniqu
return false;
}
#elif defined(__POSIX__)
bool AdapterUtils::GetIfAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer)
bool AdapterUtils::GetAdapter(const std::string& name, Adapter* adapter, AdapterBuffer* buffer)
{
ifaddrs* adapterInfo;
ifaddrs* ifa;
ifaddrs* pAdapter;
int error = getifaddrs(&adapterInfo);
int error = getifaddrs(&ifa);
if (error)
return false;
pAdapter = adapterInfo;
std::unique_ptr<ifaddrs, IfAdaptersDeleter> adapterInfo(ifa, IfAdaptersDeleter());
pAdapter = adapterInfo.get();
do
{
@@ -189,32 +196,33 @@ bool AdapterUtils::GetIfAdapter(const std::string& name, ifaddrs* adapter, ifadd
if (pAdapter != nullptr)
{
*adapter = *pAdapter;
*buffer = adapterInfo;
buffer->swap(adapterInfo);
return true;
}
freeifaddrs(adapterInfo);
return false;
}
bool AdapterUtils::GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer)
bool AdapterUtils::GetAdapterAuto(Adapter* adapter, AdapterBuffer* buffer)
{
ifaddrs* adapterInfo;
ifaddrs* ifa;
ifaddrs* pAdapter;
int error = getifaddrs(&adapterInfo);
int error = getifaddrs(&ifa);
if (error)
return false;
pAdapter = adapterInfo;
std::unique_ptr<ifaddrs, IfAdaptersDeleter> adapterInfo(ifa, IfAdaptersDeleter());
pAdapter = adapterInfo.get();
do
{
if ((pAdapter->ifa_flags & IFF_LOOPBACK) == 0 &&
(pAdapter->ifa_flags & IFF_UP) != 0)
{
//Search for an adapter with;
//IPv4 Address
//Gateway
// Search for an adapter with;
// IPv4 Address,
// Gateway.
bool hasIPv4 = false;
bool hasGateway = false;
@@ -228,7 +236,7 @@ bool AdapterUtils::GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer)
if (hasIPv4 && hasGateway)
{
*adapter = *pAdapter;
*buffer = adapterInfo;
buffer->swap(adapterInfo);
return true;
}
}
@@ -236,14 +244,47 @@ bool AdapterUtils::GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer)
pAdapter = pAdapter->ifa_next;
} while (pAdapter);
freeifaddrs(adapterInfo);
return false;
}
#endif
//AdapterIP
// AdapterMAC.
#ifdef _WIN32
std::optional<IP_Address> AdapterUtils::GetAdapterIP(PIP_ADAPTER_ADDRESSES adapter)
std::optional<MAC_Address> AdapterUtils::GetAdapterMAC(Adapter* adapter)
{
if (adapter != nullptr && adapter->PhysicalAddressLength == 6)
return *(MAC_Address*)adapter->PhysicalAddress;
return std::nullopt;
}
#elif defined(__POSIX__)
#ifdef __linux__
std::optional<MAC_Address> AdapterUtils::GetAdapterMAC(Adapter* adapter)
{
struct ifreq ifr;
strcpy(ifr.ifr_name, adapter->ifa_name);
int fd = socket(AF_INET, SOCK_DGRAM, 0);
int ret = ioctl(fd, SIOCGIFHWADDR, &ifr);
close(fd);
if (ret == 0)
return *(MAC_Address*)ifr.ifr_hwaddr.sa_data;
return std::nullopt;
}
#else
std::optional<MAC_Address> AdapterUtils::GetAdapterMAC(Adapter* adapter)
{
Console.Error("DEV9: Unsupported OS, can't get MAC address");
return std::nullopt;
}
#endif
#endif
// AdapterIP.
#ifdef _WIN32
std::optional<IP_Address> AdapterUtils::GetAdapterIP(Adapter* adapter)
{
PIP_ADAPTER_UNICAST_ADDRESS address = nullptr;
if (adapter != nullptr)
@@ -261,7 +302,7 @@ std::optional<IP_Address> AdapterUtils::GetAdapterIP(PIP_ADAPTER_ADDRESSES adapt
return std::nullopt;
}
#elif defined(__POSIX__)
std::optional<IP_Address> AdapterUtils::GetAdapterIP(ifaddrs* adapter)
std::optional<IP_Address> AdapterUtils::GetAdapterIP(Adapter* adapter)
{
sockaddr* address = nullptr;
if (adapter != nullptr)
@@ -279,9 +320,9 @@ std::optional<IP_Address> AdapterUtils::GetAdapterIP(ifaddrs* adapter)
}
#endif
//Gateways
// Gateways.
#ifdef _WIN32
std::vector<IP_Address> AdapterUtils::GetGateways(PIP_ADAPTER_ADDRESSES adapter)
std::vector<IP_Address> AdapterUtils::GetGateways(Adapter* adapter)
{
if (adapter == nullptr)
return {};
@@ -303,10 +344,10 @@ std::vector<IP_Address> AdapterUtils::GetGateways(PIP_ADAPTER_ADDRESSES adapter)
}
#elif defined(__POSIX__)
#ifdef __linux__
std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
std::vector<IP_Address> AdapterUtils::GetGateways(Adapter* adapter)
{
///proc/net/route contains some information about gateway addresses,
//and separates the information about by each interface.
// /proc/net/route contains some information about gateway addresses,
// and separates the information about by each interface.
if (adapter == nullptr)
return {};
@@ -325,8 +366,8 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
routeLines.push_back(line);
route.close();
//Columns are as follows (first-line header):
//Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
// Columns are as follows (first-line header):
// Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT.
for (size_t i = 1; i < routeLines.size(); i++)
{
std::string line = routeLines[i];
@@ -349,14 +390,14 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
return collection;
}
#elif defined(__FreeBSD__) || (__APPLE__)
std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
std::vector<IP_Address> AdapterUtils::GetGateways(Adapter* adapter)
{
if (adapter == nullptr)
return {};
std::vector<IP_Address> collection;
//Get index for our adapter by matching the adapter name
// Get index for our adapter by matching the adapter name.
int ifIndex = -1;
struct if_nameindex* ifNI;
@@ -379,14 +420,14 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
}
if_freenameindex(ifNI);
//Check if we found the adapter
// Check if we found the adapter.
if (ifIndex == -1)
{
Console.Error("DEV9: Failed to get index for adapter");
return collection;
}
//Find the gateway by looking though the routing information
// Find the gateway by looking though the routing information.
int name[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
size_t bufferLen = 0;
@@ -396,7 +437,7 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
return collection;
}
//len is an estimate, double it to be safe
// bufferLen is an estimate, double it to be safe.
bufferLen *= 2;
std::unique_ptr<u8[]> buffer = std::make_unique<u8[]>(bufferLen);
@@ -416,7 +457,7 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
sockaddr* sockaddrs = (sockaddr*)(hdr + 1);
pxAssert(sockaddrs[RTAX_DST].sa_family == AF_INET);
//Default gateway has no destination address
// Default gateway has no destination address.
sockaddr_in* sockaddr = (sockaddr_in*)&sockaddrs[RTAX_DST];
if (sockaddr->sin_addr.s_addr != 0)
continue;
@@ -429,7 +470,7 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
return collection;
}
#else
std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
std::vector<IP_Address> AdapterUtils::GetGateways(Adapter* adapter)
{
Console.Error("DEV9: Unsupported OS, can't find Gateway");
return {};
@@ -437,9 +478,9 @@ std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
#endif
#endif
//DNS
// DNS.
#ifdef _WIN32
std::vector<IP_Address> AdapterUtils::GetDNS(PIP_ADAPTER_ADDRESSES adapter)
std::vector<IP_Address> AdapterUtils::GetDNS(Adapter* adapter)
{
if (adapter == nullptr)
return {};
@@ -460,9 +501,9 @@ std::vector<IP_Address> AdapterUtils::GetDNS(PIP_ADAPTER_ADDRESSES adapter)
return collection;
}
#elif defined(__POSIX__)
std::vector<IP_Address> AdapterUtils::GetDNS(ifaddrs* adapter)
std::vector<IP_Address> AdapterUtils::GetDNS(Adapter* adapter)
{
//On Linux and OSX, DNS is system wide, not adapter specific, so we can ignore adapter
// On Linux and OSX, DNS is system wide, not adapter specific, so we can ignore the adapter parameter.
// Parse /etc/resolv.conf for all of the "nameserver" entries.
// These are the DNS servers the machine is configured to use.
+17 -14
View File
@@ -26,25 +26,28 @@
#include <string>
#include <optional>
#include "DEV9/PacketReader/MAC_Address.h"
#include "DEV9/PacketReader/IP/IP_Address.h"
namespace AdapterUtils
{
#ifdef _WIN32
bool GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer);
bool GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer);
std::optional<PacketReader::IP::IP_Address> GetAdapterIP(PIP_ADAPTER_ADDRESSES adapter);
//Mask
std::vector<PacketReader::IP::IP_Address> GetGateways(PIP_ADAPTER_ADDRESSES adapter);
std::vector<PacketReader::IP::IP_Address> GetDNS(PIP_ADAPTER_ADDRESSES adapter);
typedef IP_ADAPTER_ADDRESSES Adapter;
typedef std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterBuffer;
#elif defined(__POSIX__)
bool GetIfAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer);
bool GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer);
std::optional<PacketReader::IP::IP_Address> GetAdapterIP(ifaddrs* adapter);
//Mask
std::vector<PacketReader::IP::IP_Address> GetGateways(ifaddrs* adapter);
std::vector<PacketReader::IP::IP_Address> GetDNS(ifaddrs* adapter);
typedef ifaddrs Adapter;
struct IfAdaptersDeleter
{
void operator()(ifaddrs* buffer) const { freeifaddrs(buffer); }
};
typedef std::unique_ptr<ifaddrs, IfAdaptersDeleter> AdapterBuffer;
#endif
bool GetAdapter(const std::string& name, Adapter* adapter, AdapterBuffer* buffer);
bool GetAdapterAuto(Adapter* adapter, AdapterBuffer* buffer);
std::optional<PacketReader::MAC_Address> GetAdapterMAC(Adapter* adapter);
std::optional<PacketReader::IP::IP_Address> GetAdapterIP(Adapter* adapter);
// Mask.
std::vector<PacketReader::IP::IP_Address> GetGateways(Adapter* adapter);
std::vector<PacketReader::IP::IP_Address> GetDNS(Adapter* adapter);
}; // namespace AdapterUtils
@@ -0,0 +1,79 @@
/* 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 "ARP_PacketEditor.h"
#ifdef _WIN32
#include "winsock.h"
#else
#include <arpa/inet.h>
#endif
namespace PacketReader::ARP
{
ARP_PacketEditor::ARP_PacketEditor(PayloadPtr* pkt)
: basePkt{pkt}
{
}
u16 ARP_PacketEditor::GetHardwareType()
{
return ntohs(*(u16*)&basePkt->data[0]);
}
u16 ARP_PacketEditor::GetProtocol()
{
return ntohs(*(u16*)&basePkt->data[2]);
}
u8 ARP_PacketEditor::GetHardwareAddressLength()
{
return basePkt->data[4];
}
u8 ARP_PacketEditor::GetProtocolAddressLength()
{
return basePkt->data[5];
}
u16 ARP_PacketEditor::GetOp()
{
return ntohs(*(u16*)&basePkt->data[6]);
}
u8* ARP_PacketEditor::SenderHardwareAddress()
{
return &basePkt->data[8];
}
u8* ARP_PacketEditor::SenderProtocolAddress()
{
int offset = 8 + GetHardwareAddressLength();
return &basePkt->data[offset];
}
u8* ARP_PacketEditor::TargetHardwareAddress()
{
int offset = 8 + GetHardwareAddressLength() + GetProtocolAddressLength();
return &basePkt->data[offset];
}
u8* ARP_PacketEditor::TargetProtocolAddress()
{
int offset = 8 + 2 * GetHardwareAddressLength() + GetProtocolAddressLength();
return &basePkt->data[offset];
}
} // namespace PacketReader::ARP
@@ -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 "DEV9/PacketReader/Payload.h"
namespace PacketReader::ARP
{
std::vector<void*> m_buffers;
size_t m_blocksize;
size_t m_pos, m_reserved;
u8* m_ptr;
class ARP_PacketEditor
{
private:
PayloadPtr* basePkt;
public:
GSCodeBuffer(size_t blocksize = 4096 * 64); // 256k
virtual ~GSCodeBuffer();
public:
void* GetBuffer(size_t size);
void ReleaseBuffer(size_t size);
};
ARP_PacketEditor(PayloadPtr* pkt);
u16 GetHardwareType();
u16 GetProtocol();
u8 GetHardwareAddressLength();
u8 GetProtocolAddressLength();
u16 GetOp();
u8* SenderHardwareAddress();
u8* SenderProtocolAddress();
u8* TargetHardwareAddress();
u8* TargetProtocolAddress();
};
} // namespace PacketReader::ARP
+4 -4
View File
@@ -27,8 +27,8 @@ namespace PacketReader
EthernetFrame::EthernetFrame(NetPacket* pkt)
{
int offset = 0;
NetLib::ReadByteArray((u8*)pkt->buffer, &offset, 6, destinationMAC);
NetLib::ReadByteArray((u8*)pkt->buffer, &offset, 6, sourceMAC);
NetLib::ReadMACAddress((u8*)pkt->buffer, &offset, &destinationMAC);
NetLib::ReadMACAddress((u8*)pkt->buffer, &offset, &sourceMAC);
headerLength = 14; //(6+6+2)
@@ -51,8 +51,8 @@ namespace PacketReader
int counter = 0;
pkt->size = headerLength + payload->GetLength();
NetLib::WriteByteArray((u8*)pkt->buffer, &counter, 6, destinationMAC);
NetLib::WriteByteArray((u8*)pkt->buffer, &counter, 6, sourceMAC);
NetLib::WriteMACAddress((u8*)pkt->buffer, &counter, destinationMAC);
NetLib::WriteMACAddress((u8*)pkt->buffer, &counter, sourceMAC);
//
NetLib::WriteUInt16((u8*)pkt->buffer, &counter, protocol);
//
+3 -2
View File
@@ -16,6 +16,7 @@
#pragma once
#include "DEV9/net.h"
#include "MAC_Address.h"
#include "Payload.h"
namespace PacketReader
@@ -34,8 +35,8 @@ namespace PacketReader
class EthernetFrame
{
public:
u8 destinationMAC[6] = {0};
u8 sourceMAC[6] = {0};
MAC_Address destinationMAC{};
MAC_Address sourceMAC{};
u16 protocol = 0;
int headerLength = 14;
@@ -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 "EthernetFrameEditor.h"
#ifdef _WIN32
#include "winsock.h"
#else
#include <arpa/inet.h>
#endif
namespace PacketReader
{
EthernetFrameEditor::EthernetFrameEditor(NetPacket* pkt)
: basePkt{pkt}
{
headerLength = 14; //(6+6+2)
//Note: we don't have to worry about the Ethernet Frame CRC as it is not included in the packet
//Note: We don't support tagged frames
payload = std::make_unique<PayloadPtr>((u8*)&basePkt->buffer[14], pkt->size - headerLength);
}
MAC_Address EthernetFrameEditor::GetDestinationMAC()
{
return *(MAC_Address*)&basePkt->buffer[0];
}
void EthernetFrameEditor::SetDestinationMAC(MAC_Address value)
{
*(MAC_Address*)&basePkt->buffer[0] = value;
}
MAC_Address EthernetFrameEditor::GetSourceMAC()
{
return *(MAC_Address*)&basePkt->buffer[6];
}
void EthernetFrameEditor::SetSourceMAC(MAC_Address value)
{
*(MAC_Address*)&basePkt->buffer[6] = value;
}
u16 EthernetFrameEditor::GetProtocol()
{
return ntohs(*(u16*)&basePkt->buffer[12]);
}
PayloadPtr* EthernetFrameEditor::GetPayload()
{
return payload.get();
}
} // namespace PacketReader
@@ -0,0 +1,45 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "DEV9/net.h"
#include "MAC_Address.h"
#include "Payload.h"
namespace PacketReader
{
class EthernetFrameEditor
{
public:
int headerLength = 14;
//Length
private:
NetPacket* basePkt;
std::unique_ptr<PayloadPtr> payload;
public:
EthernetFrameEditor(NetPacket* pkt);
MAC_Address GetDestinationMAC();
void SetDestinationMAC(MAC_Address value);
MAC_Address GetSourceMAC();
void SetSourceMAC(MAC_Address value);
u16 GetProtocol();
PayloadPtr* GetPayload();
};
} // namespace PacketReader
+8 -8
View File
@@ -107,9 +107,9 @@ namespace PacketReader::IP
NetLib::ReadUInt16(buffer, &offset, &checksum);
//Bits 96-127
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&sourceIP);
NetLib::ReadIPAddress(buffer, &offset, &sourceIP);
//Bits 128-159
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&destinationIP);
NetLib::ReadIPAddress(buffer, &offset, &destinationIP);
//Bits 160+
if (headerLength > 20) //IP options (if any)
@@ -194,8 +194,8 @@ namespace PacketReader::IP
NetLib::WriteByte08(buffer, offset, protocol);
NetLib::WriteUInt16(buffer, offset, checksum); //header csum
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&sourceIP);
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&destinationIP);
NetLib::WriteIPAddress(buffer, offset, sourceIP);
NetLib::WriteIPAddress(buffer, offset, destinationIP);
//options
for (size_t i = 0; i < options.size(); i++)
@@ -243,8 +243,8 @@ namespace PacketReader::IP
NetLib::WriteByte08(headerSegment, &counter, protocol);
NetLib::WriteUInt16(headerSegment, &counter, 0); //header csum
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&sourceIP);
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&destinationIP);
NetLib::WriteIPAddress(headerSegment, &counter, sourceIP);
NetLib::WriteIPAddress(headerSegment, &counter, destinationIP);
//options
for (size_t i = 0; i < options.size(); i++)
@@ -276,8 +276,8 @@ namespace PacketReader::IP
NetLib::WriteByte08(headerSegment, &counter, protocol);
NetLib::WriteUInt16(headerSegment, &counter, checksum); //header csum
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&sourceIP);
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&destinationIP);
NetLib::WriteIPAddress(headerSegment, &counter, sourceIP);
NetLib::WriteIPAddress(headerSegment, &counter, destinationIP);
//options
for (size_t i = 0; i < options.size(); i++)
@@ -263,8 +263,8 @@ namespace PacketReader::IP::TCP
u8* headerSegment = new u8[pHeaderLen];
int counter = 0;
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&srcIP);
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&dstIP);
NetLib::WriteIPAddress(headerSegment, &counter, srcIP);
NetLib::WriteIPAddress(headerSegment, &counter, dstIP);
NetLib::WriteByte08(headerSegment, &counter, 0);
NetLib::WriteByte08(headerSegment, &counter, (u8)protocol);
NetLib::WriteUInt16(headerSegment, &counter, GetLength());
@@ -291,8 +291,8 @@ namespace PacketReader::IP::TCP
u8* headerSegment = new u8[pHeaderLen];
int counter = 0;
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&srcIP);
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&dstIP);
NetLib::WriteIPAddress(headerSegment, &counter, srcIP);
NetLib::WriteIPAddress(headerSegment, &counter, dstIP);
NetLib::WriteByte08(headerSegment, &counter, 0);
NetLib::WriteByte08(headerSegment, &counter, (u8)protocol);
NetLib::WriteUInt16(headerSegment, &counter, GetLength());
@@ -27,13 +27,13 @@ namespace PacketReader::IP::UDP::DHCP
DHCPopSubnet::DHCPopSubnet(u8* data, int offset)
{
offset += 2;
NetLib::ReadByteArray(data, &offset, 4, (u8*)&subnetMask);
NetLib::ReadIPAddress(data, &offset, &subnetMask);
}
void DHCPopSubnet::WriteBytes(u8* buffer, int* offset)
{
NetLib::WriteByte08(buffer, offset, GetCode());
NetLib::WriteByte08(buffer, offset, GetLength() - 2);
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&subnetMask);
NetLib::WriteIPAddress(buffer, offset, subnetMask);
}
DHCPopRouter::DHCPopRouter(const std::vector<IP_Address>& routerIPs)
@@ -137,14 +137,14 @@ namespace PacketReader::IP::UDP::DHCP
DHCPopBCIP::DHCPopBCIP(u8* data, int offset)
{
offset += 2;
NetLib::ReadByteArray(data, &offset, 4, (u8*)&broadcastIP);
NetLib::ReadIPAddress(data, &offset, &broadcastIP);
}
void DHCPopBCIP::WriteBytes(u8* buffer, int* offset)
{
NetLib::WriteByte08(buffer, offset, GetCode());
NetLib::WriteByte08(buffer, offset, GetLength() - 2);
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&broadcastIP);
NetLib::WriteIPAddress(buffer, offset, broadcastIP);
}
bool DHCPopNBIOSType::GetHNode()
@@ -228,14 +228,14 @@ namespace PacketReader::IP::UDP::DHCP
DHCPopREQIP::DHCPopREQIP(u8* data, int offset)
{
offset += 2;
NetLib::ReadByteArray(data, &offset, 4, (u8*)&requestedIP);
NetLib::ReadIPAddress(data, &offset, &requestedIP);
}
void DHCPopREQIP::WriteBytes(u8* buffer, int* offset)
{
NetLib::WriteByte08(buffer, offset, GetCode());
NetLib::WriteByte08(buffer, offset, GetLength() - 2);
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&requestedIP);
NetLib::WriteIPAddress(buffer, offset, requestedIP);
}
DHCPopIPLT::DHCPopIPLT(u32 LeaseTime)
@@ -279,14 +279,14 @@ namespace PacketReader::IP::UDP::DHCP
DHCPopSERVIP::DHCPopSERVIP(u8* data, int offset)
{
offset += 2;
NetLib::ReadByteArray(data, &offset, 4, (u8*)&serverIP);
NetLib::ReadIPAddress(data, &offset, &serverIP);
}
void DHCPopSERVIP::WriteBytes(u8* buffer, int* offset)
{
NetLib::WriteByte08(buffer, offset, GetCode());
NetLib::WriteByte08(buffer, offset, GetLength() - 2);
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&serverIP);
NetLib::WriteIPAddress(buffer, offset, serverIP);
}
DHCPopREQLIST::DHCPopREQLIST(const std::vector<u8>& requestList)
@@ -36,16 +36,16 @@ namespace PacketReader::IP::UDP::DHCP
NetLib::ReadUInt16(buffer, &offset, &flags);
//Bits 96-127 //Bytes 12-15
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&clientIP);
NetLib::ReadIPAddress(buffer, &offset, &clientIP);
//Bits 128-159 //Bytes 16-19
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&yourIP);
NetLib::ReadIPAddress(buffer, &offset, &yourIP);
//Bits 160-191 //Bytes 20-23
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&serverIP);
NetLib::ReadIPAddress(buffer, &offset, &serverIP);
//Bits 192-223 //Bytes 24-27
NetLib::ReadByteArray(buffer, &offset, 4, (u8*)&gatewayIP);
NetLib::ReadIPAddress(buffer, &offset, &gatewayIP);
//Bits 192+ //Bytes 28-43
NetLib::ReadByteArray(buffer, &offset, 16, clientHardwareAddress);
@@ -194,10 +194,10 @@ namespace PacketReader::IP::UDP::DHCP
NetLib::WriteUInt16(buffer, offset, seconds);
NetLib::WriteUInt16(buffer, offset, flags);
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&clientIP);
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&yourIP);
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&serverIP);
NetLib::WriteByteArray(buffer, offset, 4, (u8*)&gatewayIP);
NetLib::WriteIPAddress(buffer, offset, clientIP);
NetLib::WriteIPAddress(buffer, offset, yourIP);
NetLib::WriteIPAddress(buffer, offset, serverIP);
NetLib::WriteIPAddress(buffer, offset, gatewayIP);
NetLib::WriteByteArray(buffer, offset, 16, clientHardwareAddress);
//empty bytes
@@ -93,8 +93,8 @@ namespace PacketReader::IP::UDP
u8* headerSegment = new u8[pHeaderLen];
int counter = 0;
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&srcIP);
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&dstIP);
NetLib::WriteIPAddress(headerSegment, &counter, srcIP);
NetLib::WriteIPAddress(headerSegment, &counter, dstIP);
NetLib::WriteByte08(headerSegment, &counter, 0);
NetLib::WriteByte08(headerSegment, &counter, (u8)protocol);
NetLib::WriteUInt16(headerSegment, &counter, GetLength());
@@ -120,8 +120,8 @@ namespace PacketReader::IP::UDP
u8* headerSegment = new u8[pHeaderLen];
int counter = 0;
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&srcIP);
NetLib::WriteByteArray(headerSegment, &counter, 4, (u8*)&dstIP);
NetLib::WriteIPAddress(headerSegment, &counter, srcIP);
NetLib::WriteIPAddress(headerSegment, &counter, dstIP);
NetLib::WriteByte08(headerSegment, &counter, 0);
NetLib::WriteByte08(headerSegment, &counter, (u8)protocol);
NetLib::WriteUInt16(headerSegment, &counter, GetLength());
@@ -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,8 +15,23 @@
#pragma once
//#define ENABLE_VTUNE
namespace PacketReader
{
#pragma pack(push, 1)
struct MAC_Address
{
union
{
u8 bytes[6];
struct
{
u32 integer03;
u16 short45;
} u;
};
#define ENABLE_JIT_RASTERIZER
//#define DISABLE_HW_TEXTURE_CACHE // Slow but fixes a lot of bugs
bool operator==(const MAC_Address& other) const { return (this->u.integer03 == other.u.integer03) && (this->u.short45 == other.u.short45); }
bool operator!=(const MAC_Address& other) const { return (this->u.integer03 != other.u.integer03) || (this->u.short45 != other.u.short45); }
};
#pragma pack(pop)
} // namespace PacketReader
-75
View File
@@ -1,75 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 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 "NetLib.h"
#ifdef _WIN32
#include "winsock.h"
#else
#include <arpa/inet.h>
#endif
namespace PacketReader::NetLib
{
void WriteByte08(u8* data, int* index, u8 value)
{
data[*index] = value;
*index += sizeof(u8);
}
void WriteUInt16(u8* data, int* index, u16 value)
{
*(u16*)&data[*index] = htons(value);
*index += sizeof(u16);
}
void WriteUInt32(u8* data, int* index, u32 value)
{
*(u32*)&data[*index] = htonl(value);
*index += sizeof(u32);
}
//Special
void WriteByteArray(u8* data, int* index, int length, u8* value)
{
memcpy(&data[*index], value, length);
*index += length;
}
//Read
void ReadByte08(u8* data, int* index, u8* value)
{
*value = data[*index];
*index += sizeof(u8);
}
void ReadUInt16(u8* data, int* index, u16* value)
{
*value = ntohs(*(u16*)&data[*index]);
*index += sizeof(u16);
}
void ReadUInt32(u8* data, int* index, u32* value)
{
*value = ntohl(*(u32*)&data[*index]);
*index += sizeof(u32);
}
//Special
void ReadByteArray(u8* data, int* index, int length, u8* value)
{
memcpy(value, &data[*index], length);
*index += length;
}
} // namespace PacketReader::NetLib
+73 -8
View File
@@ -15,17 +15,82 @@
#pragma once
#include "DEV9/PacketReader/MAC_Address.h"
#include "DEV9/PacketReader/IP/IP_Address.h"
#ifdef _WIN32
#include "winsock.h"
#else
#include <arpa/inet.h>
#endif
namespace PacketReader::NetLib
{
void WriteByte08(u8* data, int* index, u8 value);
void WriteUInt16(u8* data, int* index, u16 value);
void WriteUInt32(u8* data, int* index, u32 value);
// Write.
inline void WriteByte08(u8* data, int* index, u8 value)
{
data[*index] = value;
*index += sizeof(u8);
}
inline void WriteUInt16(u8* data, int* index, u16 value)
{
*(u16*)&data[*index] = htons(value);
*index += sizeof(u16);
}
inline void WriteUInt32(u8* data, int* index, u32 value)
{
*(u32*)&data[*index] = htonl(value);
*index += sizeof(u32);
}
void WriteByteArray(u8* data, int* index, int length, u8* value);
// Special write.
inline void WriteMACAddress(u8* data, int* index, PacketReader::MAC_Address value)
{
*(PacketReader::MAC_Address*)&data[*index] = value;
*index += sizeof(PacketReader::MAC_Address);
}
inline void WriteIPAddress(u8* data, int* index, PacketReader::IP::IP_Address value)
{
*(PacketReader::IP::IP_Address*)&data[*index] = value;
*index += sizeof(PacketReader::IP::IP_Address);
}
inline void WriteByteArray(u8* data, int* index, int length, u8* value)
{
memcpy(&data[*index], value, length);
*index += length;
}
void ReadByte08(u8* data, int* index, u8* value);
void ReadUInt16(u8* data, int* index, u16* value);
void ReadUInt32(u8* data, int* index, u32* value);
// Read.
inline void ReadByte08(u8* data, int* index, u8* value)
{
*value = data[*index];
*index += sizeof(u8);
}
inline void ReadUInt16(u8* data, int* index, u16* value)
{
*value = ntohs(*(u16*)&data[*index]);
*index += sizeof(u16);
}
inline void ReadUInt32(u8* data, int* index, u32* value)
{
*value = ntohl(*(u32*)&data[*index]);
*index += sizeof(u32);
}
void ReadByteArray(u8* data, int* index, int length, u8* value);
// Special read.
inline void ReadMACAddress(u8* data, int* index, PacketReader::MAC_Address* value)
{
*value = *(PacketReader::MAC_Address*)&data[*index];
*index += sizeof(PacketReader::MAC_Address);
}
inline void ReadIPAddress(u8* data, int* index, PacketReader::IP::IP_Address* value)
{
*value = *(PacketReader::IP::IP_Address*)&data[*index];
*index += sizeof(PacketReader::IP::IP_Address);
}
inline void ReadByteArray(u8* data, int* index, int length, u8* value)
{
memcpy(value, &data[*index], length);
*index += length;
}
} // namespace PacketReader::NetLib
@@ -168,7 +168,7 @@ namespace Sessions
}
return nullptr;
}
DevCon.WriteLn("DEV9: TCP: [SRV]Sending %d bytes", recived);
DevCon.WriteLn("DEV9: TCP: [SRV] Sending %d bytes", recived);
PayloadData* recivedData = new PayloadData(recived);
memcpy(recivedData->data.get(), buffer.get(), recived);
@@ -116,7 +116,7 @@ namespace Sessions
if (ret == SOCKET_ERROR)
{
hasData = false;
Console.WriteLn("DEV9: UDP: select failed. Error Code: %d",
Console.Error("DEV9: UDP: select failed. Error Code: %d",
#ifdef _WIN32
WSAGetLastError());
#elif defined(__POSIX__)
+10 -8
View File
@@ -37,6 +37,8 @@
#include <wil/com.h>
#include <wil/resource.h>
#include "DEV9/PacketReader/MAC_Address.h"
//=============
// TAP IOCTLs
//=============
@@ -206,7 +208,7 @@ AdapterOptions TAPAdapter::GetAdapterOptions()
return AdapterOptions::None;
}
static int TAPGetMACAddress(HANDLE handle, u8* addr)
static int TAPGetMACAddress(HANDLE handle, PacketReader::MAC_Address* addr)
{
DWORD len = 0;
@@ -551,17 +553,17 @@ TAPAdapter::TAPAdapter()
cancel = CreateEvent(NULL, TRUE, FALSE, NULL);
u8 hostMAC[6];
u8 newMAC[6];
PacketReader::MAC_Address hostMAC;
PacketReader::MAC_Address newMAC;
TAPGetMACAddress(htap, hostMAC);
memcpy(newMAC, ps2MAC, 6);
TAPGetMACAddress(htap, &hostMAC);
newMAC = ps2MAC;
//Lets take the hosts last 2 bytes to make it unique on Xlink
newMAC[5] = hostMAC[4];
newMAC[4] = hostMAC[5];
newMAC.bytes[5] = hostMAC.bytes[4];
newMAC.bytes[4] = hostMAC.bytes[5];
SetMACAddress(newMAC);
SetMACAddress(&newMAC);
IP_ADAPTER_ADDRESSES adapter;
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
+12 -13
View File
@@ -178,8 +178,8 @@ using namespace PacketReader::IP;
using namespace PacketReader::IP::UDP;
const IP_Address NetAdapter::internalIP{{{192, 0, 2, 1}}};
const u8 NetAdapter::broadcastMAC[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
const u8 NetAdapter::internalMAC[6] = {0x76, 0x6D, 0xF4, 0x63, 0x30, 0x31};
const MAC_Address NetAdapter::broadcastMAC{{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}};
const MAC_Address NetAdapter::internalMAC{{{0x76, 0x6D, 0xF4, 0x63, 0x30, 0x31}}};
NetAdapter::NetAdapter()
{
@@ -268,15 +268,14 @@ void NetAdapter::InspectRecv(NetPacket* pkt)
}
}
void NetAdapter::SetMACAddress(u8* mac)
void NetAdapter::SetMACAddress(MAC_Address* mac)
{
if (mac == nullptr)
memcpy(ps2MAC, defaultMAC, 6);
ps2MAC = defaultMAC;
else
memcpy(ps2MAC, mac, 6);
ps2MAC = *mac;
for (int i = 0; i < 3; i++)
dev9.eeprom[i] = ((u16*)ps2MAC)[i];
*(MAC_Address*)&dev9.eeprom[0] = ps2MAC;
//The checksum seems to be all the values of the mac added up in 16bit chunks
dev9.eeprom[3] = (dev9.eeprom[0] + dev9.eeprom[1] + dev9.eeprom[2]) & 0xffff;
@@ -284,13 +283,13 @@ void NetAdapter::SetMACAddress(u8* mac)
bool NetAdapter::VerifyPkt(NetPacket* pkt, int read_size)
{
if ((memcmp(pkt->buffer, ps2MAC, 6) != 0) && (memcmp(pkt->buffer, &broadcastMAC, 6) != 0))
if ((*(MAC_Address*)&pkt->buffer[0] != ps2MAC) && (*(MAC_Address*)&pkt->buffer[0] != broadcastMAC))
{
//ignore strange packets
return false;
}
if (memcmp(pkt->buffer + 6, ps2MAC, 6) == 0)
if (*(MAC_Address*)&pkt->buffer[6] == ps2MAC)
{
//avoid pcap looping packets
return false;
@@ -347,8 +346,8 @@ bool NetAdapter::InternalServerRecv(NetPacket* pkt)
ippkt->destinationIP = {{{255, 255, 255, 255}}};
ippkt->sourceIP = internalIP;
EthernetFrame frame(ippkt);
memcpy(frame.sourceMAC, internalMAC, 6);
memcpy(frame.destinationMAC, ps2MAC, 6);
frame.sourceMAC = internalMAC;
frame.destinationMAC = ps2MAC;
frame.protocol = (u16)EtherType::IPv4;
frame.WritePacket(pkt);
return true;
@@ -361,8 +360,8 @@ bool NetAdapter::InternalServerRecv(NetPacket* pkt)
ippkt->destinationIP = ps2IP;
ippkt->sourceIP = internalIP;
EthernetFrame frame(ippkt);
memcpy(frame.sourceMAC, internalMAC, 6);
memcpy(frame.destinationMAC, ps2MAC, 6);
frame.sourceMAC = internalMAC;
frame.destinationMAC = ps2MAC;
frame.protocol = (u16)EtherType::IPv4;
frame.WritePacket(pkt);
InspectRecv(pkt);
+6 -5
View File
@@ -34,6 +34,7 @@
#include "Config.h"
#include "PacketReader/MAC_Address.h"
#include "PacketReader/IP/IP_Address.h"
#include "InternalServers/DHCP_Server.h"
#include "InternalServers/DNS_Logger.h"
@@ -42,7 +43,7 @@
struct ConfigDEV9;
// first three recognized by Xlink as Sony PS2
const u8 defaultMAC[6] = {0x00, 0x04, 0x1F, 0x82, 0x30, 0x31};
const PacketReader::MAC_Address defaultMAC = {{{0x00, 0x04, 0x1F, 0x82, 0x30, 0x31}}};
struct NetPacket
{
@@ -93,9 +94,9 @@ public:
static const PacketReader::IP::IP_Address internalIP;
protected:
u8 ps2MAC[6];
static const u8 broadcastMAC[6];
static const u8 internalMAC[6];
PacketReader::MAC_Address ps2MAC;
static const PacketReader::MAC_Address broadcastMAC;
static const PacketReader::MAC_Address internalMAC;
private:
//Only set if packet sent to the internal IP address
@@ -126,7 +127,7 @@ public:
virtual ~NetAdapter();
protected:
void SetMACAddress(u8* mac);
void SetMACAddress(PacketReader::MAC_Address* mac);
bool VerifyPkt(NetPacket* pkt, int read_size);
void InspectRecv(NetPacket* pkt);
+213 -302
View File
@@ -23,22 +23,16 @@
#include "common/StringUtil.h"
#include <WinSock2.h>
#include <iphlpapi.h>
#elif defined(__linux__)
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#elif defined(__POSIX__)
#include <sys/types.h>
#include <ifaddrs.h>
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include "pcap_io.h"
#include "DEV9.h"
#include "AdapterUtils.h"
#include "net.h"
#include "PacketReader/EthernetFrame.h"
#include "PacketReader/EthernetFrameEditor.h"
#include "PacketReader/ARP/ARP_PacketEditor.h"
#ifndef PCAP_NETMASK_UNKNOWN
#define PCAP_NETMASK_UNKNOWN 0xffffffff
#endif
@@ -47,237 +41,9 @@
#define PCAPPREFIX "\\Device\\NPF_"
#endif
pcap_t* adhandle;
pcap_dumper_t* dump_pcap = nullptr;
char errbuf[PCAP_ERRBUF_SIZE];
int pcap_io_running = 0;
bool pcap_io_switched;
bool pcap_io_blocking;
extern u8 eeprom[];
char namebuff[256];
ip_address ps2_ip;
mac_address ps2_mac;
mac_address host_mac;
// Fetches the MAC address and prints it
int GetMACAddress(const std::string& adapter, mac_address* addr)
{
int retval = 0;
#ifdef _WIN32
IP_ADAPTER_ADDRESSES adapterInfo;
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
if (AdapterUtils::GetWin32Adapter(adapter, &adapterInfo, &buffer))
{
memcpy(addr, adapterInfo.PhysicalAddress, 6);
retval = 1;
}
#elif defined(__linux__)
struct ifreq ifr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
strcpy(ifr.ifr_name, adapter.c_str());
if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr))
{
retval = 1;
memcpy(addr, ifr.ifr_hwaddr.sa_data, 6);
}
else
{
Console.Error("Could not get MAC address for adapter: %s", adapter.c_str());
}
close(fd);
#else
Console.Error("Could not get MAC address for adapter, OS not supported");
#endif
return retval;
}
int pcap_io_init(const std::string& adapter, bool switched, mac_address virtual_mac)
{
struct bpf_program fp;
char filter[1024] = "ether broadcast or ether dst ";
int dlt;
char* dlt_name;
Console.WriteLn("DEV9: Opening adapter '%s'...", adapter.c_str());
pcap_io_switched = switched;
#ifdef _WIN32
std::string pcapAdapter = PCAPPREFIX + adapter;
#else
std::string pcapAdapter = adapter;
#endif
/* Open the adapter */
if ((adhandle = pcap_open_live(pcapAdapter.c_str(), // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
switched ? 1 : 0,
1, // read timeout
errbuf // error buffer
)) == NULL)
{
Console.Error("DEV9: %s", errbuf);
Console.Error("DEV9: Unable to open the adapter. %s is not supported by pcap", adapter.c_str());
return -1;
}
if (switched)
{
char virtual_mac_str[18];
sprintf(virtual_mac_str, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", virtual_mac.bytes[0], virtual_mac.bytes[1], virtual_mac.bytes[2], virtual_mac.bytes[3], virtual_mac.bytes[4], virtual_mac.bytes[5]);
strcat(filter, virtual_mac_str);
// fprintf(stderr, "Trying pcap filter: %s\n", filter);
if (pcap_compile(adhandle, &fp, filter, 1, PCAP_NETMASK_UNKNOWN) == -1)
{
Console.Error("DEV9: Error calling pcap_compile: %s", pcap_geterr(adhandle));
return -1;
}
if (pcap_setfilter(adhandle, &fp) == -1)
{
Console.Error("DEV9: Error setting filter: %s", pcap_geterr(adhandle));
return -1;
}
}
if (pcap_setnonblock(adhandle, 1, errbuf) == -1)
{
Console.Error("DEV9: Error setting non-blocking: %s", pcap_geterr(adhandle));
Console.Error("DEV9: Continuing in blocking mode");
pcap_io_blocking = true;
}
else
pcap_io_blocking = false;
dlt = pcap_datalink(adhandle);
dlt_name = (char*)pcap_datalink_val_to_name(dlt);
Console.Error("DEV9: Device uses DLT %d: %s", dlt, dlt_name);
switch (dlt)
{
case DLT_EN10MB:
//case DLT_IEEE802_11:
break;
default:
Console.Error("ERROR: Unsupported DataLink Type (%d): %s", dlt, dlt_name);
pcap_close(adhandle);
return -1;
}
#ifdef DEBUG
const std::string plfile(s_strLogPath + "/pkt_log.pcap");
dump_pcap = pcap_dump_open(adhandle, plfile.c_str());
#endif
pcap_io_running = 1;
Console.WriteLn("DEV9: Adapter Ok.");
return 0;
}
#ifdef _WIN32
int gettimeofday(struct timeval* tv, void* tz)
{
unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */
GetSystemTimeAsFileTime((LPFILETIME)&ns100);
tv->tv_usec = (long)((ns100 / 10L) % 1000000L);
tv->tv_sec = (long)((ns100 - 116444736000000000L) / 10000000L);
return (0);
}
#endif
int pcap_io_send(void* packet, int plen)
{
if (pcap_io_running <= 0)
return -1;
if (!pcap_io_switched)
{
if (((ethernet_header*)packet)->protocol == 0x0008) //IP
{
ps2_ip = ((ip_header*)((u8*)packet + sizeof(ethernet_header)))->src;
}
if (((ethernet_header*)packet)->protocol == 0x0608) //ARP
{
ps2_ip = ((arp_packet*)((u8*)packet + sizeof(ethernet_header)))->p_src;
((arp_packet*)((u8*)packet + sizeof(ethernet_header)))->h_src = host_mac;
}
((ethernet_header*)packet)->src = host_mac;
}
if (dump_pcap)
{
static struct pcap_pkthdr ph;
gettimeofday(&ph.ts, NULL);
ph.caplen = plen;
ph.len = plen;
pcap_dump((u_char*)dump_pcap, &ph, (u_char*)packet);
}
return pcap_sendpacket(adhandle, (u_char*)packet, plen);
}
int pcap_io_recv(void* packet, int max_len)
{
static struct pcap_pkthdr* header;
static const u_char* pkt_data1;
if (pcap_io_running <= 0)
return -1;
if ((pcap_next_ex(adhandle, &header, &pkt_data1)) > 0)
{
if ((int)header->len > max_len)
return -1;
memcpy(packet, pkt_data1, header->len);
if (!pcap_io_switched)
{
{
if (((ethernet_header*)packet)->protocol == 0x0008)
{
ip_header* iph = ((ip_header*)((u8*)packet + sizeof(ethernet_header)));
if (ip_compare(iph->dst, ps2_ip) == 0)
{
((ethernet_header*)packet)->dst = ps2_mac;
}
}
if (((ethernet_header*)packet)->protocol == 0x0608)
{
arp_packet* aph = ((arp_packet*)((u8*)packet + sizeof(ethernet_header)));
if (ip_compare(aph->p_dst, ps2_ip) == 0)
{
((ethernet_header*)packet)->dst = ps2_mac;
((arp_packet*)((u8*)packet + sizeof(ethernet_header)))->h_dst = ps2_mac;
}
}
}
}
if (dump_pcap)
pcap_dump((u_char*)dump_pcap, header, (u_char*)packet);
return header->len;
}
return -1;
}
void pcap_io_close()
{
if (dump_pcap)
pcap_dump_close(dump_pcap);
if (adhandle)
pcap_close(adhandle);
pcap_io_running = 0;
}
using namespace PacketReader;
using namespace PacketReader::ARP;
using namespace PacketReader::IP;
PCAPAdapter::PCAPAdapter()
: NetAdapter()
@@ -289,50 +55,62 @@ PCAPAdapter::PCAPAdapter()
return;
#endif
mac_address hostMAC;
mac_address newMAC;
#ifdef _WIN32
std::string pcapAdapter = PCAPPREFIX + EmuConfig.DEV9.EthDevice;
#else
std::string pcapAdapter = EmuConfig.DEV9.EthDevice;
#endif
GetMACAddress(EmuConfig.DEV9.EthDevice, &hostMAC);
memcpy(&newMAC, ps2MAC, 6);
switched = EmuConfig.DEV9.EthApi == Pcsx2Config::DEV9Options::NetApi::PCAP_Switched;
//Lets take the hosts last 2 bytes to make it unique on Xlink
newMAC.bytes[5] = hostMAC.bytes[4];
newMAC.bytes[4] = hostMAC.bytes[5];
SetMACAddress((u8*)&newMAC);
host_mac = hostMAC;
ps2_mac = newMAC; //Needed outside of this class
if (pcap_io_init(EmuConfig.DEV9.EthDevice, EmuConfig.DEV9.EthApi == Pcsx2Config::DEV9Options::NetApi::PCAP_Switched, newMAC) == -1)
if (!InitPCAP(pcapAdapter, switched))
{
Console.Error("DEV9: Can't open Device '%s'", EmuConfig.DEV9.EthDevice.c_str());
return;
}
#ifdef _WIN32
IP_ADAPTER_ADDRESSES adapter;
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
if (AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
InitInternalServer(&adapter);
AdapterUtils::Adapter adapter;
AdapterUtils::AdapterBuffer buffer;
std::optional<MAC_Address> adMAC = std::nullopt;
const bool foundAdapter = AdapterUtils::GetAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
if (foundAdapter)
adMAC = AdapterUtils::GetAdapterMAC(&adapter);
else
Console.Error("DEV9: Failed to get adapter information");
if (adMAC.has_value())
{
hostMAC = adMAC.value();
MAC_Address newMAC = ps2MAC;
//Lets take the hosts last 2 bytes to make it unique on Xlink
newMAC.bytes[5] = hostMAC.bytes[4];
newMAC.bytes[4] = hostMAC.bytes[5];
SetMACAddress(&newMAC);
}
else if (switched)
Console.Error("DEV9: Failed to get MAC address for adapter, proceeding with hardcoded MAC address");
else
{
Console.Error("DEV9: Failed to get adapter information");
InitInternalServer(nullptr);
Console.Error("DEV9: Failed to get MAC address for adapter");
pcap_close(hpcap);
hpcap = nullptr;
return;
}
#elif defined(__POSIX__)
ifaddrs adapter;
ifaddrs* buffer;
if (AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
if (switched && !SetMACSwitchedFilter(ps2MAC))
{
pcap_close(hpcap);
hpcap = nullptr;
Console.Error("DEV9: Can't open Device '%s'", EmuConfig.DEV9.EthDevice.c_str());
return;
}
if (foundAdapter)
InitInternalServer(&adapter);
freeifaddrs(buffer);
}
else
{
Console.Error("DEV9: Failed to get adapter information");
InitInternalServer(nullptr);
}
#endif
}
AdapterOptions PCAPAdapter::GetAdapterOptions()
{
@@ -340,70 +118,88 @@ AdapterOptions PCAPAdapter::GetAdapterOptions()
}
bool PCAPAdapter::blocks()
{
pxAssert(pcap_io_running);
return pcap_io_blocking;
pxAssert(hpcap);
return blocking;
}
bool PCAPAdapter::isInitialised()
{
return !!pcap_io_running;
return hpcap != nullptr;
}
//gets a packet.rv :true success
bool PCAPAdapter::recv(NetPacket* pkt)
{
if (!pcap_io_blocking && NetAdapter::recv(pkt))
pxAssert(hpcap);
if (!blocking && NetAdapter::recv(pkt))
return true;
int size = pcap_io_recv(pkt->buffer, sizeof(pkt->buffer));
if (size > 0 && VerifyPkt(pkt, size))
pcap_pkthdr* header;
const u_char* pkt_data;
// pcap bridged will pick up packets not intended for us, returning false on those packets will incur a 1ms wait.
// This delays getting packets we need, so instead loop untill a valid packet, or no packet, is returned from pcap_next_ex.
while (pcap_next_ex(hpcap, &header, &pkt_data) > 0)
{
InspectRecv(pkt);
return true;
if (header->len > sizeof(pkt->buffer))
{
Console.Error("DEV9: Dropped jumbo frame of size: %u", header->len);
continue;
}
pxAssert(header->len == header->caplen);
memcpy(pkt->buffer, pkt_data, header->len);
pkt->size = (int)header->len;
if (!switched)
SetMACBridgedRecv(pkt);
if (VerifyPkt(pkt, header->len))
{
InspectRecv(pkt);
return true;
}
// continue.
}
else
return false;
return false;
}
//sends the packet .rv :true success
bool PCAPAdapter::send(NetPacket* pkt)
{
pxAssert(hpcap);
InspectSend(pkt);
if (NetAdapter::send(pkt))
return true;
if (pcap_io_send(pkt->buffer, pkt->size))
{
// TODO: loopback broadcast packets to host pc in switched mode.
if (!switched)
SetMACBridgedSend(pkt);
if (pcap_sendpacket(hpcap, (u_char*)pkt->buffer, pkt->size))
return false;
}
else
{
return true;
}
}
void PCAPAdapter::reloadSettings()
{
#ifdef _WIN32
IP_ADAPTER_ADDRESSES adapter;
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
if (AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
AdapterUtils::Adapter adapter;
AdapterUtils::AdapterBuffer buffer;
if (AdapterUtils::GetAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
ReloadInternalServer(&adapter);
else
ReloadInternalServer(nullptr);
#elif defined(__POSIX__)
ifaddrs adapter;
ifaddrs* buffer;
if (AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
{
ReloadInternalServer(&adapter);
freeifaddrs(buffer);
}
else
ReloadInternalServer(nullptr);
#endif
}
PCAPAdapter::~PCAPAdapter()
{
pcap_io_close();
if (hpcap)
{
pcap_close(hpcap);
hpcap = nullptr;
}
}
std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
@@ -415,6 +211,7 @@ std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
return nic;
#endif
char errbuf[PCAP_ERRBUF_SIZE];
pcap_if_t* alldevs;
pcap_if_t* d;
@@ -440,7 +237,7 @@ std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
IP_ADAPTER_ADDRESSES adapterInfo;
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
if (AdapterUtils::GetWin32Adapter(entry.guid, &adapterInfo, &buffer))
if (AdapterUtils::GetAdapter(entry.guid, &adapterInfo, &buffer))
entry.name = StringUtil::WideStringToUTF8String(std::wstring(adapterInfo.FriendlyName));
else
{
@@ -470,3 +267,117 @@ std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
return nic;
}
// Opens device for capture and sets non-blocking.
bool PCAPAdapter::InitPCAP(const std::string& adapter, bool promiscuous)
{
char errbuf[PCAP_ERRBUF_SIZE];
Console.WriteLn("DEV9: Opening adapter '%s'...", adapter.c_str());
// Open the adapter.
if ((hpcap = pcap_open_live(adapter.c_str(), // Name of the device.
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
promiscuous ? 1 : 0,
1, // Read timeout.
errbuf // Error buffer.
)) == nullptr)
{
Console.Error("DEV9: %s", errbuf);
Console.Error("DEV9: Unable to open the adapter. %s is not supported by pcap", adapter.c_str());
return false;
}
if (pcap_setnonblock(hpcap, 1, errbuf) == -1)
{
Console.Error("DEV9: Error setting non-blocking: %s", pcap_geterr(hpcap));
Console.Error("DEV9: Continuing in blocking mode");
blocking = true;
}
else
blocking = false;
// Validate.
const int dlt = pcap_datalink(hpcap);
const char* dlt_name = pcap_datalink_val_to_name(dlt);
Console.Error("DEV9: Device uses DLT %d: %s", dlt, dlt_name);
switch (dlt)
{
case DLT_EN10MB:
//case DLT_IEEE802_11:
break;
default:
Console.Error("ERROR: Unsupported DataLink Type (%d): %s", dlt, dlt_name);
pcap_close(hpcap);
hpcap = nullptr;
return false;
}
Console.WriteLn("DEV9: Adapter Ok.");
return true;
}
bool PCAPAdapter::SetMACSwitchedFilter(MAC_Address mac)
{
bpf_program fp;
char filter[1024] = "ether broadcast or ether dst ";
char virtual_mac_str[18];
sprintf(virtual_mac_str, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", mac.bytes[0], mac.bytes[1], mac.bytes[2], mac.bytes[3], mac.bytes[4], mac.bytes[5]);
strcat(filter, virtual_mac_str);
if (pcap_compile(hpcap, &fp, filter, 1, PCAP_NETMASK_UNKNOWN) == -1)
{
Console.Error("DEV9: Error calling pcap_compile: %s", pcap_geterr(hpcap));
return false;
}
int setFilterRet;
if ((setFilterRet = pcap_setfilter(hpcap, &fp)) == -1)
Console.Error("DEV9: Error setting filter: %s", pcap_geterr(hpcap));
pcap_freecode(&fp);
return setFilterRet != -1;
}
void PCAPAdapter::SetMACBridgedRecv(NetPacket* pkt)
{
EthernetFrameEditor frame(pkt);
if (frame.GetProtocol() == (u16)EtherType::IPv4) // IP
{
// Compare DEST IP in IP with the PS2's IP, if they match, change DEST MAC to ps2MAC.
PayloadPtr* payload = frame.GetPayload();
IP_Packet ippkt(payload->data, payload->GetLength());
if (ippkt.destinationIP == ps2IP)
frame.SetDestinationMAC(ps2MAC);
}
if (frame.GetProtocol() == (u16)EtherType::ARP) // ARP
{
// Compare DEST IP in ARP with the PS2's IP, if they match, DEST MAC to ps2MAC on both ARP and ETH Packet headers.
ARP_PacketEditor arpPkt(frame.GetPayload());
if (*(IP_Address*)arpPkt.TargetProtocolAddress() == ps2IP)
{
frame.SetDestinationMAC(ps2MAC);
*(MAC_Address*)arpPkt.TargetHardwareAddress() = ps2MAC;
}
}
}
void PCAPAdapter::SetMACBridgedSend(NetPacket* pkt)
{
EthernetFrameEditor frame(pkt);
if (frame.GetProtocol() == (u16)EtherType::IPv4) // IP
{
PayloadPtr* payload = frame.GetPayload();
IP_Packet ippkt(payload->data, payload->GetLength());
ps2IP = ippkt.sourceIP;
}
if (frame.GetProtocol() == (u16)EtherType::ARP) // ARP
{
ARP_PacketEditor arpPkt(frame.GetPayload());
ps2IP = *(IP_Address*)arpPkt.SenderProtocolAddress();
*(MAC_Address*)arpPkt.SenderHardwareAddress() = hostMAC;
}
frame.SetSourceMAC(hostMAC);
}
+18 -149
View File
@@ -16,163 +16,24 @@
#pragma once
#include "pcap.h"
#include "net.h"
#ifdef __cplusplus
extern "C" {
#endif
//#ifndef _WIN32
#pragma pack(push, 1)
typedef struct _ip_address
{
u_char bytes[4];
} ip_address;
typedef struct _mac_address
{
u_char bytes[6];
} mac_address;
typedef struct _ethernet_header
{
mac_address dst;
mac_address src;
u_short protocol;
} ethernet_header;
typedef struct _arp_packet
{
u_short hw_type;
u_short protocol;
u_char h_addr_len;
u_char p_addr_len;
u_short operation;
mac_address h_src;
ip_address p_src;
mac_address h_dst;
ip_address p_dst;
} arp_packet;
typedef struct _ip_header
{
u_char ver_hlen; /* version << 4 | header length >> 2 */
u_char type; /* type of service */
u_short len; /* total length */
u_short id; /* identification */
u_short offset; /* fragment offset field */
u_char ttl; /* time to live */
u_char proto; /* protocol */
u_short hdr_csum; /* checksum */
ip_address src; /* source and dest address */
ip_address dst;
} ip_header;
/* Internet Control Message Protocol Constants and Packet Format */
/* ic_type field */
#define ICT_ECHORP 0 /* Echo reply */
#define ICT_DESTUR 3 /* Destination unreachable */
#define ICT_SRCQ 4 /* Source quench */
#define ICT_REDIRECT 5 /* Redirect message type */
#define ICT_ECHORQ 8 /* Echo request */
#define ICT_TIMEX 11 /* Time exceeded */
#define ICT_PARAMP 12 /* Parameter Problem */
#define ICT_TIMERQ 13 /* Timestamp request */
#define ICT_TIMERP 14 /* Timestamp reply */
#define ICT_INFORQ 15 /* Information request */
#define ICT_INFORP 16 /* Information reply */
#define ICT_MASKRQ 17 /* Mask request */
#define ICT_MASKRP 18 /* Mask reply */
/* ic_code field */
#define ICC_NETUR 0 /* dest unreachable, net unreachable */
#define ICC_HOSTUR 1 /* dest unreachable, host unreachable */
#define ICC_PROTOUR 2 /* dest unreachable, proto unreachable */
#define ICC_PORTUR 3 /* dest unreachable, port unreachable */
#define ICC_FNADF 4 /* dest unr, frag needed & don't frag */
#define ICC_SRCRT 5 /* dest unreachable, src route failed */
#define ICC_NETRD 0 /* redirect: net */
#define ICC_HOSTRD 1 /* redirect: host */
#define IC_TOSNRD 2 /* redirect: type of service, net */
#define IC_TOSHRD 3 /* redirect: type of service, host */
#define ICC_TIMEX 0 /* time exceeded, ttl */
#define ICC_FTIMEX 1 /* time exceeded, frag */
#define IC_HLEN 8 /* octets */
#define IC_PADLEN 3 /* pad length (octets) */
#define IC_RDTTL 300 /* ttl for redirect routes */
/* ICMP packet format (following the IP header) */
typedef struct _icmp_header
{ /* ICMP packet */
char type; /* type of message (ICT_* above)*/
char code; /* code (ICC_* above) */
short csum; /* checksum of ICMP header+data */
union
{
struct
{
int ic1_id : 16; /* echo type, a message id */
int ic1_seq : 16; /* echo type, a seq. number */
} ic1;
ip_address ic2_gw; /* for redirect, gateway */
struct
{
char ic3_ptr; /* pointer, for ICT_PARAMP */
char ic3_pad[IC_PADLEN];
} ic3;
int ic4_mbz; /* must be zero */
} icu;
} icmp_header;
/*typedef struct _udp_header {
u16 src_port;
u16 dst_port;
u16 len;
u16 csum;
} udp_header;*/
typedef struct _full_arp_packet
{
ethernet_header header;
arp_packet arp;
} full_arp_packet;
#pragma pack(pop)
#define ARP_REQUEST 0x0100 //values are big-endian
#define mac_compare(a, b) (memcmp(&(a), &(b), 6))
#define ip_compare(a, b) (memcmp(&(a), &(b), 4))
//#endif
/*
int pcap_io_init(char *adapter);
int pcap_io_send(void* packet, int plen);
int pcap_io_recv(void* packet, int max_len);
void pcap_io_close();
int pcap_io_get_dev_num();
char* pcap_io_get_dev_desc(int num);
char* pcap_io_get_dev_name(int num);
*/
#include "PacketReader/MAC_Address.h"
#ifdef _WIN32
bool load_pcap();
void unload_pcap();
#endif
#ifdef __cplusplus
}
#endif
class PCAPAdapter : public NetAdapter
{
private:
pcap_t* hpcap = nullptr;
bool switched;
bool blocking;
PacketReader::IP::IP_Address ps2IP{};
PacketReader::MAC_Address hostMAC;
public:
PCAPAdapter();
virtual bool blocks();
@@ -185,4 +46,12 @@ public:
virtual ~PCAPAdapter();
static std::vector<AdapterEntry> GetAdapters();
static AdapterOptions GetAdapterOptions();
private:
bool InitPCAP(const std::string& adapter, bool promiscuous);
void InitPCAPDumper();
bool SetMACSwitchedFilter(PacketReader::MAC_Address mac);
void SetMACBridgedRecv(NetPacket* pkt);
void SetMACBridgedSend(NetPacket* pkt);
};
+32 -105
View File
@@ -27,10 +27,6 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <unistd.h>
#ifdef __linux__
#include <sys/ioctl.h>
#endif
#endif
#include "sockets.h"
@@ -160,13 +156,12 @@ SocketAdapter::SocketAdapter()
{
bool foundAdapter;
#ifdef _WIN32
IP_ADAPTER_ADDRESSES adapter;
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
AdapterUtils::Adapter adapter;
AdapterUtils::AdapterBuffer buffer;
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
{
foundAdapter = AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
foundAdapter = AdapterUtils::GetAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
if (!foundAdapter)
{
@@ -185,7 +180,7 @@ SocketAdapter::SocketAdapter()
}
else
{
foundAdapter = AdapterUtils::GetWin32AdapterAuto(&adapter, &buffer);
foundAdapter = AdapterUtils::GetAdapterAuto(&adapter, &buffer);
adapterIP = {};
if (!foundAdapter)
@@ -194,42 +189,6 @@ SocketAdapter::SocketAdapter()
return;
}
}
#elif defined(__POSIX__)
ifaddrs adapter;
ifaddrs* buffer;
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
{
foundAdapter = AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
if (!foundAdapter)
{
Console.Error("DEV9: Socket: Failed to Get Adapter");
return;
}
std::optional<IP_Address> adIP = AdapterUtils::GetAdapterIP(&adapter);
if (adIP.has_value())
adapterIP = adIP.value();
else
{
Console.Error("DEV9: Socket: Failed To Get Adapter IP");
freeifaddrs(buffer);
return;
}
}
else
{
foundAdapter = AdapterUtils::GetIfAdapterAuto(&adapter, &buffer);
adapterIP = {0};
if (!foundAdapter)
{
Console.Error("DEV9: Socket: Auto Selection Failed, Check You Connection or Manually Specify Adapter");
return;
}
}
#endif
//For DHCP, we need to override some settings
//DNS settings as per direct adapters
@@ -239,38 +198,21 @@ SocketAdapter::SocketAdapter()
const IP_Address gateway = internalIP;
InitInternalServer(&adapter, true, ps2IP, subnet, gateway);
#ifdef __POSIX__
freeifaddrs(buffer);
#endif
u8 hostMAC[6];
u8 newMAC[6];
#ifdef _WIN32
memcpy(hostMAC, adapter.PhysicalAddress, 6);
#elif defined(__linux__)
struct ifreq ifr;
int fd = socket(AF_INET, SOCK_DGRAM, 0);
strcpy(ifr.ifr_name, adapter.ifa_name);
if (0 == ioctl(fd, SIOCGIFHWADDR, &ifr))
memcpy(hostMAC, ifr.ifr_hwaddr.sa_data, 6);
else
std::optional<MAC_Address> adMAC = AdapterUtils::GetAdapterMAC(&adapter);
if (adMAC.has_value())
{
memcpy(hostMAC, ps2MAC, 6);
Console.Error("Could not get MAC address for adapter: %s", adapter.ifa_name);
MAC_Address hostMAC = adMAC.value();
MAC_Address newMAC = ps2MAC;
//Lets take the hosts last 2 bytes to make it unique on Xlink
newMAC.bytes[5] = hostMAC.bytes[4];
newMAC.bytes[4] = hostMAC.bytes[5];
SetMACAddress(&newMAC);
}
::close(fd);
#else
memcpy(hostMAC, ps2MAC, 6);
Console.Error("Could not get MAC address for adapter, OS not supported");
#endif
memcpy(newMAC, ps2MAC, 6);
//Lets take the hosts last 2 bytes to make it unique on Xlink
newMAC[5] = hostMAC[4];
newMAC[4] = hostMAC[5];
SetMACAddress(newMAC);
else
Console.Error("DEV9: Socket: Failed to get MAC address for adapter");
#ifdef _WIN32
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
@@ -326,8 +268,8 @@ bool SocketAdapter::recv(NetPacket* pkt)
ipPkt->sourceIP = session->destIP;
EthernetFrame frame(ipPkt);
memcpy(frame.sourceMAC, internalMAC, 6);
memcpy(frame.destinationMAC, ps2MAC, 6);
frame.sourceMAC = internalMAC;
frame.destinationMAC = ps2MAC;
frame.protocol = (u16)EtherType::IPv4;
frame.WritePacket(pkt);
@@ -384,17 +326,17 @@ bool SocketAdapter::send(NetPacket* pkt)
//it's trying to resolve the virtual gateway's mac addr
{
ARP_Packet* arpRet = new ARP_Packet(6, 4);
memcpy(arpRet->targetHardwareAddress.get(), arpPkt.senderHardwareAddress.get(), 6);
memcpy(arpRet->senderHardwareAddress.get(), internalMAC, 6);
memcpy(arpRet->targetProtocolAddress.get(), arpPkt.senderProtocolAddress.get(), 4);
memcpy(arpRet->senderProtocolAddress.get(), arpPkt.targetProtocolAddress.get(), 4);
*(MAC_Address*)arpRet->targetHardwareAddress.get() = *(MAC_Address*)arpPkt.senderHardwareAddress.get();
*(MAC_Address*)arpRet->senderHardwareAddress.get() = internalMAC;
*(IP_Address*)arpRet->targetProtocolAddress.get() = *(IP_Address*)arpPkt.senderProtocolAddress.get();
*(IP_Address*)arpRet->senderProtocolAddress.get() = *(IP_Address*)arpPkt.targetProtocolAddress.get();
arpRet->op = 2,
arpRet->protocol = arpPkt.protocol;
arpRet->hardwareType = arpPkt.hardwareType;
EthernetFrame* retARP = new EthernetFrame(arpRet);
memcpy(retARP->destinationMAC, ps2MAC, 6);
memcpy(retARP->sourceMAC, internalMAC, 6);
retARP->destinationMAC = ps2MAC;
retARP->sourceMAC = internalMAC;
retARP->protocol = (u16)EtherType::ARP;
vRecBuffer.Enqueue(retARP);
@@ -431,36 +373,21 @@ void SocketAdapter::reset()
void SocketAdapter::reloadSettings()
{
bool foundAdapter = false;
#ifdef _WIN32
IP_ADAPTER_ADDRESSES adapter;
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
AdapterUtils::Adapter adapter;
AdapterUtils::AdapterBuffer buffer;
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
foundAdapter = AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
foundAdapter = AdapterUtils::GetAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
else
foundAdapter = AdapterUtils::GetWin32AdapterAuto(&adapter, &buffer);
#elif defined(__POSIX__)
ifaddrs adapter;
ifaddrs* buffer;
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
foundAdapter = AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
else
foundAdapter = AdapterUtils::GetIfAdapterAuto(&adapter, &buffer);
#endif
foundAdapter = AdapterUtils::GetAdapterAuto(&adapter, &buffer);
const IP_Address ps2IP = {{{internalIP.bytes[0], internalIP.bytes[1], internalIP.bytes[2], 100}}};
const IP_Address subnet{{{255, 255, 255, 0}}};
const IP_Address gateway = internalIP;
if (foundAdapter)
{
ReloadInternalServer(&adapter, true, ps2IP, subnet, gateway);
#ifdef __POSIX__
freeifaddrs(buffer);
#endif
}
else
{
pxAssert(false);
@@ -572,7 +499,7 @@ bool SocketAdapter::SendUDP(ConnectionKey Key, IP_Packet* ipPkt)
{
UDP_Session* s = nullptr;
if (udp.sourcePort == udp.destinationPort || //Used for LAN games that assume the destination port
if (abs(udp.sourcePort - udp.destinationPort) <= 10 || //Used for games that assume the destination/source port
ipPkt->destinationIP == dhcpServer.broadcastIP || //Broadcast packets
ipPkt->destinationIP == IP_Address{{{255, 255, 255, 255}}} || //Limited Broadcast packets
(ipPkt->destinationIP.bytes[0] & 0xF0) == 0xE0) //Multicast address start with 0b1110
@@ -591,7 +518,7 @@ bool SocketAdapter::SendUDP(ConnectionKey Key, IP_Packet* ipPkt)
fKey.ps2Port = udp.sourcePort;
fKey.srvPort = 0;
Console.WriteLn("DEV9: Socket: Creating New UDPFixedPort with port %d", udp.destinationPort);
Console.WriteLn("DEV9: Socket: Creating New UDPFixedPort with port %d", udp.sourcePort);
fPort = new UDP_FixedPort(fKey, adapterIP, udp.sourcePort);
fPort->AddConnectionClosedHandler([&](BaseSession* session) { HandleFixedPortClosed(session); });
@@ -603,7 +530,7 @@ bool SocketAdapter::SendUDP(ConnectionKey Key, IP_Packet* ipPkt)
fixedUDPPorts.Add(udp.sourcePort, fPort);
}
Console.WriteLn("DEV9: Socket: Creating New UDP Connection from FixedPort %d", udp.destinationPort);
Console.WriteLn("DEV9: Socket: Creating New UDP Connection from FixedPort %d to %d", udp.sourcePort, udp.destinationPort);
s = fPort->NewClientSession(Key,
ipPkt->destinationIP == dhcpServer.broadcastIP || ipPkt->destinationIP == IP_Address{{{255, 255, 255, 255}}},
(ipPkt->destinationIP.bytes[0] & 0xF0) == 0xE0);

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