Compare commits

...
279 Commits
Author SHA1 Message Date
Connor McLaughlin 0bb7cc0a1a GS: Add texture dumping/replacement/reload replacement hotkeys
Qt only.
2022-05-11 14:44:42 +01:00
Connor McLaughlin 322ff3fcb9 GS/TextureReplacements: Add options to filter dumping to direct/palette textures 2022-05-11 14:44:42 +01:00
Connor McLaughlin d329cabf07 GS/TextureReplacements: Fix queued items not getting purged after shutdown 2022-05-11 14:44:42 +01:00
Connor McLaughlin 38c48e8b6a Vulkan/Context: Don't write timestamp on an unreset query 2022-05-11 13:07:58 +01:00
Mrlinkwii cd0b349496 GUI: update hyperlink in WX 2022-05-11 12:58:40 +01:00
TheLastRar 7f1932e282 DEV9: Fix double calling freeifaddrs() 2022-05-11 13:14:11 +02:00
Connor McLaughlin 17f2fb4471 Qt: Fix nightly builds not showing version in title bar 2022-05-11 13:13:39 +02:00
PCSX2 Bot 022a9cc6df PAD: Update to latest controller database. 2022-05-09 20:20:19 +02:00
Connor McLaughlin c88db3221c GS/TextureCache: Flush dirty areas of textures during TC move
Dark Cloud does a bunch of VRAM writes overlapping the render target,
then moves over the top of it. If we didn't flush these, the target
would still be considered dirty, and later we'd trash the move
destination, and/or not use it as a source.
2022-05-09 17:45:53 +01:00
TellowKrinkle bd3e1299a3 GS:MTL: Disable blending when color isn't written
Can come up in two-pass alpha, and Metal doesn't like it if blending uses SRC1 and your shader doesn't output it
2022-05-09 17:43:47 +01:00
TellowKrinkle 3a97688804 GS: Fix TextureMinMax when coordinates are completely outside of min/max 2022-05-09 17:43:47 +01:00
TellowKrinkle 3f027b2698 GS:SW: Clamp Z with unsigned clamp 2022-05-09 17:34:19 +01:00
Mrlinkwii 916754ea6d GameDB: add VUclamping to 'Monster Hunter 2' and 'Monster Hunter G' 2022-05-09 17:29:20 +01:00
TellowKrinkle 335633a5e0 CI: Update SDL 2022-05-09 10:28:58 -05:00
Connor McLaughlin 925bfc2a99 Tests: Set PCSX2_CORE macro
They shouldn't be using wx, and it gets rid of the pthreads4w reference.
2022-05-09 16:06:33 +01:00
Connor McLaughlin d19c767ad1 Common/Dependencies: Use deletion for declaring non-copyable
This is the preferred method in modern C++.
2022-05-09 16:06:33 +01:00
Connor McLaughlin d2347d9972 Common/Threading: Replace TLS macros with standard thread_local 2022-05-09 16:06:33 +01:00
Connor McLaughlin f8dcff9fc4 Common: Remove references to pthreads4w
It's only needed for wx now.
2022-05-09 16:06:33 +01:00
Connor McLaughlin e5716922a3 Common/Threading: Move a bunch of unnecessary wrappers to gui 2022-05-09 16:06:33 +01:00
Connor McLaughlin 65e956a01c Misc: Replace use of Threading::Mutex with std::mutex in core code 2022-05-09 16:06:33 +01:00
Connor McLaughlin a93829557b SaveState: Misc refactoring and improvements
- Block until saves are completed when resuming.
 - Save shutdown state asynchronously.
 - Add function to read screenshot out of zip file (useful for
   previous, now we're using zstd).
2022-05-09 10:20:48 +01:00
Connor McLaughlin c21d475bbd Qt: Implement save-state-on-shutdown 2022-05-09 10:20:48 +01:00
Connor McLaughlin 935dd046da 3rdparty/SDL2: Bump to 2.0.22 release
Fixes a crash on shutdown in Windows::Gaming::Input.
2022-05-09 10:01:45 +01:00
refractionpcsx2 1b2d9f0c5d GS: Scissor opt - handle reverse read sprites 2022-05-08 18:22:12 +01:00
Connor McLaughlin 4baea67e75 Common: Remove RwMutex
It wasn't used, and if we need it, we can use std::shared_mutex.
2022-05-08 05:40:59 +01:00
Connor McLaughlin 1e8332f36a Misc: Move pxThread and friends to gui 2022-05-08 05:40:59 +01:00
Connor McLaughlin 096696bed7 Misc: Replace core usage of Semaphore with KernelSemaphore
i.e. decouple it from the UI.
2022-05-08 05:40:59 +01:00
Connor McLaughlin 756cd1ee47 System: Move old SysThread junk to gui 2022-05-08 05:40:59 +01:00
Connor McLaughlin 64534542a9 Threading: Move a couple of function declarations to correct location 2022-05-08 05:40:59 +01:00
Connor McLaughlin b22e31c302 Common: Add WIN32_LEAN_AND_MEAN and NOMINMAX to RedtapeWindows.h
Otherwise, it doesn't get set for cmake.
2022-05-08 05:40:59 +01:00
Connor McLaughlin 008beb4896 ThreadedFileReader: Fix possible race with synchronous reads 2022-05-08 05:10:09 +01:00
refractionpcsx2 576bcc6979 GameDB: Add HPO for Dog's Life 2022-05-08 02:54:47 +01:00
refractionpcsx2 4ec345a239 GS: Improve read heights with screen offset disabled 2022-05-08 01:16:04 +01:00
RedDevilus 972bfbcccc GameDB: Monster Hunter 1
Fixes lighting on character models as caves and other locations don't turn mobs into glow-in-the-dark creatures by themselves.
2022-05-07 23:27:46 +01:00
RedDevilus f59fbaf0eb GameDB: Star Ocean 3
Certain areas have bloom effects which are misaligned, this should fix it. Though minor regression has to be made in the minimap as full round sprite is too aggressive for bloom filter.
2022-05-07 23:08:53 +01:00
refractionpcsx2 631ed8c0fd GUI-WX: Restore panel size override.
Fixes the panels going wonky after the recent dead code removal
2022-05-07 16:10:32 +01:00
Connor McLaughlin 41e8a2a7d1 MTGS: Purge pxThread 2022-05-07 15:43:03 +01:00
Connor McLaughlin 599626b709 MTVU: Purge pxThread 2022-05-07 15:43:03 +01:00
Immersion95 0ae17ddb1a GS: Adding KOF2002 CRC IDs
Adding:
- The King of Fighters 2002 (EUR)
- The King of Fighters 2002 (JAP)
- The King of Fighters 2002 - SNK Best Collection (JAP)
- The King of Fighters 2002 (USA) from Disc 1 of the bundle of The King of Fighters 02/03
2022-05-07 15:33:27 +01:00
Immersion95 7353c26a4f GS-TC: Don't skip depth lookup on KOF2002
Don't skip draw calls on KOF2002
2022-05-07 15:33:27 +01:00
Immersion95 b8769e954e GS: Adding KOF2002 CRC Title
Adding KOF2002 CRC Title
2022-05-07 15:33:27 +01:00
Connor McLaughlin 81cd2d9be9 Qt: Add placeholder for when no games are in list 2022-05-07 15:32:59 +01:00
Connor McLaughlin 90707c453d Qt: Rework VM pausing when popup dialogs are opened
Also cleans up fullscreen transitions further.
2022-05-07 15:32:59 +01:00
Connor McLaughlin ec0e9f078c Qt: Confirm disc change type when switching to game list 2022-05-07 15:32:59 +01:00
Connor McLaughlin 98b537575f Qt: Rework display widget swapping 2022-05-07 15:32:59 +01:00
arcum42@gmail.com 233195b020 Remove macros that 'might be needed again in the future'. 2022-05-07 05:26:46 +01:00
arcum42@gmail.com 7d71e28bfc Delete various unused px stuff. 2022-05-07 05:26:46 +01:00
arcum42@gmail.com 13e09953af Remove unused code in Dependencies.h 2022-05-07 05:26:46 +01:00
Connor McLaughlin a85ca4108c GS/DX11: Fix a possible texture leak with sw blend and tex-is-ds 2022-05-06 09:37:53 +01:00
Connor McLaughlin 8620febeb3 GL/Context: Load wayland-egl dynamically
Gets rid of the dependency on libwayland-egl, allowing us to always use
the system version.

Solves missing symbol issues by including it in the AppImage.
2022-05-06 01:00:24 +01:00
Connor McLaughlin af4c047c41 MetalHostDisplay: Fix fullscreen in Qt interface 2022-05-05 23:23:48 +01:00
Connor McLaughlin bec9b34f54 Vulkan/SwapChain: Fix crash on fullscreen toggle with Mac 2022-05-05 23:23:48 +01:00
refractionpcsx2 9989daec94 GSWindow: Remove force disable full screen hack now the GS Window doesn't suck 2022-05-05 23:19:35 +01:00
Mrlinkwii c86dd7397d microVU : correct logging and remove not needed comments 2022-05-05 23:13:33 +01:00
Connor McLaughlin eefc81ed8c Qt: Fix incorrect resources directory on config reset 2022-05-05 09:51:56 +01:00
Connor McLaughlin 91c717376f Qt: Use app bundle resources directory on Mac 2022-05-05 09:51:56 +01:00
Connor McLaughlin 344c918b65 Qt: Fix possible race when shutting down (Mac) 2022-05-05 09:51:56 +01:00
Connor McLaughlin deeda519b0 Qt: Remove unused host display includes from EmuThread.cpp 2022-05-05 09:51:56 +01:00
Connor McLaughlin 2db12b9d84 Qt: Hook up axis/vibration scale in controller settings 2022-05-05 09:51:56 +01:00
Connor McLaughlin 378588c67d Qt: Implement more command line arguments 2022-05-05 09:51:56 +01:00
Connor McLaughlin 119b6bdfd5 Qt: Fix not-render-to-main after start fullscreen+toggle 2022-05-05 09:51:56 +01:00
Connor McLaughlin 8751a2d330 Qt: Make win32 console less garbage 2022-05-05 09:51:56 +01:00
Connor McLaughlin 4543ddbcc2 Common/FileSystem: Don't recompress already compressed files 2022-05-05 09:46:52 +01:00
Immersion95 77a7b18b29 GameDB: Add patches for remaining KOF series
Fix for Depth precision.
Game fills upper 16bits of depth with 0xFFFF.
This results in a really high 32 bit value which is then converted to float because both hw and sw renderers lack double precision the lower 16 bits of the initial 32 bit value lose precision.

PAL : KOF2002+KOF2003
NTSC-J : NGBC+KOF2002+KOF2003
2022-05-05 09:45:43 +01:00
lightningterror 749aef1a64 GS-d3d11: Get rid of vendor check in device.
Rely on the vendor check we already use for best renderer selection.
2022-05-04 21:31:58 +02:00
lightningterror 8091b6bc1b GS: Adjust default renderer based on vendor and feature level.
Vulkan default:
Nvidia Maxwell gen2 and higher.

OpenGL default:
From Fermi to Mawell gen1.

Everything else Direct3D11.
2022-05-04 21:31:58 +02:00
refractionpcsx2 4efa845580 GS: Add missing CRC for SNK vs Capcom Chaos (J) 2022-05-04 13:23:25 +01:00
Linus Heckemann 8c9ae90753 Wayland fixes (#5979)
* Linux/PAD: only attempt to reset X screensaver on X11

This would previously crash PCSX2 after 4096 frames on Wayland.

* Linux: only grab pointer on X11

This silently disables the functionality on Wayland, but that's one
step better than the previous behaviour: PCSX2 would crash when
Shift-F12 was pressed.
2022-05-03 23:24:47 -07:00
7oxicshadow d1117aafac Allow commandline params to be passed through to the patched apprun file (#5777) 2022-05-03 23:24:10 -07:00
TellowKrinkle a565182b2b GS:SW: Fix lod on C rasterizer 2022-05-04 01:02:36 -05:00
TellowKrinkle 650b0ae646 GS:SW: Prevent CDrawScanline from trashing unused Z bits 2022-05-03 21:47:57 -05:00
TellowKrinkle b677619f32 GS: Formatting 2022-05-03 21:47:57 -05:00
TellowKrinkle 2fa8f09a21 GS:SW: Only run zclamp once
Also fixes clamping in the wrong spot in the C SW rasterizer
2022-05-03 21:47:57 -05:00
lightningterror 73c9279907 GS: Cleanup variable declarations/initalizations.
GSDevice11, 12, ogl, GSRendererHW.
2022-05-03 23:28:02 +02:00
Mrlinkwii 7d8912f170 GameDB: add 'VIF1StallHack' to 'Ikusa Gami' 2022-05-03 16:31:24 +01:00
lightningterror 2601ba53d4 GS-hw: Add brackets to the recommended crc selection just in case. 2022-05-03 11:58:51 +02:00
lightningterror 81baaaa98a GS-hw: Fix recommended crc for dx12.
Full level should be selected.
Once rov is added we can remove it.
2022-05-03 11:42:40 +02:00
TellowKrinkle c2638131b4 GS:SW: Merge SSE and AVX implementations of CDrawScanline 2022-05-02 16:28:45 -05:00
TellowKrinkle 586486b81c GS:SW: Merge SSE and AVX implementations of CSetupPrim 2022-05-02 16:28:45 -05:00
PCSX2 Bot af75ac00e2 PAD: Update to latest controller database. 2022-05-02 18:03:05 +02:00
RedDevilus 67b66c1780 GameDB: Sniper Elite + Naruto Shippuuden Ninja 3-5 + GT4
Adds FMV switch for both and adds special texture half pixeloffset for Sniper Elite.
Finally adding Halfpixel normal offset for Gran Turismo 4.
2022-05-02 15:04:28 +01:00
RedDevilus b3dce680b0 GSHWHack: Comment CrashBandicoot
Explains what the actual CRC does and why.
2022-05-02 15:04:08 +01:00
RedDevilus d01a59650f GSCrc: Add missing Crash Bandicoot 2022-05-02 15:04:08 +01:00
RedDevilus 5ae987d48e GameDB: Crash Bandicoot - Wrath of Cortex
Adds missing gamefixes that influenced random corruptions and the famous fog wall.
2022-05-02 15:04:08 +01:00
Connor McLaughlin 6a6ecbf826 Common: Remove ThreadCPUTimer as it's unused now 2022-05-02 14:25:05 +01:00
Connor McLaughlin 4bdf180145 PerformanceMetrics: Switch to ThreadHandle 2022-05-02 14:25:05 +01:00
Connor McLaughlin 6ebb8c2e91 Threading: Add ThreadHandle class 2022-05-02 14:25:05 +01:00
Connor McLaughlin 5eae7a6328 Threading/Win32: Use QueryThreadCycleTime() for thread CPU time 2022-05-02 14:25:05 +01:00
TheLastRar 7d81c979fe DEV9: Fix Auto Adapter in Socket backend on Mac and FreeBSD 2022-05-02 15:01:41 +02:00
TheLastRar c06ac00677 DEV9: Allow DHCP Server to find Gateway on Mac and FreeBSD 2022-05-02 15:01:41 +02:00
refractionpcsx2 85c754b456 GS: Limit scissor optimisation, fix repeat condition
Only allow scissors to happen on single draws, multiple draws (likely using it as a texture map) will possibly falsely limit the range.
2022-05-02 04:58:57 +01:00
refractionpcsx2 35d3547b62 GS: Fix up SW FMV switch behaviour 2022-05-02 04:53:51 +01:00
Immersion95 8661f42fce GameDB: Add SoftwareRendererFMVHack for KOF Orochi/Nests. (#5987)
The FMV has black frames when upscaled.
2022-05-02 01:46:04 +02:00
refractionpcsx2 a28098c4f8 GS: Account for frame offset in output circuit 2022-05-01 13:15:08 +01:00
arcum42@gmail.com d45f34ee8b Remove iMisc.cpp, and move the code to System.cpp/h. 2022-05-01 11:43:14 +01:00
Connor McLaughlin d552f8dc43 GS/HW: Implement moves in texture cache 2022-05-01 11:40:34 +01:00
Connor McLaughlin b45360b49e VMManager: Don't load WS patches zip multiple times 2022-05-01 11:37:35 +01:00
Connor McLaughlin fffdf8d671 Counters: Fix software renderer FMV fix with auto renderer 2022-05-01 11:36:57 +01:00
Connor McLaughlin 2634134481 microVU: Remove unused VSync() callback 2022-05-01 11:36:37 +01:00
Connor McLaughlin c0ac71611b GS: Remove GSState.cpp
Seems like old/unused code, and we have a replacement GSDump replayer
now anyway.
2022-05-01 11:36:37 +01:00
Mrlinkwii 63ecdfefe3 Gamedb:add 'XGKickHack' to 'WRC II Extreme' 2022-04-30 22:04:41 +01:00
lightningterror 6345e8e467 GS-hw: Cleanup Half pixel offset Normal.
Now that custom res is removed, we don't need to split modx and mody.

Also purely rely on the tc to handle the HPO hack.
2022-04-30 18:30:11 +02:00
Ziemas e96545ca29 IopCounters: missing include 2022-04-29 09:50:29 +01:00
arcum42 dc08858e0f build: Remove i386_flag, as it is no longer used. (#5897)
* build: Remove i386_flag, as it is no longer used.

build: Put back in ncpu.

* build: Move ncpu to set_make.
2022-04-28 13:35:15 -07:00
Mrlinkwii f5787f9ba0 GameDB: Japanese entries Batch 3 2022-04-28 17:11:32 +01:00
refractionpcsx2 a271fe11e9 GS: limit merge circuit memory read height 2022-04-28 16:32:36 +01:00
RedDevilus a20a3866d0 Qt: Append warning for Manual Hardware Renderer Fixes
Same as the WX side where if you enable this option for doing hardware renderer or upscaling fixes it will disable the automatic settings from the GameDB.
But in tooltip version.
2022-04-27 16:14:07 +01:00
RedDevilus 28d25fdf33 WX: Append warning for Manual HW Hacks
WX and Qt both will disable renderer and upscaling fixes if you want to manually handle the renderer and upscaling fixes. For years enabling this option didn't do much harm for users even if you didn't change any other setting, but since 1.7 development series automatised these to a degree it would be nice for users to know why their game looks potentially awful.
2022-04-27 16:14:07 +01:00
Connor McLaughlin f13ad4fcb3 InputManager: Switch InputEventHandler to std::variant 2022-04-27 15:32:52 +01:00
Connor McLaughlin a524410b0a Qt: Fix firing multiple bindings with chords 2022-04-27 15:32:52 +01:00
TellowKrinkle 8e23d8d557 GS: Fix ReadTexture on unaligned reads
No longer reads out of bounds
2022-04-27 09:33:20 +01:00
Connor McLaughlin 59531f005e Patch: Merge patch and patchHelper 2022-04-27 09:09:38 +01:00
Connor McLaughlin 4c8cba53ef Patch: Fix incorrect format string on patch error 2022-04-27 09:09:38 +01:00
Mrlinkwii 34cd53249d GameDB: Japanese entries Batch 2 2022-04-27 09:08:13 +01:00
Connor McLaughlin 14ce344a3f GS: Merge GSRendererNew and GSRendererHW 2022-04-27 09:06:05 +01:00
TellowKrinkle cc5142000b MTGS: Prevent the emulator from crashing if GS fails to init 2022-04-27 01:49:59 -05:00
TellowKrinkle 1ad6532f1a GS:MTL: Report error if no Metal devices are available 2022-04-27 01:49:59 -05:00
TellowKrinkle f136a1a970 WX: Make GSDumpViewer override picker properly show only enabled options 2022-04-27 01:49:59 -05:00
TellowKrinkle a959ec7571 CI:macOS: Disable OpenGL
It won't work
2022-04-27 01:49:59 -05:00
TellowKrinkle e1a6304e32 CMake: Set version based on git tag 2022-04-27 01:49:59 -05:00
TellowKrinkle be05c95026 CI:macOS: Add MoltenVK to build 2022-04-27 01:49:59 -05:00
TellowKrinkle 3983e542b2 CI: Enable macOS artifacts 2022-04-27 01:49:59 -05:00
TellowKrinkle 3d76652b5f macOS: Build dependencies manually 2022-04-27 01:49:59 -05:00
lightningterror 6532dbced4 GameDB: Add preload frame data for Ninja Assault.
Fixes intro captions not displaying.
2022-04-27 00:45:36 +02:00
refractionpcsx2 fe27ebefc8 GS: Ignore fractional parts when reducing tex ranges 2022-04-26 16:57:49 +01:00
Connor McLaughlin 6e84613a14 GS: Make renderer a global 2022-04-26 10:33:05 +01:00
Connor McLaughlin 568ebc6199 GS/HW: Don't clear temporary copies for HDR/DS
Invalidating is enough here.
2022-04-26 09:45:53 +01:00
Connor McLaughlin cf1d67d927 GS: Adjust texture coverage based on scissor
A good test case here is Resident Evil 4, the shuffles draw over the
entire framebuffer, but get scissored to each strip.
2022-04-26 09:45:53 +01:00
Connor McLaughlin 8181cc8528 GS: Only copy texture coverage area for current FRAME/Z sources 2022-04-26 09:45:53 +01:00
Connor McLaughlin b344ee094f GS: Make CopyRect() take a destination offset 2022-04-26 09:45:53 +01:00
TellowKrinkle b042aeacf5 PAD: Fix race on shutdown 2022-04-26 00:01:58 -05:00
NightFyre fea58d2271 GameDB: SOCOM Combined Assault NTSC Patch (#5964) 2022-04-26 00:43:23 +01:00
refractionpcsx2 ca5da27170 GS: Correct display offsets for Interlaced (FFMD) Framebuffers 2022-04-26 00:35:52 +01:00
RedDevilus 11eab828c4 Qt: Fix VuClamp values
This was an oversight, probably from copying the EEClamp value variables.
2022-04-25 23:28:03 +01:00
RedDevilus 8ca3f9a9c2 GameDB: SOCOM 3 + Combined Assault
Fixes SPS and invisible/flickering characters.
2022-04-25 23:28:03 +01:00
Mrlinkwii deb044357b GameDB: game fixes for 'DMC', 'Fatal Frame' and 'MX vs. ATV - Untamed' 2022-04-25 23:04:37 +01:00
PCSX2 Bot 00c07d2dff PAD: Update to latest controller database. 2022-04-25 18:09:59 +02:00
Connor McLaughlin 185ed3ce0b MTGS: Combine init/read FIFO and remove several MTGS waits 2022-04-25 13:32:53 +01:00
BuildTools 3b043250b6 UI: Rename Ultra Blending to Maximum Blending
Rename Ultra Blending to Maximum Blending
2022-04-25 11:43:04 +02:00
Connor McLaughlin 3359b3c7ab GS/DX11: Fix possible use-after-free on cached RT/DS 2022-04-25 09:27:43 +01:00
TellowKrinkle 6b1e483d28 GS: fbfetch full_barrier and one_barrier are identical 2022-04-24 23:10:38 -05:00
TellowKrinkle d3faa05479 GS:MTL: Avoid uchar in shaders
Intel compiler's uchar codegen is buggy
2022-04-24 23:10:38 -05:00
Connor McLaughlin 73f17be890 Qt: Implement proper data directory selection 2022-04-24 06:08:37 +01:00
refractionpcsx2 9292ceedb1 GS: Correct SetScaling when ignoring offsets (FB size) 2022-04-24 01:43:08 +01:00
refractionpcsx2 d1470a9935 GS: Clean up some code and correct heights when offset by 1 2022-04-24 01:43:08 +01:00
arcum42@gmail.com 38fa137cfd build: Include CrashHandler.cpp in cmake. Fixes #5938. 2022-04-24 01:42:10 +01:00
qurious-pixel a7288d8ad8 BUILD: exclude libgmodule-2.0 2022-04-23 18:22:31 +02:00
Connor McLaughlin 0692517f13 ElfObject: Ignore section headers when offset is invalid
This happens in V-Rally 3:

(ELF) Section header offset 14853196 is larger than file size 5898828
2022-04-22 13:09:31 +01:00
Connor McLaughlin 4f44e3fc46 GS/SW: Get rid of extra pointers to perfmon 2022-04-22 11:37:11 +01:00
Connor McLaughlin 14398da51f GS/SW: Fix use-after-free on worker thread shutdown 2022-04-22 11:37:11 +01:00
Sam H 6e8897d62b build: use system wayland libs if available (appimage) 2022-04-21 19:27:38 +01:00
Connor McLaughlin 69da1e4559 Qt: Install crash handler on startup 2022-04-21 14:21:49 +01:00
Connor McLaughlin abde47fa18 Common: Add CrashHandler 2022-04-21 14:21:49 +01:00
seta-san f46b406cbd ReadMe.md: Clarify only Windows 8.0 dropped. 2022-04-20 21:16:48 +01:00
RedDevilus 48313b42a2 GameDB: Mosquito + RE Dead Aim + Ice Age
Adds some missing upscaling fixes for Mister Mosquito (blurriness when upscaling) and quite a few for Resident Evil - Dead Aim.
Along with Ice Age Meltdown upscaling and a rare SPS issue and Ice Age 3 upscaling.
2022-04-20 21:07:39 +01:00
Connor McLaughlin 1e06b57f25 VMManager: Fix disc path when specifying source type 2022-04-19 12:34:03 +01:00
lightningterror 8a6c896dde vcxproj.filters: Adjust d3d shader and source file group naming to accommodate d3d12 addition. 2022-04-19 10:54:45 +02:00
lightningterror b3c7b07813 GS-qt: Gray out texture barriers and geometry shaders on d3d or sw renderers. 2022-04-19 10:52:59 +02:00
lightningterror 65072ddbe5 readme: Remove broken screenshots.
Ideally we should put new ones.
2022-04-18 22:38:44 +02:00
lightningterror d42fb851a2 GS-wx: Gray out texture barriers and geometry shader options on d3d. 2022-04-18 22:01:25 +02:00
lightningterror ea0791a3bf pine: Fix Wswitch-bool warning. 2022-04-18 21:10:35 +02:00
lightningterror 8d4df7f74b spu2: Fix Wunused-private-field warning. 2022-04-18 21:10:35 +02:00
PCSX2 Bot 4b07eae80e PAD: Update to latest controller database. 2022-04-18 18:02:26 +02:00
lightningterror 77162ff637 GS-d3d11: Purge the NVIDIA hack.
The driver issue got resolved by nvidia.
2022-04-18 17:25:32 +02:00
Timothy O'Barr e10f414724 CDVD: Rename cdrom files to Ps1CD for clarity of function (#5907) 2022-04-18 12:15:23 +01:00
Mrlinkwii 53c3f253e6 GameDB:add 'EETimingHack' to'Harry Potter and the Chamber of Secrets' 2022-04-18 12:14:22 +01:00
Connor McLaughlin b0f20c9973 GS/DX11: Fix MMOD=1 merge background color 2022-04-18 04:29:19 +01:00
Sam H 5c3ae656a0 GS: fix display width calculation for frame when offsets off 2022-04-17 23:21:50 +01:00
TellowKrinkle a98efdfedd GS: Per-selector C draw scanline 2022-04-17 15:22:49 -05:00
TellowKrinkle 3b8eb6731c Add more values to GSScanlineSelector ToString 2022-04-17 15:22:49 -05:00
TellowKrinkle 89bc4707ab Add to_string to GSScanlineSelector 2022-04-17 15:22:49 -05:00
TellowKrinkle e5a8b01980 GS: Always compile C rasterizer 2022-04-17 15:22:49 -05:00
Connor McLaughlin 7194542029 Qt: Fix fullscreening in Wayland 2022-04-17 11:56:37 +01:00
Connor McLaughlin 06beadba74 CdRom: Fix clear error bit in StartReading() 2022-04-17 11:42:48 +01:00
Connor McLaughlin b10249af7d CdRom: Remove Speed field/add accessor instead
This way it doesn't break save states.
2022-04-17 11:42:48 +01:00
Ty Lamontagne 1f04214461 Dmac: LegacyDmac.cpp -> Dmac.cpp 2022-04-17 10:54:39 +01:00
SeraphisCain 39d611e870 GameDB: Transformers Tatakai, T3: The Redemption, Urban Reign
GameDB fixes for a few games.
2022-04-17 10:47:09 +01:00
Connor McLaughlin b913d39a50 Common/Timer: Fix closing invalid handle on Win32
Only is an issue if you have a debugger attached and the exception
enabled.
2022-04-17 10:45:22 +01:00
TellowKrinkle eb60e9aa9b Common: Avoid libstdc++ assert 2022-04-17 10:44:02 +01:00
Mrlinkwii 53bb0c508f GameDB: upscaling fixes and documentation updates 2022-04-16 19:40:26 +01:00
Connor McLaughlin 1c50d3e4b3 GS: Add stat for barriers 2022-04-16 19:10:18 +01:00
Connor McLaughlin de724d9570 GS/HW: Skip unnecessary barriers (usually two pass alpha) 2022-04-16 19:10:18 +01:00
Connor McLaughlin e8293b2e06 GS/Vulkan: PrimID DATE doesn't need feedback loop 2022-04-16 19:10:18 +01:00
refractionpcsx2 904345ff82 GS: Get display width for frame when offsets off 2022-04-16 18:21:00 +01:00
Connor McLaughlin d16592817b Frontend/OpenGLHostDisplay: Remove unused variables
clang likes to whinge about this one.
2022-04-16 13:57:23 +02:00
Connor McLaughlin 14f1a78608 GS/DX12: Fix DATE not being set in shader macros 2022-04-16 03:57:04 +01:00
refractionpcsx2 68c2a68087 microVU: Clean up warnings 2022-04-16 03:20:54 +01:00
refractionpcsx2 ae83f729db USB: Clean up warnings 2022-04-16 03:20:54 +01:00
refractionpcsx2 c53f4d0d63 SPU2: Clean up warnings 2022-04-16 03:20:54 +01:00
refractionpcsx2 cbb3134740 App/BIOS: Clean up warnings 2022-04-16 03:20:54 +01:00
refractionpcsx2 9b97c157f2 Recording: Clean up warnings 2022-04-16 03:20:54 +01:00
refractionpcsx2 11cf244e97 GS: Clean up warnings 2022-04-16 03:20:54 +01:00
kenshen112 6673bd9212 CDVD.cpp: Remove Elf parser from ps1 mode. 2022-04-16 03:19:21 +01:00
kenshen112 02dfc5d20d cdrom: Update status flags and implementations for PSX CD-Rom.
Added SEEKERROR and IDERROR status. Set StatP to account for SEEKS, READS and shell open.
Added speed to cdrom struct instead of cdvd. Adjustments to cdlPlay to be in line with No$ description.
Added MODE_INIT. Removed old needless hack. Added ToDo in cdlPlay
2022-04-16 03:19:21 +01:00
SeraphisCain 565ff86ab4 GameDB: Several game fixes and a gamelist entry correction (#5872) 2022-04-16 02:50:36 +01:00
refractionpcsx2 5a77790859 BIOS/GUI: Mark Qt only variables as maybe unused 2022-04-16 02:59:21 +02:00
refractionpcsx2 66101f8628 SPU2: Clean up warnings 2022-04-16 02:59:21 +02:00
refractionpcsx2 2f70b153f2 GS: Clean up warnings, fix a small error. 2022-04-16 02:59:21 +02:00
refractionpcsx2 31fe9979dd GS: Fix undefined behaviour on interlacing 2022-04-15 22:12:04 +01:00
RedDevilus 4fc6e9240c OSD: Minor clean up
Fixes variable for interlacemode
2022-04-15 22:01:48 +01:00
RedDevilus 0eae59ee66 GameDB: Black
GameDB Black roundsprite to half for lighting.
2022-04-15 22:01:48 +01:00
RedDevilus 8e6cd47f25 PCSX2: Fix Interlacing Ini
Oversight in having the correct config for the ini. Replaced CycleMipmap mode with the CycleInterlace one for correct OSD message.
2022-04-15 20:34:51 +01:00
Connor McLaughlin ecdbe17fba Wx: Fix widescreen patch loading 2022-04-15 19:44:05 +01:00
Connor McLaughlin 0e9dcf74b2 Common/Semaphore: Fix WaitWithYield() returning immediately
This caused the WaitGS() issued from the main thread when applying
renderer settings (while the core thread was paused) to return
immediately, and a massive race resuming.
2022-04-15 19:43:22 +01:00
RedDevilus 5297c2a995 GameDB: Japanese entries
Adds a bunch of gamefixes and upscaling fixes to games as well as just entries.
Fixes:
- 0 Story
- Amagami
- Bleach Blade Battlers 2nd
- Chobits
- D.C. Da Capo The Origin
- Pandora - Kimi no Namae o Boku wa Shiru
- Katekyoo Hitman Reborn! Nerae!? Ring x Vongola Trainers
- Kateikyoushi Hitman Reborn!! Let's Ansatsu! Nerawareta 10 Daime!
- Kino no Tabi - The Beautiful World
- Kyuuketsu-hime Yui - Sen'yashou
- Shikigami no Shiro - Nanayozuki Gensoukyoku
- Secret of Evangelion
2022-04-15 19:41:48 +01:00
Connor McLaughlin edf5e2c14e Vulkan/Context: Use static loading for vk_mem_alloc
In doing so, we simplify things a bit, as we can assume Vulkan 1.1
support. It needed it before anyway, and would crash on Vulkan 1.0
drivers.
2022-04-15 19:41:12 +01:00
Connor McLaughlin 9180adb850 VulkanHostDisplay: Handle surface loss better
Just try again next frame.
2022-04-15 19:41:12 +01:00
Connor McLaughlin 1b080f1777 Vulkan/Loader: Make vkDestroyInstance() a module import 2022-04-15 19:41:12 +01:00
Connor McLaughlin 0a2584172a GS/HW: Clear blend bits for color dest blend 2022-04-15 16:55:24 +02:00
Connor McLaughlin 1993203d26 GS: Add Direct3D 12 renderer 2022-04-15 12:56:41 +01:00
Connor McLaughlin 3c18cdcb1f Frontend: Add D3D12HostDisplay 2022-04-15 12:56:41 +01:00
Connor McLaughlin e767fb8d35 Common: Add D3D12 wrapper/helper classes 2022-04-15 12:56:41 +01:00
Connor McLaughlin 3255422836 Common/StringUtil: Optimize equal stride copy case 2022-04-15 12:56:41 +01:00
Connor McLaughlin 67fa06b933 3rdparty/imgui: Enable DX12 backend 2022-04-15 12:56:41 +01:00
Connor McLaughlin 398e468c9e 3rdparty: Add D3D12MemoryAllocator 2022-04-15 12:56:41 +01:00
Connor McLaughlin f7ee35e578 Wx: Reset/restore API state after window resize 2022-04-15 12:56:41 +01:00
Connor McLaughlin 800b458d3d Wx: Fix incorrect OSD scale after resize on Windows 2022-04-15 12:56:41 +01:00
Connor McLaughlin 3f31a4d25b GS: Fix edge case of broken alpha with no-DSB+ATST 2022-04-15 12:56:41 +01:00
Connor McLaughlin 0592abd31b GL/ContextEGL: Fix broken surface creation
Regression from #5676.
2022-04-15 11:46:07 +01:00
refractionpcsx2 55d546b892 GS: Maintain framebuffer size when not using offsets
This reduces blurriness
2022-04-15 11:07:22 +01:00
refractionpcsx2 f28e42c4fe GS: Set correct framebuffer size for output 2022-04-15 11:07:22 +01:00
refractionpcsx2 7cdc849ffa GS: Clean up new DISPLAY Merging code. 2022-04-15 11:07:22 +01:00
refractionpcsx2 eed04b3ff3 GS: Redesign some of the offset code for FFMD
Half height buffers need to be drawn half height, not stretched to full height during the draw, it will be bad times.
2022-04-15 11:07:22 +01:00
refractionpcsx2 e2044eba66 GS/Window: Add Automatic 4:3/3:2 mode, keep 4:3 separate 2022-04-15 11:07:22 +01:00
refractionpcsx2 06e6d12e2f GS: Added automatic 3:2 aspect for 480p mode 2022-04-15 11:07:22 +01:00
refractionpcsx2 48fd68ca87 GS: Implement PCRTC Offsets
This is off by default because people will complain about black borders, but I've tried to keep it to a minimum.

Enabling this option (Screen Offsets in the graphics settings) will allow you to position the screen in games which allow you to do so, maintain correct aspect ratios, and screen shake effects which are done on PCRTC (WipEout Fusion for example) will work.
2022-04-15 11:07:22 +01:00
refractionpcsx2 7ad59a7af1 GS: Remove NTSC Saturation option (No longer required) 2022-04-15 11:07:22 +01:00
refractionpcsx2 bae2c9c1d8 GS: Saturate DISPLAY heights and limit max height 2022-04-15 11:07:22 +01:00
Connor McLaughlin 3d171686b5 CI/Windows: Switch to Qt 6.3.0 2022-04-15 08:53:02 +01:00
Connor McLaughlin f86b3a32cd Qt: Switch to QtEntryPoint.lib instead of explicit main() 2022-04-15 08:53:02 +01:00
Connor McLaughlin 59d6113ee4 VSProps: Fix Qt TLS plugins not getting copied 2022-04-15 08:53:02 +01:00
Connor McLaughlin f270f34865 Qt: Move to Qt 6.3.0 2022-04-15 08:53:02 +01:00
Connor McLaughlin b2514d49d2 3rdparty/wx: Fix compilation in MSVC conformance mode 2022-04-15 08:53:02 +01:00
Tyler Wilding 2951068e0c memcard: Detect and attempt to repair broken index files from the v1.7.2115 bug 2022-04-15 08:47:46 +01:00
Ty Lamontagne a4dcaa7c14 BiosTools: Allow BIOS region patching 2022-04-15 08:44:46 +01:00
TellowKrinkle b90de6d89f PAD: Process keycodes the same way on Linux and macOS 2022-04-15 08:43:12 +01:00
BuildTools 532a7addd4 Documentation: Update recommended OpenGL version 2022-04-15 08:42:59 +01:00
tcoyvwac 5389178644 Common: Prefer standard algorithms
GL/ContextEGL.cpp:
Prefer std::find_if over ranged-for.
2022-04-15 08:42:29 +01:00
tcoyvwac 6cbdc8c8b7 Common: Prefer pre-built array-form to assign values.
GL/ContextEGL.cpp:
Replace raw-index manipulation / arithmetic as logic. Now a variable-length array.
2022-04-15 08:42:29 +01:00
tcoyvwac 6e6a70b8ed Common: Prefer returning std::array by lambda expression
GL/ContextEGL.cpp:
Replace raw-index manipulation / arithmetic as logic. Variable now using IIFE (Immediately invoked function expression) to strengthen immutability.
2022-04-15 08:42:29 +01:00
TellowKrinkle 1a0a0423e7 Core: Switch MTGS and SysThreadBase to WorkSema 2022-04-15 08:41:58 +01:00
TellowKrinkle b28779b0f6 Common: Add dead thread support to WorkSema
MTGS supports having exceptions kill the thread and send their result back to a thread calling WaitGS...
2022-04-15 08:41:58 +01:00
TellowKrinkle 63fd349e3c GS: Switch GSJobQueue to WorkSema 2022-04-15 08:41:58 +01:00
TellowKrinkle 481c92c1c8 MTVU: Use WorkSema 2022-04-15 08:41:58 +01:00
TellowKrinkle d733730950 Common: Add WorkSema 2022-04-15 08:41:58 +01:00
SeraphisCain 93a9e5dd83 GameDB: Fixes for Wrestle Kingdom 1 + 2 (#5863) 2022-04-15 08:24:14 +01:00
TellowKrinkle db9672509c 3rdparty: Update fmt to 8.1.1 2022-04-15 08:22:13 +01:00
Mrlinkwii ffe69d313b GameDB: add missing serials 2022-04-15 08:19:43 +01:00
Silent 502a44e9f5 XInputSource: Add support for SCP API extension
Allows to query pressure sensitive DualShock 3 buttons via
XInput when DsHidMini is used in SXS mode, with its xinput1_3.dll dropped
in the emulator directory.
2022-04-15 08:18:57 +01:00
Silent 5e913b0e9e XInputSource: Fix triggers input range 2022-04-15 08:18:57 +01:00
Connor McLaughlin 864651ce8d System: Purge WinCompressNTFS.cpp
This is the most overengineered, stupid rubbish I've ever seen.
2022-04-15 08:15:40 +01:00
Connor McLaughlin 850deed6c1 HwRegs: Swap wxString desc() for std::string 2022-04-15 08:15:40 +01:00
Connor McLaughlin 63424b765d CDVD: Purge wxString 2022-04-15 08:15:40 +01:00
Connor McLaughlin a635e84d82 FileSystem: Add path splitting helpers 2022-04-15 08:15:40 +01:00
Connor McLaughlin 6991f819f3 SaveState: Switch to zstd compression
zstd can be 10x+ fast compressing, 2x+ decompressing at default levels,
and provides slightly better ratios.

There's a hidden option in the config, SavestateZstdCompression, which
you can set to false if you want to use deflate.
2022-04-15 08:15:40 +01:00
Connor McLaughlin a22c634cd4 3rdparty: Add zstd 2022-04-15 08:15:40 +01:00
Connor McLaughlin 80aaa962ec Common: Move IniInterface to WX GUI
Qt doesn't use it.
2022-04-15 08:15:40 +01:00
Connor McLaughlin 876ea3db52 Common: Purge pxStreams and some other wx string routines 2022-04-15 08:15:40 +01:00
Connor McLaughlin 1bfc0f3138 CDVD: Remove wxStr from SYSTEM.CNF parsing 2022-04-15 08:15:40 +01:00
Connor McLaughlin 5fa9427323 Patch: Store gamedb patches as single string 2022-04-15 08:15:40 +01:00
Connor McLaughlin 29cea58471 Patch: Remove all wx usage 2022-04-15 08:15:40 +01:00
Connor McLaughlin 4779bc830a StringUtil: Add more whitespace cleaners and ParseAssignmentString 2022-04-15 08:15:40 +01:00
Connor McLaughlin dd8a645986 SaveState: Use libzip instead of wx 2022-04-15 08:15:40 +01:00
Connor McLaughlin 9aa2c52b20 3rdparty: Add libzip 2022-04-15 08:15:40 +01:00
Connor McLaughlin 0914b2a474 Qt: Fix compiling without Vulkan renderer 2022-04-15 07:21:18 +01:00
Connor McLaughlin d387a1f4dc GS: Support compiling without OpenGL renderer 2022-04-15 07:21:18 +01:00
arcum42 3488aa54be Remove wx code from build.sh and a bit of cleanup. (#5817)
* build: Fix up the menu printed by build.sh.

* build: Removed wx code from build.sh.
2022-04-14 22:04:26 -07:00
lightningterror de541aeba9 GS: Remove unused default configs. 2022-04-14 12:07:59 +02:00
lightningterror 5fb00bd6c7 GS: Fix some log warnings. 2022-04-14 00:47:08 +02:00
kenshen112 fdabc82342 Remove IopCommon.h added proper includes to files. Removing circle includes in several files that sometimes was several layers deep 2022-04-11 21:25:20 +01:00
refractionpcsx2 e5f90f176c Emitter: Fix s8 problem with displacements 2022-04-11 21:09:12 +01:00
PCSX2 Bot 6438547edc PAD: Update to latest controller database. 2022-04-11 18:33:35 +02:00
dependabot[bot] 0f0ab25fe8 Bump actions/upload-artifact from 2 to 3
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2 to 3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-11 10:45:35 +01:00
TellowKrinkle fc7a20dd0f wx: Fix compile on wx 3.1.6 2022-04-11 10:45:06 +01:00
TellowKrinkle f8c7237bba i18n: Formatting 2022-04-11 10:45:06 +01:00
Ty Lamontagne 00af7d6835 GSState: Remove transfer direction warning 2022-04-10 07:19:52 +01:00
refractionpcsx2 86fb8e5809 GS: Flush PRIM on write if pending PRIM draw had TME 2022-04-08 11:46:27 +01:00
RedDevilus 29964c3f26 Qt: Fix interlacing
I actually made it backwards compatible but then reverted this line at the last minute, rendering the Qt variant useless. This fixes it again.
2022-04-08 08:24:54 +01:00
RedDevilus ec787d090d Qt: Add Gzipped
WX supported this, I don't see why not add to Qt. Though no idea why anyone wants to use it above CSO or CHD if you look at filesize.
2022-04-08 08:24:54 +01:00
421 changed files with 35616 additions and 10474 deletions
+2 -2
View File
@@ -86,7 +86,7 @@ jobs:
CCACHE_COMPRESS: true
CCACHE_COMPRESSLEVEL: 9
CCACHE_MAXSIZE: 100M
SDL: SDL2-2.0.16
SDL: SDL2-2.0.22
PATCHELF_VERSION: 0.12
steps:
@@ -208,7 +208,7 @@ jobs:
- name: Upload artifact
if: matrix.appimage == true
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: ${{ steps.artifact-metadata.outputs.name }}
path: ci-artifacts
+68 -33
View File
@@ -6,31 +6,8 @@ on:
push:
branches:
- master
paths-ignore:
- '**/*.md'
- '**/*.bat'
- '**/*.cmd'
- '**/*.props'
- '**/*.sln'
- '.clang-format'
- '.codacy.yaml'
- '.github/*'
- '.github/workflows/lint-gamedb.yml'
- '.github/workflows/linux-workflow.yml'
- '.github/workflows/pr-triage.yml'
- '.github/workflows/scripts/windows/**'
- '.github/workflows/scripts/validation/**'
- '.github/workflows/windows-workflow.yml'
- '.gitignore'
- 'bin/PCSX2_keys.ini.default'
- 'build.sh'
- 'buildbot.xml'
- 'pcsx2/CDVD/Windows/**'
- 'pcsx2/DEV9/Win32/**'
- 'pcsx2/PAD/Windows/**'
- 'pcsx2/SPU2/Windows/**'
- 'pcsx2/USB/Win32/**'
- 'pcsx2/windows/**'
tags:
- v*
pull_request:
branches:
- master
@@ -73,7 +50,7 @@ jobs:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
# Set some sort of timeout in the event of run-away builds. We are limited on concurrent jobs so, get rid of them.
timeout-minutes: 30
timeout-minutes: 60
steps:
# NOTE - useful for debugging
@@ -96,17 +73,26 @@ jobs:
HOMEBREW_NO_INSTALL_CLEANUP: 1
HOMEBREW_NO_ANALYTICS: 1
run: |
# To save time, only brew update if running the install without it fails
function do-install() {
brew install sound-touch portaudio wxwidgets sdl2 libsamplerate
}
if ! do-install; then
brew unlink libjpeg libpng # Conflicts with our self-built dependencies
# Unlike other packages, brew's MoltenVK build uses MoltenVK's minimum macOS version of 10.13 so we can use it
if ! brew install molten-vk; then
brew update
do-install
brew install molten-vk
fi
- name: Cache Dependencies
id: cache-deps
uses: actions/cache@v3
with:
path: ~/deps
key: ${{ matrix.os }} ${{ matrix.platform }} deps ${{ hashFiles('.github/workflows/scripts/macos/build-dependencies.sh') }}
- name: Build Dependencies
if: steps.cache-deps.outputs.cache-hit != 'true'
run: .github/workflows/scripts/macos/build-dependencies.sh
- name: Generate CMake Files
run: cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_PO=FALSE -DLTO_PCSX2_CORE=ON -B build .
run: cmake -DCMAKE_PREFIX_PATH="$HOME/deps" -DCMAKE_BUILD_TYPE=Release -DUSE_OPENGL=OFF -DDISABLE_ADVANCE_SIMD=ON -DLTO_PCSX2_CORE=ON -B build .
- name: Build PCSX2
working-directory: build
@@ -115,3 +101,52 @@ jobs:
- name: Run Tests
working-directory: build
run: make -j$(getconf _NPROCESSORS_ONLN) unittests
- name: Prepare Artifact Metadata
id: artifact-metadata
run: |
if [ ${{ github.event_name }} == "pull_request" ]; then
PR_SHA=$(git rev-parse --short "${{ github.event.pull_request.head.sha }}")
ARTIFACT_NAME="PCSX2"
if [ -n "${{ github.event.pull_request.number }}" ]; then
PR_NUM=${{ github.event.pull_request.number }}
ARTIFACT_NAME="${ARTIFACT_NAME}-pr[${PR_NUM}]"
fi
ARTIFACT_NAME="${ARTIFACT_NAME}-sha[${PR_SHA}]"
if [ -n "${{ github.event.pull_request.title }}" ]; then
PR_TITLE=$(echo "${{ github.event.pull_request.title }}" | tr -cd '[a-zA-Z0-9[:space:]]_-')
ARTIFACT_NAME="${ARTIFACT_NAME}-title[${PR_TITLE}"
fi
else
SHA=$(git rev-parse --short "$GITHUB_SHA")
ARTIFACT_NAME="PCSX2-sha[${SHA}"
fi
TRIMMED_ARTIFACT_NAME=$(printf "%.199s]" "$ARTIFACT_NAME")
echo "name=$TRIMMED_ARTIFACT_NAME"
echo "##[set-output name=name;]${TRIMMED_ARTIFACT_NAME}"
- name: Prepare Build Artifacts
run: |
cp /usr/local/lib/libMoltenVK.dylib build/pcsx2/PCSX2.app/Contents/Frameworks/
mv build/pcsx2/PCSX2.app "${{ steps.artifact-metadata.outputs.name }}.app"
tar cvzf "${{ steps.artifact-metadata.outputs.name }}.tar.gz" "${{ steps.artifact-metadata.outputs.name }}.app"
mkdir ci-artifacts
cp "${{ steps.artifact-metadata.outputs.name }}.tar.gz" ci-artifacts/macOS.tar.gz
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: ${{ steps.artifact-metadata.outputs.name }}
path: "*.tar.gz"
- name: Upload Assets and Potential Publish Release
if: github.repository == 'PCSX2/pcsx2' && startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ secrets.BOT_PAT }}
ASSET_DIR: ${{ github.WORKSPACE }}/ci-artifacts
ASSET_EXTENSION: tar.gz
TAG_TO_SEARCH_FOR: ${{ github.REF }}
run: |
cd .github/workflows/scripts/releases/upload-release-artifacts
npm ci
node index.js
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/bash
$APPDIR/AppRun-patched
$APPDIR/AppRun-patched "$@"
@@ -1,6 +1,12 @@
#!/bin/bash
export LD_LIBRARY_PATH="$APPDIR/usr/lib:$LD_LIBRARY_PATH"
# use system wayland if available otherwise use the appimage provided wayland
if [[ $(ldconfig -p | grep libwayland-client | wc -l) -lt 1 ]]; then
export LD_LIBRARY_PATH="$APPDIR/usr/lib/wayland:$LD_LIBRARY_PATH"
fi
export BINARY_NAME=$(basename "$ARGV0")
if [[ ! -e "$PWD/$BINARY_NAME.config" ]]; then
mkdir "$PWD/$BINARY_NAME.config"
+9 -2
View File
@@ -49,8 +49,15 @@ cp --dereference /lib/"$LIBARCH"/libgcc_s.so.1 "$GITHUB_WORKSPACE"/squashfs-root
chmod +x .github/workflows/scripts/linux/app-variables.sh
cp .github/workflows/scripts/linux/app-variables.sh "$GITHUB_WORKSPACE"/squashfs-root/apprun-hooks
export UPD_INFO="gh-releases-zsync|PCSX2|pcsx2|latest|$name.AppImage.zsync"
export OUTPUT="$name.AppImage"
/tmp/squashfs-root/AppRun --appdir="$GITHUB_WORKSPACE"/squashfs-root/ --plugin gtk -d "$GITHUB_WORKSPACE"/squashfs-root/PCSX2.desktop -i "$GITHUB_WORKSPACE"/squashfs-root/PCSX2.png --output appimage
/tmp/squashfs-root/AppRun --appdir="$GITHUB_WORKSPACE"/squashfs-root/ --plugin gtk -d "$GITHUB_WORKSPACE"/squashfs-root/PCSX2.desktop -i "$GITHUB_WORKSPACE"/squashfs-root/PCSX2.png
# see LD_LIBRARY_PATH in app-variables.sh - the intent is to use system wayland if available but fall back to app-image provided
# a little bit hacky but should ensure maximum compatibility
mkdir -p squashfs-root/usr/lib/wayland
mv squashfs-root/usr/lib/libwayland-* squashfs-root/usr/lib/wayland
rm squashfs-root/usr/lib/libgmodule-2.0.so.0
curl -sSfL "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-$ARCH.AppImage" -o ./appimagetool-"$ARCH".AppImage
chmod a+x appimagetool*.AppImage
./appimagetool-"$ARCH".AppImage "$GITHUB_WORKSPACE"/squashfs-root "$name.AppImage"
mkdir -p "$GITHUB_WORKSPACE"/ci-artifacts/
ls -al .
mv "$name.AppImage" "$GITHUB_WORKSPACE"/ci-artifacts # && mv "$name.AppImage.zsync" "$GITHUB_WORKSPACE"/ci-artifacts
+104
View File
@@ -0,0 +1,104 @@
#!/bin/bash
set -e
export MACOSX_DEPLOYMENT_TARGET=10.13
INSTALLDIR="$HOME/deps"
NPROCS="$(getconf _NPROCESSORS_ONLN)"
SDL=SDL2-2.0.22
PNG=1.6.37
JPG=9e
SAMPLERATE=libsamplerate-0.1.9
PORTAUDIO=pa_stable_v190700_20210406
SOUNDTOUCH=soundtouch-2.3.1
WXWIDGETS=3.1.6
mkdir deps-build
cd deps-build
export PKG_CONFIG_PATH="$INSTALLDIR/lib/pkgconfig:$PKG_CONFIG_PATH"
export LDFLAGS="-L$INSTALLDIR/lib -dead_strip $LDFLAGS"
export CFLAGS="-I$INSTALLDIR/include -Os $CFLAGS"
export CXXFLAGS="-I$INSTALLDIR/include -Os $CXXFLAGS"
cat > SHASUMS <<EOF
fe7cbf3127882e3fc7259a75a0cb585620272c51745d3852ab9dd87960697f2e $SDL.tar.gz
505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca libpng-$PNG.tar.xz
4077d6a6a75aeb01884f708919d25934c93305e49f7e3f36db9129320e6f4f3d jpegsrc.v$JPG.tar.gz
0a7eb168e2f21353fb6d84da152e4512126f7dc48ccb0be80578c565413444c1 $SAMPLERATE.tar.gz
47efbf42c77c19a05d22e627d42873e991ec0c1357219c0d74ce6a2948cb2def $PORTAUDIO.tgz
6900996607258496ce126924a19fe9d598af9d892cf3f33d1e4daaa9b42ae0b1 $SOUNDTOUCH.tar.gz
4980e86c6494adcd527a41fc0a4e436777ba41d1893717d7b7176c59c2061c25 wxWidgets-$WXWIDGETS.tar.bz2
EOF
curl -L \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$PNG/libpng-$PNG.tar.xz" \
-O "https://www.ijg.org/files/jpegsrc.v$JPG.tar.gz" \
-O "http://www.mega-nerd.com/SRC/$SAMPLERATE.tar.gz" \
-O "http://files.portaudio.com/archives/$PORTAUDIO.tgz" \
-O "https://www.surina.net/soundtouch/$SOUNDTOUCH.tar.gz" \
-O "https://github.com/wxWidgets/wxWidgets/releases/download/v$WXWIDGETS/wxWidgets-$WXWIDGETS.tar.bz2" \
shasum -a 256 --check SHASUMS
echo "Installing SDL..."
tar xf "$SDL.tar.gz"
cd "$SDL"
./configure --prefix "$INSTALLDIR" --without-x
make "-j$NPROCS"
make install
cd ..
echo "Installing libpng..."
tar xf "libpng-$PNG.tar.xz"
cd "libpng-$PNG"
./configure --prefix "$INSTALLDIR" --disable-dependency-tracking
make "-j$NPROCS"
make install
cd ..
echo "Installing libjpeg..."
tar xf "jpegsrc.v$JPG.tar.gz"
cd "jpeg-$JPG"
./configure --prefix "$INSTALLDIR" --disable-dependency-tracking
make "-j$NPROCS"
make install
cd ..
echo "Installing libsamplerate..."
tar xf "$SAMPLERATE.tar.gz"
cd "$SAMPLERATE"
sed -i "" "s/Carbon.h/Carbon\\/Carbon.h/" examples/audio_out.c
./configure --prefix "$INSTALLDIR" --disable-dependency-tracking --disable-sndfile
make "-j$NPROCS"
make install
cd ..
echo "Installing portaudio..."
tar xf "$PORTAUDIO.tgz"
cd portaudio
./configure --prefix "$INSTALLDIR" --enable-mac-universal=no
make "-j$NPROCS"
make install
cd ..
echo "Installing soundtouch..."
tar xf "$SOUNDTOUCH.tar.gz"
cd "$SOUNDTOUCH"
cmake -B build -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=MinSizeRel
make -C build "-j$NPROCS"
make -C build install
cd ..
echo "Installing wx..."
tar xf "wxWidgets-$WXWIDGETS.tar.bz2"
cd "wxWidgets-$WXWIDGETS"
./configure --prefix "$INSTALLDIR" --with-macosx-version-min="$MACOSX_DEPLOYMENT_TARGET" --enable-clipboard --enable-dnd --enable-std_string --with-cocoa --with-libiconv --with-libjpeg --with-libpng --with-zlib --without-libtiff --without-regex
make "-j$NPROCS"
make install
cd ..
echo "Cleaning up..."
cd ..
rm -r deps-build
@@ -113,7 +113,8 @@ const { data: releaseAssetsPost } = await octokit.rest.repos.listReleaseAssets({
let expectedAssets = {
"windows-64bit-sse4": false,
"windows-64bit-avx2": false,
"linux-appimage-64bit": false
"linux-appimage-64bit": false,
"macos": false,
}
for (var i = 0; i < releaseAssetsPost.length; i++) {
+5 -5
View File
@@ -85,9 +85,9 @@ jobs:
shell: cmd
run: |
cd 3rdparty\qt
aria2c https://github.com/PCSX2/pcsx2-windows-dependencies/releases/download/2022-01-20/qt-6.2.2-x64.7z
7z x qt-6.2.2-x64.7z
del qt-6.2.2-x64.7z
aria2c https://github.com/PCSX2/pcsx2-windows-dependencies/releases/download/2022-04-13/qt-6.3.0-x64.7z
7z x qt-6.3.0-x64.7z
del qt-6.3.0-x64.7z
- name: Generate CMake
if: matrix.configuration == 'CMake'
@@ -162,7 +162,7 @@ jobs:
echo "##[set-output name=simd;]${SIMD}"
- name: Upload artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
continue-on-error: true
with:
name: ${{ steps.artifact-metadata.outputs.name }}
@@ -178,7 +178,7 @@ jobs:
- name: Upload artifact - with symbols
if: matrix.configuration != 'CMake'
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
continue-on-error: true
with:
name: ${{ steps.artifact-metadata.outputs.name }}-symbols
+6
View File
@@ -33,3 +33,9 @@
[submodule "3rdparty/sdl2/SDL"]
path = 3rdparty/sdl2/SDL
url = https://github.com/libsdl-org/SDL.git
[submodule "3rdparty/libzip/libzip"]
path = 3rdparty/libzip/libzip
url = https://github.com/nih-at/libzip.git
[submodule "3rdparty/zstd/zstd"]
path = 3rdparty/zstd/zstd
url = https://github.com/facebook/zstd.git
+3
View File
@@ -0,0 +1,3 @@
# 1.0.0</b> (2019-09-02)
First published version.
+7
View File
@@ -0,0 +1,7 @@
add_library(D3D12MemAlloc
include/D3D12MemAlloc.h
src/D3D12MemAlloc.cpp
)
target_include_directories(D3D12MemAlloc PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+52
View File
@@ -0,0 +1,52 @@
Notices and licenses file
_________________________
AMD copyrighted code (MIT)
Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Dependecnies on microsoft-directx-graphics-samples v-u (MIT)
Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved.
Copyright (c) Microsoft. All rights reserved.
This code is licensed under the MIT License (MIT).
THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
gpuopen-librariesandsdks-vulkanmemoryallocator v-u (MIT)
Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+113
View File
@@ -0,0 +1,113 @@
# D3D12 Memory Allocator
Easy to integrate memory allocation library for Direct3D 12.
**Documentation:** Browse online: [D3D12 Memory Allocator](https://gpuopen-librariesandsdks.github.io/D3D12MemoryAllocator/html/) (generated from Doxygen-style comments in [src/D3D12MemAlloc.h](src/D3D12MemAlloc.h))
**License:** MIT. See [LICENSE.txt](LICENSE.txt)
**Changelog:** See [CHANGELOG.md](CHANGELOG.md)
**Product page:** [D3D12 Memory Allocator on GPUOpen](https://gpuopen.com/gaming-product/d3d12-memory-allocator/)
**Build status:**
Windows: [![Build status](https://ci.appveyor.com/api/projects/status/860i07bxv55ydgvg?svg=true)](https://ci.appveyor.com/project/adam-sawicki-amd/d3d12memoryallocator)
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator.svg)](http://isitmaintained.com/project/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator "Average time to resolve an issue")
# Problem
Memory allocation and resource (buffer and texture) creation in new, explicit graphics APIs (Vulkan® and Direct3D 12) is difficult comparing to older graphics APIs like Direct3D 11 or OpenGL® because it is recommended to allocate bigger blocks of memory and assign parts of them to resources. [Vulkan Memory Allocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/) is a library that implements this functionality for Vulkan. It is available online since 2017 and it is successfully used in many software projects, including some AAA game studios. This is an equivalent library for D3D12.
# Features
This library can help developers to manage memory allocations and resource creation by offering function `Allocator::CreateResource` similar to the standard `ID3D12Device::CreateCommittedResource`. It internally:
- Allocates and keeps track of bigger memory heaps, used and unused ranges inside them, finds best matching unused ranges to create new resources there as placed resources.
- Automatically respects size and alignment requirements for created resources.
- Automatically handles resource heap tier - whether it's `D3D12_RESOURCE_HEAP_TIER_1` that requires to keep certain classes of resources separate or `D3D12_RESOURCE_HEAP_TIER_2` that allows to keep them all together.
Additional features:
- Well-documented - description of all classes and functions provided, along with chapters that contain general description and example code.
- Thread-safety: Library is designed to be used in multithreaded code.
- Configuration: Fill optional members of `ALLOCATOR_DESC` structure to provide custom CPU memory allocator and other parameters.
- Customization and integration with custom engines: Predefine appropriate macros to provide your own implementation of external facilities used by the library, like assert, mutex, and atomic.
- Support for resource aliasing (overlap).
- Custom memory pools: Create a pool with desired parameters (e.g. fixed or limited maximum size, custom `D3D12_HEAP_PROPERTIES` and `D3D12_HEAP_FLAGS`) and allocate memory out of it.
- Linear allocator: Create a pool with linear algorithm and use it for much faster allocations and deallocations in free-at-once, stack, double stack, or ring buffer fashion.
- Defragmentation: Let the library move data around to free some memory blocks and make your allocations better compacted.
- Statistics: Obtain brief or detailed statistics about the amount of memory used, unused, number of allocated heaps, number of allocations etc. - globally and per memory heap type. Current memory usage and budget as reported by the system can also be queried.
- Debug annotations: Associate custom `void* pPrivateData` and debug `LPCWSTR pName` with each allocation.
- JSON dump: Obtain a string in JSON format with detailed map of internal state, including list of allocations, their string names, and gaps between them.
- Convert this JSON dump into a picture to visualize your memory using attached Python script.
- Virtual allocator - an API that exposes the core allocation algorithm to be used without allocating real GPU memory, to allocate your own stuff, e.g. sub-allocate pieces of one large buffer.
# Prerequisites
- Self-contained C++ library in single pair of H + CPP files. No external dependencies other than standard C, C++ library and Windows SDK. Some features of C++14 used. STL containers, C++ exceptions, and RTTI are not used.
- Object-oriented interface in a convention similar to D3D12.
- Error handling implemented by returning `HRESULT` error codes - same way as in D3D12.
- Interface documented using Doxygen-style comments.
# Example
Basic usage of this library is very simple. Advanced features are optional. After you created global `Allocator` object, a complete code needed to create a texture may look like this:
```cpp
D3D12_RESOURCE_DESC resourceDesc = {};
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resourceDesc.Alignment = 0;
resourceDesc.Width = 1024;
resourceDesc.Height = 1024;
resourceDesc.DepthOrArraySize = 1;
resourceDesc.MipLevels = 1;
resourceDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
resourceDesc.SampleDesc.Count = 1;
resourceDesc.SampleDesc.Quality = 0;
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
resourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
D3D12MA::ALLOCATION_DESC allocDesc = {};
allocDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
D3D12Resource* resource;
D3D12MA::Allocation* allocation;
HRESULT hr = allocator->CreateResource(
&allocDesc, &resourceDesc,
D3D12_RESOURCE_STATE_COPY_DEST, NULL,
&allocation, IID_PPV_ARGS(&resource));
```
With this one function call:
1. `ID3D12Heap` memory block is allocated if needed.
2. An unused region of the memory block is reserved for the allocation.
3. `ID3D12Resource` is created as placed resource, bound to this region.
`Allocation` is an object that represents memory assigned to this texture. It can be queried for parameters like offset and size.
# Binaries
The release comes with precompiled binary executable for "D3D12Sample" application which contains test suite. It is compiled using Visual Studio 2019, so it requires appropriate libraries to work, including "MSVCP140.dll", "VCRUNTIME140.dll", "VCRUNTIME140_1.dll". If its launch fails with error message telling about those files missing, please download and install [Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads), "x64" version.
# Copyright notice
This software package uses third party software:
- Parts of the code of [Vulkan Memory Allocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/) by AMD, license: MIT
- Parts of the code of [DirectX-Graphics-Samples](https://github.com/microsoft/DirectX-Graphics-Samples) by Microsoft, license: MIT
For more information see [NOTICES.txt](NOTICES.txt).
# Software using this library
- **[The Forge](https://github.com/ConfettiFX/The-Forge)** - cross-platform rendering framework. Apache License 2.0.
[Some other projects on GitHub](https://github.com/search?q=D3D12MemAlloc.h&type=Code) and some game development studios that use DX12 in their games.
# See also
- **[Vulkan Memory Allocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/)** - equivalent library for Vulkan. License: MIT.
- **[TerraFX.Interop.D3D12MemoryAllocator](https://github.com/terrafx/terrafx.interop.d3d12memoryallocator)** - interop bindings for this library for C#, as used by [TerraFX](https://github.com/terrafx/terrafx). License: MIT.
+46
View File
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{D45CEC7A-3171-40DD-975D-E1544CF16139}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="src\D3D12MemAlloc.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\D3D12MemAlloc.h" />
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="src\D3D12MemAlloc.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\D3D12MemAlloc.h" />
</ItemGroup>
</Project>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+58
View File
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="D3D12MA::Vector&lt;*&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<Item Name="[Capacity]">m_Capacity</Item>
<ArrayItems>
<Size>m_Count</Size>
<ValuePointer>m_pArray</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="D3D12MA::List&lt;*&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<LinkedListItems>
<Size>m_Count</Size>
<HeadPointer>m_pFront</HeadPointer>
<NextPointer>pNext</NextPointer>
<ValueNode>Value</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<!--
Due to custom way of accesing next items in
D3D12MA::IntrusiveLinkedList via methods in provided type traits,
every specialization must be manually added with
custom <NextPointer> field describing proper way of iterating the list.
-->
<Type Name="D3D12MA::IntrusiveLinkedList&lt;D3D12MA::CommittedAllocationListItemTraits&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<LinkedListItems>
<Size>m_Count</Size>
<HeadPointer>m_Front</HeadPointer>
<NextPointer>m_Committed.next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
<Type Name="D3D12MA::IntrusiveLinkedList&lt;D3D12MA::PoolListItemTraits&gt;">
<DisplayString>{{ Count={m_Count} }}</DisplayString>
<Expand>
<Item Name="[Count]">m_Count</Item>
<LinkedListItems>
<Size>m_Count</Size>
<HeadPointer>m_Front</HeadPointer>
<NextPointer>m_NextPool</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Type>
</AutoVisualizer>
+12 -6
View File
@@ -10,17 +10,23 @@ add_library(imgui
imgui/imstb_rectpack.h
imgui/imstb_textedit.h
imgui/imstb_truetype.h
include/imgui_impl_opengl3.h
src/imgui_impl_opengl3.cpp
)
target_include_directories(imgui PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/imgui" "${CMAKE_CURRENT_SOURCE_DIR}/include")
if(USE_OPENGL)
target_sources(imgui PRIVATE
include/imgui_impl_opengl3.h
src/imgui_impl_opengl3.cpp
)
target_link_libraries(imgui glad)
endif()
if(WIN32)
target_sources(imgui PRIVATE
include/imgui_impl_dx11.h
include/imgui_impl_dx12.h
src/imgui_impl_dx11.cpp
src/imgui_impl_dx12.cpp
)
endif()
target_include_directories(imgui PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/imgui" "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(imgui glad)
+2
View File
@@ -48,6 +48,7 @@
<ClInclude Include="imgui\imstb_textedit.h" />
<ClInclude Include="imgui\imstb_truetype.h" />
<ClInclude Include="include\imgui_impl_dx11.h" />
<ClInclude Include="include\imgui_impl_dx12.h" />
<ClInclude Include="include\imgui_impl_opengl3.h" />
</ItemGroup>
<ItemGroup>
@@ -57,6 +58,7 @@
<ClCompile Include="imgui\imgui_tables.cpp" />
<ClCompile Include="imgui\imgui_widgets.cpp" />
<ClCompile Include="src\imgui_impl_dx11.cpp" />
<ClCompile Include="src\imgui_impl_dx12.cpp" />
<ClCompile Include="src\imgui_impl_opengl3.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+2
View File
@@ -9,6 +9,7 @@
<ClInclude Include="imgui\imstb_truetype.h" />
<ClInclude Include="include\imgui_impl_opengl3.h" />
<ClInclude Include="include\imgui_impl_dx11.h" />
<ClInclude Include="include\imgui_impl_dx12.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="imgui\imgui.cpp" />
@@ -18,5 +19,6 @@
<ClCompile Include="imgui\imgui_widgets.cpp" />
<ClCompile Include="src\imgui_impl_dx11.cpp" />
<ClCompile Include="src\imgui_impl_opengl3.cpp" />
<ClCompile Include="src\imgui_impl_dx12.cpp" />
</ItemGroup>
</Project>
+39
View File
@@ -0,0 +1,39 @@
// dear imgui: Renderer Backend for DirectX12
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#include <dxgiformat.h> // DXGI_FORMAT
struct ID3D12Device;
struct ID3D12DescriptorHeap;
struct ID3D12GraphicsCommandList;
struct D3D12_CPU_DESCRIPTOR_HANDLE;
struct D3D12_GPU_DESCRIPTOR_HANDLE;
// cmd_list is the command list that the implementation will use to render imgui draw lists.
// Before calling the render function, caller must prepare cmd_list by resetting it and setting the appropriate
// render target and descriptor heap that contains font_srv_cpu_desc_handle/font_srv_gpu_desc_handle.
// font_srv_cpu_desc_handle and font_srv_gpu_desc_handle are handles to a single SRV descriptor to use for the internal font texture.
IMGUI_IMPL_API bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle);
IMGUI_IMPL_API void ImGui_ImplDX12_Shutdown();
IMGUI_IMPL_API void ImGui_ImplDX12_NewFrame();
IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* graphics_command_list);
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
+730
View File
@@ -0,0 +1,730 @@
// dear imgui: Renderer Backend for DirectX12
// This needs to be used along with a Platform Backend (e.g. Win32)
// Implemented features:
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
// To build this on 32-bit systems:
// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file)
// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file)
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer.
// 2021-01-11: DirectX12: Improve Windows 7 compatibility (for D3D12On7) by loading d3d12.dll dynamically.
// 2020-09-16: DirectX12: Avoid rendering calls with zero-sized scissor rectangle since it generates a validation layer warning.
// 2020-09-08: DirectX12: Clarified support for building on 32-bit systems by redefining ImTextureID.
// 2019-10-18: DirectX12: *BREAKING CHANGE* Added extra ID3D12DescriptorHeap parameter to ImGui_ImplDX12_Init() function.
// 2019-05-29: DirectX12: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2019-04-30: DirectX12: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
// 2019-03-29: Misc: Various minor tidying up.
// 2018-12-03: Misc: Added #pragma comment statement to automatically link with d3dcompiler.lib when using D3DCompile().
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
// 2018-06-12: DirectX12: Moved the ID3D12GraphicsCommandList* parameter from NewFrame() to RenderDrawData().
// 2018-06-08: Misc: Extracted imgui_impl_dx12.cpp/.h away from the old combined DX12+Win32 example.
// 2018-06-08: DirectX12: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle (to ease support for future multi-viewport).
// 2018-02-22: Merged into master with all Win32 code synchronized to other examples.
#include "imgui.h"
#include "imgui_impl_dx12.h"
// DirectX
#include <d3d12.h>
#include <dxgi1_4.h>
#include <d3dcompiler.h>
#ifdef _MSC_VER
#pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below.
#endif
// DirectX data
struct ImGui_ImplDX12_RenderBuffers
{
ID3D12Resource* IndexBuffer;
ID3D12Resource* VertexBuffer;
int IndexBufferSize;
int VertexBufferSize;
};
struct ImGui_ImplDX12_Data
{
ID3D12Device* pd3dDevice;
ID3D12RootSignature* pRootSignature;
ID3D12PipelineState* pPipelineState;
DXGI_FORMAT RTVFormat;
ID3D12Resource* pFontTextureResource;
D3D12_CPU_DESCRIPTOR_HANDLE hFontSrvCpuDescHandle;
D3D12_GPU_DESCRIPTOR_HANDLE hFontSrvGpuDescHandle;
ImGui_ImplDX12_RenderBuffers* pFrameResources;
UINT numFramesInFlight;
UINT frameIndex;
ImGui_ImplDX12_Data() { memset(this, 0, sizeof(*this)); frameIndex = UINT_MAX; }
};
struct VERTEX_CONSTANT_BUFFER
{
float mvp[4][4];
};
// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplDX12_Data* ImGui_ImplDX12_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplDX12_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
}
// Functions
static void ImGui_ImplDX12_SetupRenderState(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx, ImGui_ImplDX12_RenderBuffers* fr)
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
// Setup orthographic projection matrix into our constant buffer
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right).
VERTEX_CONSTANT_BUFFER vertex_constant_buffer;
{
float L = draw_data->DisplayPos.x;
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
float T = draw_data->DisplayPos.y;
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
float mvp[4][4] =
{
{ 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 0.0f },
{ (R+L)/(L-R), (T+B)/(B-T), 0.5f, 1.0f },
};
memcpy(&vertex_constant_buffer.mvp, mvp, sizeof(mvp));
}
// Setup viewport
D3D12_VIEWPORT vp;
memset(&vp, 0, sizeof(D3D12_VIEWPORT));
vp.Width = draw_data->DisplaySize.x;
vp.Height = draw_data->DisplaySize.y;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = vp.TopLeftY = 0.0f;
ctx->RSSetViewports(1, &vp);
// Bind shader and vertex buffers
unsigned int stride = sizeof(ImDrawVert);
unsigned int offset = 0;
D3D12_VERTEX_BUFFER_VIEW vbv;
memset(&vbv, 0, sizeof(D3D12_VERTEX_BUFFER_VIEW));
vbv.BufferLocation = fr->VertexBuffer->GetGPUVirtualAddress() + offset;
vbv.SizeInBytes = fr->VertexBufferSize * stride;
vbv.StrideInBytes = stride;
ctx->IASetVertexBuffers(0, 1, &vbv);
D3D12_INDEX_BUFFER_VIEW ibv;
memset(&ibv, 0, sizeof(D3D12_INDEX_BUFFER_VIEW));
ibv.BufferLocation = fr->IndexBuffer->GetGPUVirtualAddress();
ibv.SizeInBytes = fr->IndexBufferSize * sizeof(ImDrawIdx);
ibv.Format = sizeof(ImDrawIdx) == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
ctx->IASetIndexBuffer(&ibv);
ctx->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ctx->SetPipelineState(bd->pPipelineState);
ctx->SetGraphicsRootSignature(bd->pRootSignature);
ctx->SetGraphicsRoot32BitConstants(0, 16, &vertex_constant_buffer, 0);
// Setup blend factor
const float blend_factor[4] = { 0.f, 0.f, 0.f, 0.f };
ctx->OMSetBlendFactor(blend_factor);
}
template<typename T>
static inline void SafeRelease(T*& res)
{
if (res)
res->Release();
res = NULL;
}
// Render function
void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandList* ctx)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// FIXME: I'm assuming that this only gets called once per frame!
// If not, we can't just re-allocate the IB or VB, we'll have to do a proper allocator.
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
bd->frameIndex = bd->frameIndex + 1;
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[bd->frameIndex % bd->numFramesInFlight];
// Create and grow vertex/index buffers if needed
if (fr->VertexBuffer == NULL || fr->VertexBufferSize < draw_data->TotalVtxCount)
{
SafeRelease(fr->VertexBuffer);
fr->VertexBufferSize = draw_data->TotalVtxCount + 5000;
D3D12_HEAP_PROPERTIES props;
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
props.Type = D3D12_HEAP_TYPE_UPLOAD;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
D3D12_RESOURCE_DESC desc;
memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC));
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Width = fr->VertexBufferSize * sizeof(ImDrawVert);
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->VertexBuffer)) < 0)
return;
}
if (fr->IndexBuffer == NULL || fr->IndexBufferSize < draw_data->TotalIdxCount)
{
SafeRelease(fr->IndexBuffer);
fr->IndexBufferSize = draw_data->TotalIdxCount + 10000;
D3D12_HEAP_PROPERTIES props;
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
props.Type = D3D12_HEAP_TYPE_UPLOAD;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
D3D12_RESOURCE_DESC desc;
memset(&desc, 0, sizeof(D3D12_RESOURCE_DESC));
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Width = fr->IndexBufferSize * sizeof(ImDrawIdx);
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
if (bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&fr->IndexBuffer)) < 0)
return;
}
// Upload vertex/index data into a single contiguous GPU buffer
void* vtx_resource, *idx_resource;
D3D12_RANGE range;
memset(&range, 0, sizeof(D3D12_RANGE));
if (fr->VertexBuffer->Map(0, &range, &vtx_resource) != S_OK)
return;
if (fr->IndexBuffer->Map(0, &range, &idx_resource) != S_OK)
return;
ImDrawVert* vtx_dst = (ImDrawVert*)vtx_resource;
ImDrawIdx* idx_dst = (ImDrawIdx*)idx_resource;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
vtx_dst += cmd_list->VtxBuffer.Size;
idx_dst += cmd_list->IdxBuffer.Size;
}
fr->VertexBuffer->Unmap(0, &range);
fr->IndexBuffer->Unmap(0, &range);
// Setup desired DX state
ImGui_ImplDX12_SetupRenderState(draw_data, ctx, fr);
// Render command lists
// (Because we merged all buffers into a single one, we maintain our own offset into them)
int global_vtx_offset = 0;
int global_idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback != NULL)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplDX12_SetupRenderState(draw_data, ctx, fr);
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply Scissor/clipping rectangle, Bind texture, Draw
const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {};
texture_handle.ptr = (UINT64)pcmd->GetTexID();
ctx->SetGraphicsRootDescriptorTable(1, texture_handle);
ctx->RSSetScissorRects(1, &r);
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
}
static void ImGui_ImplDX12_CreateFontsTexture()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
{
D3D12_HEAP_PROPERTIES props;
memset(&props, 0, sizeof(D3D12_HEAP_PROPERTIES));
props.Type = D3D12_HEAP_TYPE_DEFAULT;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
D3D12_RESOURCE_DESC desc;
ZeroMemory(&desc, sizeof(desc));
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Alignment = 0;
desc.Width = width;
desc.Height = height;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
ID3D12Resource* pTexture = NULL;
bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
D3D12_RESOURCE_STATE_COPY_DEST, NULL, IID_PPV_ARGS(&pTexture));
UINT uploadPitch = (width * 4 + D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u) & ~(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1u);
UINT uploadSize = height * uploadPitch;
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Alignment = 0;
desc.Width = uploadSize;
desc.Height = 1;
desc.DepthOrArraySize = 1;
desc.MipLevels = 1;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.Flags = D3D12_RESOURCE_FLAG_NONE;
props.Type = D3D12_HEAP_TYPE_UPLOAD;
props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
ID3D12Resource* uploadBuffer = NULL;
HRESULT hr = bd->pd3dDevice->CreateCommittedResource(&props, D3D12_HEAP_FLAG_NONE, &desc,
D3D12_RESOURCE_STATE_GENERIC_READ, NULL, IID_PPV_ARGS(&uploadBuffer));
IM_ASSERT(SUCCEEDED(hr));
void* mapped = NULL;
D3D12_RANGE range = { 0, uploadSize };
hr = uploadBuffer->Map(0, &range, &mapped);
IM_ASSERT(SUCCEEDED(hr));
for (int y = 0; y < height; y++)
memcpy((void*) ((uintptr_t) mapped + y * uploadPitch), pixels + y * width * 4, width * 4);
uploadBuffer->Unmap(0, &range);
D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
srcLocation.pResource = uploadBuffer;
srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
srcLocation.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srcLocation.PlacedFootprint.Footprint.Width = width;
srcLocation.PlacedFootprint.Footprint.Height = height;
srcLocation.PlacedFootprint.Footprint.Depth = 1;
srcLocation.PlacedFootprint.Footprint.RowPitch = uploadPitch;
D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
dstLocation.pResource = pTexture;
dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dstLocation.SubresourceIndex = 0;
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = pTexture;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
ID3D12Fence* fence = NULL;
hr = bd->pd3dDevice->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
IM_ASSERT(SUCCEEDED(hr));
HANDLE event = CreateEvent(0, 0, 0, 0);
IM_ASSERT(event != NULL);
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.NodeMask = 1;
ID3D12CommandQueue* cmdQueue = NULL;
hr = bd->pd3dDevice->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&cmdQueue));
IM_ASSERT(SUCCEEDED(hr));
ID3D12CommandAllocator* cmdAlloc = NULL;
hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
IM_ASSERT(SUCCEEDED(hr));
ID3D12GraphicsCommandList* cmdList = NULL;
hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, NULL, IID_PPV_ARGS(&cmdList));
IM_ASSERT(SUCCEEDED(hr));
cmdList->CopyTextureRegion(&dstLocation, 0, 0, 0, &srcLocation, NULL);
cmdList->ResourceBarrier(1, &barrier);
hr = cmdList->Close();
IM_ASSERT(SUCCEEDED(hr));
cmdQueue->ExecuteCommandLists(1, (ID3D12CommandList* const*)&cmdList);
hr = cmdQueue->Signal(fence, 1);
IM_ASSERT(SUCCEEDED(hr));
fence->SetEventOnCompletion(1, event);
WaitForSingleObject(event, INFINITE);
cmdList->Release();
cmdAlloc->Release();
cmdQueue->Release();
CloseHandle(event);
fence->Release();
uploadBuffer->Release();
// Create texture view
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc;
ZeroMemory(&srvDesc, sizeof(srvDesc));
srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = 0;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
bd->pd3dDevice->CreateShaderResourceView(pTexture, &srvDesc, bd->hFontSrvCpuDescHandle);
SafeRelease(bd->pFontTextureResource);
bd->pFontTextureResource = pTexture;
}
// Store our identifier
// READ THIS IF THE STATIC_ASSERT() TRIGGERS:
// - Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
// - This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
// [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in the 'example_win32_direct12/example_win32_direct12.vcxproj' project file)
// [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
// [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
// [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in the example_win32_direct12/build_win32.bat file)
static_assert(sizeof(ImTextureID) >= sizeof(bd->hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet.");
io.Fonts->SetTexID((ImTextureID)bd->hFontSrvGpuDescHandle.ptr);
}
bool ImGui_ImplDX12_CreateDeviceObjects()
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
if (!bd || !bd->pd3dDevice)
return false;
if (bd->pPipelineState)
ImGui_ImplDX12_InvalidateDeviceObjects();
// Create the root signature
{
D3D12_DESCRIPTOR_RANGE descRange = {};
descRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
descRange.NumDescriptors = 1;
descRange.BaseShaderRegister = 0;
descRange.RegisterSpace = 0;
descRange.OffsetInDescriptorsFromTableStart = 0;
D3D12_ROOT_PARAMETER param[2] = {};
param[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
param[0].Constants.ShaderRegister = 0;
param[0].Constants.RegisterSpace = 0;
param[0].Constants.Num32BitValues = 16;
param[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
param[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
param[1].DescriptorTable.NumDescriptorRanges = 1;
param[1].DescriptorTable.pDescriptorRanges = &descRange;
param[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
D3D12_STATIC_SAMPLER_DESC staticSampler = {};
staticSampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
staticSampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
staticSampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
staticSampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
staticSampler.MipLODBias = 0.f;
staticSampler.MaxAnisotropy = 0;
staticSampler.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS;
staticSampler.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
staticSampler.MinLOD = 0.f;
staticSampler.MaxLOD = 0.f;
staticSampler.ShaderRegister = 0;
staticSampler.RegisterSpace = 0;
staticSampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
D3D12_ROOT_SIGNATURE_DESC desc = {};
desc.NumParameters = _countof(param);
desc.pParameters = param;
desc.NumStaticSamplers = 1;
desc.pStaticSamplers = &staticSampler;
desc.Flags =
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS;
// Load d3d12.dll and D3D12SerializeRootSignature() function address dynamically to facilitate using with D3D12On7.
// See if any version of d3d12.dll is already loaded in the process. If so, give preference to that.
HMODULE d3d12_dll = ::GetModuleHandleA("d3d12.dll");
if (d3d12_dll == NULL)
return false;
PFN_D3D12_SERIALIZE_ROOT_SIGNATURE D3D12SerializeRootSignatureFn = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)::GetProcAddress(d3d12_dll, "D3D12SerializeRootSignature");
if (D3D12SerializeRootSignatureFn == NULL)
return false;
ID3DBlob* blob = NULL;
if (D3D12SerializeRootSignatureFn(&desc, D3D_ROOT_SIGNATURE_VERSION_1, &blob, NULL) != S_OK)
return false;
bd->pd3dDevice->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(&bd->pRootSignature));
blob->Release();
}
// By using D3DCompile() from <d3dcompiler.h> / d3dcompiler.lib, we introduce a dependency to a given version of d3dcompiler_XX.dll (see D3DCOMPILER_DLL_A)
// If you would like to use this DX12 sample code but remove this dependency you can:
// 1) compile once, save the compiled shader blobs into a file or source code and pass them to CreateVertexShader()/CreatePixelShader() [preferred solution]
// 2) use code to detect any version of the DLL and grab a pointer to D3DCompile from the DLL.
// See https://github.com/ocornut/imgui/pull/638 for sources and details.
D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc;
memset(&psoDesc, 0, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
psoDesc.NodeMask = 1;
psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
psoDesc.pRootSignature = bd->pRootSignature;
psoDesc.SampleMask = UINT_MAX;
psoDesc.NumRenderTargets = 1;
psoDesc.RTVFormats[0] = bd->RTVFormat;
psoDesc.SampleDesc.Count = 1;
psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
ID3DBlob* vertexShaderBlob;
ID3DBlob* pixelShaderBlob;
// Create the vertex shader
{
static const char* vertexShader =
"cbuffer vertexBuffer : register(b0) \
{\
float4x4 ProjectionMatrix; \
};\
struct VS_INPUT\
{\
float2 pos : POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
\
struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
\
PS_INPUT main(VS_INPUT input)\
{\
PS_INPUT output;\
output.pos = mul( ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\
output.col = input.col;\
output.uv = input.uv;\
return output;\
}";
if (FAILED(D3DCompile(vertexShader, strlen(vertexShader), NULL, NULL, NULL, "main", "vs_5_0", 0, 0, &vertexShaderBlob, NULL)))
return false; // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
psoDesc.VS = { vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize() };
// Create the input layout
static D3D12_INPUT_ELEMENT_DESC local_layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, pos), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)IM_OFFSETOF(ImDrawVert, uv), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, (UINT)IM_OFFSETOF(ImDrawVert, col), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
};
psoDesc.InputLayout = { local_layout, 3 };
}
// Create the pixel shader
{
static const char* pixelShader =
"struct PS_INPUT\
{\
float4 pos : SV_POSITION;\
float4 col : COLOR0;\
float2 uv : TEXCOORD0;\
};\
SamplerState sampler0 : register(s0);\
Texture2D texture0 : register(t0);\
\
float4 main(PS_INPUT input) : SV_Target\
{\
float4 out_col = input.col * texture0.Sample(sampler0, input.uv); \
return out_col; \
}";
if (FAILED(D3DCompile(pixelShader, strlen(pixelShader), NULL, NULL, NULL, "main", "ps_5_0", 0, 0, &pixelShaderBlob, NULL)))
{
vertexShaderBlob->Release();
return false; // NB: Pass ID3D10Blob* pErrorBlob to D3DCompile() to get error showing in (const char*)pErrorBlob->GetBufferPointer(). Make sure to Release() the blob!
}
psoDesc.PS = { pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize() };
}
// Create the blending setup
{
D3D12_BLEND_DESC& desc = psoDesc.BlendState;
desc.AlphaToCoverageEnable = false;
desc.RenderTarget[0].BlendEnable = true;
desc.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
desc.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
}
// Create the rasterizer state
{
D3D12_RASTERIZER_DESC& desc = psoDesc.RasterizerState;
desc.FillMode = D3D12_FILL_MODE_SOLID;
desc.CullMode = D3D12_CULL_MODE_NONE;
desc.FrontCounterClockwise = FALSE;
desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
desc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
desc.DepthClipEnable = true;
desc.MultisampleEnable = FALSE;
desc.AntialiasedLineEnable = FALSE;
desc.ForcedSampleCount = 0;
desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
}
// Create depth-stencil State
{
D3D12_DEPTH_STENCIL_DESC& desc = psoDesc.DepthStencilState;
desc.DepthEnable = false;
desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D12_COMPARISON_FUNC_ALWAYS;
desc.StencilEnable = false;
desc.FrontFace.StencilFailOp = desc.FrontFace.StencilDepthFailOp = desc.FrontFace.StencilPassOp = D3D12_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D12_COMPARISON_FUNC_ALWAYS;
desc.BackFace = desc.FrontFace;
}
HRESULT result_pipeline_state = bd->pd3dDevice->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&bd->pPipelineState));
vertexShaderBlob->Release();
pixelShaderBlob->Release();
if (result_pipeline_state != S_OK)
return false;
ImGui_ImplDX12_CreateFontsTexture();
return true;
}
void ImGui_ImplDX12_InvalidateDeviceObjects()
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
if (!bd || !bd->pd3dDevice)
return;
ImGuiIO& io = ImGui::GetIO();
SafeRelease(bd->pRootSignature);
SafeRelease(bd->pPipelineState);
SafeRelease(bd->pFontTextureResource);
io.Fonts->SetTexID(NULL); // We copied bd->pFontTextureView to io.Fonts->TexID so let's clear that as well.
for (UINT i = 0; i < bd->numFramesInFlight; i++)
{
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
SafeRelease(fr->IndexBuffer);
SafeRelease(fr->VertexBuffer);
}
}
bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FORMAT rtv_format, ID3D12DescriptorHeap* cbv_srv_heap,
D3D12_CPU_DESCRIPTOR_HANDLE font_srv_cpu_desc_handle, D3D12_GPU_DESCRIPTOR_HANDLE font_srv_gpu_desc_handle)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
// Setup backend capabilities flags
ImGui_ImplDX12_Data* bd = IM_NEW(ImGui_ImplDX12_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_dx12";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
bd->pd3dDevice = device;
bd->RTVFormat = rtv_format;
bd->hFontSrvCpuDescHandle = font_srv_cpu_desc_handle;
bd->hFontSrvGpuDescHandle = font_srv_gpu_desc_handle;
bd->pFrameResources = new ImGui_ImplDX12_RenderBuffers[num_frames_in_flight];
bd->numFramesInFlight = num_frames_in_flight;
bd->frameIndex = UINT_MAX;
IM_UNUSED(cbv_srv_heap); // Unused in master branch (will be used by multi-viewports)
// Create buffers with a default size (they will later be grown as needed)
for (int i = 0; i < num_frames_in_flight; i++)
{
ImGui_ImplDX12_RenderBuffers* fr = &bd->pFrameResources[i];
fr->IndexBuffer = NULL;
fr->VertexBuffer = NULL;
fr->IndexBufferSize = 10000;
fr->VertexBufferSize = 5000;
}
return true;
}
void ImGui_ImplDX12_Shutdown()
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX12_InvalidateDeviceObjects();
delete[] bd->pFrameResources;
io.BackendRendererName = NULL;
io.BackendRendererUserData = NULL;
IM_DELETE(bd);
}
void ImGui_ImplDX12_NewFrame()
{
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplDX12_Init()?");
if (!bd->pPipelineState)
ImGui_ImplDX12_CreateDeviceObjects();
}
+30
View File
@@ -0,0 +1,30 @@
set(BUILD_SHARED_LIBS OFF CACHE BOOL "")
set(LIBZIP_DO_INSTALL OFF CACHE BOOL "")
set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "")
set(ENABLE_GNUTLS OFF CACHE BOOL "")
set(ENABLE_MBEDTLS OFF CACHE BOOL "")
set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "")
set(ENABLE_BZIP2 OFF CACHE BOOL "")
set(ENABLE_LZMA OFF CACHE BOOL "")
set(ENABLE_ZSTD ON CACHE BOOL "")
set(BUILD_TOOLS OFF CACHE BOOL "")
set(BUILD_REGRESS OFF CACHE BOOL "")
set(BUILD_EXAMPLES OFF CACHE BOOL "")
set(BUILD_DOC OFF CACHE BOOL "")
if(WIN32)
# Needed otherwise find_package() will look in the system.
set(ZLIB_FOUND TRUE)
set(ZLIB_LIBRARY "$<TARGET_FILE:pcsx2-zlib>")
set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/zlib")
endif()
# Fill in the location of zstd, so find_package() doesn't try to use
# a potentially-old system version. It also picks up Zstd::Zstd.
set(Zstd_FOUND TRUE)
set(Zstd_LIBRARY "$<TARGET_FILE:pcsx2-zstd>")
set(Zstd_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../zstd/zstd/lib")
add_subdirectory(libzip EXCLUDE_FROM_ALL)
Vendored Submodule
+1
Submodule 3rdparty/libzip/libzip added at bdc03ab23b
+179
View File
@@ -0,0 +1,179 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{20B2E9FE-F020-42A0-B324-956F5B06EA68}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="libzip\lib\zip_add.c" />
<ClCompile Include="libzip\lib\zip_add_dir.c" />
<ClCompile Include="libzip\lib\zip_add_entry.c" />
<ClCompile Include="libzip\lib\zip_algorithm_deflate.c" />
<ClCompile Include="libzip\lib\zip_algorithm_zstd.c" />
<ClCompile Include="libzip\lib\zip_buffer.c" />
<ClCompile Include="libzip\lib\zip_close.c" />
<ClCompile Include="libzip\lib\zip_crypto_win.c" />
<ClCompile Include="libzip\lib\zip_delete.c" />
<ClCompile Include="libzip\lib\zip_dirent.c" />
<ClCompile Include="libzip\lib\zip_dir_add.c" />
<ClCompile Include="libzip\lib\zip_discard.c" />
<ClCompile Include="libzip\lib\zip_entry.c" />
<ClCompile Include="libzip\lib\zip_error.c" />
<ClCompile Include="libzip\lib\zip_error_clear.c" />
<ClCompile Include="libzip\lib\zip_error_get.c" />
<ClCompile Include="libzip\lib\zip_error_get_sys_type.c" />
<ClCompile Include="libzip\lib\zip_error_strerror.c" />
<ClCompile Include="libzip\lib\zip_error_to_str.c" />
<ClCompile Include="libzip\lib\zip_extra_field.c" />
<ClCompile Include="libzip\lib\zip_extra_field_api.c" />
<ClCompile Include="libzip\lib\zip_fclose.c" />
<ClCompile Include="libzip\lib\zip_fdopen.c" />
<ClCompile Include="libzip\lib\zip_file_add.c" />
<ClCompile Include="libzip\lib\zip_file_error_clear.c" />
<ClCompile Include="libzip\lib\zip_file_error_get.c" />
<ClCompile Include="libzip\lib\zip_file_get_comment.c" />
<ClCompile Include="libzip\lib\zip_file_get_external_attributes.c" />
<ClCompile Include="libzip\lib\zip_file_get_offset.c" />
<ClCompile Include="libzip\lib\zip_file_rename.c" />
<ClCompile Include="libzip\lib\zip_file_replace.c" />
<ClCompile Include="libzip\lib\zip_file_set_comment.c" />
<ClCompile Include="libzip\lib\zip_file_set_encryption.c" />
<ClCompile Include="libzip\lib\zip_file_set_external_attributes.c" />
<ClCompile Include="libzip\lib\zip_file_set_mtime.c" />
<ClCompile Include="libzip\lib\zip_file_strerror.c" />
<ClCompile Include="libzip\lib\zip_fopen.c" />
<ClCompile Include="libzip\lib\zip_fopen_encrypted.c" />
<ClCompile Include="libzip\lib\zip_fopen_index.c" />
<ClCompile Include="libzip\lib\zip_fopen_index_encrypted.c" />
<ClCompile Include="libzip\lib\zip_fread.c" />
<ClCompile Include="libzip\lib\zip_fseek.c" />
<ClCompile Include="libzip\lib\zip_ftell.c" />
<ClCompile Include="libzip\lib\zip_get_archive_comment.c" />
<ClCompile Include="libzip\lib\zip_get_archive_flag.c" />
<ClCompile Include="libzip\lib\zip_get_encryption_implementation.c" />
<ClCompile Include="libzip\lib\zip_get_file_comment.c" />
<ClCompile Include="libzip\lib\zip_get_name.c" />
<ClCompile Include="libzip\lib\zip_get_num_entries.c" />
<ClCompile Include="libzip\lib\zip_get_num_files.c" />
<ClCompile Include="libzip\lib\zip_hash.c" />
<ClCompile Include="libzip\lib\zip_io_util.c" />
<ClCompile Include="libzip\lib\zip_libzip_version.c" />
<ClCompile Include="libzip\lib\zip_memdup.c" />
<ClCompile Include="libzip\lib\zip_name_locate.c" />
<ClCompile Include="libzip\lib\zip_new.c" />
<ClCompile Include="libzip\lib\zip_open.c" />
<ClCompile Include="libzip\lib\zip_pkware.c" />
<ClCompile Include="libzip\lib\zip_progress.c" />
<ClCompile Include="libzip\lib\zip_random_win32.c" />
<ClCompile Include="libzip\lib\zip_rename.c" />
<ClCompile Include="libzip\lib\zip_replace.c" />
<ClCompile Include="libzip\lib\zip_set_archive_comment.c" />
<ClCompile Include="libzip\lib\zip_set_archive_flag.c" />
<ClCompile Include="libzip\lib\zip_set_default_password.c" />
<ClCompile Include="libzip\lib\zip_set_file_comment.c" />
<ClCompile Include="libzip\lib\zip_set_file_compression.c" />
<ClCompile Include="libzip\lib\zip_set_name.c" />
<ClCompile Include="libzip\lib\zip_source_accept_empty.c" />
<ClCompile Include="libzip\lib\zip_source_begin_write.c" />
<ClCompile Include="libzip\lib\zip_source_begin_write_cloning.c" />
<ClCompile Include="libzip\lib\zip_source_buffer.c" />
<ClCompile Include="libzip\lib\zip_source_call.c" />
<ClCompile Include="libzip\lib\zip_source_close.c" />
<ClCompile Include="libzip\lib\zip_source_commit_write.c" />
<ClCompile Include="libzip\lib\zip_source_compress.c" />
<ClCompile Include="libzip\lib\zip_source_crc.c" />
<ClCompile Include="libzip\lib\zip_source_error.c" />
<ClCompile Include="libzip\lib\zip_source_file_common.c" />
<ClCompile Include="libzip\lib\zip_source_file_stdio.c" />
<ClCompile Include="libzip\lib\zip_source_file_win32.c" />
<ClCompile Include="libzip\lib\zip_source_file_win32_ansi.c" />
<ClCompile Include="libzip\lib\zip_source_file_win32_named.c" />
<ClCompile Include="libzip\lib\zip_source_file_win32_utf16.c" />
<ClCompile Include="libzip\lib\zip_source_file_win32_utf8.c" />
<ClCompile Include="libzip\lib\zip_source_free.c" />
<ClCompile Include="libzip\lib\zip_source_function.c" />
<ClCompile Include="libzip\lib\zip_source_get_file_attributes.c" />
<ClCompile Include="libzip\lib\zip_source_is_deleted.c" />
<ClCompile Include="libzip\lib\zip_source_layered.c" />
<ClCompile Include="libzip\lib\zip_source_open.c" />
<ClCompile Include="libzip\lib\zip_source_pkware_decode.c" />
<ClCompile Include="libzip\lib\zip_source_pkware_encode.c" />
<ClCompile Include="libzip\lib\zip_source_read.c" />
<ClCompile Include="libzip\lib\zip_source_remove.c" />
<ClCompile Include="libzip\lib\zip_source_rollback_write.c" />
<ClCompile Include="libzip\lib\zip_source_seek.c" />
<ClCompile Include="libzip\lib\zip_source_seek_write.c" />
<ClCompile Include="libzip\lib\zip_source_stat.c" />
<ClCompile Include="libzip\lib\zip_source_supports.c" />
<ClCompile Include="libzip\lib\zip_source_tell.c" />
<ClCompile Include="libzip\lib\zip_source_tell_write.c" />
<ClCompile Include="libzip\lib\zip_source_window.c" />
<ClCompile Include="libzip\lib\zip_source_winzip_aes_decode.c" />
<ClCompile Include="libzip\lib\zip_source_winzip_aes_encode.c" />
<ClCompile Include="libzip\lib\zip_source_write.c" />
<ClCompile Include="libzip\lib\zip_source_zip.c" />
<ClCompile Include="libzip\lib\zip_source_zip_new.c" />
<ClCompile Include="libzip\lib\zip_stat.c" />
<ClCompile Include="libzip\lib\zip_stat_index.c" />
<ClCompile Include="libzip\lib\zip_stat_init.c" />
<ClCompile Include="libzip\lib\zip_strerror.c" />
<ClCompile Include="libzip\lib\zip_string.c" />
<ClCompile Include="libzip\lib\zip_unchange.c" />
<ClCompile Include="libzip\lib\zip_unchange_all.c" />
<ClCompile Include="libzip\lib\zip_unchange_archive.c" />
<ClCompile Include="libzip\lib\zip_unchange_data.c" />
<ClCompile Include="libzip\lib\zip_utf-8.c" />
<ClCompile Include="libzip\lib\zip_winzip_aes.c" />
<ClCompile Include="private\zip_err_str.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="libzip\lib\compat.h" />
<ClInclude Include="libzip\lib\zip.h" />
<ClInclude Include="libzip\lib\zipint.h" />
<ClInclude Include="libzip\lib\zip_crypto.h" />
<ClInclude Include="libzip\lib\zip_crypto_win.h" />
<ClInclude Include="libzip\lib\zip_source_file.h" />
<ClInclude Include="libzip\lib\zip_source_file_stdio.h" />
<ClInclude Include="libzip\lib\zip_source_file_win32.h" />
<ClInclude Include="private\config.h" />
<ClInclude Include="zipconf.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\zstd\zstd.vcxproj">
<Project>{52244028-937a-44e9-a76b-2bea18fd239a}</Project>
</ProjectReference>
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>ZIP_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\zstd\zstd\lib;$(SolutionDir)3rdparty\zlib;$(ProjectDir)private;$(ProjectDir)libzip\lib;$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
+137
View File
@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="libzip\lib\zip_unchange_all.c" />
<ClCompile Include="libzip\lib\zip_unchange_archive.c" />
<ClCompile Include="libzip\lib\zip_unchange_data.c" />
<ClCompile Include="libzip\lib\zip_utf-8.c" />
<ClCompile Include="libzip\lib\zip_winzip_aes.c" />
<ClCompile Include="libzip\lib\zip_add.c" />
<ClCompile Include="libzip\lib\zip_add_dir.c" />
<ClCompile Include="libzip\lib\zip_add_entry.c" />
<ClCompile Include="libzip\lib\zip_algorithm_deflate.c" />
<ClCompile Include="libzip\lib\zip_buffer.c" />
<ClCompile Include="libzip\lib\zip_close.c" />
<ClCompile Include="libzip\lib\zip_crypto_win.c" />
<ClCompile Include="libzip\lib\zip_delete.c" />
<ClCompile Include="libzip\lib\zip_dir_add.c" />
<ClCompile Include="libzip\lib\zip_dirent.c" />
<ClCompile Include="libzip\lib\zip_discard.c" />
<ClCompile Include="libzip\lib\zip_entry.c" />
<ClCompile Include="libzip\lib\zip_error.c" />
<ClCompile Include="libzip\lib\zip_error_clear.c" />
<ClCompile Include="libzip\lib\zip_error_get.c" />
<ClCompile Include="libzip\lib\zip_error_get_sys_type.c" />
<ClCompile Include="libzip\lib\zip_error_strerror.c" />
<ClCompile Include="libzip\lib\zip_error_to_str.c" />
<ClCompile Include="libzip\lib\zip_extra_field.c" />
<ClCompile Include="libzip\lib\zip_extra_field_api.c" />
<ClCompile Include="libzip\lib\zip_fclose.c" />
<ClCompile Include="libzip\lib\zip_fdopen.c" />
<ClCompile Include="libzip\lib\zip_file_add.c" />
<ClCompile Include="libzip\lib\zip_file_error_clear.c" />
<ClCompile Include="libzip\lib\zip_file_error_get.c" />
<ClCompile Include="libzip\lib\zip_file_get_comment.c" />
<ClCompile Include="libzip\lib\zip_file_get_external_attributes.c" />
<ClCompile Include="libzip\lib\zip_file_get_offset.c" />
<ClCompile Include="libzip\lib\zip_file_rename.c" />
<ClCompile Include="libzip\lib\zip_file_replace.c" />
<ClCompile Include="libzip\lib\zip_file_set_comment.c" />
<ClCompile Include="libzip\lib\zip_file_set_encryption.c" />
<ClCompile Include="libzip\lib\zip_file_set_external_attributes.c" />
<ClCompile Include="libzip\lib\zip_file_set_mtime.c" />
<ClCompile Include="libzip\lib\zip_file_strerror.c" />
<ClCompile Include="libzip\lib\zip_fopen.c" />
<ClCompile Include="libzip\lib\zip_fopen_encrypted.c" />
<ClCompile Include="libzip\lib\zip_fopen_index.c" />
<ClCompile Include="libzip\lib\zip_fopen_index_encrypted.c" />
<ClCompile Include="libzip\lib\zip_fread.c" />
<ClCompile Include="libzip\lib\zip_fseek.c" />
<ClCompile Include="libzip\lib\zip_ftell.c" />
<ClCompile Include="libzip\lib\zip_get_archive_comment.c" />
<ClCompile Include="libzip\lib\zip_get_archive_flag.c" />
<ClCompile Include="libzip\lib\zip_get_encryption_implementation.c" />
<ClCompile Include="libzip\lib\zip_get_file_comment.c" />
<ClCompile Include="libzip\lib\zip_get_name.c" />
<ClCompile Include="libzip\lib\zip_get_num_entries.c" />
<ClCompile Include="libzip\lib\zip_get_num_files.c" />
<ClCompile Include="libzip\lib\zip_hash.c" />
<ClCompile Include="libzip\lib\zip_io_util.c" />
<ClCompile Include="libzip\lib\zip_libzip_version.c" />
<ClCompile Include="libzip\lib\zip_memdup.c" />
<ClCompile Include="libzip\lib\zip_name_locate.c" />
<ClCompile Include="libzip\lib\zip_new.c" />
<ClCompile Include="libzip\lib\zip_open.c" />
<ClCompile Include="libzip\lib\zip_pkware.c" />
<ClCompile Include="libzip\lib\zip_progress.c" />
<ClCompile Include="libzip\lib\zip_random_win32.c" />
<ClCompile Include="libzip\lib\zip_rename.c" />
<ClCompile Include="libzip\lib\zip_replace.c" />
<ClCompile Include="libzip\lib\zip_set_archive_comment.c" />
<ClCompile Include="libzip\lib\zip_set_archive_flag.c" />
<ClCompile Include="libzip\lib\zip_set_default_password.c" />
<ClCompile Include="libzip\lib\zip_set_file_comment.c" />
<ClCompile Include="libzip\lib\zip_set_file_compression.c" />
<ClCompile Include="libzip\lib\zip_set_name.c" />
<ClCompile Include="libzip\lib\zip_source_accept_empty.c" />
<ClCompile Include="libzip\lib\zip_source_begin_write.c" />
<ClCompile Include="libzip\lib\zip_source_begin_write_cloning.c" />
<ClCompile Include="libzip\lib\zip_source_buffer.c" />
<ClCompile Include="libzip\lib\zip_source_call.c" />
<ClCompile Include="libzip\lib\zip_source_close.c" />
<ClCompile Include="libzip\lib\zip_source_commit_write.c" />
<ClCompile Include="libzip\lib\zip_source_compress.c" />
<ClCompile Include="libzip\lib\zip_source_crc.c" />
<ClCompile Include="libzip\lib\zip_source_error.c" />
<ClCompile Include="libzip\lib\zip_source_file_common.c" />
<ClCompile Include="libzip\lib\zip_source_file_stdio.c" />
<ClCompile Include="libzip\lib\zip_source_file_win32.c" />
<ClCompile Include="libzip\lib\zip_source_file_win32_ansi.c" />
<ClCompile Include="libzip\lib\zip_source_file_win32_named.c" />
<ClCompile Include="libzip\lib\zip_source_file_win32_utf8.c" />
<ClCompile Include="libzip\lib\zip_source_file_win32_utf16.c" />
<ClCompile Include="libzip\lib\zip_source_free.c" />
<ClCompile Include="libzip\lib\zip_source_function.c" />
<ClCompile Include="libzip\lib\zip_source_get_file_attributes.c" />
<ClCompile Include="libzip\lib\zip_source_is_deleted.c" />
<ClCompile Include="libzip\lib\zip_source_layered.c" />
<ClCompile Include="libzip\lib\zip_source_open.c" />
<ClCompile Include="libzip\lib\zip_source_pkware_decode.c" />
<ClCompile Include="libzip\lib\zip_source_pkware_encode.c" />
<ClCompile Include="libzip\lib\zip_source_read.c" />
<ClCompile Include="libzip\lib\zip_source_remove.c" />
<ClCompile Include="libzip\lib\zip_source_rollback_write.c" />
<ClCompile Include="libzip\lib\zip_source_seek.c" />
<ClCompile Include="libzip\lib\zip_source_seek_write.c" />
<ClCompile Include="libzip\lib\zip_source_stat.c" />
<ClCompile Include="libzip\lib\zip_source_supports.c" />
<ClCompile Include="libzip\lib\zip_source_tell.c" />
<ClCompile Include="libzip\lib\zip_source_tell_write.c" />
<ClCompile Include="libzip\lib\zip_source_window.c" />
<ClCompile Include="libzip\lib\zip_source_winzip_aes_decode.c" />
<ClCompile Include="libzip\lib\zip_source_winzip_aes_encode.c" />
<ClCompile Include="libzip\lib\zip_source_write.c" />
<ClCompile Include="libzip\lib\zip_source_zip.c" />
<ClCompile Include="libzip\lib\zip_source_zip_new.c" />
<ClCompile Include="libzip\lib\zip_stat.c" />
<ClCompile Include="libzip\lib\zip_stat_index.c" />
<ClCompile Include="libzip\lib\zip_stat_init.c" />
<ClCompile Include="libzip\lib\zip_strerror.c" />
<ClCompile Include="libzip\lib\zip_string.c" />
<ClCompile Include="libzip\lib\zip_unchange.c" />
<ClCompile Include="private\zip_err_str.c" />
<ClCompile Include="libzip\lib\zip_algorithm_zstd.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="libzip\lib\zipint.h" />
<ClInclude Include="libzip\lib\compat.h" />
<ClInclude Include="libzip\lib\zip.h" />
<ClInclude Include="libzip\lib\zip_crypto.h" />
<ClInclude Include="libzip\lib\zip_crypto_win.h" />
<ClInclude Include="libzip\lib\zip_source_file.h" />
<ClInclude Include="libzip\lib\zip_source_file_stdio.h" />
<ClInclude Include="libzip\lib\zip_source_file_win32.h" />
<ClInclude Include="private\config.h" />
<ClInclude Include="zipconf.h" />
</ItemGroup>
</Project>
+64
View File
@@ -0,0 +1,64 @@
#ifndef HAD_CONFIG_H
#define HAD_CONFIG_H
#ifndef _HAD_ZIPCONF_H
#include "zipconf.h"
#endif
/* BEGIN DEFINES */
/* #undef HAVE___PROGNAME */
#define HAVE__CLOSE
#define HAVE__DUP
#define HAVE__FDOPEN
#define HAVE__FILENO
#define HAVE__SETMODE
#define HAVE__SNPRINTF
#define HAVE__STRDUP
#define HAVE__STRICMP
#define HAVE__STRTOI64
#define HAVE__STRTOUI64
/* #undef HAVE__UMASK */
#define HAVE__UNLINK
/* #undef HAVE_ARC4RANDOM */
/* #undef HAVE_CLONEFILE */
/* #undef HAVE_COMMONCRYPTO */
#define HAVE_CRYPTO
/* #undef HAVE_FICLONERANGE */
#define HAVE_FILENO
/* #undef HAVE_FCHMOD */
/* #undef HAVE_FSEEKO */
/* #undef HAVE_FTELLO */
/* #undef HAVE_GETPROGNAME */
/* #undef HAVE_GNUTLS */
/* #undef HAVE_LIBBZ2 */
/* #undef HAVE_LIBLZMA */
#define HAVE_LIBZSTD
/* #undef HAVE_LOCALTIME_R */
/* #undef HAVE_MBEDTLS */
/* #undef HAVE_MKSTEMP */
/* #undef HAVE_NULLABLE */
/* #undef HAVE_OPENSSL */
#define HAVE_SETMODE
#define HAVE_SNPRINTF
/* #undef HAVE_STRCASECMP */
#define HAVE_STRDUP
#define HAVE_STRICMP
#define HAVE_STRTOLL
#define HAVE_STRTOULL
/* #undef HAVE_STRUCT_TM_TM_ZONE */
#define HAVE_STDBOOL_H
/* #undef HAVE_STRINGS_H */
/* #undef HAVE_UNISTD_H */
#define HAVE_WINDOWS_CRYPTO
#define SIZEOF_OFF_T 4
#define SIZEOF_SIZE_T 8
/* #undef HAVE_DIRENT_H */
/* #undef HAVE_FTS_H */
/* #undef HAVE_NDIR_H */
/* #undef HAVE_SYS_DIR_H */
/* #undef HAVE_SYS_NDIR_H */
/* #undef WORDS_BIGENDIAN */
#define HAVE_SHARED
/* END DEFINES */
#define PACKAGE "libzip"
#define VERSION "1.8.0"
#endif /* HAD_CONFIG_H */
+77
View File
@@ -0,0 +1,77 @@
/*
This file was generated automatically by CMake
from zip.h and zipint.h; make changes there.
*/
#include "zipint.h"
#define L ZIP_ET_LIBZIP
#define N ZIP_ET_NONE
#define S ZIP_ET_SYS
#define Z ZIP_ET_ZLIB
#define E ZIP_DETAIL_ET_ENTRY
#define G ZIP_DETAIL_ET_GLOBAL
const struct _zip_err_info _zip_err_str[] = {
{ N, "No error" },
{ N, "Multi-disk zip archives not supported" },
{ S, "Renaming temporary file failed" },
{ S, "Closing zip archive failed" },
{ S, "Seek error" },
{ S, "Read error" },
{ S, "Write error" },
{ N, "CRC error" },
{ N, "Containing zip archive was closed" },
{ N, "No such file" },
{ N, "File already exists" },
{ S, "Can't open file" },
{ S, "Failure to create temporary file" },
{ Z, "Zlib error" },
{ N, "Malloc failure" },
{ N, "Entry has been changed" },
{ N, "Compression method not supported" },
{ N, "Premature end of file" },
{ N, "Invalid argument" },
{ N, "Not a zip archive" },
{ N, "Internal error" },
{ L, "Zip archive inconsistent" },
{ S, "Can't remove file" },
{ N, "Entry has been deleted" },
{ N, "Encryption method not supported" },
{ N, "Read-only archive" },
{ N, "No password provided" },
{ N, "Wrong password provided" },
{ N, "Operation not supported" },
{ N, "Resource still in use" },
{ S, "Tell error" },
{ N, "Compressed data invalid" },
{ N, "Operation cancelled" },
};
const int _zip_err_str_count = sizeof(_zip_err_str)/sizeof(_zip_err_str[0]);
const struct _zip_err_info _zip_err_details[] = {
{ G, "no detail" },
{ G, "central directory overlaps EOCD, or there is space between them" },
{ G, "archive comment length incorrect" },
{ G, "central directory length invalid" },
{ E, "central header invalid" },
{ G, "central directory count of entries is incorrect" },
{ E, "local and central headers do not match" },
{ G, "wrong EOCD length" },
{ G, "EOCD64 overlaps EOCD, or there is space between them" },
{ G, "EOCD64 magic incorrect" },
{ G, "EOCD64 and EOCD do not match" },
{ G, "invalid value in central directory" },
{ E, "variable size fields overflow header" },
{ E, "invalid UTF-8 in filename" },
{ E, "invalid UTF-8 in comment" },
{ E, "invalid Zip64 extra field" },
{ E, "invalid WinZip AES extra field" },
{ E, "garbage at end of extra fields" },
{ E, "extra field length is invalid" },
{ E, "file length in header doesn't match actual file length" },
};
const int _zip_err_details_count = sizeof(_zip_err_details)/sizeof(_zip_err_details[0]);
+51
View File
@@ -0,0 +1,51 @@
#ifndef _HAD_ZIPCONF_H
#define _HAD_ZIPCONF_H
/*
zipconf.h -- platform specific include file
This file was generated automatically by CMake
based on ../cmake-zipconf.h.in.
*/
#define LIBZIP_VERSION "1.8.0"
#define LIBZIP_VERSION_MAJOR 1
#define LIBZIP_VERSION_MINOR 8
#define LIBZIP_VERSION_MICRO 0
/* #undef ZIP_STATIC */
#define _Nullable
#define _Nonnull
#if !defined(__STDC_FORMAT_MACROS)
#define __STDC_FORMAT_MACROS 1
#endif
#include <inttypes.h>
typedef int8_t zip_int8_t;
typedef uint8_t zip_uint8_t;
typedef int16_t zip_int16_t;
typedef uint16_t zip_uint16_t;
typedef int32_t zip_int32_t;
typedef uint32_t zip_uint32_t;
typedef int64_t zip_int64_t;
typedef uint64_t zip_uint64_t;
#define ZIP_INT8_MIN (-ZIP_INT8_MAX-1)
#define ZIP_INT8_MAX 0x7f
#define ZIP_UINT8_MAX 0xff
#define ZIP_INT16_MIN (-ZIP_INT16_MAX-1)
#define ZIP_INT16_MAX 0x7fff
#define ZIP_UINT16_MAX 0xffff
#define ZIP_INT32_MIN (-ZIP_INT32_MAX-1L)
#define ZIP_INT32_MAX 0x7fffffffL
#define ZIP_UINT32_MAX 0xffffffffLU
#define ZIP_INT64_MIN (-ZIP_INT64_MAX-1LL)
#define ZIP_INT64_MAX 0x7fffffffffffffffLL
#define ZIP_UINT64_MAX 0xffffffffffffffffULL
#endif /* zipconf.h */
+2
View File
@@ -195,6 +195,7 @@
<ClInclude Include="SDL\src\SDL_error_c.h" />
<ClInclude Include="SDL\src\SDL_hints_c.h" />
<ClInclude Include="SDL\src\SDL_internal.h" />
<ClInclude Include="SDL\src\SDL_list.h" />
<ClInclude Include="SDL\src\sensor\dummy\SDL_dummysensor.h" />
<ClInclude Include="SDL\src\sensor\SDL_sensor_c.h" />
<ClInclude Include="SDL\src\sensor\SDL_syssensor.h" />
@@ -350,6 +351,7 @@
<ClCompile Include="SDL\src\SDL_dataqueue.c" />
<ClCompile Include="SDL\src\SDL_error.c" />
<ClCompile Include="SDL\src\SDL_hints.c" />
<ClCompile Include="SDL\src\SDL_list.c" />
<ClCompile Include="SDL\src\SDL_log.c" />
<ClCompile Include="SDL\src\sensor\dummy\SDL_dummysensor.c" />
<ClCompile Include="SDL\src\sensor\SDL_sensor.c" />
+2
View File
@@ -756,6 +756,7 @@
<ClInclude Include="SDL\src\SDL_hints_c.h" />
<ClInclude Include="SDL\src\SDL_internal.h" />
<ClInclude Include="SDL\src\hidapi\SDL_hidapi_c.h" />
<ClInclude Include="SDL\src\SDL_list.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="SDL\src\audio\wasapi\SDL_wasapi.c" />
@@ -1245,5 +1246,6 @@
<ClCompile Include="SDL\src\power\windows\SDL_syspower.c">
<Filter>power\windows</Filter>
</ClCompile>
<ClCompile Include="SDL\src\SDL_list.c" />
</ItemGroup>
</Project>
+2 -1
View File
@@ -466,7 +466,8 @@ WX_STRCMP_FUNC(wxStricmp, wxCRT_StricmpA, wxCRT_StricmpW, wxStricmp_String)
// forward-declare the template and implement it below WX_STRCMP_FUNC. OTOH,
// this fails to compile with VC6, so don't do it for VC. It also causes
// problems with GCC visibility in newer GCC versions.
#if !(defined(__VISUALC__) || (wxCHECK_GCC_VERSION(3,5) && !wxCHECK_GCC_VERSION(4,7))) || defined(__clang__)
// PCSX2: MSVC in conformance mode also requires declaration before use.
#if (wxCHECK_GCC_VERSION(3,5) && !wxCHECK_GCC_VERSION(4,7)) || defined(__clang__) || defined(__VISUALC__)
#define wxNEEDS_DECL_BEFORE_TEMPLATE
#endif
+37
View File
@@ -0,0 +1,37 @@
enable_language(C ASM)
add_library(pcsx2-zstd
zstd/lib/common/debug.c
zstd/lib/common/entropy_common.c
zstd/lib/common/error_private.c
zstd/lib/common/fse_decompress.c
zstd/lib/common/pool.c
zstd/lib/common/threading.c
zstd/lib/common/xxhash.c
zstd/lib/common/zstd_common.c
zstd/lib/compress/fse_compress.c
zstd/lib/compress/hist.c
zstd/lib/compress/huf_compress.c
zstd/lib/compress/zstd_compress.c
zstd/lib/compress/zstd_compress_literals.c
zstd/lib/compress/zstd_compress_sequences.c
zstd/lib/compress/zstd_compress_superblock.c
zstd/lib/compress/zstd_double_fast.c
zstd/lib/compress/zstd_fast.c
zstd/lib/compress/zstd_lazy.c
zstd/lib/compress/zstd_ldm.c
zstd/lib/compress/zstdmt_compress.c
zstd/lib/compress/zstd_opt.c
zstd/lib/decompress/huf_decompress.c
zstd/lib/decompress/zstd_ddict.c
zstd/lib/decompress/zstd_decompress_block.c
zstd/lib/decompress/zstd_decompress.c
)
if(NOT MSVC AND ${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
target_sources(pcsx2-zstd PRIVATE zstd/lib/decompress/huf_decompress_amd64.S)
endif()
target_include_directories(pcsx2-zstd PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/zstd/lib")
add_library(Zstd::Zstd ALIAS pcsx2-zstd)
Vendored Submodule
+1
Submodule 3rdparty/zstd/zstd added at e47e674cd0
+104
View File
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)common\vsprops\BaseProjectConfig.props" />
<Import Project="$(SolutionDir)common\vsprops\WinSDK.props" />
<PropertyGroup Label="Globals">
<ProjectGuid>{52244028-937A-44E9-A76B-2BEA18FD239A}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization Condition="$(Configuration.Contains(Release))">true</WholeProgramOptimization>
<UseDebugLibraries Condition="$(Configuration.Contains(Debug))">true</UseDebugLibraries>
<UseDebugLibraries Condition="!$(Configuration.Contains(Debug))">false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings" />
<ImportGroup Label="PropertySheets">
<Import Project="..\DefaultProjectRootDir.props" />
<Import Project="..\3rdparty.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="..\..\common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="..\..\common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="..\..\common\vsprops\CodeGen_Release.props" />
<Import Condition="!$(Configuration.Contains(Release))" Project="..\..\common\vsprops\IncrementalLinking.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<ClInclude Include="zstd\lib\common\bitstream.h" />
<ClInclude Include="zstd\lib\common\compiler.h" />
<ClInclude Include="zstd\lib\common\cpu.h" />
<ClInclude Include="zstd\lib\common\debug.h" />
<ClInclude Include="zstd\lib\common\error_private.h" />
<ClInclude Include="zstd\lib\common\fse.h" />
<ClInclude Include="zstd\lib\common\huf.h" />
<ClInclude Include="zstd\lib\common\mem.h" />
<ClInclude Include="zstd\lib\common\pool.h" />
<ClInclude Include="zstd\lib\common\portability_macros.h" />
<ClInclude Include="zstd\lib\common\threading.h" />
<ClInclude Include="zstd\lib\common\xxhash.h" />
<ClInclude Include="zstd\lib\common\zstd_deps.h" />
<ClInclude Include="zstd\lib\common\zstd_internal.h" />
<ClInclude Include="zstd\lib\common\zstd_trace.h" />
<ClInclude Include="zstd\lib\compress\clevels.h" />
<ClInclude Include="zstd\lib\compress\hist.h" />
<ClInclude Include="zstd\lib\compress\zstdmt_compress.h" />
<ClInclude Include="zstd\lib\compress\zstd_compress_internal.h" />
<ClInclude Include="zstd\lib\compress\zstd_compress_literals.h" />
<ClInclude Include="zstd\lib\compress\zstd_compress_sequences.h" />
<ClInclude Include="zstd\lib\compress\zstd_compress_superblock.h" />
<ClInclude Include="zstd\lib\compress\zstd_cwksp.h" />
<ClInclude Include="zstd\lib\compress\zstd_double_fast.h" />
<ClInclude Include="zstd\lib\compress\zstd_fast.h" />
<ClInclude Include="zstd\lib\compress\zstd_lazy.h" />
<ClInclude Include="zstd\lib\compress\zstd_ldm.h" />
<ClInclude Include="zstd\lib\compress\zstd_ldm_geartab.h" />
<ClInclude Include="zstd\lib\compress\zstd_opt.h" />
<ClInclude Include="zstd\lib\decompress\zstd_ddict.h" />
<ClInclude Include="zstd\lib\decompress\zstd_decompress_block.h" />
<ClInclude Include="zstd\lib\decompress\zstd_decompress_internal.h" />
<ClInclude Include="zstd\lib\zdict.h" />
<ClInclude Include="zstd\lib\zstd.h" />
<ClInclude Include="zstd\lib\zstd_errors.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="zstd\lib\common\debug.c" />
<ClCompile Include="zstd\lib\common\entropy_common.c" />
<ClCompile Include="zstd\lib\common\error_private.c" />
<ClCompile Include="zstd\lib\common\fse_decompress.c" />
<ClCompile Include="zstd\lib\common\pool.c" />
<ClCompile Include="zstd\lib\common\threading.c" />
<ClCompile Include="zstd\lib\common\xxhash.c" />
<ClCompile Include="zstd\lib\common\zstd_common.c" />
<ClCompile Include="zstd\lib\compress\fse_compress.c" />
<ClCompile Include="zstd\lib\compress\hist.c" />
<ClCompile Include="zstd\lib\compress\huf_compress.c" />
<ClCompile Include="zstd\lib\compress\zstdmt_compress.c" />
<ClCompile Include="zstd\lib\compress\zstd_compress.c" />
<ClCompile Include="zstd\lib\compress\zstd_compress_literals.c" />
<ClCompile Include="zstd\lib\compress\zstd_compress_sequences.c" />
<ClCompile Include="zstd\lib\compress\zstd_compress_superblock.c" />
<ClCompile Include="zstd\lib\compress\zstd_double_fast.c" />
<ClCompile Include="zstd\lib\compress\zstd_fast.c" />
<ClCompile Include="zstd\lib\compress\zstd_lazy.c" />
<ClCompile Include="zstd\lib\compress\zstd_ldm.c" />
<ClCompile Include="zstd\lib\compress\zstd_opt.c" />
<ClCompile Include="zstd\lib\decompress\huf_decompress.c" />
<ClCompile Include="zstd\lib\decompress\zstd_ddict.c" />
<ClCompile Include="zstd\lib\decompress\zstd_decompress.c" />
<ClCompile Include="zstd\lib\decompress\zstd_decompress_block.c" />
</ItemGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\zstd\zstd\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
+67
View File
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClInclude Include="zstd\lib\zdict.h" />
<ClInclude Include="zstd\lib\zstd.h" />
<ClInclude Include="zstd\lib\zstd_errors.h" />
<ClInclude Include="zstd\lib\common\pool.h" />
<ClInclude Include="zstd\lib\common\portability_macros.h" />
<ClInclude Include="zstd\lib\common\threading.h" />
<ClInclude Include="zstd\lib\common\xxhash.h" />
<ClInclude Include="zstd\lib\common\zstd_deps.h" />
<ClInclude Include="zstd\lib\common\zstd_internal.h" />
<ClInclude Include="zstd\lib\common\zstd_trace.h" />
<ClInclude Include="zstd\lib\common\bitstream.h" />
<ClInclude Include="zstd\lib\common\compiler.h" />
<ClInclude Include="zstd\lib\common\cpu.h" />
<ClInclude Include="zstd\lib\common\debug.h" />
<ClInclude Include="zstd\lib\common\error_private.h" />
<ClInclude Include="zstd\lib\common\fse.h" />
<ClInclude Include="zstd\lib\common\huf.h" />
<ClInclude Include="zstd\lib\common\mem.h" />
<ClInclude Include="zstd\lib\compress\zstd_compress_internal.h" />
<ClInclude Include="zstd\lib\compress\zstd_compress_literals.h" />
<ClInclude Include="zstd\lib\compress\zstd_compress_sequences.h" />
<ClInclude Include="zstd\lib\compress\zstd_compress_superblock.h" />
<ClInclude Include="zstd\lib\compress\zstd_cwksp.h" />
<ClInclude Include="zstd\lib\compress\zstd_double_fast.h" />
<ClInclude Include="zstd\lib\compress\zstd_fast.h" />
<ClInclude Include="zstd\lib\compress\zstd_lazy.h" />
<ClInclude Include="zstd\lib\compress\zstd_ldm.h" />
<ClInclude Include="zstd\lib\compress\zstd_ldm_geartab.h" />
<ClInclude Include="zstd\lib\compress\zstd_opt.h" />
<ClInclude Include="zstd\lib\compress\zstdmt_compress.h" />
<ClInclude Include="zstd\lib\compress\clevels.h" />
<ClInclude Include="zstd\lib\compress\hist.h" />
<ClInclude Include="zstd\lib\decompress\zstd_ddict.h" />
<ClInclude Include="zstd\lib\decompress\zstd_decompress_block.h" />
<ClInclude Include="zstd\lib\decompress\zstd_decompress_internal.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="zstd\lib\common\pool.c" />
<ClCompile Include="zstd\lib\common\threading.c" />
<ClCompile Include="zstd\lib\common\xxhash.c" />
<ClCompile Include="zstd\lib\common\zstd_common.c" />
<ClCompile Include="zstd\lib\common\debug.c" />
<ClCompile Include="zstd\lib\common\entropy_common.c" />
<ClCompile Include="zstd\lib\common\error_private.c" />
<ClCompile Include="zstd\lib\common\fse_decompress.c" />
<ClCompile Include="zstd\lib\compress\zstd_compress_literals.c" />
<ClCompile Include="zstd\lib\compress\zstd_compress_sequences.c" />
<ClCompile Include="zstd\lib\compress\zstd_compress_superblock.c" />
<ClCompile Include="zstd\lib\compress\zstd_double_fast.c" />
<ClCompile Include="zstd\lib\compress\zstd_fast.c" />
<ClCompile Include="zstd\lib\compress\zstd_lazy.c" />
<ClCompile Include="zstd\lib\compress\zstd_ldm.c" />
<ClCompile Include="zstd\lib\compress\zstd_opt.c" />
<ClCompile Include="zstd\lib\compress\zstdmt_compress.c" />
<ClCompile Include="zstd\lib\compress\fse_compress.c" />
<ClCompile Include="zstd\lib\compress\hist.c" />
<ClCompile Include="zstd\lib\compress\huf_compress.c" />
<ClCompile Include="zstd\lib\compress\zstd_compress.c" />
<ClCompile Include="zstd\lib\decompress\huf_decompress.c" />
<ClCompile Include="zstd\lib\decompress\zstd_ddict.c" />
<ClCompile Include="zstd\lib\decompress\zstd_decompress.c" />
<ClCompile Include="zstd\lib\decompress\zstd_decompress_block.c" />
</ItemGroup>
</Project>
+57 -27
View File
@@ -26,8 +26,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wx30_base", "3rdparty\wxwid
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpng", "3rdparty\libpng\projects\vstudio\libpng\libpng.vcxproj", "{D6973076-9317-4EF2-A0B8-B7A18AC0713E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pthreads4w", "3rdparty\pthreads4w\build\pthreads4w.vcxproj", "{0FAE817D-9A32-4830-857E-81DA57246E16}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "baseclasses", "3rdparty\baseclasses\baseclasses.vcxproj", "{27F17499-A372-4408-8AFA-4F9F4584FBD3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liblzma", "3rdparty\xz\liblzma.vcxproj", "{12728250-16EC-4DC6-94D7-E21DD88947F8}"
@@ -58,6 +56,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang", "3rdparty\glslang
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL", "3rdparty\sdl2\SDL.vcxproj", "{812B4434-FD6B-4CB2-8865-5FD8EB34B046}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzip", "3rdparty\libzip\libzip.vcxproj", "{20B2E9FE-F020-42A0-B324-956F5B06EA68}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zstd", "3rdparty\zstd\zstd.vcxproj", "{52244028-937A-44E9-A76B-2BEA18FD239A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "d3d12memalloc", "3rdparty\d3d12memalloc\d3d12memalloc.vcxproj", "{D45CEC7A-3171-40DD-975D-E1544CF16139}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug AVX2|x64 = Debug AVX2|x64
@@ -68,6 +72,18 @@ Global
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug AVX2|x64.ActiveCfg = Debug AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug AVX2|x64.Build.0 = Debug AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug|x64.ActiveCfg = Debug|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug|x64.Build.0 = Debug|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel AVX2|x64.ActiveCfg = Devel AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel AVX2|x64.Build.0 = Devel AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel|x64.ActiveCfg = Devel|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel|x64.Build.0 = Devel|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release AVX2|x64.ActiveCfg = Release AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release AVX2|x64.Build.0 = Release AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release|x64.ActiveCfg = Release|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release|x64.Build.0 = Release|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug AVX2|x64.ActiveCfg = Debug|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug AVX2|x64.Build.0 = Debug|x64
{E9B51944-7E6D-4BCD-83F2-7BBD5A46182D}.Debug|x64.ActiveCfg = Debug|x64
@@ -152,18 +168,6 @@ Global
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release AVX2|x64.Build.0 = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.Build.0 = Release|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug AVX2|x64.ActiveCfg = Debug|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug AVX2|x64.Build.0 = Debug|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug|x64.ActiveCfg = Debug|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Debug|x64.Build.0 = Debug|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel AVX2|x64.ActiveCfg = Devel|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel AVX2|x64.Build.0 = Devel|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel|x64.ActiveCfg = Devel|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Devel|x64.Build.0 = Devel|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release AVX2|x64.ActiveCfg = Release|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release AVX2|x64.Build.0 = Release|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release|x64.ActiveCfg = Release|x64
{0FAE817D-9A32-4830-857E-81DA57246E16}.Release|x64.Build.0 = Release|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug AVX2|x64.ActiveCfg = Debug|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug AVX2|x64.Build.0 = Debug|x64
{27F17499-A372-4408-8AFA-4F9F4584FBD3}.Debug|x64.ActiveCfg = Debug|x64
@@ -284,18 +288,6 @@ Global
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release AVX2|x64.Build.0 = Release|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release|x64.ActiveCfg = Release|x64
{88FB34EC-845E-4F21-A552-F1573B9ED167}.Release|x64.Build.0 = Release|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug AVX2|x64.ActiveCfg = Debug AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug AVX2|x64.Build.0 = Debug AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug|x64.ActiveCfg = Debug|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Debug|x64.Build.0 = Debug|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel AVX2|x64.ActiveCfg = Devel AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel AVX2|x64.Build.0 = Devel AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel|x64.ActiveCfg = Devel|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Devel|x64.Build.0 = Devel|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release AVX2|x64.ActiveCfg = Release AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release AVX2|x64.Build.0 = Release AVX2|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release|x64.ActiveCfg = Release|x64
{2A016F21-87AE-4154-8271-1F57E91408E9}.Release|x64.Build.0 = Release|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|x64.ActiveCfg = Debug|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug AVX2|x64.Build.0 = Debug|x64
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266}.Debug|x64.ActiveCfg = Debug|x64
@@ -356,6 +348,42 @@ Global
{812B4434-FD6B-4CB2-8865-5FD8EB34B046}.Release AVX2|x64.Build.0 = Release|x64
{812B4434-FD6B-4CB2-8865-5FD8EB34B046}.Release|x64.ActiveCfg = Release|x64
{812B4434-FD6B-4CB2-8865-5FD8EB34B046}.Release|x64.Build.0 = Release|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug AVX2|x64.ActiveCfg = Debug|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug AVX2|x64.Build.0 = Debug|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug|x64.ActiveCfg = Debug|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug|x64.Build.0 = Debug|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Devel AVX2|x64.ActiveCfg = Devel|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Devel AVX2|x64.Build.0 = Devel|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Devel|x64.ActiveCfg = Devel|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Devel|x64.Build.0 = Devel|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Release AVX2|x64.ActiveCfg = Release|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Release AVX2|x64.Build.0 = Release|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Release|x64.ActiveCfg = Release|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Release|x64.Build.0 = Release|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Debug AVX2|x64.ActiveCfg = Debug|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Debug AVX2|x64.Build.0 = Debug|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Debug|x64.ActiveCfg = Debug|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Debug|x64.Build.0 = Debug|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Devel AVX2|x64.ActiveCfg = Devel|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Devel AVX2|x64.Build.0 = Devel|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Devel|x64.ActiveCfg = Devel|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Devel|x64.Build.0 = Devel|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Release AVX2|x64.ActiveCfg = Release|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Release AVX2|x64.Build.0 = Release|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Release|x64.ActiveCfg = Release|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Release|x64.Build.0 = Release|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Debug AVX2|x64.ActiveCfg = Debug|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Debug AVX2|x64.Build.0 = Debug|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Debug|x64.ActiveCfg = Debug|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Debug|x64.Build.0 = Debug|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Devel AVX2|x64.ActiveCfg = Devel|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Devel AVX2|x64.Build.0 = Devel|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Devel|x64.ActiveCfg = Devel|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Devel|x64.Build.0 = Devel|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Release AVX2|x64.ActiveCfg = Release|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Release AVX2|x64.Build.0 = Release|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Release|x64.ActiveCfg = Release|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -368,7 +396,6 @@ Global
{01F4CE10-2CFB-41A8-B41F-E54337868A1D} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{0FAE817D-9A32-4830-857E-81DA57246E16} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{27F17499-A372-4408-8AFA-4F9F4584FBD3} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{12728250-16EC-4DC6-94D7-E21DD88947F8} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{449AD25E-424A-4714-BABC-68706CDCC33B} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
@@ -382,6 +409,9 @@ Global
{DE9653B6-17DD-356A-9EE0-28A731772587} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{EF6834A9-11F3-4331-BC34-21B325ABB180} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{812B4434-FD6B-4CB2-8865-5FD8EB34B046} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{20B2E9FE-F020-42A0-B324-956F5B06EA68} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{52244028-937A-44E9-A76B-2BEA18FD239A} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{D45CEC7A-3171-40DD-975D-E1544CF16139} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0BC474EA-3628-45D3-9DBC-E22D0B7E0F77}
+45 -1
View File
@@ -1,4 +1,3 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31606.5
@@ -63,6 +62,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imgui", "3rdparty\imgui\img
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang", "3rdparty\glslang\glslang.vcxproj", "{EF6834A9-11F3-4331-BC34-21B325ABB180}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libzip", "3rdparty\libzip\libzip.vcxproj", "{20B2E9FE-F020-42A0-B324-956F5B06EA68}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zstd", "3rdparty\zstd\zstd.vcxproj", "{52244028-937A-44E9-A76B-2BEA18FD239A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "d3d12memalloc", "3rdparty\d3d12memalloc\d3d12memalloc.vcxproj", "{D45CEC7A-3171-40DD-975D-E1544CF16139}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug AVX2|x64 = Debug AVX2|x64
@@ -361,6 +366,42 @@ Global
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release AVX2|x64.Build.0 = Release|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release|x64.ActiveCfg = Release|x64
{EF6834A9-11F3-4331-BC34-21B325ABB180}.Release|x64.Build.0 = Release|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug AVX2|x64.ActiveCfg = Debug|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug AVX2|x64.Build.0 = Debug|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug|x64.ActiveCfg = Debug|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Debug|x64.Build.0 = Debug|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Devel AVX2|x64.ActiveCfg = Devel|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Devel AVX2|x64.Build.0 = Devel|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Devel|x64.ActiveCfg = Devel|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Devel|x64.Build.0 = Devel|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Release AVX2|x64.ActiveCfg = Release|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Release AVX2|x64.Build.0 = Release|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Release|x64.ActiveCfg = Release|x64
{20B2E9FE-F020-42A0-B324-956F5B06EA68}.Release|x64.Build.0 = Release|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Debug AVX2|x64.ActiveCfg = Debug|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Debug AVX2|x64.Build.0 = Debug|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Debug|x64.ActiveCfg = Debug|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Debug|x64.Build.0 = Debug|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Devel AVX2|x64.ActiveCfg = Devel|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Devel AVX2|x64.Build.0 = Devel|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Devel|x64.ActiveCfg = Devel|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Devel|x64.Build.0 = Devel|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Release AVX2|x64.ActiveCfg = Release|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Release AVX2|x64.Build.0 = Release|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Release|x64.ActiveCfg = Release|x64
{52244028-937A-44E9-A76B-2BEA18FD239A}.Release|x64.Build.0 = Release|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Debug AVX2|x64.ActiveCfg = Debug|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Debug AVX2|x64.Build.0 = Debug|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Debug|x64.ActiveCfg = Debug|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Debug|x64.Build.0 = Debug|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Devel AVX2|x64.ActiveCfg = Devel|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Devel AVX2|x64.Build.0 = Devel|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Devel|x64.ActiveCfg = Devel|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Devel|x64.Build.0 = Devel|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Release AVX2|x64.ActiveCfg = Release|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Release AVX2|x64.Build.0 = Release|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Release|x64.ActiveCfg = Release|x64
{D45CEC7A-3171-40DD-975D-E1544CF16139}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -388,6 +429,9 @@ Global
{1EC8B3C0-8FB3-46DE-A2E0-A9121203F266} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{88FB34EC-845E-4F21-A552-F1573B9ED167} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{EF6834A9-11F3-4331-BC34-21B325ABB180} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{20B2E9FE-F020-42A0-B324-956F5B06EA68} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{52244028-937A-44E9-A76B-2BEA18FD239A} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
{D45CEC7A-3171-40DD-975D-E1544CF16139} = {78EBE642-7A4D-4EA7-86BE-5639C6646C38}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0BC474EA-3628-45D3-9DBC-E22D0B7E0F77}
+2 -6
View File
@@ -31,7 +31,7 @@ _Note: Recommended Single Thread Performance is based on moderately complex game
| Operating System | CPU | GPU | RAM |
| ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
| - Windows 10 (64 bit) <br/> - Ubuntu 19.04/Debian or newer, Arch Linux, or other distro (64 bit) | - Supports AVX2 <br/> - [PassMark Single Thread Performance](https://www.cpubenchmark.net/singleThread.html) rating near or greater than 2100 <br/> - Four physical cores, with or without hyperthreading | - Direct3D11 support <br/> - OpenGL 4.5 support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 6000 (GeForce GTX 1050 Ti) <br/> - 4 GB Video Memory | 8 GB |
| - Windows 10 (64 bit) <br/> - Ubuntu 19.04/Debian or newer, Arch Linux, or other distro (64 bit) | - Supports AVX2 <br/> - [PassMark Single Thread Performance](https://www.cpubenchmark.net/singleThread.html) rating near or greater than 2100 <br/> - Four physical cores, with or without hyperthreading | - Direct3D11 support <br/> - OpenGL 4.6 support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 6000 (GeForce GTX 1050 Ti) <br/> - 4 GB Video Memory | 8 GB |
_Note: Recommended GPU is based on 3x Internal, ~1080p resolution requirements. Higher resolutions will require stronger cards; 6x Internal, ~4K resolution will require a [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 12000 (GeForce GTX 1070 Ti). Just like CPU requirements, this is also highly game dependent. A quick reference for GPU **intensive games**: [Wiki](https://wiki.pcsx2.net/Category:GPU_intensive_games)_
@@ -39,7 +39,7 @@ _Note: Recommended GPU is based on 3x Internal, ~1080p resolution requirements.
- You need the [Visual C++ 2019 x86 Redistributables](https://support.microsoft.com/en-us/help/2977003/) to run PCSX2.
- Windows XP and Direct3D9 support was dropped after stable release 1.4.0.
- Windows 7 and Windows 8 support was dropped after stable release 1.6.0.
- Windows 7 and Windows 8.0 support was dropped after stable release 1.6.0.
- 32 bit support was dropped after stable release 1.6.0.
- Make sure to update your operating system and drivers to ensure you have the best experience possible. Having a newer GPU is also recommended so you have the latest supported drivers.
- Because of copyright issues, and the complexity of trying to work around it, you need a BIOS dump extracted from a legitimately-owned PS2 console to use the emulator. For more information about the BIOS and how to get it from your console, visit [this page](pcsx2/Docs/PCSX2_FAQ.md#question-13-where-do-i-get-a-ps2-bios).
@@ -47,8 +47,4 @@ _Note: Recommended GPU is based on 3x Internal, ~1080p resolution requirements.
- Requirements benchmarks are based on a statistic from the Passmark CPU bench marking software. When we say "STR", we are referring to Passmark's "Single Thread Rating" statistic. You can look up your CPU on [Passmark's website for CPUs](https://cpubenchmark.net) to see how it compares to PCSX2's requirements.
- Vulkan requires an up-to-date GPU driver; old drivers may cause graphical problems.
### Screenshots
![Okami](https://pcsx2.net/images/stories/gitsnaps/okami_n1s.jpg "Okami") ![Final Fantasy XII](https://pcsx2.net/images/stories/gitsnaps/finalfantasy12izjs_s2.jpg "Final Fantasy XII") ![Shadow of the Colossus](https://pcsx2.net/images/stories/gitsnaps/sotc6s2.jpg "Shadow of the Colossus") ![DragonBall Z Budokai Tenkaichi 3](https://pcsx2.net/images/stories/gitsnaps/DBZ-BT-3s.jpg "DragonBall Z Budokai Tenkaichi 3") ![Kingdom Hearts 2: Final Mix](https://pcsx2.net/images/stories/gitsnaps/kh2_fm_n1s2.jpg "Kingdom Hearts 2: Final Mix") ![God of War 2](https://pcsx2.net/images/stories/gitsnaps/gow2_s2.jpg "God of War 2") ![Metal Gear Solid 3: Snake Eater](https://pcsx2.net/images/stories/gitsnaps/mgs3-1_s2.jpg "Metal Gear Solid 3: Snake Eater") ![Rogue Galaxy](https://pcsx2.net/images/stories/gitsnaps/rogue_galaxy_n1s2.jpg "Rogue Galaxy")
Want more? [Check out the PCSX2 website](https://pcsx2.net/demo-videos-screenshots/screenshots.html).
Binary file not shown.
File diff suppressed because it is too large Load Diff
+97 -80
View File
@@ -29,24 +29,27 @@
03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000290000000000000,8Bitdo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
03000000c82d00003038000000000000,8Bitdo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
03000000c82d00000290000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
03000000c82d00003038000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows,
03000000c82d000012ab000000000000,8BitDo NES30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000022000000090000000000000,8Bitdo NES30 Pro,a:b1,b:b0,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000203800000900000000000000,8Bitdo NES30 Pro,a:b1,b:b0,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00002038000000000000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000131000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000431000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00002867000000000000,8BitDo S30 Modkit,a:b0,b:b1,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000060000000000000,8Bitdo SF30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Windows,
03000000c82d00000061000000000000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000102800000900000000000000,8Bitdo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Windows,
03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00003028000000000000,8Bitdo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
@@ -59,22 +62,22 @@
03000000c82d00000121000000000000,8BitDo SN30 Pro for Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000a00500003232000000000000,8Bitdo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000d81d00000e00000000000000,AC02,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
030000008f0e00001200000000000000,Acme GA02,a:b0,b:b1,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:b2,y:b3,platform:Windows,
03000000c01100000355000000000000,Acrux,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,
03000000fa190000f0ff000000000000,Acteck AGJ 3200,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:Windows,
030000006d0400000bc2000000000000,Action,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows,
030000006d0400000bc2000000000000,Logitech WingMan Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows,
03000000d1180000402c000000000000,ADT1,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a5,x:b3,y:b4,platform:Windows,
030000006f0e00001301000000000000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e00001302000000000000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e00001304000000000000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e00001413000000000000,Afterglow,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,
030000006f0e00003901000000000000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000ab1200000103000000000000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000ad1b000000f9000000000000,Afterglow,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e00001301000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e00001302000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e00001304000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e00001413000000000000,Afterglow Xbox 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,
030000006f0e00003901000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000ab1200000103000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000ad1b000000f9000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00003608000000000000,Afterglow 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,
030000006f0e00000263000000000000,Afterglow 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,
030000006f0e00001101000000000000,Afterglow 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,
@@ -92,8 +95,8 @@
03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000ef0500000300000000000000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
03000000fd0500000230000000000000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,
03000000ef0500000300000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
03000000fd0500000230000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,
03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000d6200000e557000000000000,Batarang 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:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows,
@@ -130,7 +133,7 @@
030000003807000002cb000000000000,Cyborg,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000a306000022f6000000000000,Cyborg V.3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000f806000000a3000000000000,DA Leader,a:b7,b:b6,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b8,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:b3,rightx:a2,righty:a3,start:b12,x:b4,y:b5,platform:Windows,
030000001a1c00000001000000000000,Datel,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,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000001a1c00000001000000000000,Datel Arcade Joystick,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,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000451300000830000000000000,Defender Game Racer X7,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:Windows,
030000007d0400000840000000000000,Destroyer Tiltpad,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows,
03000000791d00000103000000000000,Dual Box Wii,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -161,19 +164,19 @@
03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
030000008f0e00000f31000000000000,EXEQ,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:b3,y:b2,platform:Windows,
03000000341a00000108000000000000,EXEQ RF Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000790000003018000000000000,F300,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,
03000000242f00003900000000000000,F300 Elite,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:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000790000003018000000000000,Mayflash F300 Arcade Joystick,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,
03000000242f00003900000000000000,Mayflash F300 Elite Arcade Joystick,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:a5,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00008401000000000000,Faceoff Deluxe Nintendo Switch 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,
030000006f0e00008001000000000000,Faceoff Pro Nintendo Switch 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,
03000000021000000090000000000000,FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
0300000011040000c600000000000000,FC801,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
03000000852100000201000000000000,FF GP1,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,
03000000380700002847000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000380700002847000000000000,Xbox 360 Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000ad1b000028f0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000ad1b00002ef0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000ad1b000038f0000000000000,Fightpad TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
03000000380700001847000000000000,Fightstick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
03000000380700008031000000000000,Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
03000000380700001847000000000000,Mad Catz Street Fighter 4 Xbox 360 FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
03000000380700008031000000000000,Mad Catz FightStick Alpha PS3 ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
03000000f806000001a3000000000000,Firestorm,a:b9,b:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b10,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b12,x:b8,y:b4,platform:Windows,
03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows,
03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows,
@@ -182,23 +185,24 @@
03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows,
03000000b40400001224000000000000,Flydigi Vader 2 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,paddle3:b17,paddle4:b18,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows,
03000000ac0500002d02000000000000,GameSir G4,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:a5,start:b11,x:b3,y:b4,platform:Windows,
0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
03000000260900002625000000000000,GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,
03000000341a000005f7000000000000,GameCube Controller,a:b2,b:b3,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b1,y:b0,platform:Windows,
03000000430b00000500000000000000,GameCube Controller,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,platform:Windows,
03000000790000004718000000000000,GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b0,x:b2,y:b3,start:b9,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a5,righty:a2,rightshoulder:b7,lefttrigger:a3,righttrigger:a4,platform:Windows,
030000008f0e00000d31000000000000,Gamepad 3 Turbo,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,
03000000280400000140000000000000,GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
03000000ac0500003d03000000000000,GameSir G3,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000ac0500002d02000000000000,GameSir G4,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:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000ac0500004d04000000000000,GameSir G4,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:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
0300000047530000616d000000000000,GameStop,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:Windows,
03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,platform:Windows,
030000008f0e00001411000000000000,Gamo2 Divaller PS4 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:Windows,
030000008f0e00001411000000000000,Gamo2 Divaller,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,
03000000120c0000a857000000000000,Gator Claw,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
03000000c9110000f055000000000000,GC100XF,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:Windows,
030000008305000009a0000000000000,Genius,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:Windows,
@@ -218,18 +222,18 @@
030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
03000000ac0500006b05000000000000,GT2a,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:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000341a00000302000000000000,Hama Scorpad,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,
03000000fd0500003902000000000000,Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows,
03000000fd0500002a26000000000000,Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,
03000000fd0500002f26000000000000,Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,platform:Windows,
03000000fd0500003902000000000000,InterAct Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows,
03000000fd0500002a26000000000000,InterAct Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,
03000000fd0500002f26000000000000,InterAct Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,platform:Windows,
030000000d0f00004900000000000000,Hatsune Miku Sho 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:a3,start:b9,x:b0,y:b3,platform:Windows,
030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,
030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000d81400000862000000000000,HitBox Edition Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
03000000632500002605000000000000,HJD X,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,
030000000d0f00000a00000000000000,Hori DOA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00005100000000000000,Hori Fighting,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:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008600000000000000,Hori Fighting Commander,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f0000ba00000000000000,Hori Fighting Commander,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,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00005100000000000000,Hori Fighting Commander PS3,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:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,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,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00008500000000000000,Hori Fighting Commander 2016 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:Windows,
030000000d0f00002500000000000000,Hori Fighting Commander 3,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:Windows,
030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -243,8 +247,8 @@
030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,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,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows,
030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008700000000000000,Hori Fightstick mini 4,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:Windows,
030000000d0f00008800000000000000,Hori Fightstick mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
030000000d0f00008700000000000000,Hori Fightstick Mini 4,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:Windows,
030000000d0f00008800000000000000,Hori Fightstick Mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
030000000d0f00002100000000000000,Hori Fightstick V3,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:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00002700000000000000,Hori Fightstick V3,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:Windows,
030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows,
@@ -285,7 +289,7 @@
030000000d0f00006600000000000000,Horipad 4 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,
030000000d0f00004200000000000000,Horipad A,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:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000ad1b000001f5000000000000,Horipad EXT2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005b1c00002400000000000000,Horipad Mini,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
030000000d0f0000ee00000000000000,Horipad Mini 4,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:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -354,7 +358,7 @@
030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,
03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,back:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b4,leftstick:b0,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
03000000242f00007300000000000000,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:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
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,
@@ -370,7 +374,7 @@
030000005e0400000e00000000000000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows,
030000005e0400002700000000000000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Windows,
03000000280d00000202000000000000,Miller Lite Cantroller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b5,x:b2,y:b3,platform:Windows,
030000005b1c00002500000000000000,Mini,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
030000005b1c00002500000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
03000000ad1b000023f0000000000000,MLG,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a6,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
03000000ad1b00003ef0000000000000,MLG Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
03000000380700006382000000000000,MLG 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,
@@ -401,9 +405,9 @@
030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows,
03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows,
03000000152000000182000000000000,NGDS,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:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,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:Windows,
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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows,
030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,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:Windows,
030000007e0500001720000000000000,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:Windows,
03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows,
03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,platform:Windows,
@@ -528,7 +532,7 @@
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,
03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,leftshoulder:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,platform:Windows,
@@ -541,6 +545,7 @@
030000006f0e00001e01000000000000,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:Windows,
030000006f0e00002801000000000000,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:Windows,
030000006f0e00002f01000000000000,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:Windows,
030000006f0e00008701000000000000,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:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
@@ -661,7 +666,6 @@
03000000120c0000ab57000000000000,Warrior Joypad JS083,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
030000007e0500003003000000000000,WiiU Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
0300000032150000030a000000000000,Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000ff02000000000000,Wired Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
0300000032150000140a000000000000,Wolverine,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000002e160000efbe000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,
03000000380700001647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -701,6 +705,7 @@
030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000fd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e0000a802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e0000c802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
03000000c62400003a54000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -708,7 +713,6 @@
03000000341a00000608000000000000,Xeox,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:Windows,
03000000450c00002043000000000000,Xeox SL6556BK,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:Windows,
030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,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:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000172700004431000000000000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000786901006e70000000000000,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -728,21 +732,24 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d000012ab000001000000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00002028000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000022000000090000001000000,8Bitdo NES30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000c82d00000190000001000000,8Bitdo NES30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000c82d00000190000001000000,8BitDo NES30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000102800000900000000000000,8Bitdo SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00004028000000010000,8Bitdo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000a00500003232000008010000,8Bitdo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000a00500003232000009010000,8Bitdo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X,
@@ -750,7 +757,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000ef0500000300000000020000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X,
03000000ef0500000300000000020000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X,
03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
03000000c62400001b89000000010000,BDA MOGA XP5-X 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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000d62000002a79000000010000,BDA PS4 Fightpad,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,
@@ -761,8 +768,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000a306000022f6000001030000,Cyborg V3 Rumble Pad 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:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000791d00000103000009010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
030000000d0f00008400000000010000,Fighting Commander,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,
030000000d0f00008500000000010000,Fighting Commander,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,
030000000d0f00008400000000010000,Hori Fighting Commander 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: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,
030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle3:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Mac OS X,
03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,
@@ -804,6 +811,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S+,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,
03000000790000000600000007010000,Marvo GT-004,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:Mac OS X,
03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,x:b8,y:b12,start:b36,rightshoulder:b28,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a4,rightx:a20,righty:a8,lefttrigger:a12,righttrigger:a16,platform:Mac OS X,
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,
@@ -833,6 +841,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
030000004c0500006802000000000000,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:Mac OS X,
030000004c0500006802000000010000,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:Mac OS X,
030000004c0500006802000072050000,PS3 Controller,a:b14,b:b13,x:b15,y:b12,back:b0,guide:b16,start:b3,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpdown:b6,dpleft:b7,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Mac OS X,
030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -860,7 +869,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
030000004c050000e60c000000010000,Sony DualSense,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,
030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,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,
030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,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,
03000000d11800000094000000010000,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:Mac OS X,
@@ -912,7 +921,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Linux,
03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001038000000010000,8Bitdo FC30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Linux,
05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Linux,
03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,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:b4,y:b3,platform:Linux,
@@ -920,20 +929,23 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,
03000000022000000090000011010000,8Bitdo NES30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Linux,
03000000c82d00000190000011010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000203800000900000000010000,8Bitdo NES30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Linux,
05000000c82d00002038000000010000,8Bitdo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000022000000090000011010000,8BitDo NES30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Linux,
03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Linux,
05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Linux,
05000000c82d00000061000000010000,8Bitdo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
030000003512000012ab000010010000,8Bitdo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
030000003512000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000102800000900000000010000,8Bitdo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00003028000000010000,8Bitdo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,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:b4,y:b3,platform:Linux,
03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
@@ -943,8 +955,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000a00500003232000001000000,8Bitdo Zero,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000008010000,8Bitdo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
050000005e040000e002000030110000,8BitDo Zero 2,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
@@ -974,8 +986,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000503200000210000045010000,Atari 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:b3,y:b2,platform:Linux,
05000000503200000210000046010000,Atari 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:b3,y:b2,platform:Linux,
05000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:-a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux,
03000000120c00000500000010010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
03000000ef0500000300000000010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
03000000120c00000500000010010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
03000000ef0500000300000000010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
03000000c62400001b89000011010000,BDA 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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000d62000002a79000011010000,BDA PS4 Fightpad,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,
03000000c21100000791000011010000,Be1 GC101 Controller 1.03,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,
@@ -1002,9 +1014,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,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,
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,
@@ -1024,11 +1037,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000632500002605000010010000,HJDX,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:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000000d0f00000d00000000010000,Hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,
030000000d0f00006d00000020010000,Hori EDGE 301,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,
030000000d0f00008500000010010000,Hori Fighting Commander,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,
030000000d0f00008600000002010000,Hori Fighting Commander,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,
030000000d0f00008500000010010000,Hori Fighting Commander 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,
030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,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,
030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One 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,
030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,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,
030000000d0f00001000000011010000,Hori Fightstick 3,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,
03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00004d00000011010000,HORI Gem Pad 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:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -1097,12 +1110,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000ad1b000016f0000090040000,Mad Catz 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,
03000000120c00000500000000010000,Manta Dualshock 2,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:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000790000004318000010010000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000242f00007300000011010000,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:Linux,
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,
0300000025090000e803000001010000,Mayflash Wii Classic Controller,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,
03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,x:b0,y:b1,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b5,righttrigger:b7,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,
030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,
@@ -1116,6 +1130,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000d102000001010000,Microsoft Xbox One,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,
030000005e040000d102000003020000,Microsoft Xbox One,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,
060000005e040000120b000009050000,Microsoft Xbox One,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,
030000005e040000120b00000b050000,Microsoft Xbox One,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,
030000005e040000dd02000003020000,Microsoft Xbox One 2015,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,
030000005e040000e302000003020000,Microsoft Xbox One Elite,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,
030000005e040000000b000008040000,Microsoft Xbox One Elite 2,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,
@@ -1132,6 +1147,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,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,
05000000c62400001a89000000010000,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:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000250900006688000000010000,MP8866 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:Linux,
030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
030000006b140000010c000010010000,Nacon GC 400ES,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:Linux,
030000000d0f00000900000010010000,Natec Genesis P44,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,
030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -1146,7 +1163,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000004c69632050726f20436f6e00,Nintendo Switch 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:Linux,
050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux,
050000007e0500001920000001000000,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:Linux,
03000000d620000013a7000011010000,Nintendo Switch PowerA Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
@@ -1156,6 +1172,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000010000000100000003000000,Nintendo Wii Remote,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,
050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,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:b3,y:b2,platform:Linux,
030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
050000007e0500001920000001000000,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:Linux,
050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,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:Linux,
@@ -1278,8 +1295,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000bc2000000055000010010000,Shanwan PS3 PC ,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005f140000c501000010010000,Shanwan Trust,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,
03000000341a00000908000010010000,SL6566,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,
030000004c050000e60c000011810000,Sony DualSense,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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000e60c000000810000,Sony DualSense,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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
030000004c050000e60c000011810000,PS5 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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000e60c000000810000,PS5 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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000cc09000001000000,Sony DualShock 4,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,
03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,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:Linux,
@@ -1308,6 +1325,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000457500002211000010010000,SZMY Power Gamepad,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,
030000008f0e00001431000010010000,SZMY Power 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,
03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,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:Linux,
030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,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:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,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:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000020b3000010010000,Thrustmaster Dual Trigger,a:b0,b:b2,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:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000023b3000000010000,Thrustmaster Dual Trigger PlayStation 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:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -1360,17 +1378,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000005e040000ea0200000b050000,Xbox One S 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,
030000005e040000120b000001050000,Xbox Series 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,
030000005e040000120b000005050000,Xbox Series 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,
030000005e040000120b00000d050000,Xbox Series 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,misc1:b11,platform:Linux,
030000005e040000120b00000d050000,Xbox Series 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,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000120b00000b050000,Xbox Series 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,
050000005e040000130b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000450c00002043000010010000,XEOX SL6556 BK,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,
03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,
03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,
xinput,XInput 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,
+22 -1
View File
@@ -18,11 +18,12 @@ struct VS_OUTPUT
float4 c : COLOR;
};
cbuffer cb0
cbuffer cb0 : register(b0)
{
float4 BGColor;
int EMODA;
int EMODC;
int cb0_pad[2];
};
static const float3x3 rgb2yuv =
@@ -405,4 +406,24 @@ PS_OUTPUT ps_yuv(PS_INPUT input)
return output;
}
float ps_stencil_image_init_0(PS_INPUT input) : SV_Target
{
float c;
if ((127.5f / 255.0f) < sample_c(input.t).a) // < 0x80 pass (== 0x80 should not pass)
c = float(-1);
else
c = float(0x7FFFFFFF);
return c;
}
float ps_stencil_image_init_1(PS_INPUT input) : SV_Target
{
float c;
if (sample_c(input.t).a < (127.5f / 255.0f)) // >= 0x80 pass
c = float(-1);
else
c = float(0x7FFFFFFF);
return c;
}
#endif
+1 -1
View File
@@ -3,7 +3,7 @@
Texture2D Texture;
SamplerState Sampler;
cbuffer cb0
cbuffer cb0 : register(b0)
{
float4 BGColor;
int EMODA;
+42
View File
@@ -61,6 +61,7 @@
#define PS_NO_COLOR1 0
#define PS_NO_ABLEND 0
#define PS_ONLY_ALPHA 0
#define PS_DATE 0
#endif
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
@@ -99,16 +100,23 @@ struct PS_INPUT
#else
nointerpolation float4 c : COLOR0;
#endif
#if PS_DATE > 10 || PS_DATE == 3
uint primid : SV_PrimitiveID;
#endif
};
struct PS_OUTPUT
{
#if !PS_NO_COLOR
#if PS_DATE > 10
float c : SV_Target;
#else
float4 c0 : SV_Target0;
#if !PS_NO_COLOR1
float4 c1 : SV_Target1;
#endif
#endif
#endif
#if PS_ZCLAMP
float depth : SV_Depth;
#endif
@@ -117,10 +125,15 @@ struct PS_OUTPUT
Texture2D<float4> Texture : register(t0);
Texture2D<float4> Palette : register(t1);
Texture2D<float4> RtTexture : register(t2);
Texture2D<float> PrimMinTexture : register(t3);
SamplerState TextureSampler : register(s0);
SamplerState PaletteSampler : register(s1);
#ifdef DX12
cbuffer cb0 : register(b0)
#else
cbuffer cb0
#endif
{
float2 VertexScale;
float2 VertexOffset;
@@ -131,7 +144,11 @@ cbuffer cb0
uint pad_cb0;
};
#ifdef DX12
cbuffer cb1 : register(b1)
#else
cbuffer cb1
#endif
{
float3 FogColor;
float AREF;
@@ -853,6 +870,29 @@ PS_OUTPUT ps_main(PS_INPUT input)
if (C.a < A_one) C.a += A_one;
}
#if PS_DATE == 3
// Note gl_PrimitiveID == stencil_ceil will be the primitive that will update
// the bad alpha value so we must keep it.
int stencil_ceil = int(PrimMinTexture.Load(int3(input.p.xy, 0)));
if (int(input.primid) > stencil_ceil)
discard;
#endif
// Get first primitive that will write a failling alpha value
#if PS_DATE == 11
// DATM == 0
// Pixel with alpha equal to 1 will failed (128-255)
output.c = (C.a > 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
#elif PS_DATE == 12
// DATM == 1
// Pixel with alpha equal to 0 will failed (0-127)
output.c = (C.a < 127.5f) ? float(input.primid) : float(0x7FFFFFFF);
#else
// Not primid DATE setup
ps_blend(C, alpha_blend, input.p.xy);
ps_dither(C.rgb, input.p.xy);
@@ -878,6 +918,8 @@ PS_OUTPUT ps_main(PS_INPUT input)
#endif
#endif
#endif
#if PS_ZCLAMP
output.depth = min(input.p.z, MaxDepthPS);
#endif
+24 -54
View File
@@ -18,24 +18,6 @@
set -u
# Function declarations
set_ncpu_toolfile()
{
ncpu=$(getconf NPROCESSORS_ONLN 2>/dev/null || getconf _NPROCESSORS_ONLN)
if [ "$(uname -s)" = 'Darwin' ]; then
i386_flag="-DCMAKE_OSX_ARCHITECTURES=i386"
elif [ "$(uname -s)" != 'FreeBSD' ]; then
i386_flag="-DCMAKE_TOOLCHAIN_FILE=cmake/linux-compiler-i386-multilib.cmake"
fi
}
switch_wxconfig()
{
# Helper to easily switch wx-config on my system
if [ "$(uname -m)" = "x86_64" ] && [ -e "/usr/lib/i386-linux-gnu/wx/config/gtk2-unicode-3.0" ]; then
sudo update-alternatives --set wx-config /usr/lib/x86_64-linux-gnu/wx/config/gtk2-unicode-3.0
fi
}
find_freetype()
{
if [ "$(uname -m)" = "x86_64" ] && [ -e "/usr/include/x86_64-linux-gnu/freetype2/ft2build.h" ]; then
@@ -45,6 +27,7 @@ find_freetype()
set_make()
{
ncpu=$(getconf NPROCESSORS_ONLN 2>/dev/null || getconf _NPROCESSORS_ONLN)
if command -v ninja >/dev/null ; then
flags="$flags -GNinja"
make=ninja
@@ -160,7 +143,6 @@ build="$root/build"
coverity_dir="cov-int"
coverity_result=pcsx2-coverity.xz
set_ncpu_toolfile
set_make
for ARG in "$@"; do
@@ -193,34 +175,36 @@ for ARG in "$@"; do
echo $ARG
# Unknown option
echo "** User options **"
echo "--dev / --devel : Build PCSX2 as a Development build."
echo "--debug : Build PCSX2 as a Debug build."
echo "--prof : Build PCSX2 as a Profiler build (release + debug symbol)."
echo "--release : Build PCSX2 as a Release build."
echo "--dev / --devel : Build PCSX2 as a Development build."
echo "--dbg / --debug : Build PCSX2 as a Debug build."
echo "--prof : Build PCSX2 as a Profiler build (release + debug symbol)."
echo "--rel / --release : Build PCSX2 as a Release build."
echo
echo "--clean : Do a clean build."
echo "--no-simd : Only allow sse2"
echo "--clean : Do a clean build. (Remove anything in the build directory)"
echo "--no-simd : Only allow sse2."
echo
echo "** Distribution Compatibilities **"
echo "--no-portaudio : Skip portaudio for SPU2."
echo "--use-system-yaml : Use system rapidyaml library"
echo "--no-portaudio : Skip portaudio for SPU2."
echo "--use-system-yaml : Use system rapidyaml library."
echo
echo "** Expert Developer option **"
echo "--gtk2 : use GTK 2 instead of GTK 3"
echo "--no-trans : Don't regenerate mo files when building."
echo "--clang : Build with Clang/llvm"
echo "--intel : Build with ICC (Intel compiler)"
echo "--lto : Use Link Time Optimization"
echo "--pgo-generate : Executable will generate profiling information when run"
echo "--pgo-optimize : Use previously generated profiling information"
echo "--gtk2 : use GTK 2 instead of GTK 3."
echo "--no-trans : Don't regenerate mo files when building."
echo "--strip : Strip binaries to save a small amount of space."
echo "--clang : Build with Clang/llvm."
echo "--intel : Build with ICC (Intel compiler)."
echo "--lto : Use Link Time Optimization."
echo "--pgo-generate : Executable will generate profiling information when run."
echo "--pgo-optimize : Use previously generated profiling information."
echo "-D<argument> : Add <argument> to the flags passed."
echo
echo "** Quality & Assurance (Please install the external tool) **"
echo "--asan : Enable Address sanitizer"
echo "--clang-tidy : Do a clang-tidy analysis. Results can be found in build directory"
echo "--cppcheck : Do a cppcheck analysis. Results can be found in build directory"
echo "--coverity : Do a build for coverity"
echo "--vtune : Plug GS with VTUNE"
echo "--ftime-trace : Analyse build time. Clang only."
echo "--asan : Enable Address sanitizer."
echo "--clang-tidy : Do a clang-tidy analysis. Results can be found in build directory."
echo "--cppcheck : Do a cppcheck analysis. Results can be found in build directory."
echo "--coverity : Do a build for coverity."
echo "--vtune : Plug GS with VTUNE."
echo "--ftime-trace : Analyse build time. Clang only."
exit 1
esac
@@ -232,8 +216,6 @@ if [ "$cleanBuild" -eq 1 ]; then
rm -fr "$build"/*
fi
switch_wxconfig
# Workaround for Debian. Cmake failed to find freetype include path
find_freetype
@@ -251,30 +233,18 @@ cd "$build"
set_compiler
############################################################
# CPP check build
############################################################
if [ "$cppcheck" -eq 1 ] && command -v cppcheck >/dev/null ; then
run_cppcheck
fi
############################################################
# Clang tidy build
############################################################
if [ "$clangTidy" -eq 1 ] && command -v clang-tidy >/dev/null ; then
run_clangtidy
fi
############################################################
# Coverity build
############################################################
if [ "$CoverityBuild" -eq 1 ] && command -v cov-build >/dev/null ; then
run_coverity
fi
############################################################
# Real build
############################################################
$make 2>&1 | tee -a "$log"
$make install 2>&1 | tee -a "$log"
+5
View File
@@ -38,6 +38,7 @@ option(USE_VTUNE "Plug VTUNE to profile GS JIT.")
# Graphical option
#-------------------------------------------------------------------------------
option(BUILD_REPLAY_LOADERS "Build GS replayer to ease testing (developer option)")
option(USE_OPENGL "Enable OpenGL GS renderer" ON)
option(USE_VULKAN "Enable Vulkan GS renderer" ON)
#-------------------------------------------------------------------------------
@@ -206,6 +207,10 @@ if(USE_VTUNE)
list(APPEND PCSX2_DEFS ENABLE_VTUNE)
endif()
if(USE_OPENGL)
list(APPEND PCSX2_DEFS ENABLE_OPENGL)
endif()
if(USE_VULKAN)
list(APPEND PCSX2_DEFS ENABLE_VULKAN)
endif()
+4 -1
View File
@@ -57,7 +57,10 @@ function(get_git_version_info)
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
endif()
if(PCSX2_GIT_REV)
if ("${PCSX2_GIT_TAG}" MATCHES "^v([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" PCSX2_VERSION_LONG "${PCSX2_GIT_TAG}")
string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" PCSX2_VERSION_SHORT "${PCSX2_GIT_TAG}")
elseif(PCSX2_GIT_REV)
set(PCSX2_VERSION_LONG "${PCSX2_GIT_REV}")
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?(-[a-z][a-z0-9]+)?" PCSX2_VERSION_SHORT "${PCSX2_VERSION_LONG}")
else()
+20 -11
View File
@@ -16,6 +16,7 @@ if (WIN32)
add_subdirectory(3rdparty/wil EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/wxwidgets3.0 EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/xz EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/D3D12MemAlloc EXCLUDE_FROM_ALL)
else()
## Use cmake package to find module
if (Linux)
@@ -29,8 +30,10 @@ else()
# Using find_package OpenGL without either setting your opengl preference to GLVND or LEGACY
# is deprecated as of cmake 3.11.
set(OpenGL_GL_PREFERENCE GLVND)
find_package(OpenGL REQUIRED)
if(USE_OPENGL)
set(OpenGL_GL_PREFERENCE GLVND)
find_package(OpenGL REQUIRED)
endif()
find_package(PNG REQUIRED)
find_package(Vtune)
@@ -115,15 +118,14 @@ else()
include(CheckLib)
if(UNIX AND NOT APPLE)
check_lib(EGL EGL EGL/egl.h)
if(USE_OPENGL)
check_lib(EGL EGL EGL/egl.h)
endif()
if(X11_API)
check_lib(X11_XCB X11-xcb X11/Xlib-xcb.h)
check_lib(XCB xcb xcb/xcb.h)
check_lib(XRANDR xrandr)
endif()
if(WAYLAND_API)
find_package(Wayland REQUIRED)
endif()
if(Linux)
check_lib(AIO aio libaio.h)
@@ -164,9 +166,9 @@ else()
## Use pcsx2 package to find module
find_package(HarfBuzz)
endif()
endif()
if(WAYLAND_API)
find_package(Wayland REQUIRED)
if(WAYLAND_API)
find_package(Wayland REQUIRED)
endif()
endif()
endif(WIN32)
@@ -234,10 +236,13 @@ if(NOT USE_SYSTEM_YAML)
endif()
endif()
# We could use a system version of zstd, but is it going to be recent enough?
add_subdirectory(3rdparty/zstd EXCLUDE_FROM_ALL)
if(QT_BUILD)
# Default to bundled Qt6 for Windows.
if(WIN32 AND NOT DEFINED Qt6_DIR)
set(Qt6_DIR ${CMAKE_SOURCE_DIR}/3rdparty/qt/6.2.2/msvc2019_64/lib/cmake/Qt6)
set(Qt6_DIR ${CMAKE_SOURCE_DIR}/3rdparty/qt/6.3.0/msvc2019_64/lib/cmake/Qt6)
endif()
# Find the Qt components that we need.
@@ -259,9 +264,13 @@ else()
set(BIN2CPPDEP ${CMAKE_SOURCE_DIR}/linux_various/hex2h.pl)
endif()
add_subdirectory(3rdparty/glad EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/simpleini EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/imgui EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/libzip EXCLUDE_FROM_ALL)
if(USE_OPENGL)
add_subdirectory(3rdparty/glad EXCLUDE_FROM_ALL)
endif()
if(USE_VULKAN)
add_subdirectory(3rdparty/glslang EXCLUDE_FROM_ALL)
+90 -52
View File
@@ -14,32 +14,24 @@ target_sources(common PRIVATE
EventSource.inl
SafeArray.inl
Console.cpp
CrashHandler.cpp
EventSource.cpp
Exceptions.cpp
FastFormatString.cpp
FastJmp.cpp
GL/Context.cpp
GL/Program.cpp
GL/ShaderCache.cpp
GL/StreamBuffer.cpp
FileSystem.cpp
IniInterface.cpp
Mutex.cpp
Misc.cpp
MD5Digest.cpp
PathUtils.cpp
PrecompiledHeader.cpp
Perf.cpp
ProgressCallback.cpp
pxStreams.cpp
pxTranslate.cpp
RwMutex.cpp
Semaphore.cpp
SettingsWrapper.cpp
StringHelpers.cpp
StringUtil.cpp
Timer.cpp
ThreadTools.cpp
WindowInfo.cpp
emitter/bmi.cpp
emitter/cpudetect.cpp
@@ -71,6 +63,7 @@ target_sources(common PRIVATE
Assertions.h
boost_spsc_queue.hpp
Console.h
CrashHandler.h
Dependencies.h
EnumOps.h
EventSource.h
@@ -78,10 +71,6 @@ target_sources(common PRIVATE
FastJmp.h
FileSystem.h
General.h
GL/Context.h
GL/Program.h
GL/ShaderCache.h
GL/StreamBuffer.h
HashCombine.h
MemcpyFast.h
MemsetFast.inl
@@ -92,12 +81,9 @@ target_sources(common PRIVATE
PrecompiledHeader.h
ProgressCallback.h
pxForwardDefs.h
pxStreams.h
RedtapeWindows.h
RwMutex.h
SafeArray.h
ScopedGuard.h
ScopedPtrMT.h
SettingsInterface.h
SettingsWrapper.h
StringHelpers.h
@@ -106,7 +92,6 @@ target_sources(common PRIVATE
Threading.h
TraceLog.h
WindowInfo.h
wxBaseTools.h
emitter/cpudetect_internal.h
emitter/implement/dwshift.h
emitter/implement/group1.h
@@ -134,6 +119,22 @@ target_sources(common PRIVATE
emitter/x86types.h
)
if(USE_OPENGL)
target_sources(common PRIVATE
GL/Context.cpp
GL/Program.cpp
GL/ShaderCache.cpp
GL/StreamBuffer.cpp
)
target_sources(common PRIVATE
GL/Context.h
GL/Program.h
GL/ShaderCache.h
GL/StreamBuffer.h
)
target_link_libraries(common PUBLIC glad)
endif()
if(USE_VULKAN)
target_link_libraries(common PUBLIC
Vulkan-Headers glslang
@@ -169,53 +170,90 @@ endif()
if(WIN32)
enable_language(ASM_MASM)
target_sources(common PRIVATE FastJmp.asm)
target_link_libraries(common PUBLIC WIL::WIL pthreads4w Winmm.lib)
target_link_libraries(common PUBLIC WIL::WIL D3D12MemAlloc Winmm.lib)
target_sources(common PRIVATE
CrashHandler.cpp
CrashHandler.h
FastJmp.asm
StackWalker.cpp
StackWalker.h
D3D11/ShaderCache.cpp
D3D11/ShaderCache.h
D3D11/ShaderCompiler.cpp
D3D11/ShaderCompiler.h
GL/ContextWGL.cpp
GL/ContextWGL.h
D3D12/Builders.cpp
D3D12/Builders.h
D3D12/Context.cpp
D3D12/Context.h
D3D12/DescriptorHeapManager.cpp
D3D12/DescriptorHeapManager.h
D3D12/ShaderCache.cpp
D3D12/ShaderCache.h
D3D12/StreamBuffer.cpp
D3D12/StreamBuffer.h
D3D12/Texture.cpp
D3D12/Texture.h
D3D12/Util.cpp
D3D12/Util.h
)
target_link_libraries(common PUBLIC pthreads4w Winmm.lib opengl32.lib)
elseif(APPLE)
target_sources(common PRIVATE
GL/ContextAGL.mm
GL/ContextAGL.h
)
set_source_files_properties(GL/ContextAGL.mm PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
target_compile_options(common PRIVATE -fobjc-arc)
target_link_options(common PRIVATE -fobjc-link-runtime)
else()
if(X11_API OR WAYLAND_API)
target_sources(common PRIVATE
GL/ContextEGL.cpp
GL/ContextEGL.h
)
target_link_libraries(common PRIVATE PkgConfig::EGL)
endif()
endif()
if(X11_API)
if(USE_OPENGL)
if(WIN32)
target_sources(common PRIVATE
GL/ContextEGLX11.cpp
GL/ContextEGLX11.h
GL/ContextWGL.cpp
GL/ContextWGL.h
)
target_compile_definitions(common PUBLIC "VULKAN_USE_X11=1")
if(TARGET PkgConfig::XRANDR)
target_link_libraries(common PRIVATE PkgConfig::XRANDR)
target_compile_definitions(common PRIVATE "HAS_XRANDR=1")
target_link_libraries(common PUBLIC opengl32.lib)
elseif(APPLE)
target_sources(common PRIVATE
GL/ContextAGL.mm
GL/ContextAGL.h
)
set_source_files_properties(GL/ContextAGL.mm PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
target_compile_options(common PRIVATE -fobjc-arc)
target_link_options(common PRIVATE -fobjc-link-runtime)
else()
if(X11_API OR WAYLAND_API)
target_sources(common PRIVATE
GL/ContextEGL.cpp
GL/ContextEGL.h
)
target_link_libraries(common PRIVATE PkgConfig::EGL)
endif()
if(X11_API)
target_sources(common PRIVATE
GL/ContextEGLX11.cpp
GL/ContextEGLX11.h
)
if(TARGET PkgConfig::XRANDR)
target_link_libraries(common PRIVATE PkgConfig::XRANDR)
target_compile_definitions(common PRIVATE "HAS_XRANDR=1")
endif()
endif()
if(WAYLAND_API)
target_sources(common PRIVATE
GL/ContextEGLWayland.cpp
GL/ContextEGLWayland.h
)
endif()
endif()
endif()
if(WAYLAND_API)
target_sources(common PRIVATE
GL/ContextEGLWayland.cpp
GL/ContextEGLWayland.h
)
target_link_libraries(common PRIVATE ${WAYLAND_EGL_LIBRARIES})
target_compile_definitions(common PUBLIC "VULKAN_USE_WAYLAND=1")
if(USE_VULKAN)
if(APPLE)
# Needed for Metal surface creation.
target_compile_options(common PRIVATE -fobjc-arc)
target_link_options(common PRIVATE -fobjc-link-runtime)
elseif(NOT WIN32)
if(X11_API)
target_compile_definitions(common PUBLIC "VULKAN_USE_X11=1")
endif()
if(WAYLAND_API)
target_compile_definitions(common PUBLIC "VULKAN_USE_WAYLAND=1")
endif()
endif()
endif()
@@ -224,7 +262,7 @@ if (USE_GCC AND CMAKE_INTERPROCEDURAL_OPTIMIZATION)
set_source_files_properties(FastJmp.cpp PROPERTIES COMPILE_FLAGS -fno-lto)
endif()
target_link_libraries(common PRIVATE ${LIBC_LIBRARIES} PUBLIC wxWidgets::all glad)
target_link_libraries(common PRIVATE ${LIBC_LIBRARIES} PUBLIC wxWidgets::all)
target_compile_features(common PUBLIC cxx_std_17)
target_include_directories(common PUBLIC ../3rdparty/include ../)
target_compile_definitions(common PUBLIC "${PCSX2_DEFS}")
+2 -2
View File
@@ -20,10 +20,10 @@
using namespace Threading;
// thread-local console indentation setting.
static DeclareTls(int) conlog_Indent(0);
static thread_local int conlog_Indent(0);
// thread-local console color storage.
static DeclareTls(ConsoleColors) conlog_Color(DefaultConsoleColor);
static thread_local ConsoleColors conlog_Color(DefaultConsoleColor);
#ifdef __POSIX__
#include <unistd.h>
+228
View File
@@ -0,0 +1,228 @@
/* 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 "Pcsx2Defs.h"
#include "CrashHandler.h"
#include "FileSystem.h"
#include "StringUtil.h"
#include <cinttypes>
#include <cstdio>
#include <ctime>
#if defined(_WIN32) && !defined(_UWP)
#include "RedtapeWindows.h"
#include "StackWalker.h"
#include <DbgHelp.h>
class CrashHandlerStackWalker : public StackWalker
{
public:
explicit CrashHandlerStackWalker(HANDLE out_file);
~CrashHandlerStackWalker();
protected:
void OnOutput(LPCSTR szText) override;
private:
HANDLE m_out_file;
};
CrashHandlerStackWalker::CrashHandlerStackWalker(HANDLE out_file)
: StackWalker(RetrieveVerbose, nullptr, GetCurrentProcessId(), GetCurrentProcess())
, m_out_file(out_file)
{
}
CrashHandlerStackWalker::~CrashHandlerStackWalker()
{
if (m_out_file)
CloseHandle(m_out_file);
}
void CrashHandlerStackWalker::OnOutput(LPCSTR szText)
{
if (m_out_file)
{
DWORD written;
WriteFile(m_out_file, szText, static_cast<DWORD>(std::strlen(szText)), &written, nullptr);
}
OutputDebugStringA(szText);
}
static bool WriteMinidump(HMODULE hDbgHelp, HANDLE hFile, HANDLE hProcess, DWORD process_id, DWORD thread_id,
PEXCEPTION_POINTERS exception, MINIDUMP_TYPE type)
{
using PFNMINIDUMPWRITEDUMP =
BOOL(WINAPI*)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
PFNMINIDUMPWRITEDUMP minidump_write_dump = hDbgHelp ?
reinterpret_cast<PFNMINIDUMPWRITEDUMP>(GetProcAddress(hDbgHelp, "MiniDumpWriteDump")) :
nullptr;
if (!minidump_write_dump)
return false;
MINIDUMP_EXCEPTION_INFORMATION mei;
PMINIDUMP_EXCEPTION_INFORMATION mei_ptr = nullptr;
if (exception)
{
mei.ThreadId = thread_id;
mei.ExceptionPointers = exception;
mei.ClientPointers = FALSE;
mei_ptr = &mei;
}
return minidump_write_dump(hProcess, process_id, hFile, type, mei_ptr, nullptr, nullptr);
}
static std::wstring s_write_directory;
static HMODULE s_dbghelp_module = nullptr;
static PVOID s_veh_handle = nullptr;
static bool s_in_crash_handler = false;
static void GenerateCrashFilename(wchar_t* buf, size_t len, const wchar_t* prefix, const wchar_t* extension)
{
SYSTEMTIME st = {};
GetLocalTime(&st);
_snwprintf_s(buf, len, _TRUNCATE, L"%s%scrash-%04u-%02u-%02u-%02u-%02u-%02u-%03u.%s",
prefix ? prefix : L"", prefix ? L"\\" : L"",
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, extension);
}
static LONG NTAPI ExceptionHandler(PEXCEPTION_POINTERS exi)
{
if (s_in_crash_handler)
return EXCEPTION_CONTINUE_SEARCH;
switch (exi->ExceptionRecord->ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
case EXCEPTION_BREAKPOINT:
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_OVERFLOW:
case EXCEPTION_PRIV_INSTRUCTION:
case EXCEPTION_ILLEGAL_INSTRUCTION:
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
case EXCEPTION_STACK_OVERFLOW:
case EXCEPTION_GUARD_PAGE:
break;
default:
return EXCEPTION_CONTINUE_SEARCH;
}
// if the debugger is attached, let it take care of it.
if (IsDebuggerPresent())
return EXCEPTION_CONTINUE_SEARCH;
s_in_crash_handler = true;
wchar_t filename[1024] = {};
GenerateCrashFilename(filename, std::size(filename), s_write_directory.empty() ? nullptr : s_write_directory.c_str(), L"txt");
// might fail
HANDLE hFile = CreateFileW(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr);
if (hFile != INVALID_HANDLE_VALUE)
{
char line[1024];
DWORD written;
std::snprintf(line, std::size(line), "Exception 0x%08X at 0x%p\n", exi->ExceptionRecord->ExceptionCode,
exi->ExceptionRecord->ExceptionAddress);
WriteFile(hFile, line, static_cast<DWORD>(std::strlen(line)), &written, nullptr);
}
GenerateCrashFilename(filename, std::size(filename), s_write_directory.empty() ? nullptr : s_write_directory.c_str(), L"dmp");
const MINIDUMP_TYPE minidump_type =
static_cast<MINIDUMP_TYPE>(MiniDumpNormal | MiniDumpWithHandleData | MiniDumpWithProcessThreadData |
MiniDumpWithThreadInfo | MiniDumpWithIndirectlyReferencedMemory);
const HANDLE hMinidumpFile = CreateFileW(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, nullptr);
if (hMinidumpFile == INVALID_HANDLE_VALUE ||
!WriteMinidump(s_dbghelp_module, hMinidumpFile, GetCurrentProcess(), GetCurrentProcessId(),
GetCurrentThreadId(), exi, minidump_type))
{
static const char error_message[] = "Failed to write minidump file.\n";
if (hFile != INVALID_HANDLE_VALUE)
{
DWORD written;
WriteFile(hFile, error_message, sizeof(error_message) - 1, &written, nullptr);
}
}
if (hMinidumpFile != INVALID_HANDLE_VALUE)
CloseHandle(hMinidumpFile);
CrashHandlerStackWalker sw(hFile);
sw.ShowCallstack(GetCurrentThread(), exi->ContextRecord);
if (hFile != INVALID_HANDLE_VALUE)
CloseHandle(hFile);
return EXCEPTION_CONTINUE_SEARCH;
}
bool CrashHandler::Install()
{
// load dbghelp at install/startup, that way we're not LoadLibrary()'ing after a crash
// .. because that probably wouldn't go down well.
s_dbghelp_module = StackWalker::LoadDbgHelpLibrary();
s_veh_handle = AddVectoredExceptionHandler(0, ExceptionHandler);
return (s_veh_handle != nullptr);
}
void CrashHandler::SetWriteDirectory(const std::string_view& dump_directory)
{
if (!s_veh_handle)
return;
s_write_directory = StringUtil::UTF8StringToWideString(dump_directory);
}
void CrashHandler::Uninstall()
{
if (s_veh_handle)
{
RemoveVectoredExceptionHandler(s_veh_handle);
s_veh_handle = nullptr;
}
if (s_dbghelp_module)
{
FreeLibrary(s_dbghelp_module);
s_dbghelp_module = nullptr;
}
}
#else
bool CrashHandler::Install()
{
return false;
}
void CrashHandler::SetWriteDirectory(const std::string_view& dump_directory)
{
}
void CrashHandler::Uninstall()
{
}
#endif
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
* 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-
@@ -13,18 +13,11 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string_view>
#include <wx/app.h>
#include <wx/datetime.h>
#include <wx/thread.h>
namespace Threading
namespace CrashHandler
{
extern const wxTimeSpan def_yieldgui_interval;
extern bool _WaitGui_RecursionGuard(const wxChar* name);
extern void YieldToMain();
extern bool AllowDeletions();
} // namespace Threading
bool Install();
void SetWriteDirectory(const std::string_view& dump_directory);
void Uninstall();
} // namespace CrashHandler
+312
View File
@@ -0,0 +1,312 @@
/* 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 "common/PrecompiledHeader.h"
#include "common/D3D12/Builders.h"
#include "common/D3D12/Context.h"
#include "common/D3D12/ShaderCache.h"
#include "common/Console.h"
#include <cstdarg>
#include <limits>
using namespace D3D12;
GraphicsPipelineBuilder::GraphicsPipelineBuilder()
{
Clear();
}
void GraphicsPipelineBuilder::Clear()
{
std::memset(&m_desc, 0, sizeof(m_desc));
std::memset(m_input_elements.data(), 0, sizeof(D3D12_INPUT_ELEMENT_DESC) * m_input_elements.size());
m_desc.NodeMask = 1;
m_desc.SampleMask = 0xFFFFFFFF;
m_desc.SampleDesc.Count = 1;
}
wil::com_ptr_nothrow<ID3D12PipelineState> GraphicsPipelineBuilder::Create(ID3D12Device* device, bool clear /*= true*/)
{
wil::com_ptr_nothrow<ID3D12PipelineState> ps;
HRESULT hr = device->CreateGraphicsPipelineState(&m_desc, IID_PPV_ARGS(ps.put()));
if (FAILED(hr))
{
Console.Error("CreateGraphicsPipelineState() failed: %08X", hr);
return {};
}
if (clear)
Clear();
return ps;
}
wil::com_ptr_nothrow<ID3D12PipelineState> GraphicsPipelineBuilder::Create(ID3D12Device* device, ShaderCache& cache,
bool clear /*= true*/)
{
wil::com_ptr_nothrow<ID3D12PipelineState> pso = cache.GetPipelineState(device, m_desc);
if (!pso)
return {};
if (clear)
Clear();
return pso;
}
void GraphicsPipelineBuilder::SetRootSignature(ID3D12RootSignature* rs)
{
m_desc.pRootSignature = rs;
}
void GraphicsPipelineBuilder::SetVertexShader(const ID3DBlob* blob)
{
SetVertexShader(const_cast<ID3DBlob*>(blob)->GetBufferPointer(), static_cast<u32>(const_cast<ID3DBlob*>(blob)->GetBufferSize()));
}
void GraphicsPipelineBuilder::SetVertexShader(const void* data, u32 data_size)
{
m_desc.VS.pShaderBytecode = data;
m_desc.VS.BytecodeLength = data_size;
}
void GraphicsPipelineBuilder::SetGeometryShader(const ID3DBlob* blob)
{
SetGeometryShader(const_cast<ID3DBlob*>(blob)->GetBufferPointer(), static_cast<u32>(const_cast<ID3DBlob*>(blob)->GetBufferSize()));
}
void GraphicsPipelineBuilder::SetGeometryShader(const void* data, u32 data_size)
{
m_desc.GS.pShaderBytecode = data;
m_desc.GS.BytecodeLength = data_size;
}
void GraphicsPipelineBuilder::SetPixelShader(const ID3DBlob* blob)
{
SetPixelShader(const_cast<ID3DBlob*>(blob)->GetBufferPointer(), static_cast<u32>(const_cast<ID3DBlob*>(blob)->GetBufferSize()));
}
void GraphicsPipelineBuilder::SetPixelShader(const void* data, u32 data_size)
{
m_desc.PS.pShaderBytecode = data;
m_desc.PS.BytecodeLength = data_size;
}
void GraphicsPipelineBuilder::AddVertexAttribute(const char* semantic_name, u32 semantic_index, DXGI_FORMAT format,
u32 buffer, u32 offset)
{
const u32 index = m_desc.InputLayout.NumElements;
m_input_elements[index].SemanticIndex = semantic_index;
m_input_elements[index].SemanticName = semantic_name;
m_input_elements[index].Format = format;
m_input_elements[index].AlignedByteOffset = offset;
m_input_elements[index].InputSlot = buffer;
m_input_elements[index].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
m_input_elements[index].InstanceDataStepRate = 0;
m_desc.InputLayout.pInputElementDescs = m_input_elements.data();
m_desc.InputLayout.NumElements++;
}
void GraphicsPipelineBuilder::SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE type)
{
m_desc.PrimitiveTopologyType = type;
}
void GraphicsPipelineBuilder::SetRasterizationState(D3D12_FILL_MODE polygon_mode, D3D12_CULL_MODE cull_mode,
bool front_face_ccw)
{
m_desc.RasterizerState.FillMode = polygon_mode;
m_desc.RasterizerState.CullMode = cull_mode;
m_desc.RasterizerState.FrontCounterClockwise = front_face_ccw;
}
void GraphicsPipelineBuilder::SetMultisamples(u32 multisamples)
{
m_desc.RasterizerState.MultisampleEnable = multisamples > 1;
m_desc.SampleDesc.Count = multisamples;
}
void GraphicsPipelineBuilder::SetNoCullRasterizationState()
{
SetRasterizationState(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, false);
}
void GraphicsPipelineBuilder::SetDepthState(bool depth_test, bool depth_write, D3D12_COMPARISON_FUNC compare_op)
{
m_desc.DepthStencilState.DepthEnable = depth_test;
m_desc.DepthStencilState.DepthWriteMask = depth_write ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
m_desc.DepthStencilState.DepthFunc = compare_op;
}
void GraphicsPipelineBuilder::SetStencilState(bool stencil_test, u8 read_mask, u8 write_mask,
const D3D12_DEPTH_STENCILOP_DESC& front, const D3D12_DEPTH_STENCILOP_DESC& back)
{
m_desc.DepthStencilState.StencilEnable = stencil_test;
m_desc.DepthStencilState.StencilReadMask = read_mask;
m_desc.DepthStencilState.StencilWriteMask = write_mask;
m_desc.DepthStencilState.FrontFace = front;
m_desc.DepthStencilState.BackFace = back;
}
void GraphicsPipelineBuilder::SetNoDepthTestState()
{
SetDepthState(false, false, D3D12_COMPARISON_FUNC_ALWAYS);
}
void GraphicsPipelineBuilder::SetNoStencilState()
{
D3D12_DEPTH_STENCILOP_DESC empty = {};
SetStencilState(false, 0, 0, empty, empty);
}
void GraphicsPipelineBuilder::SetBlendState(u32 rt, bool blend_enable, D3D12_BLEND src_factor, D3D12_BLEND dst_factor,
D3D12_BLEND_OP op, D3D12_BLEND alpha_src_factor,
D3D12_BLEND alpha_dst_factor, D3D12_BLEND_OP alpha_op,
u8 write_mask /*= 0xFF*/)
{
m_desc.BlendState.RenderTarget[rt].BlendEnable = blend_enable;
m_desc.BlendState.RenderTarget[rt].SrcBlend = src_factor;
m_desc.BlendState.RenderTarget[rt].DestBlend = dst_factor;
m_desc.BlendState.RenderTarget[rt].BlendOp = op;
m_desc.BlendState.RenderTarget[rt].SrcBlendAlpha = alpha_src_factor;
m_desc.BlendState.RenderTarget[rt].DestBlendAlpha = alpha_dst_factor;
m_desc.BlendState.RenderTarget[rt].BlendOpAlpha = alpha_op;
m_desc.BlendState.RenderTarget[rt].RenderTargetWriteMask = write_mask;
if (rt > 0)
m_desc.BlendState.IndependentBlendEnable = TRUE;
}
void GraphicsPipelineBuilder::SetNoBlendingState()
{
SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, D3D12_BLEND_ZERO,
D3D12_BLEND_OP_ADD, D3D12_COLOR_WRITE_ENABLE_ALL);
m_desc.BlendState.IndependentBlendEnable = FALSE;
}
void GraphicsPipelineBuilder::ClearRenderTargets()
{
m_desc.NumRenderTargets = 0;
for (u32 i = 0; i < sizeof(m_desc.RTVFormats) / sizeof(m_desc.RTVFormats[0]); i++)
m_desc.RTVFormats[i] = DXGI_FORMAT_UNKNOWN;
}
void GraphicsPipelineBuilder::SetRenderTarget(u32 rt, DXGI_FORMAT format)
{
m_desc.RTVFormats[rt] = format;
if (rt >= m_desc.NumRenderTargets)
m_desc.NumRenderTargets = rt + 1;
}
void GraphicsPipelineBuilder::ClearDepthStencilFormat()
{
m_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
}
void GraphicsPipelineBuilder::SetDepthStencilFormat(DXGI_FORMAT format)
{
m_desc.DSVFormat = format;
}
RootSignatureBuilder::RootSignatureBuilder()
{
Clear();
}
void RootSignatureBuilder::Clear()
{
m_desc = {};
m_desc.pParameters = m_params.data();
m_params = {};
m_descriptor_ranges = {};
m_num_descriptor_ranges = 0;
}
wil::com_ptr_nothrow<ID3D12RootSignature> RootSignatureBuilder::Create(bool clear /*= true*/)
{
wil::com_ptr_nothrow<ID3D12RootSignature> rs = g_d3d12_context->CreateRootSignature(&m_desc);
if (!rs)
return {};
if (clear)
Clear();
return rs;
}
void RootSignatureBuilder::SetInputAssemblerFlag()
{
m_desc.Flags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
}
u32 RootSignatureBuilder::Add32BitConstants(u32 shader_reg, u32 num_values, D3D12_SHADER_VISIBILITY visibility)
{
const u32 index = m_desc.NumParameters++;
m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
m_params[index].ShaderVisibility = visibility;
m_params[index].Constants.ShaderRegister = shader_reg;
m_params[index].Constants.RegisterSpace = 0;
m_params[index].Constants.Num32BitValues = num_values;
return index;
}
u32 RootSignatureBuilder::AddCBVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility)
{
const u32 index = m_desc.NumParameters++;
m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
m_params[index].ShaderVisibility = visibility;
m_params[index].Descriptor.ShaderRegister = shader_reg;
m_params[index].Descriptor.RegisterSpace = 0;
return index;
}
u32 RootSignatureBuilder::AddSRVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility)
{
const u32 index = m_desc.NumParameters++;
m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
m_params[index].ShaderVisibility = visibility;
m_params[index].Descriptor.ShaderRegister = shader_reg;
m_params[index].Descriptor.RegisterSpace = 0;
return index;
}
u32 RootSignatureBuilder::AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE rt, u32 start_shader_reg, u32 num_shader_regs,
D3D12_SHADER_VISIBILITY visibility)
{
const u32 index = m_desc.NumParameters++;
const u32 dr_index = m_num_descriptor_ranges++;
m_descriptor_ranges[dr_index].RangeType = rt;
m_descriptor_ranges[dr_index].NumDescriptors = num_shader_regs;
m_descriptor_ranges[dr_index].BaseShaderRegister = start_shader_reg;
m_descriptor_ranges[dr_index].RegisterSpace = 0;
m_descriptor_ranges[dr_index].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
m_params[index].DescriptorTable.pDescriptorRanges = &m_descriptor_ranges[dr_index];
m_params[index].DescriptorTable.NumDescriptorRanges = 1;
m_params[index].ShaderVisibility = visibility;
return index;
}
+121
View File
@@ -0,0 +1,121 @@
/* 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/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/RedtapeWindows.h"
#include <array>
#include <d3d12.h>
#include <wil/com.h>
namespace D3D12
{
class ShaderCache;
class RootSignatureBuilder
{
public:
enum : u32
{
MAX_PARAMETERS = 16,
MAX_DESCRIPTOR_RANGES = 16
};
RootSignatureBuilder();
void Clear();
wil::com_ptr_nothrow<ID3D12RootSignature> Create(bool clear = true);
void SetInputAssemblerFlag();
u32 Add32BitConstants(u32 shader_reg, u32 num_values, D3D12_SHADER_VISIBILITY visibility);
u32 AddCBVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility);
u32 AddSRVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility);
u32 AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE rt, u32 start_shader_reg, u32 num_shader_regs,
D3D12_SHADER_VISIBILITY visibility);
private:
D3D12_ROOT_SIGNATURE_DESC m_desc{};
std::array<D3D12_ROOT_PARAMETER, MAX_PARAMETERS> m_params{};
std::array<D3D12_DESCRIPTOR_RANGE, MAX_DESCRIPTOR_RANGES> m_descriptor_ranges{};
u32 m_num_descriptor_ranges = 0;
};
class GraphicsPipelineBuilder
{
public:
enum : u32
{
MAX_VERTEX_ATTRIBUTES = 16,
};
GraphicsPipelineBuilder();
~GraphicsPipelineBuilder() = default;
void Clear();
wil::com_ptr_nothrow<ID3D12PipelineState> Create(ID3D12Device* device, bool clear = true);
wil::com_ptr_nothrow<ID3D12PipelineState> Create(ID3D12Device* device, ShaderCache& cache, bool clear = true);
void SetRootSignature(ID3D12RootSignature* rs);
void SetVertexShader(const void* data, u32 data_size);
void SetGeometryShader(const void* data, u32 data_size);
void SetPixelShader(const void* data, u32 data_size);
void SetVertexShader(const ID3DBlob* blob);
void SetGeometryShader(const ID3DBlob* blob);
void SetPixelShader(const ID3DBlob* blob);
void AddVertexAttribute(const char* semantic_name, u32 semantic_index, DXGI_FORMAT format, u32 buffer, u32 offset);
void SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE type);
void SetRasterizationState(D3D12_FILL_MODE polygon_mode, D3D12_CULL_MODE cull_mode, bool front_face_ccw);
void SetMultisamples(u32 multisamples);
void SetNoCullRasterizationState();
void SetDepthState(bool depth_test, bool depth_write, D3D12_COMPARISON_FUNC compare_op);
void SetStencilState(bool stencil_test, u8 read_mask, u8 write_mask, const D3D12_DEPTH_STENCILOP_DESC& front, const D3D12_DEPTH_STENCILOP_DESC& back);
void SetNoDepthTestState();
void SetNoStencilState();
void SetBlendState(u32 rt, bool blend_enable, D3D12_BLEND src_factor, D3D12_BLEND dst_factor, D3D12_BLEND_OP op,
D3D12_BLEND alpha_src_factor, D3D12_BLEND alpha_dst_factor, D3D12_BLEND_OP alpha_op,
u8 write_mask = D3D12_COLOR_WRITE_ENABLE_ALL);
void SetNoBlendingState();
void ClearRenderTargets();
void SetRenderTarget(u32 rt, DXGI_FORMAT format);
void ClearDepthStencilFormat();
void SetDepthStencilFormat(DXGI_FORMAT format);
private:
D3D12_GRAPHICS_PIPELINE_STATE_DESC m_desc{};
std::array<D3D12_INPUT_ELEMENT_DESC, MAX_VERTEX_ATTRIBUTES> m_input_elements{};
};
} // namespace D3D12
+679
View File
@@ -0,0 +1,679 @@
/* 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 "common/PrecompiledHeader.h"
#include "common/D3D12/Context.h"
#include "common/Assertions.h"
#include "common/ScopedGuard.h"
#include "common/Console.h"
#include "D3D12MemAlloc.h"
#include <algorithm>
#include <array>
#include <dxgi1_4.h>
#include <queue>
#include <vector>
std::unique_ptr<D3D12::Context> g_d3d12_context;
using namespace D3D12;
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
// Private D3D12 state
static HMODULE s_d3d12_library;
static PFN_D3D12_CREATE_DEVICE s_d3d12_create_device;
static PFN_D3D12_GET_DEBUG_INTERFACE s_d3d12_get_debug_interface;
static PFN_D3D12_SERIALIZE_ROOT_SIGNATURE s_d3d12_serialize_root_signature;
static bool LoadD3D12Library()
{
if ((s_d3d12_library = LoadLibraryW(L"d3d12.dll")) == nullptr ||
(s_d3d12_create_device =
reinterpret_cast<PFN_D3D12_CREATE_DEVICE>(GetProcAddress(s_d3d12_library, "D3D12CreateDevice"))) == nullptr ||
(s_d3d12_get_debug_interface = reinterpret_cast<PFN_D3D12_GET_DEBUG_INTERFACE>(
GetProcAddress(s_d3d12_library, "D3D12GetDebugInterface"))) == nullptr ||
(s_d3d12_serialize_root_signature = reinterpret_cast<PFN_D3D12_SERIALIZE_ROOT_SIGNATURE>(
GetProcAddress(s_d3d12_library, "D3D12SerializeRootSignature"))) == nullptr)
{
Console.Error("d3d12.dll could not be loaded.");
s_d3d12_create_device = nullptr;
s_d3d12_get_debug_interface = nullptr;
s_d3d12_serialize_root_signature = nullptr;
if (s_d3d12_library)
FreeLibrary(s_d3d12_library);
s_d3d12_library = nullptr;
return false;
}
return true;
}
static void UnloadD3D12Library()
{
s_d3d12_serialize_root_signature = nullptr;
s_d3d12_get_debug_interface = nullptr;
s_d3d12_create_device = nullptr;
if (s_d3d12_library)
{
FreeLibrary(s_d3d12_library);
s_d3d12_library = nullptr;
}
}
#else
static const PFN_D3D12_CREATE_DEVICE s_d3d12_create_device = D3D12CreateDevice;
static const PFN_D3D12_GET_DEBUG_INTERFACE s_d3d12_get_debug_interface = D3D12GetDebugInterface;
static const PFN_D3D12_SERIALIZE_ROOT_SIGNATURE s_d3d12_serialize_root_signature = D3D12SerializeRootSignature;
static bool LoadD3D12Library()
{
return true;
}
static void UnloadD3D12Library() {}
#endif
Context::Context() = default;
Context::~Context()
{
DestroyResources();
}
Context::ComPtr<ID3DBlob> Context::SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc)
{
ComPtr<ID3DBlob> blob;
ComPtr<ID3DBlob> error_blob;
const HRESULT hr = s_d3d12_serialize_root_signature(desc, D3D_ROOT_SIGNATURE_VERSION_1, blob.put(),
error_blob.put());
if (FAILED(hr))
{
Console.Error("D3D12SerializeRootSignature() failed: %08X", hr);
if (error_blob)
Console.Error("%s", error_blob->GetBufferPointer());
return {};
}
return blob;
}
D3D12::Context::ComPtr<ID3D12RootSignature> Context::CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc)
{
ComPtr<ID3DBlob> blob = SerializeRootSignature(desc);
if (!blob)
return {};
ComPtr<ID3D12RootSignature> rs;
const HRESULT hr =
m_device->CreateRootSignature(0, blob->GetBufferPointer(), blob->GetBufferSize(), IID_PPV_ARGS(rs.put()));
if (FAILED(hr))
{
Console.Error("CreateRootSignature() failed: %08X", hr);
return {};
}
return rs;
}
bool Context::SupportsTextureFormat(DXGI_FORMAT format)
{
constexpr u32 required = D3D12_FORMAT_SUPPORT1_TEXTURE2D | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE;
D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {format};
return SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))) &&
(support.Support1 & required) == required;
}
bool Context::Create(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer)
{
pxAssertRel(!g_d3d12_context, "No context exists");
if (!LoadD3D12Library())
return false;
g_d3d12_context.reset(new Context());
if (!g_d3d12_context->CreateDevice(dxgi_factory, adapter_index, enable_debug_layer) ||
!g_d3d12_context->CreateCommandQueue() || !g_d3d12_context->CreateAllocator() ||
!g_d3d12_context->CreateFence() || !g_d3d12_context->CreateDescriptorHeaps() ||
!g_d3d12_context->CreateCommandLists() || !g_d3d12_context->CreateTimestampQuery() ||
!g_d3d12_context->CreateTextureStreamBuffer())
{
Destroy();
return false;
}
return true;
}
void Context::Destroy()
{
if (g_d3d12_context)
g_d3d12_context.reset();
UnloadD3D12Library();
}
u32 Context::GetAdapterVendorID() const
{
if (!m_adapter)
return 0;
DXGI_ADAPTER_DESC desc;
if (FAILED(m_adapter->GetDesc(&desc)))
return 0;
return desc.VendorId;
}
bool Context::CreateDevice(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer)
{
ComPtr<IDXGIAdapter> adapter;
HRESULT hr = dxgi_factory->EnumAdapters(adapter_index, &adapter);
if (FAILED(hr))
{
Console.Error("Adapter %u not found, using default", adapter_index);
adapter = nullptr;
}
else
{
DXGI_ADAPTER_DESC adapter_desc;
if (SUCCEEDED(adapter->GetDesc(&adapter_desc)))
{
char adapter_name_buffer[128];
const int name_length = WideCharToMultiByte(CP_UTF8, 0, adapter_desc.Description,
static_cast<int>(std::wcslen(adapter_desc.Description)),
adapter_name_buffer, std::size(adapter_name_buffer), 0, nullptr);
if (name_length >= 0)
{
adapter_name_buffer[name_length] = 0;
Console.WriteLn("D3D Adapter: %s", adapter_name_buffer);
}
}
}
// Enabling the debug layer will fail if the Graphics Tools feature is not installed.
if (enable_debug_layer)
{
hr = s_d3d12_get_debug_interface(IID_PPV_ARGS(&m_debug_interface));
if (SUCCEEDED(hr))
{
m_debug_interface->EnableDebugLayer();
}
else
{
Console.Error("Debug layer requested but not available.");
enable_debug_layer = false;
}
}
// Create the actual device.
hr = s_d3d12_create_device(adapter.get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
pxAssertRel(SUCCEEDED(hr), "Create D3D12 device");
if (FAILED(hr))
return false;
// get adapter
ComPtr<IDXGIFactory4> dxgi_factory4;
if (SUCCEEDED(dxgi_factory->QueryInterface<IDXGIFactory4>(dxgi_factory4.put())))
{
const LUID luid(m_device->GetAdapterLuid());
if (FAILED(dxgi_factory4->EnumAdapterByLuid(luid, IID_PPV_ARGS(m_adapter.put()))))
Console.Error("Failed to get lookup adapter by device LUID");
}
if (enable_debug_layer)
{
ComPtr<ID3D12InfoQueue> info_queue = m_device.try_query<ID3D12InfoQueue>();
if (info_queue)
{
if (IsDebuggerPresent())
{
info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);
}
D3D12_INFO_QUEUE_FILTER filter = {};
std::array<D3D12_MESSAGE_ID, 5> id_list{
D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET,
D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH,
D3D12_MESSAGE_ID_DRAW_EMPTY_SCISSOR_RECTANGLE,
};
filter.DenyList.NumIDs = static_cast<UINT>(id_list.size());
filter.DenyList.pIDList = id_list.data();
info_queue->PushStorageFilter(&filter);
}
}
return true;
}
bool Context::CreateCommandQueue()
{
const D3D12_COMMAND_QUEUE_DESC queue_desc = {D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_PRIORITY_NORMAL,
D3D12_COMMAND_QUEUE_FLAG_NONE};
HRESULT hr = m_device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&m_command_queue));
pxAssertRel(SUCCEEDED(hr), "Create command queue");
return SUCCEEDED(hr);
}
bool Context::CreateAllocator()
{
D3D12MA::ALLOCATOR_DESC allocatorDesc = {};
allocatorDesc.pDevice = m_device.get();
allocatorDesc.pAdapter = m_adapter.get();
allocatorDesc.Flags = D3D12MA::ALLOCATOR_FLAG_SINGLETHREADED | D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED /* | D3D12MA::ALLOCATOR_FLAG_ALWAYS_COMMITTED*/;
const HRESULT hr = D3D12MA::CreateAllocator(&allocatorDesc, m_allocator.put());
if (FAILED(hr))
{
Console.Error("D3D12MA::CreateAllocator() failed with HRESULT %08X", hr);
return false;
}
return true;
}
bool Context::CreateFence()
{
HRESULT hr = m_device->CreateFence(m_completed_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence));
pxAssertRel(SUCCEEDED(hr), "Create fence");
if (FAILED(hr))
return false;
m_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr);
pxAssertRel(m_fence_event != NULL, "Create fence event");
if (!m_fence_event)
return false;
return true;
}
bool Context::CreateDescriptorHeaps()
{
static constexpr size_t MAX_SRVS = 32768;
static constexpr size_t MAX_RTVS = 16384;
static constexpr size_t MAX_DSVS = 16384;
static constexpr size_t MAX_CPU_SAMPLERS = 1024;
if (!m_descriptor_heap_manager.Create(m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, MAX_SRVS, false) ||
!m_rtv_heap_manager.Create(m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV, MAX_RTVS, false) ||
!m_dsv_heap_manager.Create(m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_DSV, MAX_DSVS, false) ||
!m_sampler_heap_manager.Create(m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, MAX_CPU_SAMPLERS, false))
{
return false;
}
// Allocate null SRV descriptor for unbound textures.
constexpr D3D12_SHADER_RESOURCE_VIEW_DESC null_srv_desc = {DXGI_FORMAT_R8G8B8A8_UNORM, D3D12_SRV_DIMENSION_TEXTURE2D,
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING};
if (!m_descriptor_heap_manager.Allocate(&m_null_srv_descriptor))
{
pxFailRel("Failed to allocate null descriptor");
return false;
}
m_device->CreateShaderResourceView(nullptr, &null_srv_desc, m_null_srv_descriptor.cpu_handle);
return true;
}
bool Context::CreateCommandLists()
{
static constexpr size_t MAX_GPU_SRVS = 32768;
static constexpr size_t MAX_GPU_SAMPLERS = 2048;
for (u32 i = 0; i < NUM_COMMAND_LISTS; i++)
{
CommandListResources& res = m_command_lists[i];
HRESULT hr;
for (u32 i = 0; i < 2; i++)
{
hr = m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
IID_PPV_ARGS(res.command_allocators[i].put()));
pxAssertRel(SUCCEEDED(hr), "Create command allocator");
if (FAILED(hr))
return false;
hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
res.command_allocators[i].get(), nullptr,
IID_PPV_ARGS(res.command_lists[i].put()));
if (FAILED(hr))
{
Console.Error("Failed to create command list: %08X", hr);
return false;
}
// Close the command lists, since the first thing we do is reset them.
hr = res.command_lists[i]->Close();
pxAssertRel(SUCCEEDED(hr), "Closing new command list failed");
if (FAILED(hr))
return false;
}
if (!res.descriptor_allocator.Create(m_device.get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, MAX_GPU_SRVS))
{
Console.Error("Failed to create per frame descriptor allocator");
return false;
}
if (!res.sampler_allocator.Create(m_device.get(), MAX_GPU_SAMPLERS))
{
Console.Error("Failed to create per frame sampler allocator");
return false;
}
}
MoveToNextCommandList();
return true;
}
bool Context::CreateTextureStreamBuffer()
{
return m_texture_stream_buffer.Create(TEXTURE_UPLOAD_BUFFER_SIZE);
}
void Context::MoveToNextCommandList()
{
m_current_command_list = (m_current_command_list + 1) % NUM_COMMAND_LISTS;
m_current_fence_value++;
// We may have to wait if this command list hasn't finished on the GPU.
CommandListResources& res = m_command_lists[m_current_command_list];
WaitForFence(res.ready_fence_value);
res.ready_fence_value = m_current_fence_value;
res.init_command_list_used = false;
// Begin command list.
res.command_allocators[1]->Reset();
res.command_lists[1]->Reset(res.command_allocators[1].get(), nullptr);
res.descriptor_allocator.Reset();
if (res.sampler_allocator.ShouldReset())
res.sampler_allocator.Reset();
if (res.has_timestamp_query)
{
// readback timestamp from the last time this cmdlist was used.
// we don't need to worry about disjoint in dx12, the frequency is reliable within a single cmdlist.
const u32 offset = (m_current_command_list * (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST));
const D3D12_RANGE read_range = {offset, offset + (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST)};
void* map;
HRESULT hr = m_timestamp_query_buffer->Map(0, &read_range, &map);
if (SUCCEEDED(hr))
{
u64 timestamps[2];
std::memcpy(timestamps, static_cast<const u8*>(map) + offset, sizeof(timestamps));
m_accumulated_gpu_time += static_cast<float>(static_cast<double>(timestamps[1] - timestamps[0]) / m_timestamp_frequency);
const D3D12_RANGE write_range = {};
m_timestamp_query_buffer->Unmap(0, &write_range);
}
else
{
Console.Warning("Map() for timestamp query failed: %08X", hr);
}
}
res.has_timestamp_query = m_gpu_timing_enabled;
if (m_gpu_timing_enabled)
{
res.command_lists[1]->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST);
}
ID3D12DescriptorHeap* heaps[2] = {res.descriptor_allocator.GetDescriptorHeap(), res.sampler_allocator.GetDescriptorHeap()};
res.command_lists[1]->SetDescriptorHeaps(std::size(heaps), heaps);
m_allocator->SetCurrentFrameIndex(static_cast<UINT>(m_current_fence_value));
}
ID3D12GraphicsCommandList4* Context::GetInitCommandList()
{
CommandListResources& res = m_command_lists[m_current_command_list];
if (!res.init_command_list_used)
{
HRESULT hr = res.command_allocators[0]->Reset();
pxAssertMsg(SUCCEEDED(hr), "Reset init command allocator failed");
res.command_lists[0]->Reset(res.command_allocators[0].get(), nullptr);
pxAssertMsg(SUCCEEDED(hr), "Reset init command list failed");
res.init_command_list_used = true;
}
return res.command_lists[0].get();
}
void Context::ExecuteCommandList(bool wait_for_completion)
{
CommandListResources& res = m_command_lists[m_current_command_list];
HRESULT hr;
if (res.has_timestamp_query)
{
// write the timestamp back at the end of the cmdlist
res.command_lists[1]->EndQuery(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
(m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST) + 1);
res.command_lists[1]->ResolveQueryData(m_timestamp_query_heap.get(), D3D12_QUERY_TYPE_TIMESTAMP,
m_current_command_list * NUM_TIMESTAMP_QUERIES_PER_CMDLIST, NUM_TIMESTAMP_QUERIES_PER_CMDLIST,
m_timestamp_query_buffer.get(), m_current_command_list * (sizeof(u64) * NUM_TIMESTAMP_QUERIES_PER_CMDLIST));
}
if (res.init_command_list_used)
{
hr = res.command_lists[0]->Close();
pxAssertRel(SUCCEEDED(hr), "Close init command list");
}
// Close and queue command list.
hr = res.command_lists[1]->Close();
pxAssertRel(SUCCEEDED(hr), "Close command list");
if (res.init_command_list_used)
{
const std::array<ID3D12CommandList*, 2> execute_lists{res.command_lists[0].get(), res.command_lists[1].get()};
m_command_queue->ExecuteCommandLists(static_cast<UINT>(execute_lists.size()), execute_lists.data());
}
else
{
const std::array<ID3D12CommandList*, 1> execute_lists{res.command_lists[1].get()};
m_command_queue->ExecuteCommandLists(static_cast<UINT>(execute_lists.size()), execute_lists.data());
}
// Update fence when GPU has completed.
hr = m_command_queue->Signal(m_fence.get(), m_current_fence_value);
pxAssertRel(SUCCEEDED(hr), "Signal fence");
MoveToNextCommandList();
if (wait_for_completion)
WaitForFence(res.ready_fence_value);
}
void Context::InvalidateSamplerGroups()
{
for (CommandListResources& res : m_command_lists)
res.sampler_allocator.InvalidateCache();
}
void Context::DeferObjectDestruction(ID3D12DeviceChild* resource)
{
if (!resource)
return;
resource->AddRef();
m_command_lists[m_current_command_list].pending_resources.emplace_back(nullptr, resource);
}
void Context::DeferResourceDestruction(D3D12MA::Allocation* allocation, ID3D12Resource* resource)
{
if (!resource)
return;
if (allocation)
allocation->AddRef();
resource->AddRef();
m_command_lists[m_current_command_list].pending_resources.emplace_back(allocation, resource);
}
void Context::DeferDescriptorDestruction(DescriptorHeapManager& manager, u32 index)
{
m_command_lists[m_current_command_list].pending_descriptors.emplace_back(manager, index);
}
void Context::DeferDescriptorDestruction(DescriptorHeapManager& manager, DescriptorHandle* handle)
{
if (handle->index == DescriptorHandle::INVALID_INDEX)
return;
m_command_lists[m_current_command_list].pending_descriptors.emplace_back(manager, handle->index);
handle->Clear();
}
void Context::DestroyPendingResources(CommandListResources& cmdlist)
{
for (const auto& dd : cmdlist.pending_descriptors)
dd.first.Free(dd.second);
cmdlist.pending_descriptors.clear();
for (const auto& it : cmdlist.pending_resources)
{
if (it.first)
it.first->Release();
it.second->Release();
}
cmdlist.pending_resources.clear();
}
void Context::DestroyResources()
{
ExecuteCommandList(true);
m_texture_stream_buffer.Destroy(false);
m_descriptor_heap_manager.Free(&m_null_srv_descriptor);
m_timestamp_query_buffer.reset();
m_timestamp_query_allocation.reset();
m_sampler_heap_manager.Destroy();
m_dsv_heap_manager.Destroy();
m_rtv_heap_manager.Destroy();
m_descriptor_heap_manager.Destroy();
m_command_lists = {};
m_current_command_list = 0;
m_completed_fence_value = 0;
m_current_fence_value = 0;
if (m_fence_event)
{
CloseHandle(m_fence_event);
m_fence_event = {};
}
m_allocator.reset();
m_command_queue.reset();
m_debug_interface.reset();
m_device.reset();
}
void Context::WaitForFence(u64 fence)
{
if (m_completed_fence_value >= fence)
return;
// Try non-blocking check.
m_completed_fence_value = m_fence->GetCompletedValue();
if (m_completed_fence_value < fence)
{
// Fall back to event.
HRESULT hr = m_fence->SetEventOnCompletion(fence, m_fence_event);
pxAssertRel(SUCCEEDED(hr), "Set fence event on completion");
WaitForSingleObject(m_fence_event, INFINITE);
m_completed_fence_value = m_fence->GetCompletedValue();
}
// Release resources for as many command lists which have completed.
u32 index = (m_current_command_list + 1) % NUM_COMMAND_LISTS;
for (u32 i = 0; i < NUM_COMMAND_LISTS; i++)
{
CommandListResources& res = m_command_lists[index];
if (m_completed_fence_value < res.ready_fence_value)
break;
DestroyPendingResources(res);
index = (index + 1) % NUM_COMMAND_LISTS;
}
}
void Context::WaitForGPUIdle()
{
u32 index = (m_current_command_list + 1) % NUM_COMMAND_LISTS;
for (u32 i = 0; i < (NUM_COMMAND_LISTS - 1); i++)
{
WaitForFence(m_command_lists[index].ready_fence_value);
index = (index + 1) % NUM_COMMAND_LISTS;
}
}
bool Context::CreateTimestampQuery()
{
constexpr u32 QUERY_COUNT = NUM_TIMESTAMP_QUERIES_PER_CMDLIST * NUM_COMMAND_LISTS;
constexpr u32 BUFFER_SIZE = sizeof(u64) * QUERY_COUNT;
const D3D12_QUERY_HEAP_DESC desc = {D3D12_QUERY_HEAP_TYPE_TIMESTAMP, QUERY_COUNT};
HRESULT hr = m_device->CreateQueryHeap(&desc, IID_PPV_ARGS(m_timestamp_query_heap.put()));
if (FAILED(hr))
{
Console.Error("CreateQueryHeap() for timestamp failed with %08X", hr);
return false;
}
const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_READBACK};
const D3D12_RESOURCE_DESC resource_desc = {
D3D12_RESOURCE_DIMENSION_BUFFER, 0, BUFFER_SIZE, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
D3D12_RESOURCE_FLAG_NONE};
hr = m_allocator->CreateResource(&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
m_timestamp_query_allocation.put(), IID_PPV_ARGS(m_timestamp_query_buffer.put()));
if (FAILED(hr))
{
Console.Error("CreateResource() for timestamp failed with %08X", hr);
return false;
}
u64 frequency;
hr = m_command_queue->GetTimestampFrequency(&frequency);
if (FAILED(hr))
{
Console.Error("GetTimestampFrequency() failed: %08X", hr);
return false;
}
m_timestamp_frequency = static_cast<double>(frequency) / 1000.0;
return true;
}
float Context::GetAndResetAccumulatedGPUTime()
{
const float time = m_accumulated_gpu_time;
m_accumulated_gpu_time = 0.0f;
return time;
}
void Context::SetEnableGPUTiming(bool enabled)
{
m_gpu_timing_enabled = enabled;
}
+207
View File
@@ -0,0 +1,207 @@
/* 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/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/RedtapeWindows.h"
#include "common/D3D12/DescriptorHeapManager.h"
#include "common/D3D12/StreamBuffer.h"
#include <array>
#include <d3d12.h>
#include <memory>
#include <vector>
#include <wil/com.h>
struct IDXGIAdapter;
struct IDXGIFactory;
namespace D3D12MA
{
class Allocator;
class Allocation;
} // namespace D3D12MA
namespace D3D12
{
class Context
{
public:
template <typename T>
using ComPtr = wil::com_ptr_nothrow<T>;
enum : u32
{
/// Number of command lists. One is being built while the other(s) are executed.
NUM_COMMAND_LISTS = 3,
/// Textures that don't fit into this buffer will be uploaded with a staging buffer.
TEXTURE_UPLOAD_BUFFER_SIZE = 64 * 1024 * 1024,
/// Maximum number of samples in a single allocation group.
SAMPLER_GROUP_SIZE = 2,
/// Start/End timestamp queries.
NUM_TIMESTAMP_QUERIES_PER_CMDLIST = 2,
};
~Context();
/// Creates new device and context.
static bool Create(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer);
/// Destroys active context.
static void Destroy();
__fi IDXGIAdapter* GetAdapter() const { return m_adapter.get(); }
__fi ID3D12Device* GetDevice() const { return m_device.get(); }
__fi ID3D12CommandQueue* GetCommandQueue() const { return m_command_queue.get(); }
__fi D3D12MA::Allocator* GetAllocator() const { return m_allocator.get(); }
/// Returns the PCI vendor ID of the device, if known.
u32 GetAdapterVendorID() const;
/// Returns the current command list, commands can be recorded directly.
ID3D12GraphicsCommandList4* GetCommandList() const
{
return m_command_lists[m_current_command_list].command_lists[1].get();
}
/// Returns the init command list for uploading.
ID3D12GraphicsCommandList4* GetInitCommandList();
/// Returns the per-frame SRV/CBV/UAV allocator.
DescriptorAllocator& GetDescriptorAllocator()
{
return m_command_lists[m_current_command_list].descriptor_allocator;
}
/// Returns the per-frame sampler allocator.
GroupedSamplerAllocator<SAMPLER_GROUP_SIZE>& GetSamplerAllocator()
{
return m_command_lists[m_current_command_list].sampler_allocator;
}
/// Invalidates GPU-side sampler caches for all command lists. Call after you've freed samplers,
/// and are going to re-use the handles from GetSamplerHeapManager().
void InvalidateSamplerGroups();
// Descriptor manager access.
DescriptorHeapManager& GetDescriptorHeapManager() { return m_descriptor_heap_manager; }
DescriptorHeapManager& GetRTVHeapManager() { return m_rtv_heap_manager; }
DescriptorHeapManager& GetDSVHeapManager() { return m_dsv_heap_manager; }
DescriptorHeapManager& GetSamplerHeapManager() { return m_sampler_heap_manager; }
const DescriptorHandle& GetNullSRVDescriptor() const { return m_null_srv_descriptor; }
StreamBuffer& GetTextureStreamBuffer() { return m_texture_stream_buffer; }
// Root signature access.
ComPtr<ID3DBlob> SerializeRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc);
ComPtr<ID3D12RootSignature> CreateRootSignature(const D3D12_ROOT_SIGNATURE_DESC* desc);
/// Fence value for current command list.
u64 GetCurrentFenceValue() const { return m_current_fence_value; }
/// Last "completed" fence.
u64 GetCompletedFenceValue() const { return m_completed_fence_value; }
/// Feature level to use when compiling shaders.
D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; }
/// Test for support for the specified texture format.
bool SupportsTextureFormat(DXGI_FORMAT format);
/// Executes the current command list.
void ExecuteCommandList(bool wait_for_completion);
/// Waits for a specific fence.
void WaitForFence(u64 fence);
/// Waits for any in-flight command buffers to complete.
void WaitForGPUIdle();
/// Defers destruction of a D3D resource (associates it with the current list).
void DeferObjectDestruction(ID3D12DeviceChild* resource);
/// Defers destruction of a D3D resource (associates it with the current list).
void DeferResourceDestruction(D3D12MA::Allocation* allocation, ID3D12Resource* resource);
/// Defers destruction of a descriptor handle (associates it with the current list).
void DeferDescriptorDestruction(DescriptorHeapManager& manager, u32 index);
void DeferDescriptorDestruction(DescriptorHeapManager& manager, DescriptorHandle* handle);
float GetAndResetAccumulatedGPUTime();
void SetEnableGPUTiming(bool enabled);
private:
struct CommandListResources
{
std::array<ComPtr<ID3D12CommandAllocator>, 2> command_allocators;
std::array<ComPtr<ID3D12GraphicsCommandList4>, 2> command_lists;
DescriptorAllocator descriptor_allocator;
GroupedSamplerAllocator<SAMPLER_GROUP_SIZE> sampler_allocator;
std::vector<std::pair<D3D12MA::Allocation*, ID3D12DeviceChild*>> pending_resources;
std::vector<std::pair<DescriptorHeapManager&, u32>> pending_descriptors;
u64 ready_fence_value = 0;
bool init_command_list_used = false;
bool has_timestamp_query = false;
};
Context();
bool CreateDevice(IDXGIFactory* dxgi_factory, u32 adapter_index, bool enable_debug_layer);
bool CreateCommandQueue();
bool CreateAllocator();
bool CreateFence();
bool CreateDescriptorHeaps();
bool CreateCommandLists();
bool CreateTextureStreamBuffer();
bool CreateTimestampQuery();
void MoveToNextCommandList();
void DestroyPendingResources(CommandListResources& cmdlist);
void DestroyResources();
ComPtr<IDXGIAdapter> m_adapter;
ComPtr<ID3D12Debug> m_debug_interface;
ComPtr<ID3D12Device> m_device;
ComPtr<ID3D12CommandQueue> m_command_queue;
ComPtr<D3D12MA::Allocator> m_allocator;
ComPtr<ID3D12Fence> m_fence;
HANDLE m_fence_event = {};
u32 m_current_fence_value = 0;
u64 m_completed_fence_value = 0;
std::array<CommandListResources, NUM_COMMAND_LISTS> m_command_lists;
u32 m_current_command_list = NUM_COMMAND_LISTS - 1;
ComPtr<ID3D12QueryHeap> m_timestamp_query_heap;
ComPtr<ID3D12Resource> m_timestamp_query_buffer;
ComPtr<D3D12MA::Allocation> m_timestamp_query_allocation;
double m_timestamp_frequency = 0.0;
float m_accumulated_gpu_time = 0.0f;
bool m_gpu_timing_enabled = false;
DescriptorHeapManager m_descriptor_heap_manager;
DescriptorHeapManager m_rtv_heap_manager;
DescriptorHeapManager m_dsv_heap_manager;
DescriptorHeapManager m_sampler_heap_manager;
DescriptorHandle m_null_srv_descriptor;
StreamBuffer m_texture_stream_buffer;
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0;
};
} // namespace D3D12
extern std::unique_ptr<D3D12::Context> g_d3d12_context;
+161
View File
@@ -0,0 +1,161 @@
/* 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 "common/PrecompiledHeader.h"
#include "common/D3D12/DescriptorHeapManager.h"
#include "common/Assertions.h"
using namespace D3D12;
DescriptorHeapManager::DescriptorHeapManager() = default;
DescriptorHeapManager::~DescriptorHeapManager() = default;
bool DescriptorHeapManager::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors,
bool shader_visible)
{
D3D12_DESCRIPTOR_HEAP_DESC desc = {type, static_cast<UINT>(num_descriptors),
shader_visible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE :
D3D12_DESCRIPTOR_HEAP_FLAG_NONE};
HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(m_descriptor_heap.put()));
pxAssertRel(SUCCEEDED(hr), "Create descriptor heap");
if (FAILED(hr))
return false;
m_heap_base_cpu = m_descriptor_heap->GetCPUDescriptorHandleForHeapStart();
m_heap_base_gpu = m_descriptor_heap->GetGPUDescriptorHandleForHeapStart();
m_num_descriptors = num_descriptors;
m_descriptor_increment_size = device->GetDescriptorHandleIncrementSize(type);
// Set all slots to unallocated (1)
const u32 bitset_count = num_descriptors / BITSET_SIZE + (((num_descriptors % BITSET_SIZE) != 0) ? 1 : 0);
m_free_slots.resize(bitset_count);
for (BitSetType& bs : m_free_slots)
bs.flip();
return true;
}
void DescriptorHeapManager::Destroy()
{
for (BitSetType& bs : m_free_slots)
{
pxAssert(bs.all());
}
m_num_descriptors = 0;
m_descriptor_increment_size = 0;
m_heap_base_cpu = {};
m_heap_base_gpu = {};
m_descriptor_heap.reset();
m_free_slots.clear();
}
bool DescriptorHeapManager::Allocate(DescriptorHandle* handle)
{
// Start past the temporary slots, no point in searching those.
for (u32 group = 0; group < m_free_slots.size(); group++)
{
BitSetType& bs = m_free_slots[group];
if (bs.none())
continue;
u32 bit = 0;
for (; bit < BITSET_SIZE; bit++)
{
if (bs[bit])
break;
}
u32 index = group * BITSET_SIZE + bit;
bs[bit] = false;
handle->index = index;
handle->cpu_handle.ptr = m_heap_base_cpu.ptr + index * m_descriptor_increment_size;
handle->gpu_handle.ptr = m_heap_base_gpu.ptr + index * m_descriptor_increment_size;
return true;
}
pxFailRel("Out of fixed descriptors");
return false;
}
void DescriptorHeapManager::Free(u32 index)
{
pxAssert(index < m_num_descriptors);
u32 group = index / BITSET_SIZE;
u32 bit = index % BITSET_SIZE;
m_free_slots[group][bit] = true;
}
void DescriptorHeapManager::Free(DescriptorHandle* handle)
{
if (handle->index == DescriptorHandle::INVALID_INDEX)
return;
Free(handle->index);
handle->Clear();
}
DescriptorAllocator::DescriptorAllocator() = default;
DescriptorAllocator::~DescriptorAllocator() = default;
bool DescriptorAllocator::Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type,
u32 num_descriptors)
{
const D3D12_DESCRIPTOR_HEAP_DESC desc = {type, static_cast<UINT>(num_descriptors),
D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE};
const HRESULT hr = device->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&m_descriptor_heap));
pxAssertRel(SUCCEEDED(hr), "Creating descriptor heap for linear allocator");
if (FAILED(hr))
return false;
m_num_descriptors = num_descriptors;
m_descriptor_increment_size = device->GetDescriptorHandleIncrementSize(type);
m_heap_base_cpu = m_descriptor_heap->GetCPUDescriptorHandleForHeapStart();
m_heap_base_gpu = m_descriptor_heap->GetGPUDescriptorHandleForHeapStart();
return true;
}
void DescriptorAllocator::Destroy()
{
m_descriptor_heap.reset();
m_descriptor_increment_size = 0;
m_num_descriptors = 0;
m_current_offset = 0;
m_heap_base_cpu = {};
m_heap_base_gpu = {};
}
bool DescriptorAllocator::Allocate(u32 num_handles, DescriptorHandle* out_base_handle)
{
if ((m_current_offset + num_handles) > m_num_descriptors)
return false;
out_base_handle->index = m_current_offset;
out_base_handle->cpu_handle.ptr =
m_heap_base_cpu.ptr + m_current_offset * m_descriptor_increment_size;
out_base_handle->gpu_handle.ptr =
m_heap_base_gpu.ptr + m_current_offset * m_descriptor_increment_size;
m_current_offset += num_handles;
return true;
}
void DescriptorAllocator::Reset()
{
m_current_offset = 0;
}
+268
View File
@@ -0,0 +1,268 @@
/* 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/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/HashCombine.h"
#include "common/RedtapeWindows.h"
#include <bitset>
#include <cstring>
#include <d3d12.h>
#include <unordered_map>
#include <vector>
#include <wil/com.h>
namespace D3D12
{
// This class provides an abstraction for D3D12 descriptor heaps.
struct DescriptorHandle final
{
enum : u32
{
INVALID_INDEX = 0xFFFFFFFF
};
D3D12_CPU_DESCRIPTOR_HANDLE cpu_handle{};
D3D12_GPU_DESCRIPTOR_HANDLE gpu_handle{};
u32 index = INVALID_INDEX;
__fi operator bool() const { return index != INVALID_INDEX; }
__fi operator D3D12_CPU_DESCRIPTOR_HANDLE() const { return cpu_handle; }
__fi operator D3D12_GPU_DESCRIPTOR_HANDLE() const { return gpu_handle; }
__fi bool operator==(const DescriptorHandle& rhs) const { return (index == rhs.index); }
__fi bool operator!=(const DescriptorHandle& rhs) const { return (index != rhs.index); }
__fi bool operator<(const DescriptorHandle& rhs) const { return (index < rhs.index); }
__fi bool operator<=(const DescriptorHandle& rhs) const { return (index <= rhs.index); }
__fi bool operator>(const DescriptorHandle& rhs) const { return (index > rhs.index); }
__fi bool operator>=(const DescriptorHandle& rhs) const { return (index >= rhs.index); }
__fi void Clear()
{
cpu_handle = {};
gpu_handle = {};
index = INVALID_INDEX;
}
};
class DescriptorHeapManager final
{
public:
DescriptorHeapManager();
~DescriptorHeapManager();
ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.get(); }
u32 GetDescriptorIncrementSize() const { return m_descriptor_increment_size; }
bool Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors, bool shader_visible);
void Destroy();
bool Allocate(DescriptorHandle* handle);
void Free(DescriptorHandle* handle);
void Free(u32 index);
private:
wil::com_ptr_nothrow<ID3D12DescriptorHeap> m_descriptor_heap;
u32 m_num_descriptors = 0;
u32 m_descriptor_increment_size = 0;
D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_cpu = {};
D3D12_GPU_DESCRIPTOR_HANDLE m_heap_base_gpu = {};
static constexpr u32 BITSET_SIZE = 1024;
using BitSetType = std::bitset<BITSET_SIZE>;
std::vector<BitSetType> m_free_slots = {};
};
class DescriptorAllocator
{
public:
DescriptorAllocator();
~DescriptorAllocator();
__fi ID3D12DescriptorHeap* GetDescriptorHeap() const { return m_descriptor_heap.get(); }
__fi u32 GetDescriptorIncrementSize() const { return m_descriptor_increment_size; }
bool Create(ID3D12Device* device, D3D12_DESCRIPTOR_HEAP_TYPE type, u32 num_descriptors);
void Destroy();
bool Allocate(u32 num_handles, DescriptorHandle* out_base_handle);
void Reset();
private:
wil::com_ptr_nothrow<ID3D12DescriptorHeap> m_descriptor_heap;
u32 m_descriptor_increment_size = 0;
u32 m_num_descriptors = 0;
u32 m_current_offset = 0;
D3D12_CPU_DESCRIPTOR_HANDLE m_heap_base_cpu = {};
D3D12_GPU_DESCRIPTOR_HANDLE m_heap_base_gpu = {};
};
template <u32 NumSamplers>
class GroupedSamplerAllocator : private DescriptorAllocator
{
struct Key
{
u32 idx[NumSamplers];
__fi bool operator==(const Key& rhs) const
{
return (std::memcmp(idx, rhs.idx, sizeof(idx)) == 0);
}
__fi bool operator!=(const Key& rhs) const
{
return (std::memcmp(idx, rhs.idx, sizeof(idx)) != 0);
}
};
struct KeyHash
{
__fi std::size_t operator()(const Key& key) const
{
size_t seed = 0;
for (u32 key : key.idx)
HashCombine(seed, key);
return seed;
}
};
public:
GroupedSamplerAllocator();
~GroupedSamplerAllocator();
using DescriptorAllocator::GetDescriptorHeap;
using DescriptorAllocator::GetDescriptorIncrementSize;
bool Create(ID3D12Device* device, u32 num_descriptors);
void Destroy();
bool LookupSingle(DescriptorHandle* gpu_handle, const DescriptorHandle& cpu_handle);
bool LookupGroup(DescriptorHandle* gpu_handle, const DescriptorHandle* cpu_handles);
// Clears cache but doesn't reset allocator.
void InvalidateCache();
void Reset();
bool ShouldReset() const;
private:
wil::com_ptr_nothrow<ID3D12Device> m_device;
std::unordered_map<Key, D3D12::DescriptorHandle, KeyHash> m_groups;
};
template <u32 NumSamplers>
GroupedSamplerAllocator<NumSamplers>::GroupedSamplerAllocator() = default;
template <u32 NumSamplers>
GroupedSamplerAllocator<NumSamplers>::~GroupedSamplerAllocator() = default;
template <u32 NumSamplers>
bool GroupedSamplerAllocator<NumSamplers>::Create(ID3D12Device* device, u32 num_descriptors)
{
if (!DescriptorAllocator::Create(device, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_descriptors))
return false;
m_device = device;
return true;
}
template <u32 NumSamplers>
void GroupedSamplerAllocator<NumSamplers>::Destroy()
{
DescriptorAllocator::Destroy();
m_device.reset();
}
template <u32 NumSamplers>
void GroupedSamplerAllocator<NumSamplers>::Reset()
{
m_groups.clear();
DescriptorAllocator::Reset();
}
template <u32 NumSamplers>
void GroupedSamplerAllocator<NumSamplers>::InvalidateCache()
{
m_groups.clear();
}
template <u32 NumSamplers>
bool GroupedSamplerAllocator<NumSamplers>::LookupSingle(DescriptorHandle* gpu_handle, const DescriptorHandle& cpu_handle)
{
Key key;
key.idx[0] = cpu_handle.index;
for (u32 i = 1; i < NumSamplers; i++)
key.idx[i] = 0;
auto it = m_groups.find(key);
if (it != m_groups.end())
{
*gpu_handle = it->second;
return true;
}
if (!Allocate(1, gpu_handle))
return false;
m_device->CopyDescriptorsSimple(1, *gpu_handle, cpu_handle, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
m_groups.emplace(key, *gpu_handle);
return true;
}
template <u32 NumSamplers>
bool GroupedSamplerAllocator<NumSamplers>::LookupGroup(DescriptorHandle* gpu_handle, const DescriptorHandle* cpu_handles)
{
Key key;
for (u32 i = 0; i < NumSamplers; i++)
key.idx[i] = cpu_handles[i].index;
auto it = m_groups.find(key);
if (it != m_groups.end())
{
*gpu_handle = it->second;
return true;
}
if (!Allocate(NumSamplers, gpu_handle))
return false;
D3D12_CPU_DESCRIPTOR_HANDLE dst_handle = *gpu_handle;
UINT dst_size = NumSamplers;
D3D12_CPU_DESCRIPTOR_HANDLE src_handles[NumSamplers];
UINT src_sizes[NumSamplers];
for (u32 i = 0; i < NumSamplers; i++)
{
src_handles[i] = cpu_handles[i];
src_sizes[i] = 1;
}
m_device->CopyDescriptors(1, &dst_handle, &dst_size, NumSamplers, src_handles, src_sizes, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER);
m_groups.emplace(key, *gpu_handle);
return true;
}
template <u32 NumSamplers>
bool GroupedSamplerAllocator<NumSamplers>::ShouldReset() const
{
// We only reset the sampler heap if more than half of the descriptors are used.
// This saves descriptor copying when there isn't a large number of sampler configs per frame.
return m_groups.size() >= (D3D12_MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE / 2);
}
} // namespace D3D12
+565
View File
@@ -0,0 +1,565 @@
/* 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 "common/PrecompiledHeader.h"
#include "common/D3D12/ShaderCache.h"
#include "common/D3D11/ShaderCompiler.h"
#include "common/FileSystem.h"
#include "common/Console.h"
#include "common/MD5Digest.h"
#include <d3dcompiler.h>
#ifdef _UWP
#include <winrt/Windows.System.Profile.h>
#endif
using namespace D3D12;
#pragma pack(push, 1)
struct CacheIndexEntry
{
u64 source_hash_low;
u64 source_hash_high;
u64 macro_hash_low;
u64 macro_hash_high;
u64 entry_point_low;
u64 entry_point_high;
u32 source_length;
u32 shader_type;
u32 file_offset;
u32 blob_size;
};
#pragma pack(pop)
static bool CanUsePipelineCache()
{
#ifdef _UWP
// GetCachedBlob crashes on XBox UWP for some reason...
const auto version_info = winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo();
const auto device_family = version_info.DeviceFamily();
return (device_family != L"Windows.Xbox");
#else
return true;
#endif
}
ShaderCache::ShaderCache()
: m_use_pipeline_cache(CanUsePipelineCache())
{
}
ShaderCache::~ShaderCache()
{
if (m_pipeline_index_file)
std::fclose(m_pipeline_index_file);
if (m_pipeline_blob_file)
std::fclose(m_pipeline_blob_file);
if (m_shader_index_file)
std::fclose(m_shader_index_file);
if (m_shader_blob_file)
std::fclose(m_shader_blob_file);
}
bool ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const
{
return (source_hash_low == key.source_hash_low && source_hash_high == key.source_hash_high &&
macro_hash_low == key.macro_hash_low && macro_hash_high == key.macro_hash_high &&
entry_point_low == key.entry_point_low && entry_point_high == key.entry_point_high &&
type == key.type && source_length == key.source_length);
}
bool ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const
{
return (source_hash_low != key.source_hash_low || source_hash_high != key.source_hash_high ||
macro_hash_low != key.macro_hash_low || macro_hash_high != key.macro_hash_high ||
entry_point_low != key.entry_point_low || entry_point_high != key.entry_point_high ||
type != key.type || source_length != key.source_length);
}
bool ShaderCache::Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_level, u32 version, bool debug)
{
m_base_path = base_path;
m_feature_level = feature_level;
m_data_version = version;
m_debug = debug;
bool result = true;
if (!base_path.empty())
{
const std::string base_shader_filename = GetCacheBaseFileName(base_path, "shaders", feature_level, debug);
const std::string shader_index_filename = base_shader_filename + ".idx";
const std::string shader_blob_filename = base_shader_filename + ".bin";
if (!ReadExisting(shader_index_filename, shader_blob_filename, m_shader_index_file, m_shader_blob_file,
m_shader_index))
{
result = CreateNew(shader_index_filename, shader_blob_filename, m_shader_index_file, m_shader_blob_file);
}
if (m_use_pipeline_cache && result)
{
const std::string base_pipelines_filename = GetCacheBaseFileName(base_path, "pipelines", feature_level, debug);
const std::string pipelines_index_filename = base_pipelines_filename + ".idx";
const std::string pipelines_blob_filename = base_pipelines_filename + ".bin";
if (!ReadExisting(pipelines_index_filename, pipelines_blob_filename, m_pipeline_index_file, m_pipeline_blob_file,
m_pipeline_index))
{
result = CreateNew(pipelines_index_filename, pipelines_blob_filename, m_pipeline_index_file, m_pipeline_blob_file);
}
}
}
return result;
}
void ShaderCache::InvalidatePipelineCache()
{
m_pipeline_index.clear();
if (m_pipeline_blob_file)
{
std::fclose(m_pipeline_blob_file);
m_pipeline_blob_file = nullptr;
}
if (m_pipeline_index_file)
{
std::fclose(m_pipeline_index_file);
m_pipeline_index_file = nullptr;
}
if (m_use_pipeline_cache)
{
const std::string base_pipelines_filename =
GetCacheBaseFileName(m_base_path, "pipelines", m_feature_level, m_debug);
const std::string pipelines_index_filename = base_pipelines_filename + ".idx";
const std::string pipelines_blob_filename = base_pipelines_filename + ".bin";
CreateNew(pipelines_index_filename, pipelines_blob_filename, m_pipeline_index_file, m_pipeline_blob_file);
}
}
bool ShaderCache::CreateNew(const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file,
std::FILE*& blob_file)
{
if (FileSystem::FileExists(index_filename.c_str()))
{
Console.Warning("Removing existing index file '%s'", index_filename.c_str());
FileSystem::DeleteFilePath(index_filename.c_str());
}
if (FileSystem::FileExists(blob_filename.c_str()))
{
Console.Warning("Removing existing blob file '%s'", blob_filename.c_str());
FileSystem::DeleteFilePath(blob_filename.c_str());
}
index_file = FileSystem::OpenCFile(index_filename.c_str(), "wb");
if (!index_file)
{
Console.Error("Failed to open index file '%s' for writing", index_filename.c_str());
return false;
}
const u32 index_version = FILE_VERSION;
if (std::fwrite(&index_version, sizeof(index_version), 1, index_file) != 1 ||
std::fwrite(&m_data_version, sizeof(m_data_version), 1, index_file) != 1)
{
Console.Error("Failed to write version to index file '%s'", index_filename.c_str());
std::fclose(index_file);
index_file = nullptr;
FileSystem::DeleteFilePath(index_filename.c_str());
return false;
}
blob_file = FileSystem::OpenCFile(blob_filename.c_str(), "w+b");
if (!blob_file)
{
Console.Error("Failed to open blob file '%s' for writing", blob_filename.c_str());
std::fclose(blob_file);
blob_file = nullptr;
FileSystem::DeleteFilePath(index_filename.c_str());
return false;
}
return true;
}
bool ShaderCache::ReadExisting(const std::string& index_filename, const std::string& blob_filename,
std::FILE*& index_file, std::FILE*& blob_file, CacheIndex& index)
{
index_file = FileSystem::OpenCFile(index_filename.c_str(), "r+b");
if (!index_file)
{
// special case here: when there's a sharing violation (i.e. two instances running),
// we don't want to blow away the cache. so just continue without a cache.
if (errno == EACCES)
{
Console.WriteLn("Failed to open shader cache index with EACCES, are you running two instances?");
return true;
}
return false;
}
u32 file_version;
u32 data_version;
if (std::fread(&file_version, sizeof(file_version), 1, index_file) != 1 || file_version != FILE_VERSION ||
std::fread(&data_version, sizeof(data_version), 1, index_file) != 1 || data_version != m_data_version)
{
Console.Error("Bad file version in '%s'", index_filename.c_str());
std::fclose(index_file);
index_file = nullptr;
return false;
}
blob_file = FileSystem::OpenCFile(blob_filename.c_str(), "a+b");
if (!blob_file)
{
Console.Error("Blob file '%s' is missing", blob_filename.c_str());
std::fclose(index_file);
index_file = nullptr;
return false;
}
std::fseek(blob_file, 0, SEEK_END);
const u32 blob_file_size = static_cast<u32>(std::ftell(blob_file));
for (;;)
{
CacheIndexEntry entry;
if (std::fread(&entry, sizeof(entry), 1, index_file) != 1 || (entry.file_offset + entry.blob_size) > blob_file_size)
{
if (std::feof(index_file))
break;
Console.Error("Failed to read entry from '%s', corrupt file?", index_filename.c_str());
index.clear();
std::fclose(blob_file);
blob_file = nullptr;
std::fclose(index_file);
index_file = nullptr;
return false;
}
const CacheIndexKey key{
entry.source_hash_low, entry.source_hash_high,
entry.macro_hash_low, entry.macro_hash_high,
entry.entry_point_low, entry.entry_point_high,
entry.source_length, static_cast<EntryType>(entry.shader_type)};
const CacheIndexData data{entry.file_offset, entry.blob_size};
index.emplace(key, data);
}
// ensure we don't write before seeking
std::fseek(index_file, 0, SEEK_END);
DevCon.WriteLn("Read %zu entries from '%s'", index.size(), index_filename.c_str());
return true;
}
std::string ShaderCache::GetCacheBaseFileName(const std::string_view& base_path, const std::string_view& type,
D3D_FEATURE_LEVEL feature_level, bool debug)
{
std::string base_filename(base_path);
base_filename += FS_OSPATH_SEPARATOR_STR "d3d12_";
base_filename += type;
base_filename += "_";
switch (feature_level)
{
case D3D_FEATURE_LEVEL_10_0:
base_filename += "sm40";
break;
case D3D_FEATURE_LEVEL_10_1:
base_filename += "sm41";
break;
case D3D_FEATURE_LEVEL_11_0:
base_filename += "sm50";
break;
default:
base_filename += "unk";
break;
}
if (debug)
base_filename += "_debug";
return base_filename;
}
union MD5Hash
{
struct
{
u64 low;
u64 high;
};
u8 hash[16];
};
ShaderCache::CacheIndexKey ShaderCache::GetShaderCacheKey(EntryType type, const std::string_view& shader_code,
const D3D_SHADER_MACRO* macros, const char* entry_point)
{
union
{
struct
{
u64 hash_low;
u64 hash_high;
};
u8 hash[16];
};
CacheIndexKey key = {};
key.type = type;
MD5Digest digest;
digest.Update(shader_code.data(), static_cast<u32>(shader_code.length()));
digest.Final(hash);
key.source_hash_low = hash_low;
key.source_hash_high = hash_high;
key.source_length = static_cast<u32>(shader_code.length());
if (macros)
{
digest.Reset();
for (const D3D_SHADER_MACRO* macro = macros; macro->Name != nullptr; macro++)
{
digest.Update(macro->Name, std::strlen(macro->Name));
digest.Update(macro->Definition, std::strlen(macro->Definition));
}
digest.Final(hash);
key.macro_hash_low = hash_low;
key.macro_hash_high = hash_high;
}
digest.Reset();
digest.Update(entry_point, static_cast<u32>(std::strlen(entry_point)));
digest.Final(hash);
key.entry_point_low = hash_low;
key.entry_point_high = hash_high;
return key;
}
ShaderCache::CacheIndexKey ShaderCache::GetPipelineCacheKey(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc)
{
MD5Digest digest;
u32 length = sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC);
if (gpdesc.VS.BytecodeLength > 0)
{
digest.Update(gpdesc.VS.pShaderBytecode, static_cast<u32>(gpdesc.VS.BytecodeLength));
length += static_cast<u32>(gpdesc.VS.BytecodeLength);
}
if (gpdesc.GS.BytecodeLength > 0)
{
digest.Update(gpdesc.GS.pShaderBytecode, static_cast<u32>(gpdesc.GS.BytecodeLength));
length += static_cast<u32>(gpdesc.GS.BytecodeLength);
}
if (gpdesc.PS.BytecodeLength > 0)
{
digest.Update(gpdesc.PS.pShaderBytecode, static_cast<u32>(gpdesc.PS.BytecodeLength));
length += static_cast<u32>(gpdesc.PS.BytecodeLength);
}
digest.Update(&gpdesc.BlendState, sizeof(gpdesc.BlendState));
digest.Update(&gpdesc.SampleMask, sizeof(gpdesc.SampleMask));
digest.Update(&gpdesc.RasterizerState, sizeof(gpdesc.RasterizerState));
digest.Update(&gpdesc.DepthStencilState, sizeof(gpdesc.DepthStencilState));
for (u32 i = 0; i < gpdesc.InputLayout.NumElements; i++)
{
const D3D12_INPUT_ELEMENT_DESC& ie = gpdesc.InputLayout.pInputElementDescs[i];
digest.Update(ie.SemanticName, static_cast<u32>(std::strlen(ie.SemanticName)));
digest.Update(&ie.SemanticIndex, sizeof(ie.SemanticIndex));
digest.Update(&ie.Format, sizeof(ie.Format));
digest.Update(&ie.InputSlot, sizeof(ie.InputSlot));
digest.Update(&ie.AlignedByteOffset, sizeof(ie.AlignedByteOffset));
digest.Update(&ie.InputSlotClass, sizeof(ie.InputSlotClass));
digest.Update(&ie.InstanceDataStepRate, sizeof(ie.InstanceDataStepRate));
length += sizeof(D3D12_INPUT_ELEMENT_DESC);
}
digest.Update(&gpdesc.IBStripCutValue, sizeof(gpdesc.IBStripCutValue));
digest.Update(&gpdesc.PrimitiveTopologyType, sizeof(gpdesc.PrimitiveTopologyType));
digest.Update(&gpdesc.NumRenderTargets, sizeof(gpdesc.NumRenderTargets));
digest.Update(gpdesc.RTVFormats, sizeof(gpdesc.RTVFormats));
digest.Update(&gpdesc.DSVFormat, sizeof(gpdesc.DSVFormat));
digest.Update(&gpdesc.SampleDesc, sizeof(gpdesc.SampleDesc));
digest.Update(&gpdesc.Flags, sizeof(gpdesc.Flags));
MD5Hash h;
digest.Final(h.hash);
return CacheIndexKey{h.low, h.high, 0, 0, 0, 0, length, EntryType::GraphicsPipeline};
}
ShaderCache::ComPtr<ID3DBlob> ShaderCache::GetShaderBlob(EntryType type, std::string_view shader_code,
const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */)
{
const auto key = GetShaderCacheKey(type, shader_code, macros, entry_point);
auto iter = m_shader_index.find(key);
if (iter == m_shader_index.end())
return CompileAndAddShaderBlob(key, shader_code, macros, entry_point);
ComPtr<ID3DBlob> blob;
HRESULT hr = D3DCreateBlob(iter->second.blob_size, blob.put());
if (FAILED(hr) || std::fseek(m_shader_blob_file, iter->second.file_offset, SEEK_SET) != 0 ||
std::fread(blob->GetBufferPointer(), 1, iter->second.blob_size, m_shader_blob_file) != iter->second.blob_size)
{
Console.Error("Read blob from file failed");
return {};
}
return blob;
}
ShaderCache::ComPtr<ID3D12PipelineState> ShaderCache::GetPipelineState(ID3D12Device* device,
const D3D12_GRAPHICS_PIPELINE_STATE_DESC& desc)
{
const auto key = GetPipelineCacheKey(desc);
auto iter = m_pipeline_index.find(key);
if (iter == m_pipeline_index.end())
return CompileAndAddPipeline(device, key, desc);
ComPtr<ID3DBlob> blob;
HRESULT hr = D3DCreateBlob(iter->second.blob_size, blob.put());
if (FAILED(hr) || std::fseek(m_pipeline_blob_file, iter->second.file_offset, SEEK_SET) != 0 ||
std::fread(blob->GetBufferPointer(), 1, iter->second.blob_size, m_pipeline_blob_file) != iter->second.blob_size)
{
Console.Error("Read blob from file failed");
return {};
}
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc_with_blob(desc);
desc_with_blob.CachedPSO.pCachedBlob = blob->GetBufferPointer();
desc_with_blob.CachedPSO.CachedBlobSizeInBytes = blob->GetBufferSize();
ComPtr<ID3D12PipelineState> pso;
hr = device->CreateGraphicsPipelineState(&desc_with_blob, IID_PPV_ARGS(pso.put()));
if (FAILED(hr))
{
Console.Warning("Creating cached PSO failed: %08X. Invalidating cache.", hr);
InvalidatePipelineCache();
pso = CompileAndAddPipeline(device, key, desc);
}
return pso;
}
ShaderCache::ComPtr<ID3DBlob> ShaderCache::CompileAndAddShaderBlob(const CacheIndexKey& key, std::string_view shader_code,
const D3D_SHADER_MACRO* macros, const char* entry_point)
{
ComPtr<ID3DBlob> blob;
switch (key.type)
{
case EntryType::VertexShader:
blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Vertex, m_feature_level, m_debug, shader_code, macros, entry_point);
break;
case EntryType::GeometryShader:
blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Geometry, m_feature_level, m_debug, shader_code, macros, entry_point);
break;
case EntryType::PixelShader:
blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Pixel, m_feature_level, m_debug, shader_code, macros, entry_point);
break;
default:
break;
}
if (!blob)
return {};
if (!m_shader_blob_file || std::fseek(m_shader_blob_file, 0, SEEK_END) != 0)
return blob;
CacheIndexData data;
data.file_offset = static_cast<u32>(std::ftell(m_shader_blob_file));
data.blob_size = static_cast<u32>(blob->GetBufferSize());
CacheIndexEntry entry = {};
entry.source_hash_low = key.source_hash_low;
entry.source_hash_high = key.source_hash_high;
entry.macro_hash_low = key.macro_hash_low;
entry.macro_hash_high = key.macro_hash_high;
entry.entry_point_low = key.entry_point_low;
entry.entry_point_high = key.entry_point_high;
entry.source_length = key.source_length;
entry.shader_type = static_cast<u32>(key.type);
entry.blob_size = data.blob_size;
entry.file_offset = data.file_offset;
if (std::fwrite(blob->GetBufferPointer(), 1, entry.blob_size, m_shader_blob_file) != entry.blob_size ||
std::fflush(m_shader_blob_file) != 0 || std::fwrite(&entry, sizeof(entry), 1, m_shader_index_file) != 1 ||
std::fflush(m_shader_index_file) != 0)
{
Console.Error("Failed to write shader blob to file");
return blob;
}
m_shader_index.emplace(key, data);
return blob;
}
ShaderCache::ComPtr<ID3D12PipelineState>
ShaderCache::CompileAndAddPipeline(ID3D12Device* device, const CacheIndexKey& key,
const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc)
{
ComPtr<ID3D12PipelineState> pso;
HRESULT hr = device->CreateGraphicsPipelineState(&gpdesc, IID_PPV_ARGS(pso.put()));
if (FAILED(hr))
{
Console.Error("Creating cached PSO failed: %08X", hr);
return {};
}
if (!m_pipeline_blob_file || std::fseek(m_pipeline_blob_file, 0, SEEK_END) != 0)
return pso;
ComPtr<ID3DBlob> blob;
hr = pso->GetCachedBlob(blob.put());
if (FAILED(hr))
{
Console.Warning("Failed to get cached PSO data: %08X", hr);
return pso;
}
CacheIndexData data;
data.file_offset = static_cast<u32>(std::ftell(m_pipeline_blob_file));
data.blob_size = static_cast<u32>(blob->GetBufferSize());
CacheIndexEntry entry = {};
entry.source_hash_low = key.source_hash_low;
entry.source_hash_high = key.source_hash_high;
entry.source_length = key.source_length;
entry.shader_type = static_cast<u32>(key.type);
entry.blob_size = data.blob_size;
entry.file_offset = data.file_offset;
if (std::fwrite(blob->GetBufferPointer(), 1, entry.blob_size, m_pipeline_blob_file) != entry.blob_size ||
std::fflush(m_pipeline_blob_file) != 0 || std::fwrite(&entry, sizeof(entry), 1, m_pipeline_index_file) != 1 ||
std::fflush(m_pipeline_index_file) != 0)
{
Console.Error("Failed to write pipeline blob to file");
return pso;
}
m_shader_index.emplace(key, data);
return pso;
}
+152
View File
@@ -0,0 +1,152 @@
/* 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/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/HashCombine.h"
#include "common/RedtapeWindows.h"
#include <cstdio>
#include <d3d12.h>
#include <string_view>
#include <unordered_map>
#include <vector>
#include <wil/com.h>
namespace D3D12
{
class ShaderCache
{
public:
template <typename T>
using ComPtr = wil::com_ptr_nothrow<T>;
enum class EntryType
{
VertexShader,
GeometryShader,
PixelShader,
ComputeShader,
GraphicsPipeline,
};
ShaderCache();
~ShaderCache();
__fi D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; }
__fi u32 GetDataVersion() const { return m_data_version; }
__fi bool UsingPipelineCache() const { return m_use_pipeline_cache; }
__fi bool UsingDebugShaders() const { return m_debug; }
bool Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_level, u32 version, bool debug);
__fi ComPtr<ID3DBlob> GetVertexShader(std::string_view shader_code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main")
{
return GetShaderBlob(EntryType::VertexShader, shader_code, macros, entry_point);
}
__fi ComPtr<ID3DBlob> GetGeometryShader(std::string_view shader_code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main")
{
return GetShaderBlob(EntryType::GeometryShader, shader_code, macros, entry_point);
}
__fi ComPtr<ID3DBlob> GetPixelShader(std::string_view shader_code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main")
{
return GetShaderBlob(EntryType::PixelShader, shader_code, macros, entry_point);
}
__fi ComPtr<ID3DBlob> GetComputeShader(std::string_view shader_code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main")
{
return GetShaderBlob(EntryType::ComputeShader, shader_code, macros, entry_point);
}
ComPtr<ID3DBlob> GetShaderBlob(EntryType type, std::string_view shader_code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
ComPtr<ID3D12PipelineState> GetPipelineState(ID3D12Device* device, const D3D12_GRAPHICS_PIPELINE_STATE_DESC& desc);
private:
static constexpr u32 FILE_VERSION = 1;
struct CacheIndexKey
{
u64 source_hash_low;
u64 source_hash_high;
u64 macro_hash_low;
u64 macro_hash_high;
u64 entry_point_low;
u64 entry_point_high;
u32 source_length;
EntryType type;
bool operator==(const CacheIndexKey& key) const;
bool operator!=(const CacheIndexKey& key) const;
};
struct CacheIndexEntryHasher
{
std::size_t operator()(const CacheIndexKey& e) const noexcept
{
std::size_t h = 0;
HashCombine(h, e.entry_point_low, e.entry_point_high, e.macro_hash_low, e.macro_hash_high,
e.source_hash_low, e.source_hash_high, e.source_length, e.type);
return h;
}
};
struct CacheIndexData
{
u32 file_offset;
u32 blob_size;
};
using CacheIndex = std::unordered_map<CacheIndexKey, CacheIndexData, CacheIndexEntryHasher>;
static std::string GetCacheBaseFileName(const std::string_view& base_path, const std::string_view& type,
D3D_FEATURE_LEVEL feature_level, bool debug);
static CacheIndexKey GetShaderCacheKey(EntryType type, const std::string_view& shader_code,
const D3D_SHADER_MACRO* macros, const char* entry_point);
static CacheIndexKey GetPipelineCacheKey(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc);
bool CreateNew(const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file,
std::FILE*& blob_file);
bool ReadExisting(const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file,
std::FILE*& blob_file, CacheIndex& index);
void InvalidatePipelineCache();
void Close();
ComPtr<ID3DBlob> CompileAndAddShaderBlob(const CacheIndexKey& key, std::string_view shader_code,
const D3D_SHADER_MACRO* macros, const char* entry_point);
ComPtr<ID3D12PipelineState> CompileAndAddPipeline(ID3D12Device* device, const CacheIndexKey& key,
const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc);
std::string m_base_path;
std::FILE* m_shader_index_file = nullptr;
std::FILE* m_shader_blob_file = nullptr;
CacheIndex m_shader_index;
std::FILE* m_pipeline_index_file = nullptr;
std::FILE* m_pipeline_blob_file = nullptr;
CacheIndex m_pipeline_index;
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0;
u32 m_data_version = 0;
bool m_use_pipeline_cache = false;
bool m_debug = false;
};
} // namespace D3D12
+282
View File
@@ -0,0 +1,282 @@
/* 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 "common/PrecompiledHeader.h"
#include "common/D3D12/StreamBuffer.h"
#include "common/D3D12/Context.h"
#include "common/Align.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "D3D12MemAlloc.h"
#include <algorithm>
#include <functional>
using namespace D3D12;
StreamBuffer::StreamBuffer() = default;
StreamBuffer::~StreamBuffer()
{
Destroy();
}
bool StreamBuffer::Create(u32 size)
{
const D3D12_RESOURCE_DESC resource_desc = {
D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
D3D12_RESOURCE_FLAG_NONE};
D3D12MA::ALLOCATION_DESC allocationDesc = {};
allocationDesc.Flags = D3D12MA::ALLOCATION_FLAG_COMMITTED;
allocationDesc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
wil::com_ptr_nothrow<ID3D12Resource> buffer;
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocationDesc,
&resource_desc, D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr, allocation.put(), IID_PPV_ARGS(buffer.put()));
pxAssertMsg(SUCCEEDED(hr), "Allocate buffer");
if (FAILED(hr))
return false;
static const D3D12_RANGE read_range = {};
u8* host_pointer;
hr = buffer->Map(0, &read_range, reinterpret_cast<void**>(&host_pointer));
pxAssertMsg(SUCCEEDED(hr), "Map buffer");
if (FAILED(hr))
return false;
Destroy(true);
m_buffer = std::move(buffer);
m_allocation = std::move(allocation);
m_host_pointer = host_pointer;
m_size = size;
m_gpu_pointer = m_buffer->GetGPUVirtualAddress();
return true;
}
bool StreamBuffer::ReserveMemory(u32 num_bytes, u32 alignment)
{
const u32 required_bytes = num_bytes + alignment;
// Check for sane allocations
if (num_bytes > m_size)
{
Console.Error("Attempting to allocate %u bytes from a %u byte stream buffer", static_cast<u32>(num_bytes),
static_cast<u32>(m_size));
pxFailRel("Stream buffer overflow");
return false;
}
// Is the GPU behind or up to date with our current offset?
UpdateCurrentFencePosition();
if (m_current_offset >= m_current_gpu_position)
{
const u32 aligned_required_bytes = (m_current_offset > 0) ? required_bytes : num_bytes;
const u32 remaining_bytes = m_size - m_current_offset;
if (aligned_required_bytes <= remaining_bytes)
{
// Place at the current position, after the GPU position.
m_current_offset = Common::AlignUp(m_current_offset, alignment);
m_current_space = m_size - m_current_offset;
return true;
}
// Check for space at the start of the buffer
// We use < here because we don't want to have the case of m_current_offset ==
// m_current_gpu_position. That would mean the code above would assume the
// GPU has caught up to us, which it hasn't.
if (required_bytes < m_current_gpu_position)
{
// Reset offset to zero, since we're allocating behind the gpu now
m_current_offset = 0;
m_current_space = m_current_gpu_position;
return true;
}
}
// Is the GPU ahead of our current offset?
if (m_current_offset < m_current_gpu_position)
{
// We have from m_current_offset..m_current_gpu_position space to use.
const u32 remaining_bytes = m_current_gpu_position - m_current_offset;
if (required_bytes < remaining_bytes)
{
// Place at the current position, since this is still behind the GPU.
m_current_offset = Common::AlignUp(m_current_offset, alignment);
m_current_space = m_current_gpu_position - m_current_offset;
return true;
}
}
// Can we find a fence to wait on that will give us enough memory?
if (WaitForClearSpace(required_bytes))
{
const u32 align_diff = Common::AlignUp(m_current_offset, alignment) - m_current_offset;
m_current_offset += align_diff;
m_current_space -= align_diff;
return true;
}
// We tried everything we could, and still couldn't get anything. This means that too much space
// in the buffer is being used by the command buffer currently being recorded. Therefore, the
// only option is to execute it, and wait until it's done.
return false;
}
void StreamBuffer::CommitMemory(u32 final_num_bytes)
{
pxAssert((m_current_offset + final_num_bytes) <= m_size);
pxAssert(final_num_bytes <= m_current_space);
m_current_offset += final_num_bytes;
m_current_space -= final_num_bytes;
}
void StreamBuffer::Destroy(bool defer)
{
if (m_host_pointer)
{
const D3D12_RANGE written_range = {0, m_size};
m_buffer->Unmap(0, &written_range);
m_host_pointer = nullptr;
}
if (m_buffer && defer)
g_d3d12_context->DeferResourceDestruction(m_allocation.get(), m_buffer.get());
m_buffer.reset();
m_allocation.reset();
m_current_offset = 0;
m_current_space = 0;
m_current_gpu_position = 0;
m_tracked_fences.clear();
}
void StreamBuffer::UpdateCurrentFencePosition()
{
// Don't create a tracking entry if the GPU is caught up with the buffer.
if (m_current_offset == m_current_gpu_position)
return;
// Has the offset changed since the last fence?
const u64 fence = g_d3d12_context->GetCurrentFenceValue();
if (!m_tracked_fences.empty() && m_tracked_fences.back().first == fence)
{
// Still haven't executed a command buffer, so just update the offset.
m_tracked_fences.back().second = m_current_offset;
return;
}
UpdateGPUPosition();
m_tracked_fences.emplace_back(fence, m_current_offset);
}
void StreamBuffer::UpdateGPUPosition()
{
auto start = m_tracked_fences.begin();
auto end = start;
const u64 completed_counter = g_d3d12_context->GetCompletedFenceValue();
while (end != m_tracked_fences.end() && completed_counter >= end->first)
{
m_current_gpu_position = end->second;
++end;
}
if (start != end)
m_tracked_fences.erase(start, end);
}
bool StreamBuffer::WaitForClearSpace(u32 num_bytes)
{
u32 new_offset = 0;
u32 new_space = 0;
u32 new_gpu_position = 0;
auto iter = m_tracked_fences.begin();
for (; iter != m_tracked_fences.end(); ++iter)
{
// Would this fence bring us in line with the GPU?
// This is the "last resort" case, where a command buffer execution has been forced
// after no additional data has been written to it, so we can assume that after the
// fence has been signaled the entire buffer is now consumed.
u32 gpu_position = iter->second;
if (m_current_offset == gpu_position)
{
new_offset = 0;
new_space = m_size;
new_gpu_position = 0;
break;
}
// Assuming that we wait for this fence, are we allocating in front of the GPU?
if (m_current_offset > gpu_position)
{
// This would suggest the GPU has now followed us and wrapped around, so we have from
// m_current_position..m_size free, as well as and 0..gpu_position.
const u32 remaining_space_after_offset = m_size - m_current_offset;
if (remaining_space_after_offset >= num_bytes)
{
// Switch to allocating in front of the GPU, using the remainder of the buffer.
new_offset = m_current_offset;
new_space = m_size - m_current_offset;
new_gpu_position = gpu_position;
break;
}
// We can wrap around to the start, behind the GPU, if there is enough space.
// We use > here because otherwise we'd end up lining up with the GPU, and then the
// allocator would assume that the GPU has consumed what we just wrote.
if (gpu_position > num_bytes)
{
new_offset = 0;
new_space = gpu_position;
new_gpu_position = gpu_position;
break;
}
}
else
{
// We're currently allocating behind the GPU. This would give us between the current
// offset and the GPU position worth of space to work with. Again, > because we can't
// align the GPU position with the buffer offset.
u32 available_space_inbetween = gpu_position - m_current_offset;
if (available_space_inbetween > num_bytes)
{
// Leave the offset as-is, but update the GPU position.
new_offset = m_current_offset;
new_space = gpu_position - m_current_offset;
new_gpu_position = gpu_position;
break;
}
}
}
// Did any fences satisfy this condition?
// Has the command buffer been executed yet? If not, the caller should execute it.
if (iter == m_tracked_fences.end() || iter->first == g_d3d12_context->GetCurrentFenceValue())
return false;
// Wait until this fence is signaled. This will fire the callback, updating the GPU position.
g_d3d12_context->WaitForFence(iter->first);
m_tracked_fences.erase(m_tracked_fences.begin(), m_current_offset == iter->second ? m_tracked_fences.end() : ++iter);
m_current_offset = new_offset;
m_current_space = new_space;
m_current_gpu_position = new_gpu_position;
return true;
}
+77
View File
@@ -0,0 +1,77 @@
/* 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/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/RedtapeWindows.h"
#include <d3d12.h>
#include <deque>
#include <utility>
#include <wil/com.h>
namespace D3D12MA
{
class Allocation;
}
namespace D3D12
{
class StreamBuffer
{
public:
StreamBuffer();
~StreamBuffer();
bool Create(u32 size);
__fi bool IsValid() const { return static_cast<bool>(m_buffer); }
__fi ID3D12Resource* GetBuffer() const { return m_buffer.get(); }
__fi D3D12_GPU_VIRTUAL_ADDRESS GetGPUPointer() const { return m_gpu_pointer; }
__fi void* GetHostPointer() const { return m_host_pointer; }
__fi void* GetCurrentHostPointer() const { return m_host_pointer + m_current_offset; }
__fi D3D12_GPU_VIRTUAL_ADDRESS GetCurrentGPUPointer() const { return m_gpu_pointer + m_current_offset; }
__fi u32 GetSize() const { return m_size; }
__fi u32 GetCurrentOffset() const { return m_current_offset; }
__fi u32 GetCurrentSpace() const { return m_current_space; }
bool ReserveMemory(u32 num_bytes, u32 alignment);
void CommitMemory(u32 final_num_bytes);
void Destroy(bool defer = true);
private:
void UpdateCurrentFencePosition();
void UpdateGPUPosition();
// Waits for as many fences as needed to allocate num_bytes bytes from the buffer.
bool WaitForClearSpace(u32 num_bytes);
u32 m_size = 0;
u32 m_current_offset = 0;
u32 m_current_space = 0;
u32 m_current_gpu_position = 0;
wil::com_ptr_nothrow<ID3D12Resource> m_buffer;
wil::com_ptr_nothrow<D3D12MA::Allocation> m_allocation;
D3D12_GPU_VIRTUAL_ADDRESS m_gpu_pointer = {};
u8* m_host_pointer = nullptr;
// List of fences and the corresponding positions in the buffer
std::deque<std::pair<u64, u32>> m_tracked_fences;
};
} // namespace D3D12
+448
View File
@@ -0,0 +1,448 @@
/* 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 "common/PrecompiledHeader.h"
#include "common/D3D12/Texture.h"
#include "common/D3D12/Context.h"
#include "common/D3D12/Util.h"
#include "common/Align.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/StringUtil.h"
#include "D3D12MemAlloc.h"
using namespace D3D12;
// Somehow NOMINMAX isn't getting set for CMake builds...
#ifdef min
#undef min
#endif
Texture::Texture() = default;
Texture::Texture(ID3D12Resource* resource, D3D12_RESOURCE_STATES state)
: m_resource(std::move(resource))
{
const D3D12_RESOURCE_DESC desc = GetDesc();
m_width = static_cast<u32>(desc.Width);
m_height = desc.Height;
m_levels = desc.MipLevels;
m_format = desc.Format;
}
Texture::Texture(Texture&& texture)
: m_resource(std::move(texture.m_resource))
, m_allocation(std::move(texture.m_allocation))
, m_srv_descriptor(texture.m_srv_descriptor)
, m_rtv_or_dsv_descriptor(texture.m_rtv_or_dsv_descriptor)
, m_width(texture.m_width)
, m_height(texture.m_height)
, m_levels(texture.m_levels)
, m_format(texture.m_format)
, m_state(texture.m_state)
, m_is_depth_view(texture.m_is_depth_view)
{
texture.m_srv_descriptor = {};
texture.m_rtv_or_dsv_descriptor = {};
texture.m_width = 0;
texture.m_height = 0;
texture.m_levels = 0;
texture.m_format = DXGI_FORMAT_UNKNOWN;
texture.m_state = D3D12_RESOURCE_STATE_COMMON;
texture.m_is_depth_view = false;
}
Texture::~Texture()
{
Destroy();
}
Texture& Texture::operator=(Texture&& texture)
{
Destroy();
m_resource = std::move(texture.m_resource);
m_allocation = std::move(texture.m_allocation);
m_srv_descriptor = texture.m_srv_descriptor;
m_rtv_or_dsv_descriptor = texture.m_rtv_or_dsv_descriptor;
m_width = texture.m_width;
m_height = texture.m_height;
m_levels = texture.m_levels;
m_format = texture.m_format;
m_state = texture.m_state;
m_is_depth_view = texture.m_is_depth_view;
texture.m_srv_descriptor = {};
texture.m_rtv_or_dsv_descriptor = {};
texture.m_width = 0;
texture.m_height = 0;
texture.m_levels = 0;
texture.m_format = DXGI_FORMAT_UNKNOWN;
texture.m_state = D3D12_RESOURCE_STATE_COMMON;
texture.m_is_depth_view = false;
return *this;
}
D3D12_RESOURCE_DESC Texture::GetDesc() const
{
return m_resource->GetDesc();
}
bool Texture::Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI_FORMAT srv_format,
DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, D3D12_RESOURCE_FLAGS flags, u32 alloc_flags)
{
D3D12_RESOURCE_DESC desc = {};
desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
desc.Width = width;
desc.Height = height;
desc.DepthOrArraySize = 1;
desc.MipLevels = levels;
desc.Format = format;
desc.SampleDesc.Count = 1;
desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
desc.Flags = flags;
D3D12_CLEAR_VALUE optimized_clear_value = {};
D3D12_RESOURCE_STATES state;
if (rtv_format != DXGI_FORMAT_UNKNOWN)
{
optimized_clear_value.Format = rtv_format;
state = D3D12_RESOURCE_STATE_RENDER_TARGET;
}
else if (dsv_format != DXGI_FORMAT_UNKNOWN)
{
optimized_clear_value.Format = dsv_format;
state = D3D12_RESOURCE_STATE_DEPTH_WRITE;
}
else
{
state = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
}
D3D12MA::ALLOCATION_DESC allocationDesc = {};
allocationDesc.Flags = static_cast<D3D12MA::ALLOCATION_FLAGS>(alloc_flags) | D3D12MA::ALLOCATION_FLAG_WITHIN_BUDGET;
allocationDesc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
ComPtr<ID3D12Resource> resource;
ComPtr<D3D12MA::Allocation> allocation;
HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(
&allocationDesc, &desc, state,
(rtv_format != DXGI_FORMAT_UNKNOWN || dsv_format != DXGI_FORMAT_UNKNOWN) ? &optimized_clear_value : nullptr,
allocation.put(), IID_PPV_ARGS(resource.put()));
if (FAILED(hr))
{
// OOM isn't fatal.
if (hr != E_OUTOFMEMORY)
Console.Error("Create texture failed: 0x%08X", hr);
return false;
}
DescriptorHandle srv_descriptor, rtv_descriptor;
bool is_depth_view = false;
if (srv_format != DXGI_FORMAT_UNKNOWN)
{
if (!CreateSRVDescriptor(resource.get(), levels, srv_format, &srv_descriptor))
return false;
}
if (rtv_format != DXGI_FORMAT_UNKNOWN)
{
pxAssert(dsv_format == DXGI_FORMAT_UNKNOWN);
if (!CreateRTVDescriptor(resource.get(), rtv_format, &rtv_descriptor))
{
g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor);
return false;
}
}
else if (dsv_format != DXGI_FORMAT_UNKNOWN)
{
if (!CreateDSVDescriptor(resource.get(), dsv_format, &rtv_descriptor))
{
g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor);
return false;
}
is_depth_view = true;
}
Destroy(true);
m_resource = std::move(resource);
m_allocation = std::move(allocation);
m_srv_descriptor = std::move(srv_descriptor);
m_rtv_or_dsv_descriptor = std::move(rtv_descriptor);
m_width = width;
m_height = height;
m_levels = levels;
m_format = format;
m_state = state;
m_is_depth_view = is_depth_view;
return true;
}
bool Texture::Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format,
DXGI_FORMAT dsv_format, D3D12_RESOURCE_STATES state)
{
const D3D12_RESOURCE_DESC desc(texture->GetDesc());
DescriptorHandle srv_descriptor, rtv_descriptor;
if (srv_format != DXGI_FORMAT_UNKNOWN)
{
if (!CreateSRVDescriptor(texture.get(), desc.MipLevels, srv_format, &srv_descriptor))
return false;
}
if (rtv_format != DXGI_FORMAT_UNKNOWN)
{
pxAssert(dsv_format == DXGI_FORMAT_UNKNOWN);
if (!CreateRTVDescriptor(texture.get(), rtv_format, &rtv_descriptor))
{
g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor);
return false;
}
}
else if (dsv_format != DXGI_FORMAT_UNKNOWN)
{
if (!CreateDSVDescriptor(texture.get(), dsv_format, &rtv_descriptor))
{
g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor);
return false;
}
}
m_resource = std::move(texture);
m_allocation.reset();
m_srv_descriptor = std::move(srv_descriptor);
m_rtv_or_dsv_descriptor = std::move(rtv_descriptor);
m_width = static_cast<u32>(desc.Width);
m_height = desc.Height;
m_levels = desc.MipLevels;
m_format = desc.Format;
m_state = state;
return true;
}
void Texture::Destroy(bool defer /* = true */)
{
if (defer)
{
g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDescriptorHeapManager(), &m_srv_descriptor);
if (m_is_depth_view)
g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDSVHeapManager(), &m_rtv_or_dsv_descriptor);
else
g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetRTVHeapManager(), &m_rtv_or_dsv_descriptor);
g_d3d12_context->DeferResourceDestruction(m_allocation.get(), m_resource.get());
m_resource.reset();
m_allocation.reset();
}
else
{
g_d3d12_context->GetDescriptorHeapManager().Free(&m_srv_descriptor);
if (m_is_depth_view)
g_d3d12_context->GetDSVHeapManager().Free(&m_rtv_or_dsv_descriptor);
else
g_d3d12_context->GetRTVHeapManager().Free(&m_rtv_or_dsv_descriptor);
m_resource.reset();
m_allocation.reset();
}
m_width = 0;
m_height = 0;
m_levels = 0;
m_format = DXGI_FORMAT_UNKNOWN;
m_is_depth_view = false;
}
void Texture::TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state)
{
if (m_state == state)
return;
ResourceBarrier(cmdlist, m_resource.get(), m_state, state);
m_state = state;
}
void Texture::TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, u32 level,
D3D12_RESOURCE_STATES before_state, D3D12_RESOURCE_STATES after_state) const
{
const D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
D3D12_RESOURCE_BARRIER_FLAG_NONE,
{{m_resource.get(), level, before_state, after_state}}};
cmdlist->ResourceBarrier(1, &barrier);
}
bool Texture::BeginStreamUpdate(u32 level, u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch)
{
const u32 copy_pitch = Common::AlignUpPow2(width * GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 upload_size = copy_pitch * height;
if (!g_d3d12_context->GetTextureStreamBuffer().ReserveMemory(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT))
{
DevCon.WriteLn("Executing command buffer while waiting for %u bytes (%ux%u) in upload buffer", upload_size, width,
height);
g_d3d12_context->ExecuteCommandList(false);
if (!g_d3d12_context->GetTextureStreamBuffer().ReserveMemory(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT))
{
Console.Error("Failed to reserve %u bytes for %ux%u upload", upload_size, width, height);
return false;
}
}
*out_data = g_d3d12_context->GetTextureStreamBuffer().GetCurrentHostPointer();
*out_data_pitch = copy_pitch;
return true;
}
void Texture::EndStreamUpdate(u32 level, u32 x, u32 y, u32 width, u32 height)
{
const u32 copy_pitch = Common::AlignUpPow2(width * GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 upload_size = copy_pitch * height;
StreamBuffer& sb = g_d3d12_context->GetTextureStreamBuffer();
const u32 sb_offset = sb.GetCurrentOffset();
sb.CommitMemory(upload_size);
CopyFromBuffer(level, x, y, width, height, copy_pitch, sb.GetBuffer(), sb_offset);
}
void Texture::CopyFromBuffer(u32 level, u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, u32 buffer_offset)
{
D3D12_TEXTURE_COPY_LOCATION src;
src.pResource = buffer;
src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
src.PlacedFootprint.Offset = buffer_offset;
src.PlacedFootprint.Footprint.Width = width;
src.PlacedFootprint.Footprint.Height = height;
src.PlacedFootprint.Footprint.Depth = 1;
src.PlacedFootprint.Footprint.RowPitch = pitch;
src.PlacedFootprint.Footprint.Format = m_format;
D3D12_TEXTURE_COPY_LOCATION dst;
dst.pResource = m_resource.get();
dst.SubresourceIndex = level;
dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
const D3D12_BOX src_box{0u, 0u, 0u, width, height, 1u};
const D3D12_RESOURCE_STATES old_state = m_state;
ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList();
TransitionToState(cmdlist, D3D12_RESOURCE_STATE_COPY_DEST);
cmdlist->CopyTextureRegion(&dst, x, y, 0, &src, &src_box);
TransitionToState(cmdlist, old_state);
}
static ID3D12Resource* CreateStagingBuffer(u32 height, const void* data, u32 pitch, u32 upload_pitch, u32 upload_size)
{
wil::com_ptr_nothrow<ID3D12Resource> resource;
wil::com_ptr_nothrow<D3D12MA::Allocation> allocation;
const D3D12MA::ALLOCATION_DESC allocation_desc = {D3D12MA::ALLOCATION_FLAG_NONE, D3D12_HEAP_TYPE_UPLOAD};
const D3D12_RESOURCE_DESC resource_desc = {
D3D12_RESOURCE_DIMENSION_BUFFER, 0, upload_size, 1, 1, 1, DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
D3D12_RESOURCE_FLAG_NONE};
HRESULT hr = g_d3d12_context->GetAllocator()->CreateResource(&allocation_desc, &resource_desc, D3D12_RESOURCE_STATE_COPY_SOURCE,
nullptr, allocation.put(), IID_PPV_ARGS(resource.put()));
if (FAILED(hr))
{
Console.Error("CreateResource() for upload staging buffer failed: %08X", hr);
return nullptr;
}
void* map;
const D3D12_RANGE read_range = {};
hr = resource->Map(0, &read_range, &map);
if (FAILED(hr))
{
Console.Error("Map() for upload staging buffer failed: %08X", hr);
return nullptr;
}
StringUtil::StrideMemCpy(map, upload_pitch, data, pitch, std::min(pitch, upload_pitch), height);
const D3D12_RANGE write_range = {0u, upload_size};
resource->Unmap(0, &write_range);
// queue them for destruction, since the upload happens in this cmdlist
g_d3d12_context->DeferResourceDestruction(allocation.get(), resource.get());
// AddRef()'ed by the defer above.
return resource.get();
}
bool Texture::LoadData(u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch)
{
const u32 texel_size = GetTexelSize(m_format);
const u32 upload_pitch = Common::AlignUpPow2(width * texel_size, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
const u32 upload_size = upload_pitch * height;
if (upload_size >= g_d3d12_context->GetTextureStreamBuffer().GetSize())
{
ID3D12Resource* staging_buffer = CreateStagingBuffer(height, data, pitch, upload_pitch, upload_size);
if (!staging_buffer)
return false;
CopyFromBuffer(level, x, y, width, height, upload_pitch, staging_buffer, 0);
return true;
}
void* write_ptr;
u32 write_pitch;
if (!BeginStreamUpdate(level, x, y, width, height, &write_ptr, &write_pitch))
return false;
StringUtil::StrideMemCpy(write_ptr, write_pitch, data, pitch, std::min(pitch, upload_pitch), height);
EndStreamUpdate(level, x, y, width, height);
return true;
}
bool Texture::CreateSRVDescriptor(ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, DescriptorHandle* dh)
{
if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh))
{
Console.Error("Failed to allocate SRV descriptor");
return false;
}
D3D12_SHADER_RESOURCE_VIEW_DESC desc = {format, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING};
desc.Texture2D.MipLevels = levels;
g_d3d12_context->GetDevice()->CreateShaderResourceView(resource, &desc, dh->cpu_handle);
return true;
}
bool Texture::CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh)
{
if (!g_d3d12_context->GetRTVHeapManager().Allocate(dh))
{
Console.Error("Failed to allocate SRV descriptor");
return false;
}
const D3D12_RENDER_TARGET_VIEW_DESC desc = {format, D3D12_RTV_DIMENSION_TEXTURE2D};
g_d3d12_context->GetDevice()->CreateRenderTargetView(resource, &desc, dh->cpu_handle);
return true;
}
bool Texture::CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh)
{
if (!g_d3d12_context->GetDSVHeapManager().Allocate(dh))
{
Console.Error("Failed to allocate SRV descriptor");
return false;
}
const D3D12_DEPTH_STENCIL_VIEW_DESC desc = {format, D3D12_DSV_DIMENSION_TEXTURE2D, D3D12_DSV_FLAG_NONE};
g_d3d12_context->GetDevice()->CreateDepthStencilView(resource, &desc, dh->cpu_handle);
return true;
}
+100
View File
@@ -0,0 +1,100 @@
/* 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/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/RedtapeWindows.h"
#include "common/D3D12/DescriptorHeapManager.h"
#include <d3d12.h>
#include <wil/com.h>
namespace D3D12MA
{
class Allocation;
}
namespace D3D12
{
class StreamBuffer;
class Texture final
{
public:
template <typename T>
using ComPtr = wil::com_ptr_nothrow<T>;
Texture();
Texture(ID3D12Resource* resource, D3D12_RESOURCE_STATES state);
Texture(Texture&& texture);
Texture(const Texture&) = delete;
~Texture();
__fi ID3D12Resource* GetResource() const { return m_resource.get(); }
__fi D3D12MA::Allocation* GetAllocation() const { return m_allocation.get(); }
__fi const DescriptorHandle& GetSRVDescriptor() const { return m_srv_descriptor; }
__fi const DescriptorHandle& GetRTVOrDSVDescriptor() const { return m_rtv_or_dsv_descriptor; }
__fi D3D12_RESOURCE_STATES GetState() const { return m_state; }
__fi u32 GetWidth() const { return m_width; }
__fi u32 GetHeight() const { return m_height; }
__fi u32 GetLevels() const { return m_levels; }
__fi DXGI_FORMAT GetFormat() const { return m_format; }
__fi operator ID3D12Resource*() const { return m_resource.get(); }
__fi operator bool() const { return static_cast<bool>(m_resource); }
bool Create(u32 width, u32 height, u32 levels, DXGI_FORMAT format, DXGI_FORMAT srv_format,
DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format, D3D12_RESOURCE_FLAGS flags, u32 alloc_flags = 0);
bool Adopt(ComPtr<ID3D12Resource> texture, DXGI_FORMAT srv_format, DXGI_FORMAT rtv_format, DXGI_FORMAT dsv_format,
D3D12_RESOURCE_STATES state);
D3D12_RESOURCE_DESC GetDesc() const;
void Destroy(bool defer = true);
void TransitionToState(ID3D12GraphicsCommandList* cmdlist, D3D12_RESOURCE_STATES state);
void TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, u32 level,
D3D12_RESOURCE_STATES before_state, D3D12_RESOURCE_STATES after_state) const;
Texture& operator=(const Texture&) = delete;
Texture& operator=(Texture&& texture);
// NOTE: Does not handle compressed formats.
bool BeginStreamUpdate(u32 level, u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch);
void EndStreamUpdate(u32 level, u32 x, u32 y, u32 width, u32 height);
bool LoadData(u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch);
void CopyFromBuffer(u32 level, u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, u32 buffer_offset);
private:
static bool CreateSRVDescriptor(ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, DescriptorHandle* dh);
static bool CreateRTVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh);
static bool CreateDSVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh);
ComPtr<ID3D12Resource> m_resource;
ComPtr<D3D12MA::Allocation> m_allocation;
DescriptorHandle m_srv_descriptor = {};
DescriptorHandle m_rtv_or_dsv_descriptor = {};
u32 m_width = 0;
u32 m_height = 0;
u32 m_levels = 0;
DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN;
D3D12_RESOURCE_STATES m_state = D3D12_RESOURCE_STATE_COMMON;
bool m_is_depth_view = false;
};
} // namespace D3D12
+93
View File
@@ -0,0 +1,93 @@
/* 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 "common/PrecompiledHeader.h"
#include "common/D3D12/Util.h"
#include "common/Assertions.h"
#include "common/StringUtil.h"
u32 D3D12::GetTexelSize(DXGI_FORMAT format)
{
switch (format)
{
case DXGI_FORMAT_R32G32B32A32_FLOAT:
case DXGI_FORMAT_BC1_UNORM:
case DXGI_FORMAT_BC2_UNORM:
case DXGI_FORMAT_BC3_UNORM:
case DXGI_FORMAT_BC7_UNORM:
return 16;
case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
return 4;
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_SNORM:
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
case DXGI_FORMAT_R32_UINT:
case DXGI_FORMAT_R32_SINT:
return 4;
case DXGI_FORMAT_B5G5R5A1_UNORM:
case DXGI_FORMAT_B5G6R5_UNORM:
case DXGI_FORMAT_R16_UINT:
case DXGI_FORMAT_R16_SINT:
return 2;
case DXGI_FORMAT_A8_UNORM:
case DXGI_FORMAT_R8_UNORM:
return 1;
default:
pxFailRel("Unknown format");
return 1;
}
}
void D3D12::SetDefaultSampler(D3D12_SAMPLER_DESC* desc)
{
desc->Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
desc->AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
desc->AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
desc->AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
desc->MipLODBias = 0;
desc->MaxAnisotropy = 1;
desc->ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
desc->BorderColor[0] = 1.0f;
desc->BorderColor[1] = 1.0f;
desc->BorderColor[2] = 1.0f;
desc->BorderColor[3] = 1.0f;
desc->MinLOD = -3.402823466e+38F; // -FLT_MAX
desc->MaxLOD = 3.402823466e+38F; // FLT_MAX
}
#ifdef _DEBUG
void D3D12::SetObjectName(ID3D12Object* object, const char* name)
{
object->SetName(StringUtil::UTF8StringToWideString(name).c_str());
}
void D3D12::SetObjectNameFormatted(ID3D12Object* object, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
SetObjectName(object, StringUtil::StdStringFromFormatV(format, ap).c_str());
va_end(ap);
}
#endif
+77
View File
@@ -0,0 +1,77 @@
/* 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/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/RedtapeWindows.h"
#include <array>
#include <d3d12.h>
namespace D3D12
{
static inline void ResourceBarrier(ID3D12GraphicsCommandList* cmdlist, ID3D12Resource* resource,
D3D12_RESOURCE_STATES from_state, D3D12_RESOURCE_STATES to_state)
{
const D3D12_RESOURCE_BARRIER barrier = {D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
D3D12_RESOURCE_BARRIER_FLAG_NONE,
{{resource, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, from_state, to_state}}};
cmdlist->ResourceBarrier(1, &barrier);
}
static inline void SetViewport(ID3D12GraphicsCommandList* cmdlist, int x, int y, int width, int height,
float min_depth = 0.0f, float max_depth = 1.0f)
{
const D3D12_VIEWPORT vp{static_cast<float>(x),
static_cast<float>(y),
static_cast<float>(width),
static_cast<float>(height),
min_depth,
max_depth};
cmdlist->RSSetViewports(1, &vp);
}
static inline void SetScissor(ID3D12GraphicsCommandList* cmdlist, int x, int y, int width, int height)
{
const D3D12_RECT r{x, y, x + width, y + height};
cmdlist->RSSetScissorRects(1, &r);
}
static inline void SetViewportAndScissor(ID3D12GraphicsCommandList* cmdlist, int x, int y, int width, int height,
float min_depth = 0.0f, float max_depth = 1.0f)
{
SetViewport(cmdlist, x, y, width, height, min_depth, max_depth);
SetScissor(cmdlist, x, y, width, height);
}
u32 GetTexelSize(DXGI_FORMAT format);
void SetDefaultSampler(D3D12_SAMPLER_DESC* desc);
#ifdef _DEBUG
void SetObjectName(ID3D12Object* object, const char* name);
void SetObjectNameFormatted(ID3D12Object* object, const char* format, ...);
#else
static inline void SetObjectName(ID3D12Object* object, const char* name)
{
}
static inline void SetObjectNameFormatted(ID3D12Object* object, const char* format, ...) {}
#endif
} // namespace D3D12
+14 -195
View File
@@ -26,8 +26,6 @@
#include <mach/mach_time.h> // mach_absolute_time()
#include "common/Threading.h"
#include "common/ThreadingInternal.h"
#include "common/wxBaseTools.h"
// --------------------------------------------------------------------------------------
// Semaphore Implementation for Darwin/OSX
@@ -57,214 +55,35 @@ static void MACH_CHECK(kern_return_t mach_retval)
}
}
Threading::Semaphore::Semaphore()
Threading::KernelSemaphore::KernelSemaphore()
{
// other platforms explicitly make a thread-private (unshared) semaphore
// here. But it seems Mach doesn't support that.
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t*)&m_sema, SYNC_POLICY_FIFO, 0));
__atomic_store_n(&m_counter, 0, __ATOMIC_RELEASE);
MACH_CHECK(semaphore_create(mach_task_self(), &m_sema, SYNC_POLICY_FIFO, 0));
}
Threading::Semaphore::~Semaphore()
Threading::KernelSemaphore::~KernelSemaphore()
{
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
MACH_CHECK(semaphore_destroy(mach_task_self(), m_sema));
}
void Threading::Semaphore::Reset()
void Threading::KernelSemaphore::Post()
{
MACH_CHECK(semaphore_destroy(mach_task_self(), (semaphore_t)m_sema));
MACH_CHECK(semaphore_create(mach_task_self(), (semaphore_t*)&m_sema, SYNC_POLICY_FIFO, 0));
__atomic_store_n(&m_counter, 0, __ATOMIC_SEQ_CST);
MACH_CHECK(semaphore_signal(m_sema));
}
void Threading::Semaphore::Post()
void Threading::KernelSemaphore::Wait()
{
if (__atomic_fetch_add(&m_counter, 1, __ATOMIC_RELEASE) < 0)
MACH_CHECK(semaphore_signal(m_sema));
MACH_CHECK(semaphore_wait(m_sema));
}
void Threading::Semaphore::Post(int multiple)
bool Threading::KernelSemaphore::TryWait()
{
for (int i = 0; i < multiple; ++i)
{
Post();
}
}
void Threading::Semaphore::WaitWithoutYield()
{
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
if (__atomic_sub_fetch(&m_counter, 1, __ATOMIC_ACQUIRE) < 0)
MACH_CHECK(semaphore_wait(m_sema));
}
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan& timeout)
{
// This method is the reason why there has to be a special Darwin
// implementation of Semaphore. Note that semaphore_timedwait() is prone
// to returning with KERN_ABORTED, which basically signifies that some
// signal has worken it up. The best official "documentation" for
// semaphore_timedwait() is the way it's used in Grand Central Dispatch,
// which is open-source.
if (__atomic_sub_fetch(&m_counter, 1, __ATOMIC_ACQUIRE) >= 0)
return true;
// on x86 platforms, mach_absolute_time() returns nanoseconds
// TODO(aktau): on iOS a scale value from mach_timebase_info will be necessary
u64 const kOneThousand = 1000;
u64 const kOneBillion = kOneThousand * kOneThousand * kOneThousand;
u64 const delta = timeout.GetMilliseconds().GetValue() * (kOneThousand * kOneThousand);
mach_timespec_t ts;
kern_return_t kr = KERN_ABORTED;
for (u64 now = mach_absolute_time(), deadline = now + delta;
kr == KERN_ABORTED; now = mach_absolute_time())
{
if (now > deadline)
{
// timed out by definition
kr = KERN_OPERATION_TIMED_OUT;
break;
}
u64 timeleft = deadline - now;
ts.tv_sec = timeleft / kOneBillion;
ts.tv_nsec = timeleft % kOneBillion;
// possible return values of semaphore_timedwait() (from XNU sources):
// internal kernel val -> return value
// THREAD_INTERRUPTED -> KERN_ABORTED
// THREAD_TIMED_OUT -> KERN_OPERATION_TIMED_OUT
// THREAD_AWAKENED -> KERN_SUCCESS
// THREAD_RESTART -> KERN_TERMINATED
// default -> KERN_FAILURE
kr = semaphore_timedwait(m_sema, ts);
}
if (kr == KERN_OPERATION_TIMED_OUT)
{
int orig = __atomic_load_n(&m_counter, __ATOMIC_RELAXED);
while (orig < 0)
{
if (__atomic_compare_exchange_n(&m_counter, &orig, orig + 1, true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
return false;
}
// Semaphore was signalled between our wait expiring and now, keep kernel sema in sync
kr = semaphore_wait(m_sema);
}
// while it's entirely possible to have KERN_FAILURE here, we should
// probably assert so we can study and correct the actual error here
// (the thread dying while someone is wainting for it).
MACH_CHECK(kr);
mach_timespec_t time = {};
kern_return_t res = semaphore_timedwait(m_sema, time);
if (res == KERN_OPERATION_TIMED_OUT)
return false;
MACH_CHECK(res);
return true;
}
// This is a wxApp-safe implementation of Wait, which makes sure and executes the App's
// pending messages *if* the Wait is performed on the Main/GUI thread. This ensures that
// user input continues to be handled and that windows continue to repaint. If the Wait is
// called from another thread, no message pumping is performed.
void Threading::Semaphore::Wait()
{
#if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL))
{
WaitWithoutYield();
}
else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
{
WaitWithoutYield();
}
else
{
while (!WaitWithoutYield(def_yieldgui_interval))
{
YieldToMain();
}
}
#else
WaitWithoutYield();
#endif
}
// This is a wxApp-safe implementation of WaitWithoutYield, which makes sure and executes the App's
// pending messages *if* the Wait is performed on the Main/GUI thread. This ensures that
// user input continues to be handled and that windows continue to repaint. If the Wait is
// called from another thread, no message pumping is performed.
//
// Returns:
// false if the wait timed out before the semaphore was signaled, or true if the signal was
// reached prior to timeout.
//
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
{
#if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL))
{
return WaitWithoutYield(timeout);
}
else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
{
return WaitWithoutYield(timeout);
}
else
{
wxTimeSpan countdown((timeout));
do
{
if (WaitWithoutYield(def_yieldgui_interval))
break;
YieldToMain();
countdown -= def_yieldgui_interval;
} while (countdown.GetMilliseconds() > 0);
return countdown.GetMilliseconds() > 0;
}
#else
return WaitWithoutYield(timeout);
#endif
}
bool Threading::Semaphore::TryWait()
{
int counter = __atomic_load_n(&m_counter, __ATOMIC_RELAXED);
while (counter > 0 && !__atomic_compare_exchange_n(&m_counter, &counter, counter - 1, true, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
;
return counter > 0;
}
// Performs an uncancellable wait on a semaphore; restoring the thread's previous cancel state
// after the wait has completed. Useful for situations where the semaphore itself is stored on
// the stack and passed to another thread via GUI message or such, avoiding complications where
// the thread might be canceled and the stack value becomes invalid.
//
// Performance note: this function has quite a bit more overhead compared to Semaphore::WaitWithoutYield(), so
// consider manually specifying the thread as uncancellable and using WaitWithoutYield() instead if you need
// to do a lot of no-cancel waits in a tight loop worker thread, for example.
//
// I'm unsure how to do this with pure Mach primitives, the docs in
// osfmk/man seem a bit out of date so perhaps there's a possibility, but
// since as far as I know Mach threads are 1-to-1 on BSD uthreads (and thus
// POSIX threads), this should work. -- aktau
void Threading::Semaphore::WaitNoCancel()
{
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
Wait();
pthread_setcancelstate(oldstate, NULL);
}
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan& timeout)
{
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
Wait(timeout);
pthread_setcancelstate(oldstate, NULL);
}
int Threading::Semaphore::Count()
{
return __atomic_load_n(&m_counter, __ATOMIC_RELAXED);
}
#endif
+44 -18
View File
@@ -15,13 +15,14 @@
#if defined(__APPLE__)
#include <sched.h>
#include <unistd.h>
#include <mach/mach_init.h>
#include <mach/thread_act.h>
#include <mach/mach_port.h>
#include "common/PrecompiledHeader.h"
#include "common/PersistentThread.h"
#include "common/Threading.h"
// Note: assuming multicore is safer because it forces the interlocked routines to use
// the LOCK prefix. The prefix works on single core CPUs fine (but is slow), but not
@@ -32,6 +33,11 @@ __forceinline void Threading::Sleep(int ms)
usleep(1000 * ms);
}
__forceinline void Threading::Timeslice()
{
sched_yield();
}
// For use in spin/wait loops, acts as a hint to Intel CPUs and should, in theory
// improve performance and reduce cpu power consumption.
__forceinline void Threading::SpinWait()
@@ -94,30 +100,50 @@ u64 Threading::GetThreadCpuTime()
return us;
}
u64 Threading::pxThread::GetCpuTime() const
{
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
// m_native_handle to implement it. Return value should be a measure of total time the
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
// which typically would be an OS-provided scalar or some sort).
if (!m_native_id)
{
return 0;
}
Threading::ThreadHandle::ThreadHandle() = default;
return getthreadtime((thread_port_t)m_native_id);
Threading::ThreadHandle::ThreadHandle(const ThreadHandle& handle)
: m_native_handle(handle.m_native_handle)
{
}
void Threading::pxThread::_platform_specific_OnStartInThread()
Threading::ThreadHandle::ThreadHandle(ThreadHandle&& handle)
: m_native_handle(handle.m_native_handle)
{
m_native_id = (uptr)mach_thread_self();
handle.m_native_handle = nullptr;
}
void Threading::pxThread::_platform_specific_OnCleanupInThread()
Threading::ThreadHandle::~ThreadHandle() = default;
Threading::ThreadHandle Threading::ThreadHandle::GetForCallingThread()
{
// cleanup of handles that were upened in
// _platform_specific_OnStartInThread
mach_port_deallocate(mach_task_self(), (thread_port_t)m_native_id);
ThreadHandle ret;
ret.m_native_handle = pthread_self();
return ret;
}
Threading::ThreadHandle& Threading::ThreadHandle::operator=(ThreadHandle&& handle)
{
m_native_handle = handle.m_native_handle;
handle.m_native_handle = nullptr;
return *this;
}
Threading::ThreadHandle& Threading::ThreadHandle::operator=(const ThreadHandle& handle)
{
m_native_handle = handle.m_native_handle;
return *this;
}
u64 Threading::ThreadHandle::GetCPUTime() const
{
return getthreadtime(pthread_mach_thread_np((pthread_t)m_native_handle));
}
bool Threading::ThreadHandle::SetAffinity(u64 processor_mask) const
{
// Doesn't appear to be possible to set affinity.
return false;
}
// name can be up to 16 bytes
+3 -43
View File
@@ -23,22 +23,6 @@
// This should prove useful....
#define wxsFormat wxString::Format
#ifdef PCSX2_DEBUG
#define tryDEBUG try
#define catchDEBUG(clause) catch (clause)
#else
#define tryDEBUG if (true)
#define catchDEBUG(clause) if (false)
#endif
#if defined(PCSX2_DEVBUILD) || defined(PCSX2_DEBUG)
#define tryDEVEL try
#define catchDEVEL catch (clause)
#else
#define tryDEBUG if (true)
#define catchDEBUG(clause) if (false)
#endif
// --------------------------------------------------------------------------------------
// ImplementEnumOperators (macro)
// --------------------------------------------------------------------------------------
@@ -134,35 +118,11 @@ static const pxEnumEnd_t pxEnumEnd = {};
//
#ifndef DeclareNoncopyableObject
#define DeclareNoncopyableObject(classname) \
private: \
explicit classname(const classname&); \
classname& operator=(const classname&)
public: \
classname(const classname&) = delete; \
classname& operator=(const classname&) = delete
#endif
// --------------------------------------------------------------------------------------
// ScopedBool - Makes sure a boolean is set back to FALSE when current scope is left
// --------------------------------------------------------------------------------------
// Exception-safe way of tracking entry and exit of various functions of execution zones.
//
class ScopedBool
{
protected:
bool* m_boolme;
public:
ScopedBool(bool& boolme)
{
boolme = true;
m_boolme = &boolme;
}
~ScopedBool()
{
*m_boolme = false;
}
};
// --------------------------------------------------------------------------------------
// _(x) / _t(x) / _d(x) / pxL(x) / pxLt(x) [macros]
// --------------------------------------------------------------------------------------
+2 -2
View File
@@ -16,7 +16,7 @@
#pragma once
#include <list>
#include "common/Threading.h"
#include <mutex>
// --------------------------------------------------------------------------------------
// EventSource< template EvtType >
@@ -41,7 +41,7 @@ protected:
ListenerList m_cache_copy;
bool m_cache_valid;
Threading::Mutex m_listeners_lock;
std::mutex m_listeners_lock;
public:
EventSource()
+6 -7
View File
@@ -14,15 +14,14 @@
*/
#pragma once
#include "common/Threading.h"
using Threading::ScopedLock;
#include "common/Pcsx2Defs.h"
#include "common/Exceptions.h"
#include "common/Console.h"
template <typename ListenerType>
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType& listener)
{
ScopedLock locker(m_listeners_lock);
std::unique_lock locker(m_listeners_lock);
// Check for duplicates before adding the event.
if (IsDebugBuild)
@@ -41,7 +40,7 @@ typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::
template <typename ListenerType>
void EventSource<ListenerType>::Remove(ListenerType& listener)
{
ScopedLock locker(m_listeners_lock);
std::unique_lock locker(m_listeners_lock);
m_cache_valid = false;
m_listeners.remove(&listener);
}
@@ -49,7 +48,7 @@ void EventSource<ListenerType>::Remove(ListenerType& listener)
template <typename ListenerType>
void EventSource<ListenerType>::Remove(const ListenerIterator& listenerHandle)
{
ScopedLock locker(m_listeners_lock);
std::unique_lock locker(m_listeners_lock);
m_cache_valid = false;
m_listeners.erase(listenerHandle);
}
+1 -15
View File
@@ -23,6 +23,7 @@
#include "common/Dependencies.h" // _ macro
#include "common/Threading.h"
#include "common/General.h"
#include "common/StringHelpers.h"
// for lack of a better place...
Fnptr_OutOfMemory pxDoOutOfMemory = NULL;
@@ -38,10 +39,6 @@ Fnptr_OutOfMemory pxDoOutOfMemory = NULL;
#define DEVASSERT_INLINE __fi
#endif
// Using a threadlocal assertion guard. Separate threads can assert at the same time.
// That's ok. What we don't want is the *same* thread recurse-asserting.
static DeclareTls(int) s_assert_guard(0);
pxDoAssertFnType* pxDoAssert = pxAssertImpl_LogIt;
// make life easier for people using VC++ IDE by using this format, which allows double-click
@@ -55,8 +52,6 @@ wxString DiagnosticOrigin::ToString(const wxChar* msg) const
if (function != NULL)
message.Write(" Function: %s\n", function);
message.Write(L" Thread: %s\n", WX_STR(Threading::pxGetCurrentThreadName()));
if (condition != NULL)
message.Write(L" Condition: %ls\n", condition);
@@ -99,15 +94,6 @@ bool pxAssertImpl_LogIt(const DiagnosticOrigin& origin, const wxChar* msg)
DEVASSERT_INLINE void pxOnAssert(const DiagnosticOrigin& origin, const wxString& msg)
{
// Recursion guard: Allow at least one recursive call. This is useful because sometimes
// we get meaningless assertions while unwinding stack traces after exceptions have occurred.
RecursionGuard guard(s_assert_guard);
if (guard.Counter > 2)
{
return pxTrap();
}
// wxWidgets doesn't come with debug builds on some Linux distros, and other distros make
// it difficult to use the debug build (compilation failures). To handle these I've had to
// bypass the internal wxWidgets assertion handler entirely, since it may not exist even if
+77
View File
@@ -214,6 +214,39 @@ std::string_view FileSystem::GetFileTitleFromPath(const std::string_view& path)
return filename.substr(0, pos);
}
std::vector<std::string_view> FileSystem::SplitWindowsPath(const std::string_view& path)
{
std::vector<std::string_view> parts;
std::string::size_type start = 0;
std::string::size_type pos = 0;
while (pos < path.size())
{
if (path[pos] != '/' && path[pos] != '\\')
{
pos++;
continue;
}
// skip consecutive separators
if (pos != start)
parts.push_back(path.substr(start, pos - start));
pos++;
start = pos;
}
if (start != pos)
parts.push_back(path.substr(start));
return parts;
}
std::vector<std::string_view> FileSystem::SplitNativePath(const std::string_view& path)
{
return StringUtil::SplitString(path, FS_OSPATH_SEPARATOR_CHARACTER, true);
}
std::vector<std::string> FileSystem::GetRootDirectoryList()
{
std::vector<std::string> results;
@@ -1150,6 +1183,45 @@ bool FileSystem::SetWorkingDirectory(const char* path)
return (SetCurrentDirectoryW(wpath.c_str()) == TRUE);
}
bool FileSystem::SetPathCompression(const char* path, bool enable)
{
const std::wstring wpath(StringUtil::UTF8StringToWideString(path));
const DWORD attrs = GetFileAttributesW(wpath.c_str());
if (attrs == INVALID_FILE_ATTRIBUTES)
return false;
const bool isCompressed = (attrs & FILE_ATTRIBUTE_COMPRESSED) != 0;
if (enable == isCompressed)
{
// already compressed/not compressed
return true;
}
const bool isFile = !(attrs & FILE_ATTRIBUTE_DIRECTORY);
const DWORD flags = isFile ? FILE_ATTRIBUTE_NORMAL : (FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_DIRECTORY);
const HANDLE handle = CreateFileW(wpath.c_str(),
FILE_GENERIC_WRITE | FILE_GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
flags,
nullptr);
if (handle == INVALID_HANDLE_VALUE)
return false;
DWORD bytesReturned = 0;
DWORD compressMode = enable ? COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE;
bool result = DeviceIoControl(
handle, FSCTL_SET_COMPRESSION,
&compressMode, 2, nullptr, 0,
&bytesReturned, nullptr);
CloseHandle(handle);
return result;
}
#else
static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, const char* Path, const char* Pattern,
@@ -1617,4 +1689,9 @@ bool FileSystem::SetWorkingDirectory(const char* path)
return (chdir(path) == 0);
}
bool FileSystem::SetPathCompression(const char* path, bool enable)
{
return false;
}
#endif
+11
View File
@@ -102,6 +102,12 @@ namespace FileSystem
/// Returns the file title (less the extension and path) from a filename.
std::string_view GetFileTitleFromPath(const std::string_view& path);
/// Splits a path into its components, handling both Windows and Unix separators.
std::vector<std::string_view> SplitWindowsPath(const std::string_view& path);
/// Splits a path into its components, only handling native separators.
std::vector<std::string_view> SplitNativePath(const std::string_view& path);
/// Returns a list of "root directories" (i.e. root/home directories on Linux, drive letters on Windows).
std::vector<std::string> GetRootDirectoryList();
@@ -169,4 +175,9 @@ namespace FileSystem
/// Sets the current working directory. Returns true if successful.
bool SetWorkingDirectory(const char* path);
/// Enables/disables NTFS compression on a file or directory.
/// Does not apply the compression flag recursively if called for a directory.
/// Does nothing and returns false on non-Windows platforms.
bool SetPathCompression(const char* path, bool enable);
}; // namespace FileSystem
+34 -43
View File
@@ -285,23 +285,18 @@ namespace GL
Console.WriteLn(
"Trying version %u.%u (%s)", version.major_version, version.minor_version,
version.profile == Context::Profile::ES ? "ES" : (version.profile == Context::Profile::Core ? "Core" : "None"));
int surface_attribs[16];
int nsurface_attribs = 0;
surface_attribs[nsurface_attribs++] = EGL_RENDERABLE_TYPE;
surface_attribs[nsurface_attribs++] = (version.profile == Profile::ES) ?
((version.major_version >= 3) ? EGL_OPENGL_ES3_BIT :
((version.major_version == 2) ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_ES_BIT)) :
EGL_OPENGL_BIT;
surface_attribs[nsurface_attribs++] = EGL_SURFACE_TYPE;
surface_attribs[nsurface_attribs++] = (m_wi.type != WindowInfo::Type::Surfaceless) ? EGL_WINDOW_BIT : 0;
surface_attribs[nsurface_attribs++] = EGL_RED_SIZE;
surface_attribs[nsurface_attribs++] = 8;
surface_attribs[nsurface_attribs++] = EGL_GREEN_SIZE;
surface_attribs[nsurface_attribs++] = 8;
surface_attribs[nsurface_attribs++] = EGL_BLUE_SIZE;
surface_attribs[nsurface_attribs++] = 8;
surface_attribs[nsurface_attribs++] = EGL_NONE;
surface_attribs[nsurface_attribs++] = 0;
const int renderable_type = version.profile == Profile::ES
? ((version.major_version >= 3) ? EGL_OPENGL_ES3_BIT : ((version.major_version == 2) ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_ES_BIT))
: EGL_OPENGL_BIT;
const int surface_attribs[] = {
EGL_RENDERABLE_TYPE, renderable_type,
EGL_SURFACE_TYPE, (m_wi.type != WindowInfo::Type::Surfaceless) ? EGL_WINDOW_BIT : 0,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_NONE
};
EGLint num_configs;
if (!eglChooseConfig(m_display, surface_attribs, nullptr, 0, &num_configs) || num_configs == 0)
@@ -318,33 +313,30 @@ namespace GL
}
configs.resize(static_cast<u32>(num_configs));
std::optional<EGLConfig> config;
for (EGLConfig check_config : configs)
{
if (CheckConfigSurfaceFormat(check_config))
m_config = [this, &configs]() {
const auto found_config = std::find_if(std::begin(configs), std::end(configs), [&](const auto& check_config) {
return CheckConfigSurfaceFormat(check_config);
});
if (found_config == std::end(configs))
{
config = check_config;
break;
Console.Warning("No EGL configs matched exactly, using first.");
return configs.front();
}
}
else
{
return *found_config;
}
}();
if (!config.has_value())
{
Console.Warning("No EGL configs matched exactly, using first.");
config = configs.front();
}
int attribs[8];
int nattribs = 0;
if (version.profile != Profile::NoProfile)
{
attribs[nattribs++] = EGL_CONTEXT_MAJOR_VERSION;
attribs[nattribs++] = version.major_version;
attribs[nattribs++] = EGL_CONTEXT_MINOR_VERSION;
attribs[nattribs++] = version.minor_version;
}
attribs[nattribs++] = EGL_NONE;
attribs[nattribs++] = 0;
const auto attribs = [version]() -> std::array<int, 8> {
if (version.profile != Profile::NoProfile)
return {
EGL_CONTEXT_MAJOR_VERSION, version.major_version,
EGL_CONTEXT_MINOR_VERSION, version.minor_version,
EGL_NONE
};
return {EGL_NONE};
}();
if (!eglBindAPI((version.profile == Profile::ES) ? EGL_OPENGL_ES_API : EGL_OPENGL_API))
{
@@ -352,7 +344,7 @@ namespace GL
return false;
}
m_context = eglCreateContext(m_display, config.value(), share_context, attribs);
m_context = eglCreateContext(m_display, m_config, share_context, attribs.data());
if (!m_context)
{
Console.Error("eglCreateContext() failed: %d", eglGetError());
@@ -363,7 +355,6 @@ namespace GL
"Got version %u.%u (%s)", version.major_version, version.minor_version,
version.profile == Context::Profile::ES ? "ES" : (version.profile == Context::Profile::Core ? "Core" : "None"));
m_config = config.value();
m_version = version;
return true;
}
+35 -7
View File
@@ -14,27 +14,34 @@
*/
#include "common/PrecompiledHeader.h"
#include "common/Console.h"
#include "ContextEGLWayland.h"
#include <wayland-egl.h>
#include <dlfcn.h>
namespace GL
{
static const char* WAYLAND_EGL_MODNAME = "libwayland-egl.so.1";
ContextEGLWayland::ContextEGLWayland(const WindowInfo& wi)
: ContextEGL(wi)
{
}
ContextEGLWayland::~ContextEGLWayland()
{
if (m_wl_window)
wl_egl_window_destroy(m_wl_window);
m_wl_egl_window_destroy(m_wl_window);
if (m_wl_module)
dlclose(m_wl_module);
}
std::unique_ptr<Context> ContextEGLWayland::Create(const WindowInfo& wi, const Version* versions_to_try,
size_t num_versions_to_try)
{
std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi);
if (!context->Initialize(versions_to_try, num_versions_to_try))
if (!context->LoadModule() || !context->Initialize(versions_to_try, num_versions_to_try))
return nullptr;
return context;
@@ -45,7 +52,7 @@ namespace GL
std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi);
context->m_display = m_display;
if (!context->CreateContextAndSurface(m_version, m_context, false))
if (!context->LoadModule() || !context->CreateContextAndSurface(m_version, m_context, false))
return nullptr;
return context;
@@ -54,7 +61,7 @@ namespace GL
void ContextEGLWayland::ResizeSurface(u32 new_surface_width, u32 new_surface_height)
{
if (m_wl_window)
wl_egl_window_resize(m_wl_window, new_surface_width, new_surface_height, 0, 0);
m_wl_egl_window_resize(m_wl_window, new_surface_width, new_surface_height, 0, 0);
ContextEGL::ResizeSurface(new_surface_width, new_surface_height);
}
@@ -63,15 +70,36 @@ namespace GL
{
if (m_wl_window)
{
wl_egl_window_destroy(m_wl_window);
m_wl_egl_window_destroy(m_wl_window);
m_wl_window = nullptr;
}
m_wl_window =
wl_egl_window_create(static_cast<wl_surface*>(m_wi.window_handle), m_wi.surface_width, m_wi.surface_height);
m_wl_egl_window_create(static_cast<wl_surface*>(m_wi.window_handle), m_wi.surface_width, m_wi.surface_height);
if (!m_wl_window)
return {};
return reinterpret_cast<EGLNativeWindowType>(m_wl_window);
}
bool ContextEGLWayland::LoadModule()
{
m_wl_module = dlopen(WAYLAND_EGL_MODNAME, RTLD_NOW | RTLD_GLOBAL);
if (!m_wl_module)
{
Console.Error("Failed to load %s.", WAYLAND_EGL_MODNAME);
return false;
}
m_wl_egl_window_create = reinterpret_cast<decltype(m_wl_egl_window_create)>(dlsym(m_wl_module, "wl_egl_window_create"));
m_wl_egl_window_destroy = reinterpret_cast<decltype(m_wl_egl_window_destroy)>(dlsym(m_wl_module, "wl_egl_window_destroy"));
m_wl_egl_window_resize = reinterpret_cast<decltype(m_wl_egl_window_resize)>(dlsym(m_wl_module, "wl_egl_window_resize"));
if (!m_wl_egl_window_create || !m_wl_egl_window_destroy || !m_wl_egl_window_resize)
{
Console.Error("Failed to load one or more functions from %s.", WAYLAND_EGL_MODNAME);
return false;
}
return true;
}
} // namespace GL
+10 -3
View File
@@ -17,7 +17,8 @@
#include "common/GL/ContextEGL.h"
#include <wayland-egl.h>
struct wl_egl_window;
struct wl_surface;
namespace GL
{
@@ -37,7 +38,13 @@ namespace GL
EGLNativeWindowType GetNativeWindow(EGLConfig config) override;
private:
wl_egl_window* m_wl_window = nullptr;
};
bool LoadModule();
wl_egl_window* m_wl_window = nullptr;
void* m_wl_module = nullptr;
wl_egl_window* (*m_wl_egl_window_create)(struct wl_surface* surface, int width, int height);
void (*m_wl_egl_window_destroy)(struct wl_egl_window* egl_window);
void (*m_wl_egl_window_resize)(struct wl_egl_window* egl_window, int width, int height, int dx, int dy);
};
} // namespace GL
-62
View File
@@ -36,68 +36,6 @@
}; \
};
// ----------------------------------------------------------------------------------------
// RecursionGuard - Basic protection against function recursion
// ----------------------------------------------------------------------------------------
// Thread safety note: If used in a threaded environment, you shoud use a handle to a __threadlocal
// storage variable (protects aaginst race conditions and, in *most* cases, is more desirable
// behavior as well.
//
// Rationale: wxWidgets has its own wxRecursionGuard, but it has a sloppy implementation with
// entirely unnecessary assertion checks.
//
class RecursionGuard
{
public:
int& Counter;
RecursionGuard(int& counter)
: Counter(counter)
{
++Counter;
}
virtual ~RecursionGuard()
{
--Counter;
}
bool IsReentrant() const { return Counter > 1; }
};
// --------------------------------------------------------------------------------------
// ICloneable / IActionInvocation / IDeletableObject
// --------------------------------------------------------------------------------------
class IActionInvocation
{
public:
virtual ~IActionInvocation() = default;
virtual void InvokeAction() = 0;
};
class ICloneable
{
public:
virtual ICloneable* Clone() const = 0;
};
class IDeletableObject
{
public:
virtual ~IDeletableObject() = default;
virtual void DeleteSelf() = 0;
virtual bool IsBeingDeleted() = 0;
protected:
// This function is GUI implementation dependent! It's implemented by PCSX2's AppHost,
// but if the SysCore is being linked to another front end, you'll need to implement this
// yourself. Most GUIs have built in message pumps. If a platform lacks one then you'll
// need to implement one yourself (yay?).
virtual void DoDeletion() = 0;
};
// --------------------------------------------------------------------------------------
// PageProtectionMode
// --------------------------------------------------------------------------------------
+4 -2
View File
@@ -14,13 +14,15 @@
*/
#if !defined(_WIN32)
#include <wx/thread.h>
#include <sys/mman.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include "common/PageFaultSource.h"
#include "common/Console.h"
#include "common/Exceptions.h"
#include "common/StringHelpers.h"
// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean
// the same thing.
@@ -55,7 +57,7 @@ static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void*)
// 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...
Threading::ScopedLock lock(PageFault_Mutex);
std::unique_lock lock(PageFault_Mutex);
Source_PageFault->Dispatch(PageFaultInfo((uptr)siginfo->si_addr & ~m_pagemask));
+100 -17
View File
@@ -14,14 +14,27 @@
*/
#if !defined(_WIN32) && !defined(__APPLE__)
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#if defined(__linux__)
#include <sys/prctl.h>
#include <sys/types.h>
#include <sched.h>
// glibc < v2.30 doesn't define gettid...
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid)
#endif
#elif defined(__unix__)
#include <pthread_np.h>
#endif
#include "common/PersistentThread.h"
#include "common/Threading.h"
// We wont need this until we actually have this more then just stubbed out, so I'm commenting this out
// to remove an unneeded dependency.
@@ -42,6 +55,11 @@ __forceinline void Threading::Sleep(int ms)
usleep(1000 * ms);
}
__forceinline void Threading::Timeslice()
{
sched_yield();
}
// For use in spin/wait loops, Acts as a hint to Intel CPUs and should, in theory
// improve performance and reduce cpu power consumption.
__forceinline void Threading::SpinWait()
@@ -96,29 +114,94 @@ u64 Threading::GetThreadCpuTime()
return get_thread_time();
}
u64 Threading::pxThread::GetCpuTime() const
Threading::ThreadHandle::ThreadHandle() = default;
Threading::ThreadHandle::ThreadHandle(const ThreadHandle& handle)
: m_native_handle(handle.m_native_handle)
#ifdef __linux__
, m_native_id(handle.m_native_id)
#endif
{
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or
// m_native_handle to implement it. Return value should be a measure of total time the
// thread has used on the CPU (scaled by the value returned by GetThreadTicksPerSecond(),
// which typically would be an OS-provided scalar or some sort).
if (!m_native_id)
return 0;
return get_thread_time(m_native_id);
}
void Threading::pxThread::_platform_specific_OnStartInThread()
Threading::ThreadHandle::ThreadHandle(ThreadHandle&& handle)
: m_native_handle(handle.m_native_handle)
#ifdef __linux__
, m_native_id(handle.m_native_id)
#endif
{
// Obtain linux-specific thread IDs or Handles here, which can be used to query
// kernel scheduler performance information.
m_native_id = (uptr)pthread_self();
handle.m_native_handle = nullptr;
#ifdef __linux__
handle.m_native_id = 0;
#endif
}
void Threading::pxThread::_platform_specific_OnCleanupInThread()
Threading::ThreadHandle::~ThreadHandle() = default;
Threading::ThreadHandle Threading::ThreadHandle::GetForCallingThread()
{
// Cleanup handles here, which were opened above.
ThreadHandle ret;
ret.m_native_handle = (void*)pthread_self();
#ifdef __linux__
ret.m_native_id = gettid();
#endif
return ret;
}
Threading::ThreadHandle& Threading::ThreadHandle::operator=(ThreadHandle&& handle)
{
m_native_handle = handle.m_native_handle;
handle.m_native_handle = nullptr;
#ifdef __linux__
m_native_id = handle.m_native_id;
handle.m_native_id = 0;
#endif
return *this;
}
Threading::ThreadHandle& Threading::ThreadHandle::operator=(const ThreadHandle& handle)
{
m_native_handle = handle.m_native_handle;
#ifdef __linux__
m_native_id = handle.m_native_id;
#endif
return *this;
}
u64 Threading::ThreadHandle::GetCPUTime() const
{
return m_native_handle ? get_thread_time((uptr)m_native_handle) : 0;
}
bool Threading::ThreadHandle::SetAffinity(u64 processor_mask) const
{
#if defined(__linux__)
cpu_set_t set;
CPU_ZERO(&set);
if (processor_mask != 0)
{
for (u32 i = 0; i < 64; i++)
{
if (processor_mask & (static_cast<u64>(1) << i))
{
CPU_SET(i, &set);
}
}
}
else
{
long num_processors = sysconf(_SC_NPROCESSORS_CONF);
for (long i = 0; i < num_processors; i++)
{
CPU_SET(i, &set);
}
}
return sched_setaffinity((pid_t)m_native_id, sizeof(set), &set) >= 0;
#else
return false;
#endif
}
void Threading::SetNameOfCurrentThread(const char* name)
+4 -2
View File
@@ -26,7 +26,10 @@
#include "EventSource.h"
#include "General.h"
#include "Assertions.h"
#include "Dependencies.h"
#include <atomic>
#include <mutex>
struct PageFaultInfo
{
@@ -314,6 +317,5 @@ extern long __stdcall SysPageFaultExceptionFilter(struct _EXCEPTION_POINTERS* ep
extern void pxInstallSignalHandler();
extern void _platform_InstallSignalHandler();
#include "Threading.h"
extern SrcType_PageFault* Source_PageFault;
extern Threading::Mutex PageFault_Mutex;
extern std::mutex PageFault_Mutex;
-209
View File
@@ -1,209 +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/Threading.h"
#include "common/ScopedPtrMT.h"
#include "common/EventSource.h"
namespace Threading
{
// --------------------------------------------------------------------------------------
// ThreadDeleteEvent
// --------------------------------------------------------------------------------------
class EventListener_Thread : public IEventDispatcher<int>
{
public:
typedef int EvtParams;
protected:
pxThread* m_thread;
public:
EventListener_Thread()
{
m_thread = NULL;
}
virtual ~EventListener_Thread() = default;
void SetThread(pxThread& thr) { m_thread = &thr; }
void SetThread(pxThread* thr) { m_thread = thr; }
void DispatchEvent(const int& params)
{
OnThreadCleanup();
}
protected:
// Invoked by the pxThread when the thread execution is ending. This is
// typically more useful than a delete listener since the extended thread information
// provided by virtualized functions/methods will be available.
// Important! This event is executed *by the thread*, so care must be taken to ensure
// thread sync when necessary (posting messages to the main thread, etc).
virtual void OnThreadCleanup() = 0;
};
/// Set the name of the current thread
void SetNameOfCurrentThread(const char* name);
// --------------------------------------------------------------------------------------
// pxThread - Helper class for the basics of starting/managing persistent threads.
// --------------------------------------------------------------------------------------
// This class is meant to be a helper for the typical threading model of "start once and
// reuse many times." This class incorporates a lot of extra overhead in stopping and
// starting threads, but in turn provides most of the basic thread-safety and event-handling
// functionality needed for a threaded operation. In practice this model is usually an
// ideal one for efficiency since Operating Systems themselves typically subscribe to a
// design where sleeping, suspending, and resuming threads is very efficient, but starting
// new threads has quite a bit of overhead.
//
// To use this as a base class for your threaded procedure, overload the following virtual
// methods:
// void OnStart();
// void ExecuteTaskInThread();
// void OnCleanupInThread();
//
// Use the public methods Start() and Cancel() to start and shutdown the thread, and use
// m_sem_event internally to post/receive events for the thread (make a public accessor for
// it in your derived class if your thread utilizes the post).
//
// Notes:
// * Constructing threads as static global vars isn't recommended since it can potentially
// confuse w32pthreads, if the static initializers are executed out-of-order (C++ offers
// no dependency options for ensuring correct static var initializations). Use heap
// allocation to create thread objects instead.
//
class pxThread
{
DeclareNoncopyableObject(pxThread);
friend void pxYield(int ms);
protected:
wxString m_name; // diagnostic name for our thread.
pthread_t m_thread;
uptr m_native_id; // typically an id, but implementing platforms can do whatever.
uptr m_native_handle; // typically a pointer/handle, but implementing platforms can do whatever.
Semaphore m_sem_event; // general wait event that's needed by most threads
Semaphore m_sem_startup; // startup sync tool
Mutex m_mtx_InThread; // used for canceling and closing threads in a deadlock-safe manner
MutexRecursive m_mtx_start; // used to lock the Start() code from starting simultaneous threads accidentally.
Mutex m_mtx_ThreadName;
std::atomic<bool> m_detached; // a boolean value which indicates if the m_thread handle is valid
std::atomic<bool> m_running; // set true by Start(), and set false by Cancel(), Block(), etc.
// exception handle, set non-NULL if the thread terminated with an exception
// Use RethrowException() to re-throw the exception using its original exception type.
ScopedPtrMT<BaseException> m_except;
EventSource<EventListener_Thread> m_evtsrc_OnDelete;
public:
virtual ~pxThread();
pxThread(const wxString& name = L"pxThread");
pthread_t GetId() const { return m_thread; }
u64 GetCpuTime() const;
virtual void Start();
virtual void Cancel(bool isBlocking = true);
virtual bool Cancel(const wxTimeSpan& timeout);
virtual bool Detach();
virtual void Block();
virtual bool Block(const wxTimeSpan& timeout);
virtual void RethrowException() const;
void AddListener(EventListener_Thread& evt);
void AddListener(EventListener_Thread* evt)
{
if (evt == NULL)
return;
AddListener(*evt);
}
void WaitOnSelf(Semaphore& mutex) const;
void WaitOnSelf(Mutex& mutex) const;
bool WaitOnSelf(Semaphore& mutex, const wxTimeSpan& timeout) const;
bool WaitOnSelf(Mutex& mutex, const wxTimeSpan& timeout) const;
bool IsRunning() const;
bool IsSelf() const;
bool HasPendingException() const { return !!m_except; }
wxString GetName() const;
void SetName(const wxString& newname);
protected:
// Extending classes should always implement your own OnStart(), which is called by
// Start() once necessary locks have been obtained. Do not override Start() directly
// unless you're really sure that's what you need to do. ;)
virtual void OnStart();
virtual void OnStartInThread();
// This is called when the thread has been canceled or exits normally. The pxThread
// automatically binds it to the pthread cleanup routines as soon as the thread starts.
virtual void OnCleanupInThread();
// Implemented by derived class to perform actual threaded task!
virtual void ExecuteTaskInThread() = 0;
void TestCancel() const;
// Yields this thread to other threads and checks for cancellation. A sleeping thread should
// always test for cancellation, however if you really don't want to, you can use Threading::Sleep()
// or better yet, disable cancellation of the thread completely with DisableCancellation().
//
// Parameters:
// ms - 'minimum' yield time in milliseconds (rough -- typically yields are longer by 1-5ms
// depending on operating system/platform). If ms is 0 or unspecified, then a single
// timeslice is yielded to other contending threads. If no threads are contending for
// time when ms==0, then no yield is done, but cancellation is still tested.
void Yield(int ms = 0)
{
pxAssert(IsSelf());
Threading::Sleep(ms);
TestCancel();
}
void FrankenMutex(Mutex& mutex);
bool AffinityAssert_AllowFromSelf(const DiagnosticOrigin& origin) const;
bool AffinityAssert_DisallowFromSelf(const DiagnosticOrigin& origin) const;
// ----------------------------------------------------------------------------
// Section of methods for internal use only.
void _platform_specific_OnStartInThread();
void _platform_specific_OnCleanupInThread();
bool _basecancel();
void _selfRunningTest(const wxChar* name) const;
void _DoSetThreadName(const wxString& name);
void _DoSetThreadName(const char* name) { SetNameOfCurrentThread(name); }
void _internal_execute();
void _try_virtual_invoke(void (pxThread::*method)());
void _ThreadCleanup();
static void* _internal_callback(void* func);
static void internal_callback_helper(void* func);
static void _pt_callback_cleanup(void* handle);
};
} // namespace Threading
+10
View File
@@ -14,10 +14,20 @@
*/
#pragma once
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <VersionHelpers.h>
#include <ShTypes.h>
#include <timeapi.h>
#include <wx/msw/wrapwin.h>
#endif
-114
View File
@@ -1,114 +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/>.
*/
#include "common/RwMutex.h"
// --------------------------------------------------------------------------------------
// RwMutex
// --------------------------------------------------------------------------------------
Threading::RwMutex::RwMutex()
{
pthread_rwlock_init(&m_rwlock, NULL);
}
Threading::RwMutex::~RwMutex()
{
pthread_rwlock_destroy(&m_rwlock);
}
void Threading::RwMutex::AcquireRead()
{
pthread_rwlock_rdlock(&m_rwlock);
}
void Threading::RwMutex::AcquireWrite()
{
pthread_rwlock_wrlock(&m_rwlock);
}
bool Threading::RwMutex::TryAcquireRead()
{
return pthread_rwlock_tryrdlock(&m_rwlock) != EBUSY;
}
bool Threading::RwMutex::TryAcquireWrite()
{
return pthread_rwlock_trywrlock(&m_rwlock) != EBUSY;
}
void Threading::RwMutex::Release()
{
pthread_rwlock_unlock(&m_rwlock);
}
// --------------------------------------------------------------------------------------
//
// --------------------------------------------------------------------------------------
Threading::BaseScopedReadWriteLock::~BaseScopedReadWriteLock()
{
if (m_IsLocked)
m_lock.Release();
}
// Provides manual unlocking of a scoped lock prior to object destruction.
void Threading::BaseScopedReadWriteLock::Release()
{
if (!m_IsLocked)
return;
m_IsLocked = false;
m_lock.Release();
}
// --------------------------------------------------------------------------------------
// ScopedReadLock / ScopedWriteLock
// --------------------------------------------------------------------------------------
Threading::ScopedReadLock::ScopedReadLock(RwMutex& locker)
: BaseScopedReadWriteLock(locker)
{
m_IsLocked = true;
m_lock.AcquireRead();
}
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
void Threading::ScopedReadLock::Acquire()
{
if (m_IsLocked)
return;
m_lock.AcquireRead();
m_IsLocked = true;
}
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex& locker)
: BaseScopedReadWriteLock(locker)
{
m_IsLocked = true;
m_lock.AcquireWrite();
}
// provides manual locking of a scoped lock, to re-lock after a manual unlocking.
void Threading::ScopedWriteLock::Acquire()
{
if (m_IsLocked)
return;
m_lock.AcquireWrite();
m_IsLocked = true;
}
// Special constructor used by ScopedTryLock
Threading::ScopedWriteLock::ScopedWriteLock(RwMutex& locker, bool isTryLock)
: BaseScopedReadWriteLock(locker)
{
//m_IsLocked = isTryLock ? m_lock.TryAcquireWrite() : false;
}
-90
View File
@@ -1,90 +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/Threading.h"
namespace Threading
{
// --------------------------------------------------------------------------------------
// RwMutex
// --------------------------------------------------------------------------------------
class RwMutex
{
DeclareNoncopyableObject(RwMutex);
protected:
pthread_rwlock_t m_rwlock;
public:
RwMutex();
virtual ~RwMutex();
virtual void AcquireRead();
virtual void AcquireWrite();
virtual bool TryAcquireRead();
virtual bool TryAcquireWrite();
virtual void Release();
};
// --------------------------------------------------------------------------------------
// BaseScopedReadWriteLock
// --------------------------------------------------------------------------------------
class BaseScopedReadWriteLock
{
DeclareNoncopyableObject(BaseScopedReadWriteLock);
protected:
RwMutex& m_lock;
bool m_IsLocked;
public:
BaseScopedReadWriteLock(RwMutex& locker)
: m_lock(locker)
{
}
virtual ~BaseScopedReadWriteLock();
void Release();
bool IsLocked() const { return m_IsLocked; }
};
// --------------------------------------------------------------------------------------
// ScopedReadLock / ScopedWriteLock
// --------------------------------------------------------------------------------------
class ScopedReadLock : public BaseScopedReadWriteLock
{
public:
ScopedReadLock(RwMutex& locker);
virtual ~ScopedReadLock() = default;
void Acquire();
};
class ScopedWriteLock : public BaseScopedReadWriteLock
{
public:
ScopedWriteLock(RwMutex& locker);
virtual ~ScopedWriteLock() = default;
void Acquire();
protected:
ScopedWriteLock(RwMutex& locker, bool isTryLock);
};
} // namespace Threading
-140
View File
@@ -1,140 +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 "Threading.h"
using Threading::ScopedLock;
// --------------------------------------------------------------------------------------
// ScopedPtrMT
// --------------------------------------------------------------------------------------
template <typename T>
class ScopedPtrMT
{
DeclareNoncopyableObject(ScopedPtrMT);
protected:
std::atomic<T*> m_ptr;
Threading::Mutex m_mtx;
public:
typedef T element_type;
wxEXPLICIT ScopedPtrMT(T* ptr = nullptr)
{
m_ptr = ptr;
}
~ScopedPtrMT() { _Delete_unlocked(); }
ScopedPtrMT& Reassign(T* ptr = nullptr)
{
T* doh = m_ptr.exchange(ptr);
if (ptr != doh)
delete doh;
return *this;
}
ScopedPtrMT& Delete() noexcept
{
ScopedLock lock(m_mtx);
_Delete_unlocked();
}
// Removes the pointer from scoped management, but does not delete!
// (ScopedPtr will be nullptr after this method)
T* DetachPtr()
{
ScopedLock lock(m_mtx);
return m_ptr.exchange(nullptr);
}
// Returns the managed pointer. Can return nullptr as a valid result if the ScopedPtrMT
// has no object in management.
T* GetPtr() const
{
return m_ptr;
}
void SwapPtr(ScopedPtrMT& other)
{
ScopedLock lock(m_mtx);
m_ptr.exchange(other.m_ptr.exchange(m_ptr.load()));
T* const tmp = other.m_ptr;
other.m_ptr = m_ptr;
m_ptr = tmp;
}
// ----------------------------------------------------------------------------
// ScopedPtrMT Operators
// ----------------------------------------------------------------------------
// I've decided to use the ATL's approach to pointer validity tests, opposed to
// the wx/boost approach (which uses some bizarre member method pointer crap, and can't
// allow the T* implicit casting.
bool operator!() const noexcept
{
return m_ptr.load() == nullptr;
}
// Equality
bool operator==(T* pT) const noexcept
{
return m_ptr == pT;
}
// Inequality
bool operator!=(T* pT) const noexcept
{
return !operator==(pT);
}
// Convenient assignment operator. ScopedPtrMT = nullptr will issue an automatic deletion
// of the managed pointer.
ScopedPtrMT& operator=(T* src)
{
return Reassign(src);
}
#if 0
operator T*() const
{
return m_ptr;
}
// Dereference operator, returns a handle to the managed pointer.
// Generates a debug assertion if the object is nullptr!
T& operator*() const
{
pxAssert(m_ptr != nullptr);
return *m_ptr;
}
T* operator->() const
{
pxAssert(m_ptr != nullptr);
return m_ptr;
}
#endif
protected:
void _Delete_unlocked() noexcept
{
delete m_ptr.exchange(nullptr);
}
};
+128 -133
View File
@@ -13,167 +13,162 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__APPLE__)
#include "common/Threading.h"
#include "common/wxBaseTools.h"
#include "common/ThreadingInternal.h"
#include "common/Assertions.h"
#ifdef _WIN32
#include "common/RedtapeWindows.h"
#endif
#include <limits>
// --------------------------------------------------------------------------------------
// Semaphore Implementations
// --------------------------------------------------------------------------------------
Threading::Semaphore::Semaphore()
{
sem_init(&m_sema, false, 0);
}
Threading::Semaphore::~Semaphore()
void Threading::WorkSema::WaitForWork()
{
sem_destroy(&m_sema);
}
void Threading::Semaphore::Reset()
{
sem_destroy(&m_sema);
sem_init(&m_sema, false, 0);
}
void Threading::Semaphore::Post()
{
sem_post(&m_sema);
}
void Threading::Semaphore::Post(int multiple)
{
#if defined(_MSC_VER)
sem_post_multiple(&m_sema, multiple);
#else
// Only w32pthreads has the post_multiple, but it's easy enough to fake:
while (multiple > 0)
// State change:
// SLEEPING, SPINNING: This is the worker thread and it's clearly not asleep or spinning, so these states should be impossible
// RUNNING_0: Change state to SLEEPING, wake up thread if WAITING_EMPTY
// RUNNING_N: Change state to RUNNING_0 (and preserve WAITING_EMPTY flag)
s32 value = m_state.load(std::memory_order_relaxed);
pxAssert(!IsDead(value));
while (!m_state.compare_exchange_weak(value, NextStateWaitForWork(value), std::memory_order_acq_rel, std::memory_order_relaxed))
;
if (IsReadyForSleep(value))
{
multiple--;
sem_post(&m_sema);
if (value & STATE_FLAG_WAITING_EMPTY)
m_empty_sema.Post();
m_sema.Wait();
// Acknowledge any additional work added between wake up request and getting here
m_state.fetch_and(STATE_FLAG_WAITING_EMPTY, std::memory_order_acquire);
}
#endif
}
void Threading::Semaphore::WaitWithoutYield()
void Threading::WorkSema::WaitForWorkWithSpin()
{
pxAssertMsg(!wxThread::IsMain(), "Unyielding semaphore wait issued from the main/gui thread. Please use Wait() instead.");
sem_wait(&m_sema);
}
bool Threading::Semaphore::WaitWithoutYield(const wxTimeSpan& timeout)
{
wxDateTime megafail(wxDateTime::UNow() + timeout);
const timespec fail = {megafail.GetTicks(), megafail.GetMillisecond() * 1000000};
return sem_timedwait(&m_sema, &fail) == 0;
}
// This is a wxApp-safe implementation of Wait, which makes sure and executes the App's
// pending messages *if* the Wait is performed on the Main/GUI thread. This ensures that
// user input continues to be handled and that windoes continue to repaint. If the Wait is
// called from another thread, no message pumping is performed.
//
void Threading::Semaphore::Wait()
{
#if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL))
s32 value = m_state.load(std::memory_order_relaxed);
pxAssert(!IsDead(value));
while (IsReadyForSleep(value))
{
sem_wait(&m_sema);
}
else if (_WaitGui_RecursionGuard(L"Semaphore::Wait"))
{
sem_wait(&m_sema);
}
else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
while (!WaitWithoutYield(def_yieldgui_interval))
YieldToMain();
}
#else
sem_wait(&m_sema);
#endif
}
// This is a wxApp-safe implementation of WaitWithoutYield, which makes sure and executes the App's
// pending messages *if* the Wait is performed on the Main/GUI thread. This ensures that
// user input continues to be handled and that windows continue to repaint. If the Wait is
// called from another thread, no message pumping is performed.
//
// Returns:
// false if the wait timed out before the semaphore was signaled, or true if the signal was
// reached prior to timeout.
//
bool Threading::Semaphore::Wait(const wxTimeSpan& timeout)
{
#if wxUSE_GUI
if (!wxThread::IsMain() || (wxTheApp == NULL))
{
return WaitWithoutYield(timeout);
}
else if (_WaitGui_RecursionGuard(L"Semaphore::TimedWait"))
{
return WaitWithoutYield(timeout);
}
else
{
//ScopedBusyCursor hourglass( Cursor_KindaBusy );
wxTimeSpan countdown((timeout));
do
if (m_state.compare_exchange_weak(value, STATE_SPINNING, std::memory_order_release, std::memory_order_relaxed))
{
if (WaitWithoutYield(def_yieldgui_interval))
break;
YieldToMain();
countdown -= def_yieldgui_interval;
} while (countdown.GetMilliseconds() > 0);
return countdown.GetMilliseconds() > 0;
if (value & STATE_FLAG_WAITING_EMPTY)
m_empty_sema.Post();
value = STATE_SPINNING;
break;
}
}
u32 waited = 0;
while (value < 0)
{
if (waited > SPIN_TIME_NS)
{
if (!m_state.compare_exchange_weak(value, STATE_SLEEPING, std::memory_order_relaxed))
continue;
m_sema.Wait();
break;
}
waited += ShortSpin();
value = m_state.load(std::memory_order_relaxed);
}
// Clear back to STATE_RUNNING_0 (but preserve waiting empty flag)
m_state.fetch_and(STATE_FLAG_WAITING_EMPTY, std::memory_order_acquire);
}
bool Threading::WorkSema::WaitForEmpty()
{
s32 value = m_state.load(std::memory_order_acquire);
while (true)
{
if (value < 0)
return !IsDead(value); // STATE_SLEEPING or STATE_SPINNING, queue is empty!
// Note: We technically only need memory_order_acquire on *failure* (because that's when we could leave without sleeping), but libstdc++ still asserts on failure < success
if (m_state.compare_exchange_weak(value, value | STATE_FLAG_WAITING_EMPTY, std::memory_order_acquire))
break;
}
pxAssertDev(!(value & STATE_FLAG_WAITING_EMPTY), "Multiple threads attempted to wait for empty (not currently supported)");
m_empty_sema.Wait();
return !IsDead(m_state.load(std::memory_order_relaxed));
}
bool Threading::WorkSema::WaitForEmptyWithSpin()
{
s32 value = m_state.load(std::memory_order_acquire);
u32 waited = 0;
while (true)
{
if (value < 0)
return !IsDead(value); // STATE_SLEEPING or STATE_SPINNING, queue is empty!
if (waited > SPIN_TIME_NS && m_state.compare_exchange_weak(value, value | STATE_FLAG_WAITING_EMPTY, std::memory_order_acquire))
break;
waited += ShortSpin();
value = m_state.load(std::memory_order_acquire);
}
pxAssertDev(!(value & STATE_FLAG_WAITING_EMPTY), "Multiple threads attempted to wait for empty (not currently supported)");
m_empty_sema.Wait();
return !IsDead(m_state.load(std::memory_order_relaxed));
}
void Threading::WorkSema::Kill()
{
s32 value = m_state.exchange(std::numeric_limits<s32>::min(), std::memory_order_release);
if (value & STATE_FLAG_WAITING_EMPTY)
m_empty_sema.Post();
}
void Threading::WorkSema::Reset()
{
m_state = STATE_RUNNING_0;
}
#if !defined(__APPLE__) // macOS implementations are in DarwinSemaphore
Threading::KernelSemaphore::KernelSemaphore()
{
#ifdef _WIN32
m_sema = CreateSemaphore(nullptr, 0, LONG_MAX, nullptr);
#else
return WaitWithoutYield(timeout);
sem_init(&m_sema, false, 0);
#endif
}
// Performs an uncancellable wait on a semaphore; restoring the thread's previous cancel state
// after the wait has completed. Useful for situations where the semaphore itself is stored on
// the stack and passed to another thread via GUI message or such, avoiding complications where
// the thread might be canceled and the stack value becomes invalid.
//
// Performance note: this function has quite a bit more overhead compared to Semaphore::WaitWithoutYield(), so
// consider manually specifying the thread as uncancellable and using WaitWithoutYield() instead if you need
// to do a lot of no-cancel waits in a tight loop worker thread, for example.
void Threading::Semaphore::WaitNoCancel()
Threading::KernelSemaphore::~KernelSemaphore()
{
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
//WaitWithoutYield();
Wait();
pthread_setcancelstate(oldstate, NULL);
#ifdef _WIN32
CloseHandle(m_sema);
#else
sem_destroy(&m_sema);
#endif
}
void Threading::Semaphore::WaitNoCancel(const wxTimeSpan& timeout)
void Threading::KernelSemaphore::Post()
{
int oldstate;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
//WaitWithoutYield( timeout );
Wait(timeout);
pthread_setcancelstate(oldstate, NULL);
#ifdef _WIN32
ReleaseSemaphore(m_sema, 1, nullptr);
#else
sem_post(&m_sema);
#endif
}
bool Threading::Semaphore::TryWait()
void Threading::KernelSemaphore::Wait()
{
#ifdef _WIN32
WaitForSingleObject(m_sema, INFINITE);
#else
sem_wait(&m_sema);
#endif
}
bool Threading::KernelSemaphore::TryWait()
{
#ifdef _WIN32
return WaitForSingleObject(m_sema, 0) == WAIT_OBJECT_0;
#else
return sem_trywait(&m_sema) == 0;
#endif
}
int Threading::Semaphore::Count()
{
int retval;
sem_getvalue(&m_sema, &retval);
return retval;
}
#endif
File diff suppressed because it is too large Load Diff
+181
View File
@@ -0,0 +1,181 @@
/**********************************************************************
*
* StackWalker.h
*
*
*
* LICENSE (http://www.opensource.org/licenses/bsd-license.php)
*
* Copyright (c) 2005-2009, Jochen Kalmbach
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* Neither the name of Jochen Kalmbach nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* **********************************************************************/
#pragma once
#include "RedtapeWindows.h"
class StackWalkerInternal; // forward
class StackWalker
{
public:
typedef enum StackWalkOptions
{
// No addition info will be retrieved
// (only the address is available)
RetrieveNone = 0,
// Try to get the symbol-name
RetrieveSymbol = 1,
// Try to get the line for this symbol
RetrieveLine = 2,
// Try to retrieve the module-infos
RetrieveModuleInfo = 4,
// Also retrieve the version for the DLL/EXE
RetrieveFileVersion = 8,
// Contains all the above
RetrieveVerbose = 0xF,
// Generate a "good" symbol-search-path
SymBuildPath = 0x10,
// Also use the public Microsoft-Symbol-Server
SymUseSymSrv = 0x20,
// Contains all the above "Sym"-options
SymAll = 0x30,
// Contains all options (default)
OptionsAll = 0x3F
} StackWalkOptions;
StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags
LPCSTR szSymPath = NULL,
DWORD dwProcessId = GetCurrentProcessId(),
HANDLE hProcess = GetCurrentProcess());
StackWalker(DWORD dwProcessId, HANDLE hProcess);
StackWalker(const StackWalker&) = delete;
virtual ~StackWalker();
static HMODULE LoadDbgHelpLibrary();
typedef BOOL(__stdcall* PReadProcessMemoryRoutine)(
HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead,
LPVOID pUserData // optional data, which was passed in "ShowCallstack"
);
BOOL LoadModules();
BOOL ShowCallstack(
HANDLE hThread = GetCurrentThread(),
const CONTEXT* context = NULL,
PReadProcessMemoryRoutine readMemoryFunction = NULL,
LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
);
BOOL ShowObject(LPVOID pObject);
#if _MSC_VER >= 1300
// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
protected:
#endif
enum
{
STACKWALK_MAX_NAMELEN = 1024
}; // max name length for found symbols
protected:
// Entry for each Callstack-Entry
typedef struct CallstackEntry
{
DWORD64 offset; // if 0, we have no valid entry
CHAR name[STACKWALK_MAX_NAMELEN];
CHAR undName[STACKWALK_MAX_NAMELEN];
CHAR undFullName[STACKWALK_MAX_NAMELEN];
DWORD64 offsetFromSmybol;
DWORD offsetFromLine;
DWORD lineNumber;
CHAR lineFileName[STACKWALK_MAX_NAMELEN];
DWORD symType;
LPCSTR symTypeString;
CHAR moduleName[STACKWALK_MAX_NAMELEN];
DWORD64 baseOfImage;
CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
} CallstackEntry;
typedef enum CallstackEntryType
{
firstEntry,
nextEntry,
lastEntry
} CallstackEntryType;
virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
virtual void OnLoadModule(LPCSTR img,
LPCSTR mod,
DWORD64 baseAddr,
DWORD size,
DWORD result,
LPCSTR symType,
LPCSTR pdbName,
ULONGLONG fileVersion);
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry);
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
virtual void OnOutput(LPCSTR szText);
StackWalkerInternal* m_sw;
HANDLE m_hProcess;
DWORD m_dwProcessId;
BOOL m_modulesLoaded;
LPSTR m_szSymPath;
int m_options;
int m_MaxRecursionCount;
static BOOL __stdcall myReadProcMem(HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead);
friend StackWalkerInternal;
}; // class StackWalker
// The following is defined for x86 (XP and higher), x64 and IA64:
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
do \
{ \
memset(&c, 0, sizeof(CONTEXT)); \
c.ContextFlags = contextFlags; \
RtlCaptureContext(&c); \
} while (0);
-17
View File
@@ -231,23 +231,6 @@ bool TryParse(wxRect& dest, const wxString& src, const wxRect& defval, const wxS
return true;
}
// returns TRUE if the parse is valid, or FALSE if it's a comment.
bool pxParseAssignmentString(const wxString& src, wxString& ldest, wxString& rdest)
{
if (src.StartsWith(L"--") || src.StartsWith(L"//") || src.StartsWith(L";"))
return false;
ldest = src.BeforeFirst(L'=').Trim(true).Trim(false);
rdest = src.AfterFirst(L'=').Trim(true).Trim(false);
return true;
}
ParsedAssignmentString::ParsedAssignmentString(const wxString& src)
{
IsComment = pxParseAssignmentString(src, lvalue, rvalue);
}
// Performs a cross-platform puts operation, which adds CRs to naked LFs on Win32 platforms,
// so that Notepad won't throw a fit and Rama can read the logs again! On Unix and Mac platforms,
// the input string is written unmodified.
-64
View File
@@ -28,46 +28,6 @@
#define WX_STR(str) (static_cast<const char*>(str.c_str()))
#endif
// --------------------------------------------------------------------------------------
// pxToUTF8
// --------------------------------------------------------------------------------------
// Converts a string to UTF8 and provides an interface for getting its length.
class pxToUTF8
{
DeclareNoncopyableObject(pxToUTF8);
protected:
wxCharBuffer m_result;
int m_length;
public:
explicit pxToUTF8(const wxString& src)
: m_result(src.ToUTF8())
{
m_length = -1;
}
size_t Length()
{
if (-1 == m_length)
m_length = strlen(m_result);
return m_length;
}
void Convert(const wxString& src)
{
m_result = src.ToUTF8();
m_length = -1;
}
const char* data() const { return m_result; }
operator const char*() const
{
return m_result.data();
}
};
extern void px_fputs(FILE* fp, const char* src);
// wxWidgets lacks one of its own...
@@ -88,28 +48,6 @@ extern bool TryParse(wxPoint& dest, const wxString& src, const wxPoint& defval =
extern bool TryParse(wxSize& dest, const wxString& src, const wxSize& defval = wxDefaultSize, const wxString& separators = L",");
extern bool TryParse(wxRect& dest, const wxString& src, const wxRect& defval = wxDefaultRect, const wxString& separators = L",");
// --------------------------------------------------------------------------------------
// ParsedAssignmentString
// --------------------------------------------------------------------------------------
// This class is a simple helper for parsing INI-style assignments, in the typical form of:
// variable = value
// filename = SomeString.txt
// integer = 15
//
// This parser supports both '//' and ';' at the head of a line as indicators of a commented
// line, and such a line will return empty strings for l- and r-value.
//
// No type handling is performed -- the user must manually parse strings into integers, etc.
// For advanced "fully functional" ini file parsing, consider using wxFileConfig instead.
//
struct ParsedAssignmentString
{
wxString lvalue;
wxString rvalue;
bool IsComment;
ParsedAssignmentString(const wxString& src);
};
// ======================================================================================
// FastFormatAscii / FastFormatUnicode (overview!)
@@ -221,8 +159,6 @@ public:
FastFormatUnicode& operator+=(const char* psz);
};
extern bool pxParseAssignmentString(const wxString& src, wxString& ldest, wxString& rdest);
#define pxsFmt FastFormatUnicode().Write
#define pxsFmtV FastFormatUnicode().WriteV
#define pxsPtr(ptr) pxsFmt("0x%016" PRIXPTR, (ptr)).c_str()
+40
View File
@@ -251,6 +251,27 @@ namespace StringUtil
return str.substr(start, end - start + 1);
}
void StripWhitespace(std::string* str)
{
{
const char* cstr = str->c_str();
std::string_view::size_type start = 0;
while (start < str->size() && std::isspace(cstr[start]))
start++;
if (start != 0)
str->erase(0, start);
}
{
const char* cstr = str->c_str();
std::string_view::size_type start = str->size();
while (start > 0 && std::isspace(cstr[start - 1]))
start--;
if (start != str->size())
str->erase(start);
}
}
std::vector<std::string_view> SplitString(const std::string_view& str, char delimiter, bool skip_empty /*= true*/)
{
std::vector<std::string_view> res;
@@ -275,6 +296,25 @@ namespace StringUtil
return res;
}
bool ParseAssignmentString(const std::string_view& str, std::string_view* key, std::string_view* value)
{
const std::string_view::size_type pos = str.find('=');
if (pos == std::string_view::npos)
{
*key = std::string_view();
*value = std::string_view();
return false;
}
*key = StripWhitespace(str.substr(0, pos));
if (pos != (str.size() - 1))
*value = StripWhitespace(str.substr(pos + 1));
else
*value = std::string_view();
return true;
}
std::wstring UTF8StringToWideString(const std::string_view& str)
{
std::wstring ret;
+13
View File
@@ -166,14 +166,24 @@ namespace StringUtil
/// Strip whitespace from the start/end of the string.
std::string_view StripWhitespace(const std::string_view& str);
void StripWhitespace(std::string* str);
/// Splits a string based on a single character delimiter.
std::vector<std::string_view> SplitString(const std::string_view& str, char delimiter, bool skip_empty = true);
/// Parses an assignment string (Key = Value) into its two components.
bool ParseAssignmentString(const std::string_view& str, std::string_view* key, std::string_view* value);
/// Strided memcpy/memcmp.
static inline void StrideMemCpy(void* dst, std::size_t dst_stride, const void* src, std::size_t src_stride,
std::size_t copy_size, std::size_t count)
{
if (src_stride == dst_stride && src_stride == copy_size)
{
std::memcpy(dst, src, src_stride * count);
return;
}
const u8* src_ptr = static_cast<const u8*>(src);
u8* dst_ptr = static_cast<u8*>(dst);
for (std::size_t i = 0; i < count; i++)
@@ -187,6 +197,9 @@ namespace StringUtil
static inline int StrideMemCmp(const void* p1, std::size_t p1_stride, const void* p2, std::size_t p2_stride,
std::size_t copy_size, std::size_t count)
{
if (p1_stride == p2_stride && p1_stride == copy_size)
return std::memcmp(p1, p2, p1_stride * count);
const u8* p1_ptr = static_cast<const u8*>(p1);
const u8* p2_ptr = static_cast<const u8*>(p2);
for (std::size_t i = 0; i < count; i++)
+117 -368
View File
@@ -15,149 +15,16 @@
#pragma once
#ifdef _WIN32
// thanks I hate it.
#include <wx/filefn.h>
#define HAVE_MODE_T
#endif
#include <semaphore.h>
#include <errno.h> // EBUSY
#include <pthread.h>
#ifdef __APPLE__
#include <mach/semaphore.h>
#endif
#include "common/Pcsx2Defs.h"
#include "common/TraceLog.h"
#include "common/General.h"
#undef Yield // release the burden of windows.h global namespace spam.
#define AffinityAssert_AllowFrom_MainUI() \
pxAssertMsg(wxThread::IsMain(), "Thread affinity violation: Call allowed from main thread only.")
// --------------------------------------------------------------------------------------
// pxThreadLog / ConsoleLogSource_Threading
// --------------------------------------------------------------------------------------
class ConsoleLogSource_Threading : ConsoleLogSource
{
typedef ConsoleLogSource _parent;
public:
using _parent::IsActive;
ConsoleLogSource_Threading();
bool Write(const wxString& thrname, const wxChar* msg)
{
return _parent::Write(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
}
bool Warn(const wxString& thrname, const wxChar* msg)
{
return _parent::Warn(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
}
bool Error(const wxString& thrname, const wxChar* msg)
{
return _parent::Error(wxsFormat(L"(thread:%s) ", WX_STR(thrname)) + msg);
}
};
extern ConsoleLogSource_Threading pxConLog_Thread;
#define pxThreadLog pxConLog_Thread.IsActive() && pxConLog_Thread
// --------------------------------------------------------------------------------------
// PCSX2_THREAD_LOCAL - Defines platform/operating system support for Thread Local Storage
// --------------------------------------------------------------------------------------
//
// TLS is enabled by default. It will be disabled at compile time for Linux plugin.
// If you link SPU2X/ZZOGL with a TLS library, you will consume a DVT slots. Slots
// are rather limited and it ends up to "impossible to dlopen the library"
// None of the above plugin uses TLS variable in a multithread context
#ifndef PCSX2_THREAD_LOCAL
#define PCSX2_THREAD_LOCAL 1
#if defined(__APPLE__)
#include <mach/semaphore.h>
#elif !defined(_WIN32)
#include <semaphore.h>
#endif
#if PCSX2_THREAD_LOCAL
#define DeclareTls(x) thread_local x
#else
#define DeclareTls(x) x
#endif
class wxTimeSpan;
namespace Threading
{
class pxThread;
class RwMutex;
extern void pxTestCancel();
extern pxThread* pxGetCurrentThread();
extern wxString pxGetCurrentThreadName();
extern u64 GetThreadCpuTime();
extern u64 GetThreadTicksPerSecond();
// Yields the current thread and provides cancellation points if the thread is managed by
// pxThread. Unmanaged threads use standard Sleep.
extern void pxYield(int ms);
} // namespace Threading
namespace Exception
{
class BaseThreadError : public RuntimeError
{
DEFINE_EXCEPTION_COPYTORS(BaseThreadError, RuntimeError)
DEFINE_EXCEPTION_MESSAGES(BaseThreadError)
public:
Threading::pxThread* m_thread;
protected:
BaseThreadError()
{
m_thread = NULL;
}
public:
explicit BaseThreadError(Threading::pxThread* _thread)
{
m_thread = _thread;
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
}
explicit BaseThreadError(Threading::pxThread& _thread)
{
m_thread = &_thread;
m_message_diag = L"An unspecified thread-related error occurred (thread=%s)";
}
virtual wxString FormatDiagnosticMessage() const;
virtual wxString FormatDisplayMessage() const;
Threading::pxThread& Thread();
const Threading::pxThread& Thread() const;
};
class ThreadCreationError : public BaseThreadError
{
DEFINE_EXCEPTION_COPYTORS(ThreadCreationError, BaseThreadError)
public:
explicit ThreadCreationError(Threading::pxThread* _thread)
{
m_thread = _thread;
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
}
explicit ThreadCreationError(Threading::pxThread& _thread)
{
m_thread = &_thread;
SetBothMsgs(L"Thread creation failure. An unspecified error occurred while trying to create the %s thread.");
}
};
} // namespace Exception
#include <atomic>
namespace Threading
{
@@ -167,6 +34,12 @@ namespace Threading
// The following set of documented functions have Linux/Win32 specific implementations,
// which are found in WinThreads.cpp and LnxThreads.cpp
extern u64 GetThreadCpuTime();
extern u64 GetThreadTicksPerSecond();
/// Set the name of the current thread
extern void SetNameOfCurrentThread(const char* name);
// Releases a timeslice to other threads.
extern void Timeslice();
@@ -181,261 +54,137 @@ namespace Threading
// sleeps the current thread for the given number of milliseconds.
extern void Sleep(int ms);
// pthread Cond is an evil api that is not suited for Pcsx2 needs.
// Let's not use it. Use mutexes and semaphores instead to create waits. (Air)
#if 0
struct WaitEvent
{
pthread_cond_t cond;
pthread_mutex_t mutex;
WaitEvent();
~WaitEvent();
void Set();
void Wait();
};
#endif
// --------------------------------------------------------------------------------------
// NonblockingMutex
// ThreadHandle
// --------------------------------------------------------------------------------------
// This is a very simple non-blocking mutex, which behaves similarly to pthread_mutex's
// trylock(), but without any of the extra overhead needed to set up a structure capable
// of blocking waits. It basically optimizes to a single InterlockedExchange.
// Abstracts an OS's handle to a thread, closing the handle when necessary. Currently,
// only used for getting the CPU time for a thread.
//
// Simple use: if TryAcquire() returns false, the Bool is already interlocked by another thread.
// If TryAcquire() returns true, you've locked the object and are *responsible* for unlocking
// it later.
//
class NonblockingMutex
class ThreadHandle
{
protected:
std::atomic_flag val;
public:
NonblockingMutex() { val.clear(); }
virtual ~NonblockingMutex() = default;
ThreadHandle();
ThreadHandle(ThreadHandle&& handle);
ThreadHandle(const ThreadHandle& handle);
~ThreadHandle();
bool TryAcquire() noexcept
{
return !val.test_and_set();
}
/// Returns a new handle for the calling thread.
static ThreadHandle GetForCallingThread();
// Can be done with a TryAcquire/Release but it is likely better to do it outside of the object
bool IsLocked()
{
pxAssertMsg(0, "IsLocked isn't supported for NonblockingMutex");
return false;
}
ThreadHandle& operator=(ThreadHandle&& handle);
ThreadHandle& operator=(const ThreadHandle& handle);
void Release()
{
val.clear();
}
operator void*() const { return m_native_handle; }
operator bool() const { return (m_native_handle != nullptr); }
/// Returns the amount of CPU time consumed by the thread, at the GetThreadTicksPerSecond() frequency.
u64 GetCPUTime() const;
/// Sets the affinity for a thread to the specified processors.
/// Obviously, only works up to 64 processors.
bool SetAffinity(u64 processor_mask) const;
private:
void* m_native_handle = nullptr;
// We need the thread ID for affinity adjustments on Linux.
#if defined(__linux__)
unsigned int m_native_id = 0;
#endif
};
class Semaphore
/// A semaphore that may not have a fast userspace path
/// (Used in other semaphore-based algorithms where the semaphore is just used for its thread sleep/wake ability)
class KernelSemaphore
{
protected:
#ifdef __APPLE__
#if defined(_WIN32)
void* m_sema;
#elif defined(__APPLE__)
semaphore_t m_sema;
int m_counter;
#else
sem_t m_sema;
#endif
public:
Semaphore();
virtual ~Semaphore();
void Reset();
KernelSemaphore();
~KernelSemaphore();
void Post();
void Post(int multiple);
void WaitWithoutYield();
bool WaitWithoutYield(const wxTimeSpan& timeout);
void WaitNoCancel();
void WaitNoCancel(const wxTimeSpan& timeout);
void WaitWithoutYieldWithSpin()
{
u32 waited = 0;
while (true)
{
if (TryWait())
return;
if (waited >= SPIN_TIME_NS)
break;
waited += ShortSpin();
}
WaitWithoutYield();
}
void Wait();
bool TryWait();
int Count();
void Wait();
bool Wait(const wxTimeSpan& timeout);
};
class Mutex
/// A semaphore for notifying a work-processing thread of new work in a (separate) queue
///
/// Usage:
/// - Processing thread loops on `WaitForWork()` followed by processing all work in the queue
/// - Threads adding work first add their work to the queue, then call `NotifyOfWork()`
class WorkSema
{
protected:
pthread_mutex_t m_mutex;
/// Semaphore for sleeping the worker thread
KernelSemaphore m_sema;
/// Semaphore for sleeping thread waiting on worker queue empty
KernelSemaphore m_empty_sema;
/// Current state (see enum below)
std::atomic<s32> m_state{0};
// Expected call frequency is NotifyOfWork > WaitForWork > WaitForEmpty
// So optimize states for fast NotifyOfWork
enum
{
/* Any <-2 state: STATE_DEAD: Thread has crashed and is awaiting revival */
STATE_SPINNING = -2, ///< Worker thread is spinning waiting for work
STATE_SLEEPING = -1, ///< Worker thread is sleeping on m_sema
STATE_RUNNING_0 = 0, ///< Worker thread is processing work, but no work has been added since it last checked for new work
/* Any >0 state: STATE_RUNNING_N: Worker thread is processing work, and work has been added since it last checked for new work */
STATE_FLAG_WAITING_EMPTY = 1 << 30, ///< Flag to indicate that a thread is sleeping on m_empty_sema (can be applied to any STATE_RUNNING)
};
bool IsDead(s32 state)
{
return state < STATE_SPINNING;
}
bool IsReadyForSleep(s32 state)
{
s32 waiting_empty_cleared = state & (STATE_FLAG_WAITING_EMPTY - 1);
return waiting_empty_cleared == STATE_RUNNING_0;
}
s32 NextStateWaitForWork(s32 current)
{
s32 new_state = IsReadyForSleep(current) ? STATE_SLEEPING : STATE_RUNNING_0;
return new_state | (current & STATE_FLAG_WAITING_EMPTY); // Preserve waiting empty flag for RUNNING_N → RUNNING_0
}
public:
Mutex();
virtual ~Mutex();
virtual bool IsRecursive() const { return false; }
void Recreate();
bool RecreateIfLocked();
void Detach();
void Acquire();
bool Acquire(const wxTimeSpan& timeout);
bool TryAcquire();
void Release();
void AcquireWithoutYield();
bool AcquireWithoutYield(const wxTimeSpan& timeout);
void Wait();
void WaitWithSpin();
bool Wait(const wxTimeSpan& timeout);
void WaitWithoutYield();
bool WaitWithoutYield(const wxTimeSpan& timeout);
protected:
// empty constructor used by MutexLockRecursive
Mutex(bool) {}
};
class MutexRecursive : public Mutex
{
public:
MutexRecursive();
virtual ~MutexRecursive();
virtual bool IsRecursive() const { return true; }
};
// --------------------------------------------------------------------------------------
// ScopedLock
// --------------------------------------------------------------------------------------
// Helper class for using Mutexes. Using this class provides an exception-safe (and
// generally clean) method of locking code inside a function or conditional block. The lock
// will be automatically released on any return or exit from the function.
//
// Const qualification note:
// ScopedLock takes const instances of the mutex, even though the mutex is modified
// by locking and unlocking. Two rationales:
//
// 1) when designing classes with accessors (GetString, GetValue, etc) that need mutexes,
// this class needs a const hack to allow those accessors to be const (which is typically
// *very* important).
//
// 2) The state of the Mutex is guaranteed to be unchanged when the calling function or
// scope exits, by any means. Only via manual calls to Release or Acquire does that
// change, and typically those are only used in very special circumstances of their own.
//
class ScopedLock
{
DeclareNoncopyableObject(ScopedLock);
protected:
Mutex* m_lock;
bool m_IsLocked;
public:
virtual ~ScopedLock();
explicit ScopedLock(const Mutex* locker = NULL);
explicit ScopedLock(const Mutex& locker);
void AssignAndLock(const Mutex& locker);
void AssignAndLock(const Mutex* locker);
void Assign(const Mutex& locker);
void Assign(const Mutex* locker);
void Release();
void Acquire();
bool IsLocked() const { return m_IsLocked; }
protected:
// Special constructor used by ScopedTryLock
ScopedLock(const Mutex& locker, bool isTryLock);
};
class ScopedTryLock : public ScopedLock
{
public:
ScopedTryLock(const Mutex& locker)
: ScopedLock(locker, true)
{
}
virtual ~ScopedTryLock() = default;
bool Failed() const { return !m_IsLocked; }
};
// --------------------------------------------------------------------------------------
// ScopedNonblockingLock
// --------------------------------------------------------------------------------------
// A ScopedTryLock branded for use with Nonblocking mutexes. See ScopedTryLock for details.
//
class ScopedNonblockingLock
{
DeclareNoncopyableObject(ScopedNonblockingLock);
protected:
NonblockingMutex& m_lock;
bool m_IsLocked;
public:
ScopedNonblockingLock(NonblockingMutex& locker)
: m_lock(locker)
, m_IsLocked(m_lock.TryAcquire())
/// Notify the worker thread that you've added new work to its queue
void NotifyOfWork()
{
// State change:
// DEAD: Stay in DEAD (starting DEAD state is INT_MIN so we can assume we won't flip over to anything else)
// SPINNING: Change state to RUNNING. Thread will notice and process the new data
// SLEEPING: Change state to RUNNING and wake worker. Thread will wake up and process the new data.
// RUNNING_0: Change state to RUNNING_N.
// RUNNING_N: Stay in RUNNING_N
s32 old = m_state.fetch_add(2, std::memory_order_release);
if (old == STATE_SLEEPING)
m_sema.Post();
}
virtual ~ScopedNonblockingLock()
{
if (m_IsLocked)
m_lock.Release();
}
bool Failed() const { return !m_IsLocked; }
};
// --------------------------------------------------------------------------------------
// ScopedLockBool
// --------------------------------------------------------------------------------------
// A ScopedLock in which you specify an external bool to get updated on locks/unlocks.
// Note that the isLockedBool should only be used as an indicator for the locked status,
// and not actually depended on for thread synchronization...
struct ScopedLockBool
{
ScopedLock m_lock;
std::atomic<bool>& m_bool;
ScopedLockBool(Mutex& mutexToLock, std::atomic<bool>& isLockedBool)
: m_lock(mutexToLock)
, m_bool(isLockedBool)
{
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
}
virtual ~ScopedLockBool()
{
m_bool.store(false, std::memory_order_relaxed);
}
void Acquire()
{
m_lock.Acquire();
m_bool.store(m_lock.IsLocked(), std::memory_order_relaxed);
}
void Release()
{
m_bool.store(false, std::memory_order_relaxed);
m_lock.Release();
}
/// Wait for work to be added to the queue
void WaitForWork();
/// Wait for work to be added to the queue, spinning for a bit before sleeping the thread
void WaitForWorkWithSpin();
/// Wait for the worker thread to finish processing all entries in the queue or die
/// Returns false if the thread is dead
bool WaitForEmpty();
/// Wait for the worker thread to finish processing all entries in the queue or die, spinning a bit before sleeping the thread
/// Returns false if the thread is dead
bool WaitForEmptyWithSpin();
/// Called by the worker thread to notify others of its death
/// Dead threads don't process work, and WaitForEmpty will return instantly even though there may be work in the queue
void Kill();
/// Reset the semaphore to the initial state
/// Should be called by the worker thread if it restarts after dying
void Reset();
};
} // namespace Threading
-181
View File
@@ -21,22 +21,13 @@
#if defined(_WIN32)
#include "RedtapeWindows.h"
#elif defined(__APPLE__)
#include <mach/mach_init.h>
#include <mach/thread_act.h>
#include <mach/mach_port.h>
#else
#include <pthread.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#endif
namespace Common
{
#ifdef _WIN32
static double s_counter_frequency;
static bool s_counter_initialized = false;
@@ -85,9 +76,7 @@ namespace Common
{
return static_cast<Value>(ns * s_counter_frequency);
}
#else
Timer::Value Timer::GetCurrentValue()
{
struct timespec tv;
@@ -124,7 +113,6 @@ namespace Common
{
return static_cast<Value>(ns);
}
#endif
Timer::Timer()
@@ -175,173 +163,4 @@ namespace Common
m_tvStartValue = value;
return ret;
}
ThreadCPUTimer::ThreadCPUTimer() = default;
ThreadCPUTimer::ThreadCPUTimer(ThreadCPUTimer&& move)
: m_thread_handle(move.m_thread_handle)
{
move.m_thread_handle = nullptr;
}
ThreadCPUTimer::~ThreadCPUTimer()
{
#ifdef _WIN32
CloseHandle(reinterpret_cast<HANDLE>(m_thread_handle));
#endif
}
ThreadCPUTimer& ThreadCPUTimer::operator=(ThreadCPUTimer&& move)
{
std::swap(m_thread_handle, move.m_thread_handle);
return *this;
}
void ThreadCPUTimer::Reset()
{
m_start_value = GetCurrentValue();
}
ThreadCPUTimer::Value ThreadCPUTimer::GetCurrentValue() const
{
#if defined(_WIN32)
FILETIME create, exit, user, kernel;
if (!m_thread_handle || !GetThreadTimes((HANDLE)m_thread_handle, &create, &exit, &user, &kernel))
return 0;
Value value = (static_cast<Value>(user.dwHighDateTime) << 32) | (static_cast<Value>(user.dwLowDateTime));
value += (static_cast<Value>(kernel.dwHighDateTime) << 32) | (static_cast<Value>(kernel.dwLowDateTime));
return value;
#elif defined(__APPLE__)
thread_basic_info_data_t info;
mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;
const kern_return_t kr = thread_info((mach_port_t) reinterpret_cast<uintptr_t>(m_thread_handle), THREAD_BASIC_INFO, (thread_info_t)&info, &count);
if (kr != KERN_SUCCESS)
return 0;
Value value = (static_cast<Value>(info.user_time.seconds) * 1000000) + (static_cast<Value>(info.user_time.microseconds));
value += (static_cast<Value>(info.system_time.seconds) * 1000000) + (static_cast<Value>(info.system_time.microseconds));
return value;
#else
clockid_t cid;
if (!m_thread_handle || pthread_getcpuclockid((pthread_t)m_thread_handle, &cid) != 0)
return 0;
struct timespec ts;
if (clock_gettime(cid, &ts) != 0)
return 0;
return (static_cast<Value>(ts.tv_nsec) + static_cast<Value>(ts.tv_sec) * 1000000000LL);
#endif
}
double ThreadCPUTimer::GetTimeSeconds() const
{
return ConvertValueToSeconds(GetCurrentValue() - m_start_value);
}
double ThreadCPUTimer::GetTimeMilliseconds() const
{
return ConvertValueToMilliseconds(GetCurrentValue() - m_start_value);
}
double ThreadCPUTimer::GetTimeNanoseconds() const
{
return ConvertValueToNanoseconds(GetCurrentValue() - m_start_value);
}
void ThreadCPUTimer::GetUsageInSecondsAndReset(Value time_diff, double* usage_time, double* usage_percent)
{
const Value new_value = GetCurrentValue();
const Value diff = new_value - m_start_value;
m_start_value = new_value;
*usage_time = ConvertValueToSeconds(diff);
*usage_percent = GetUtilizationPercentage(time_diff, diff);
}
void ThreadCPUTimer::GetUsageInMillisecondsAndReset(Value time_diff, double* usage_time, double* usage_percent)
{
const Value new_value = GetCurrentValue();
const Value diff = new_value - m_start_value;
m_start_value = new_value;
*usage_time = ConvertValueToMilliseconds(diff);
*usage_percent = GetUtilizationPercentage(time_diff, diff);
}
void ThreadCPUTimer::GetUsageInNanosecondsAndReset(Value time_diff, double* usage_time, double* usage_percent)
{
const Value new_value = GetCurrentValue();
const Value diff = new_value - m_start_value;
m_start_value = new_value;
*usage_time = ConvertValueToNanoseconds(diff);
*usage_percent = GetUtilizationPercentage(time_diff, diff);
}
double ThreadCPUTimer::GetUtilizationPercentage(Timer::Value time_diff, Value cpu_time_diff)
{
#if defined(_WIN32)
return ((static_cast<double>(cpu_time_diff) * 10000.0) / (static_cast<double>(time_diff) / s_counter_frequency));
#elif defined(__APPLE__)
// microseconds, but time_tiff is in nanoseconds, so multiply by 1000 * 100
return (static_cast<double>(cpu_time_diff) * 100000.0) / static_cast<double>(time_diff);
#else
// nanoseconds
return (static_cast<double>(cpu_time_diff) * 100.0) / static_cast<double>(time_diff);
#endif
}
double ThreadCPUTimer::ConvertValueToSeconds(Value value)
{
#if defined(_WIN32)
// 100ns units
return (static_cast<double>(value) / 10000000.0);
#elif defined(__APPLE__)
// microseconds
return (static_cast<double>(value) / 1000000.0);
#else
// nanoseconds
return (static_cast<double>(value) / 1000000000.0);
#endif
}
double ThreadCPUTimer::ConvertValueToMilliseconds(Value value)
{
#if defined(_WIN32)
return (static_cast<double>(value) / 10000.0);
#elif defined(__APPLE__)
return (static_cast<double>(value) / 1000.0);
#else
return (static_cast<double>(value) / 1000000.0);
#endif
}
double ThreadCPUTimer::ConvertValueToNanoseconds(Value value)
{
#if defined(_WIN32)
return (static_cast<double>(value) * 100.0);
#elif defined(__APPLE__)
return (static_cast<double>(value) * 1000.0);
#else
return static_cast<double>(value);
#endif
}
ThreadCPUTimer ThreadCPUTimer::GetForCallingThread()
{
ThreadCPUTimer ret;
#if defined(_WIN32)
ret.m_thread_handle = (void*)OpenThread(THREAD_QUERY_INFORMATION, FALSE, GetCurrentThreadId());
#elif defined(__APPLE__)
ret.m_thread_handle = reinterpret_cast<void*>((uintptr_t)mach_thread_self());
#else
ret.m_thread_handle = (void*)pthread_self();
#endif
ret.Reset();
return ret;
}
} // namespace Common

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