Compare commits

...
342 Commits
Author SHA1 Message Date
JordanTheToasterandrefractionpcsx2 1067ed309a GameDB: Various fixes
Fixes for missing lighting in No One Lives Forever and somehow fixes Spongebob Revenge of The Flying Dutchman not starting a new game in the PAL version.
2023-06-05 16:34:11 +01:00
refractionpcsx2 1ef9bc464d GS-HW: Only preload targets when data is needed 2023-06-05 11:26:33 +01:00
Stenzekandrefractionpcsx2 ba3a7fc11a GS/HW: Rename IsBlendedOrOpaque() to IsDiscardingDstColor()
And remove the dst color output case, this is clearly wrong when we're
using this to try to identify clears.
2023-06-05 11:26:33 +01:00
Stenzekandrefractionpcsx2 c44b4c3d35 GS/HW: Black blending should preserve RGB, not A 2023-06-05 11:26:33 +01:00
Stenzekandrefractionpcsx2 c79c79fe0e GS/HW: Fix PrimitiveCoversWithoutGaps returning true with gaps
Previously it only checked that all sprites matched in size, not that
there wasn't actually any gaps between them.
2023-06-05 11:26:33 +01:00
Stenzekandrefractionpcsx2 a7c70a3916 GS/Vulkan: Colclip drawback shouldn't use DONT_CARE load op 2023-06-05 11:26:33 +01:00
TellowKrinkleandrefractionpcsx2 325a8cba58 GS:MTL: Fix ICE on macOS 10.15
Apparently the Catalina Intel UHD 630 backend compiler ICE's on use of the bool3 constructor over a float3...
(Weirdly this happens on the Metal22 metallib compiled for 10.15 but not on the one compiled for 10.13... we do still want PrimID support if possible so I'd rather not remove it if I don't have to)
2023-06-05 11:26:23 +01:00
refractionpcsx2 35387eeabb GIF: Fix some incorrect unknown register warnings 2023-06-04 18:20:02 +01:00
Stenzekandrefractionpcsx2 9d3de8631c Patch: Add "bytes" type
Allows patching an arbitrary range of bytes.
2023-06-03 23:09:52 +01:00
Stenzekandrefractionpcsx2 940e211bb6 Patch: Improve logging 2023-06-03 23:09:52 +01:00
Mrlinkwiiandrefractionpcsx2 5eb425bc4c GameDB: Fix up some names 2023-06-02 17:57:01 +01:00
refractionpcsx2 bd6b529157 Patches: Allow duplicate lines with complex types 2023-06-01 16:08:22 +01:00
Stenzekandrefractionpcsx2 0d59e0a2e9 GS/Vulkan: Remove render area heuristics
And just set the render area to the full target every time.

Except colclip draws.
2023-06-01 15:56:25 +01:00
JordanTheToasterandrefractionpcsx2 1826d122f5 GameDB: Various fixes
Fixes for FMVs blowing up the HC in Ace Combat games and FMVs being broken in Jonnys Mad Trixx.
2023-06-01 12:06:16 +01:00
Stenzekandrefractionpcsx2 ed6dd6f6cd CI: Update build to use patches.zip instead of cheats 2023-05-31 16:38:14 +01:00
Stenzekandrefractionpcsx2 81da9fb5a4 Patch: Add new toggleable cheat and patch interface 2023-05-31 16:38:14 +01:00
Mrlinkwiiandrefractionpcsx2 ec35330593 GameDB: Fixes for Onimusha Warlords 2023-05-30 23:52:59 +01:00
Stenzekandrefractionpcsx2 f741953ee4 Qt: Add memory cards to per-game settings 2023-05-30 18:21:00 +01:00
lightningterror c0343897cd GameDB: Add full mipmap with ps2 trilinear to ESPN NFL 2K5.
Improves textures to match sw renderer.
2023-05-30 16:16:34 +02:00
refractionpcsx2andlightningterror d880f8cde5 GS-TC: Fix bugs with target resize and borders in texture min max 2023-05-30 13:32:30 +02:00
TheLastRarandrefractionpcsx2 1175bd822c Github: Update issue template
Corrects spelling of appropriate
Adds text area for logs/dumps for the application template
Clarifies that dumps should be in a zip file
2023-05-28 19:29:14 +01:00
Stenzekandrefractionpcsx2 63a141abe6 GS/HW: Don't preload large framebuffer alpha textures 2023-05-28 17:31:04 +01:00
Stenzekandrefractionpcsx2 abce57ce9c GS: Enable API debug logging in Devel builds 2023-05-28 14:55:53 +01:00
JordanTheToasterandrefractionpcsx2 c471f7cf6c GameDB: Urban Chaos Light alignment fix
Fixes light alignment at native resolution to match software.
2023-05-28 01:33:05 +01:00
TellowKrinkleandlightningterror 656c2775ac CMake: Add vtune support on Windows 2023-05-27 17:54:53 +02:00
TellowKrinkleandrefractionpcsx2 a2c6e050d7 VMManager: MacOS CPU count detection 2023-05-27 04:57:50 +01:00
Mrlinkwiiandrefractionpcsx2 f3adb05b1c GameDB: add various entries 2023-05-26 19:43:34 +01:00
Stenzekandrefractionpcsx2 bfc3d2e1d4 Patch: Rename le{short,word,double} to be{short,word,double}
MIPS is little endian, not big endian. Having little endian commands
suggests to the reader that the "normal" format is big endian, which is
obviously incorrect.
2023-05-25 16:47:36 +01:00
Stenzekandrefractionpcsx2 680affd1fe Common: Add ByteSwap.h
Provides a C++23-like std::byteswap implementation.
2023-05-25 16:47:36 +01:00
TellowKrinkleandrefractionpcsx2 ab1d2009a0 Core: Use 2MB stacks for µVU 2023-05-25 16:16:14 +01:00
lightningterror 8196f46721 GS-Metal: Fix Wunused-variable warnings. 2023-05-25 13:24:40 +02:00
Stenzekandrefractionpcsx2 44460365c0 GS/HW: Vectorize mem clears 2023-05-25 09:49:31 +01:00
Stenzekandrefractionpcsx2 38d9aa5e73 GS/HW: Detect row/page-based split clears
And turn them into a single mem clear.
2023-05-25 09:49:31 +01:00
descawedandrefractionpcsx2 830db2b326 GameDB: Fix missing textures in Galerians: Ash 2023-05-25 09:48:58 +01:00
refractionpcsx2 51165f6061 Patches: Fix parsing of double words. Expand error log. 2023-05-24 19:49:32 +01:00
Mrlinkwiiandrefractionpcsx2 2a9d38048e github: update issue templates 2023-05-24 17:44:47 +01:00
Stenzekandrefractionpcsx2 bba65b8a82 Patch: Discard patches with non-hex addresses/values 2023-05-24 12:24:47 +01:00
Stenzekandrefractionpcsx2 884086ba76 StringUtil: Fix incorrect value of endptr
And add associated unit tests.
2023-05-24 12:24:47 +01:00
Ty Lamontagneandrefractionpcsx2 1fa6614cd5 Achievements: Implement the ELF suffix hack from CDVD when hashing 2023-05-23 09:56:08 +01:00
Mrlinkwiiandlightningterror 57581724cd GameDB: add missing entries 2023-05-23 10:17:02 +02:00
lightningterror 0ae6f7efc5 GameDB: Add full mipmap with ps2 trilinear to 2002 FIFA World Cup.
Improves ground textures to match sw renderer.
2023-05-22 15:27:07 +02:00
Abel Briggsandrefractionpcsx2 d0346436fb LogSink: Log BIOS print syscall messages if EE console is enabled 2023-05-22 08:37:50 +01:00
JordanTheToasterandrefractionpcsx2 1b28980454 GameDB: HP COS Fixes
Fixes for Full mipmapping causing texture problems with Harrys and lighting being wonky at lower than full blending.
2023-05-21 15:48:25 +01:00
Stenzekandrefractionpcsx2 90a6088d61 GSRunner: Fix log file writing
Wasn't getting flushed/closed on shutdown.
2023-05-21 08:52:45 +01:00
TellowKrinkleandlightningterror 338a2beaf0 GS:MTL: Remove pre-10.14 fallback
We no longer support pre-10.14
2023-05-20 10:59:23 +02:00
TellowKrinkleandlightningterror ff9a910c1a GS:MTL: Use GSTexture base class's clear tracking 2023-05-20 10:59:23 +02:00
TellowKrinkleandlightningterror d88921bb58 GS: Remove ClearStencil from GSDevice
It's never used generically, and GSTexture's shared clear tracking doesn't support it
If anyone ever actually needs this, they should update GSTexture to make it properly tracked into a render pass load action
2023-05-20 10:59:23 +02:00
TellowKrinkleandlightningterror c1f3f0a247 GS: Fix index expand buffer size
Expansion multiplies indices by 4 for vertices, so the maximum is 65535 / 4 = 16383
2023-05-20 10:59:23 +02:00
TellowKrinkleandlightningterror df847835ad GS:MTL: Implement DrawMultiStretchRects 2023-05-20 10:59:23 +02:00
TellowKrinkleandlightningterror 8aad1c78af GS:MTL: Remove hdr copy pipeline
No longer needed
2023-05-20 10:59:23 +02:00
TellowKrinkleandlightningterror 7c97cf4799 GS:MTL: Implement InvalidateRenderTarget 2023-05-20 10:59:23 +02:00
TellowKrinkleandlightningterror fd11523cf4 GS:MTL: Implement ClearSamplerCache 2023-05-20 10:59:23 +02:00
TellowKrinkleandlightningterror a293a9bd4b GS:GL: Fix GLContextAGL compile 2023-05-20 10:59:23 +02:00
refractionpcsx2 8de0eb3c06 GameDB: Readd software FMV fix for Onimusha Warlords (PAL) 2023-05-19 06:40:06 +01:00
refractionpcsx2 8bff172f0b GS: Extract end block address in to helper function 2023-05-19 06:40:06 +01:00
refractionpcsx2 7f26595804 GS-HW: Avoid clears with new targets 2023-05-19 06:40:06 +01:00
lightningterror 68ec70f24f GameDB: Add full mipmap with ps2 trilinear to Super Monkey Ball Adventure.
Improves textures to match sw renderer.
2023-05-18 21:41:59 +02:00
lightningterror 836591a44f GameDB: Correct a couple of regions for games.
From PAL-E to PAL-A.
From NTSC-J to NTSC-K.
2023-05-18 21:41:59 +02:00
refractionpcsx2 dd4ded3d4b GameDB: Add missing COP2 patches for Call of Duty Finest Hour 2023-05-16 23:16:13 +01:00
Mrlinkwiiandrefractionpcsx2 995e294856 GameDB : fixes for Bonus Demo 6 2023-05-16 19:55:03 +01:00
Stenzekandrefractionpcsx2 c4e623eec2 VMManager: Don't rescan symbols when swapping discs
The ELF isn't changing.
2023-05-16 12:58:19 +01:00
Stenzekandrefractionpcsx2 61253d8201 VMManager: Reload settings after shutting down
Prevents any whacky settings from the previous game hanging around until
the next one boots.
2023-05-16 12:58:19 +01:00
Stenzekandrefractionpcsx2 0f05967190 CommonHost: Purge and move functions to appropriate locations 2023-05-16 12:58:19 +01:00
Stenzekandrefractionpcsx2 ad0e469f87 Misc: Clang warning fixes 2023-05-16 12:58:19 +01:00
Stenzekandrefractionpcsx2 512d24cea6 Misc: More build system cleanups
Set UTF-8 source file format globally.
Set permissive/compliance mode globally.
Get rid of include of base 3rdparty directory, be explicit.
Get rid of duplicated properties.
Get rid of leftover plugin property files.
2023-05-16 12:58:19 +01:00
Stenzekandrefractionpcsx2 0850a3fab7 Misc: Support building without -fno-operator-names
Better to have standard compliance, and MSVC in conformance mode needs
it.
2023-05-16 12:58:19 +01:00
lightningterror 16db92526c GameDB: Add full mipmap with ps2 trilinear to Rally Shox.
Also add missing db entries.

Improves textures to match sw renderer.
2023-05-16 12:30:52 +02:00
lightningterror 30ad66e8f1 VMManager: Don't lookup the bios as a game.
Fixes the gamedb log falsely pasting that a bios
is not in the db.
2023-05-16 11:26:11 +02:00
refractionpcsx2 77f600a16c GameDB: Added round sprite fixes for Street Fighter Alpha/Zero 2023-05-16 01:20:45 +01:00
refractionpcsx2 d96bf7f951 GameDB: Add upscaling fixes for Vampire Darkstalkers Collection 2023-05-16 01:20:45 +01:00
refractionpcsx2 15948c2781 GS-HW: Allow recursive HW move with temp copy 2023-05-16 01:20:45 +01:00
refractionpcsx2 b0c744bd29 GS-HW: Invalidate local mem for whole texture on local->local copy 2023-05-16 01:20:45 +01:00
Stenzekandrefractionpcsx2 5eacfe1afb x86/microVU: Reference StateEnd instead of inlining state 2023-05-16 01:20:22 +01:00
refractionpcsx2 2f985b479e GS-TC: Delete fully dirtied old targets 2023-05-16 01:19:58 +01:00
PCSX2 Botandlightningterror e61d8f2f8f PAD: Update to latest controller database. 2023-05-15 19:22:33 +02:00
refractionpcsx2 f4e338f9fb Build: Fix GS Runner compilation.
Stuff got moved, GS Runner wasn't told :)
2023-05-14 02:45:30 +01:00
Mrlinkwiiandrefractionpcsx2 9509745be9 GameDB : add missing Gran Turismo fixes 2023-05-13 22:50:29 +01:00
JordanTheToasterandrefractionpcsx2 91b47134ad GameDB: Various fixes
Various fixes for Ace Combat 4 5 and Zero to fix broken upscaling on airburst and possibly other effects.
2023-05-13 16:43:16 +01:00
Stenzekandrefractionpcsx2 6426f4432e SPU2: Get rid of dynamic allocations 2023-05-13 16:39:40 +01:00
Stenzekandrefractionpcsx2 191ea50663 GS/HW: Fix GT4 render hack 2023-05-13 16:38:53 +01:00
Stenzekandrefractionpcsx2 7f5c0fca8f MSBuild: Fix lib/pdb output directory 2023-05-13 16:29:06 +01:00
refractionpcsx2 5f8798cf94 VMManager: Split reload game swap, avoid reloading patches 2023-05-13 16:27:53 +01:00
refractionpcsx2 3aac709682 CDVD: Reload game data when swapping discs to reflect new name. 2023-05-13 16:27:53 +01:00
isJuhnandrefractionpcsx2 e3962aa794 PINE: Update to the age of Qt 2023-05-13 16:17:30 +01:00
Stenzekandrefractionpcsx2 1964bbc03a MSBuild: Rename pcsx2core to pcsx2
No need to differentiate it, since wx is gone.
2023-05-13 07:12:12 +01:00
Stenzekandrefractionpcsx2 80675399aa Misc: Various cleanup
Move files from Frontend directory to pcsx2 and/or subdirectories.
Get rid of double GS init.
Combine HostSettings and Host.
Combine Frontend/Achievements.h and Achievements.h.
2023-05-13 07:12:12 +01:00
refractionpcsx2 6fb4c724bd VS: Reorganise some file filters 2023-05-13 06:24:15 +01:00
refractionpcsx2 b34606c9ce UI: Add ability to list .mdf files 2023-05-13 05:04:34 +01:00
refractionpcsx2 4e97381709 GS-HW: Fix bug in Prim cover with no gaps + allow horizontal strips 2023-05-13 05:04:16 +01:00
refractionpcsx2 d4db49f969 GS-PCRTC: Fix up Anti-Blur with negative framebuffer offsets 2023-05-13 04:34:26 +01:00
refractionpcsx2 4b54870da1 GameDB: Add MAD deinterlace and Round sprite to NASCAR Thunder games 2023-05-13 04:34:26 +01:00
refractionpcsx2 0ae91cbf64 GS-HW: Fix annoying NASCAR offsets in PCRTC 2023-05-13 04:34:26 +01:00
Mrlinkwiiandrefractionpcsx2 041abd8abc GameDB: fix up Midnight Club memcard filters 2023-05-13 01:08:05 +01:00
Stenzekandrefractionpcsx2 43be6883df GS/HW: Remove targets when invalidate area covers valid area 2023-05-12 16:24:03 +01:00
lightningterror ad4e95cb78 SPU2: Cleanup spu2.
Constants, initializations, casts, switch cases not handling default case, unused functions.
2023-05-12 15:55:29 +02:00
Stenzekandrefractionpcsx2 38480d3aed GS/HW: Fix crash in PossibleCLUTDraw() 2023-05-12 14:19:58 +01:00
Stenzekandrefractionpcsx2 3436bb3792 GS/HW: Include FBMSK in target lookups for debug traces 2023-05-12 14:19:58 +01:00
Stenzekandrefractionpcsx2 5bab8af38f GS/HW: Rename and improve dirty alpha to valid alpha 2023-05-12 14:19:58 +01:00
Stenzekandrefractionpcsx2 61f344dd66 GS/HW: Handle texture shuffles using region repeat
Ace Combat 04 reads RG, writes to RGBA by setting a MINU of 1015.
2023-05-12 14:19:58 +01:00
Stenzekandrefractionpcsx2 1811955fce GameDB: Add SW FMV render to Poinie's Poin
Game does 640x1232 draws to clear out most (but not all) of GS memory,
then 224 high draws to 1216 high targets, presumably moving GS memory
around.

Enabling SW FMV render isn't needed for the FMV, it's just a convenient
way to remove these targets from the TC, as the clearing/copying mess
happens before the FMVs play.
2023-05-12 12:37:00 +01:00
lightningterror 449da42108 USB: Fix struct member not used warnings.
Codacy.
2023-05-11 19:57:34 +02:00
Stenzekandrefractionpcsx2 9493d3e9c9 USB/GunCon2: Adjust calibration timer
Credit to @pcnimdock for debugging.
2023-05-11 16:24:27 +01:00
Stenzekandrefractionpcsx2 e5c1052062 GS: Add option to disable vertex shader expand
And automatically disable it on Fermi (buggy driver).
2023-05-11 16:18:01 +01:00
Stenzekandrefractionpcsx2 7edc4e2cb3 GS: Remove CRC hack levels
Replace it with a boolean "Disable Render Fixes" option.
2023-05-11 16:16:15 +01:00
Stenzekandrefractionpcsx2 7ca28fc796 GS/HW: Remove aggressive CRC hacks
GSC_AceCombat4 - couldn't get this to trigger.
GSC_FFXGames - dunno what this did, but FFX has been fine for some time.
GSC_Okami - breaks a bunch of the game's effects, downsample is intentional.
GSC_RedDeadRevolver - working as intended, patch on forums.
GSC_ShinOnimusha - breaks effects, only saves 5-10% GPU at 8x.
GSC_XenosagaE3 - breaks cutscenes, minimal perf difference.
2023-05-11 16:16:15 +01:00
refractionpcsx2 72f9bf83fd SIF: Correct junk data behaviour. Fixes True Crime Streets of LA 2023-05-11 16:03:13 +01:00
forrvalhallaandrefractionpcsx2 2695ddc9fc GameDB: Various fixes 2023-05-11 09:23:54 +01:00
JordanTheToasterandrefractionpcsx2 fbcc8671ac GameDB: Various fixes
Fixes for broken refraction effect in Crash WOC and broken FMVs in Army Men 2.
2023-05-10 13:27:29 +01:00
Stenzekandrefractionpcsx2 7e76230cf8 GameDB: Enable TexInRT for Project Snowblind
Seems it does the same target offset thing:

```
TC: Target 0x3600 detected in front of TBP 0x3560 with 64,32 offset (5 pages)
```
2023-05-10 13:26:19 +01:00
Stenzekandrefractionpcsx2 ba27221bf2 GameDB: Enable TexInRT for Enthusia - Professional Racing
Fixes reflections (C32 target with offset C24 texture).
2023-05-10 13:26:19 +01:00
Stenzekandrefractionpcsx2 6cf1501050 GameDB: Change Destroy All Humans to base tex-in-rt
Since it handles offset targets now, there's no need to use the merge
path, and the former is cheaper (no copy).

However, I'm keeping it around for Guitar Hero III (eventually I'll get
back to that..)
2023-05-10 13:26:19 +01:00
Stenzekandrefractionpcsx2 a30ca0ce2a GS/HW: Remove Tomb Raider CRC hacks
It works correctly with tex-in-rt now.
2023-05-10 13:26:19 +01:00
Stenzekandrefractionpcsx2 5e3e988846 GS/HW: Allow finding targets offset behind FBP for tex-in-rt 2023-05-10 13:26:19 +01:00
Stenzekandrefractionpcsx2 bb42353c81 GS/HW: Make regions signed, and use compatible bits for tex-in-rt 2023-05-10 13:26:19 +01:00
Stenzekandrefractionpcsx2 61740fc9ed GS/HW: Break channel shuffle on CBP change
Needed for Tomb Raider: Underworld
2023-05-10 13:26:19 +01:00
Stenzekandrefractionpcsx2 ea30c90a6c GS/HW: Use source resolution rather than CRTC for channel shuffle 2023-05-10 13:26:19 +01:00
Stenzekandrefractionpcsx2 3968a82775 GS/HW: Turn GT4 CRC hack into a GSC instead
Keep the hacks with the rest of the hacks.
2023-05-10 13:26:19 +01:00
Goatman13andrefractionpcsx2 6e40081dd9 GameDB: Remove DOA2 iop patches.
Fixed in https://github.com/PCSX2/pcsx2/pull/3778
2023-05-09 18:41:40 +01:00
Stenzekandrefractionpcsx2 2b8b43c94c GS/Vulkan: Simplify and refactor swap chains 2023-05-09 13:44:56 +01:00
Stenzekandrefractionpcsx2 3f0ecc2284 GS/Vulkan: Submit cmdbuffer each frame even when surfaceless
Stops out-of-descriptor scenarios which are not realistic in the GS
runner.
2023-05-08 20:48:14 +01:00
Stenzekandrefractionpcsx2 828e86bdf4 GS: Skip draws when scissor is invalid
i.e. the bottom-right is greater than the top-left.

tombraidertitle.gs.xz hits this.
2023-05-08 20:48:14 +01:00
Stenzekandrefractionpcsx2 159d0c060f GS/Vulkan: Clear out previous texture binding when it's RT/DS 2023-05-08 20:48:14 +01:00
Stenzekandrefractionpcsx2 4a29fdb3f2 GS/Vulkan: Ensure restarted render passes don't clear
We don't want to wipe out what's done, and we don't know the clear
values anyway.
2023-05-08 20:48:14 +01:00
Stenzekandrefractionpcsx2 29da1bb9ef GS: Make context scissor.in an integer vector
Doesn't make sense for it to be floats, and saves a bunch of
conversions.
2023-05-08 20:48:14 +01:00
Stenzekandrefractionpcsx2 47636bb30f Config: Fix incorrect key for DisableShaderCache 2023-05-08 20:48:14 +01:00
Stenzekandrefractionpcsx2 5fe64396b4 GS/Vulkan: Fix incorrect layout during copy to self
Of course this happened in Dark Cloud 2.
2023-05-08 20:48:14 +01:00
Stenzekandrefractionpcsx2 75b782f261 GS/Vulkan: Enable geometryShader for Primitive ID
Apparently it is needed..
2023-05-08 20:48:14 +01:00
Stenzekandrefractionpcsx2 4a5cf0efb9 GS: Combine texture classes and add custom layout for Vulkan 2023-05-08 20:48:14 +01:00
PCSX2 Botandlightningterror cfdae77331 PAD: Update to latest controller database. 2023-05-08 18:51:41 +02:00
lightningterror ec0aaff8ac GS: Replace EmuConfig.GS with GSConfig.
EmuConfig isn't safe to run on the gs thread.
2023-05-08 12:47:56 +02:00
refractionpcsx2 f651d8e26a GameDB: Add text fix for State of Emergency 2 2023-05-06 17:43:05 +01:00
Stenzekandrefractionpcsx2 0526769808 GS/Vulkan: Remove more unused code 2023-05-06 07:18:55 +01:00
Connor McLaughlinandrefractionpcsx2 1866745936 GS/DX12: Fix building in debug 2023-05-06 04:02:29 +01:00
Stenzekandrefractionpcsx2 920c5ab266 Qt: Expose disable shader cache option 2023-05-06 03:40:00 +01:00
Stenzekandrefractionpcsx2 c57d8980a1 GS: Move Vulkan helpers from common to GS 2023-05-06 03:40:00 +01:00
Stenzekandrefractionpcsx2 0ed418834a GS: Move OpenGL helpers from common to GS 2023-05-06 03:40:00 +01:00
Stenzekandrefractionpcsx2 083969a3d2 GS: Move DirectX helpers from common to GS 2023-05-06 03:40:00 +01:00
Ty Lamontagneandrefractionpcsx2 6740fff179 Profiling: Fix missing cast breaking VTune builds on Linux
Also remove now-pointless SW-JIT VTune code.
2023-05-06 03:15:46 +01:00
JordanTheToasterandrefractionpcsx2 25e24d1d09 GameDB: More Juiced 1 FIxes
Fixes for broken headlights and enforcing high blending for more accuracy.
2023-05-06 00:52:47 +01:00
refractionpcsx2 76cc9c8b21 GS: Only update dirty on local invalidate if bp matches 2023-05-05 14:58:41 +01:00
Regan Greenandrefractionpcsx2 7dcf6b70d9 GameDB: Apply THUG2 GS HW fixes to THAW 2023-05-05 13:00:44 +01:00
Regan Greenandrefractionpcsx2 f26b26b73e GameDB: Tony Hawk's post-processing fixes 2023-05-05 13:00:44 +01:00
JordanTheToasterandrefractionpcsx2 055beaa27a GameDB: Juiced 1 FIxes
Fixes for broken window and shadow rendering headlight brightness and overbightness in hardware mode.
2023-05-05 10:21:25 +01:00
lightningterror a4623c3c63 Qt: Sort checkbox upscale and renderer hw hacks in alphabetical order. 2023-05-05 00:31:01 +02:00
Zwip-Zwap Zaponyandrefractionpcsx2 4e3a94809d GameDB: Secret Agent Clank compat and bloom fix 2023-05-04 22:37:58 +01:00
JordanTheToasterandrefractionpcsx2 5ff64899e6 GameDB: True Crime LA Fixes
Fixes for the sun going through buildings.
2023-05-04 18:00:51 +01:00
lightningterror 971f172c91 GS: Cleanup GSRenderer.
Constants, casting.
2023-05-04 16:37:39 +02:00
CharlesThobeandrefractionpcsx2 4671167a2c VIF: Fix assertion error not returning int value 2023-05-04 14:39:14 +01:00
CharlesThobeandrefractionpcsx2 7aff4ee4cb Misc: Minor cleanup 2023-05-04 14:39:14 +01:00
JordanTheToasterandrefractionpcsx2 30f7685435 GameDB: Various fixes
Fixes for Underground 1 PAL and Transformers.
2023-05-04 12:53:26 +01:00
refractionpcsx2 341f377e6d VIF: Improve IR setup for skipped unpack inputs/writes 2023-05-04 01:37:54 +01:00
refractionpcsx2 fe4788ae3f GS:MTL: Extend render pass restart avoidance code to depth-only passes
Previously only worked when the depth texture was removed, but not when the color texture was removed
2023-05-04 00:10:14 +01:00
Connor McLaughlinandrefractionpcsx2 e133e89b6b Qt: Fix crash in graphics settings on Linux 2023-05-03 16:39:48 +01:00
refractionpcsx2 bf6a0a035a VIF-JIT: Ignore completely write protected vectors 2023-05-02 23:19:02 +01:00
refractionpcsx2 790447ecc9 VIF-JIT: Use non-reserved XMM for zero register 2023-05-02 21:27:53 +01:00
Stenzekandrefractionpcsx2 47506d1433 GS/HW: Don't memclear with vertical gaps in the sprites
Xenosaga 3's FMVs clear out a top/bottom letterbox.
2023-05-02 21:12:18 +01:00
Stenzekandrefractionpcsx2 933e6aa62e GS/HW: Fix target region textures not getting invalidated
Xenosaga 3 has tex-in-RT, offsetting a source from a larger target, but
the invalidation kills the target but not the source otherwise.

Also fixes m_from_target_TEX0 being tested when it might not be valid.
2023-05-02 21:12:18 +01:00
Stenzekandrefractionpcsx2 6736ef1d44 GS/Vulkan: Add exclusive fullscreen control option 2023-05-02 19:55:43 +01:00
refractionpcsx2 3e631e047f GS-HW: Avoid clear misdetection with DATE enabled 2023-05-02 19:55:32 +01:00
refractionpcsx2 dd2d4edffc VIF-JIT: Get rid of mem read for mask 2023-05-02 18:20:55 +01:00
refractionpcsx2 fd2960c9cb VIF-JIT: Skip src reads on fill writes using regs
Clean up some of the code
2023-05-02 18:20:55 +01:00
refractionpcsx2 c2907ea58f VIF-JIT: Clean up pointless code, optimise protected vector copies 2023-05-02 18:20:55 +01:00
PCSX2 Botandlightningterror 41f62cf53d PAD: Update to latest controller database. 2023-05-02 11:49:57 +02:00
Ty Lamontagneandrefractionpcsx2 e462f1ff9c iR3000: Fix memchecks that only log 2023-05-01 07:02:21 +01:00
Ty Lamontagneandrefractionpcsx2 5b0b6191d8 iR5900: Fix memchecks that only log 2023-05-01 07:02:21 +01:00
Ty Lamontagneandrefractionpcsx2 ab9a1e4307 R5900 interpreter: Fix breakpoint exits
Exit exceptions were not being caught, causing a crash.
2023-05-01 07:02:21 +01:00
Ty Lamontagneandrefractionpcsx2 029c11c8d2 Debugger: Fix an oversight on how breakpoints are managed 2023-05-01 07:02:21 +01:00
TellowKrinkleandlightningterror e221d31b45 GS:OGL:Shaders: Formatting 2023-04-30 23:48:49 +02:00
lightningterror dfbdaa651c vcxproj.filters: Remove common_header.glsl mention.
No longer exists.
2023-04-30 23:48:49 +02:00
CharlesThobeandrefractionpcsx2 9de152b8ee Linux: implement DBus screensaver inhibitor 2023-04-30 19:18:53 +01:00
Mrlinkwiiandrefractionpcsx2 360f9afb70 GameDB: Fixes for Shin Sangoku Musou Series Collection Joukan 2023-04-30 16:41:40 +01:00
Connor McLaughlinandrefractionpcsx2 1b81825218 x86/microVU: Fix typo in VI CRC
Doesn't actually affect anything, only for debugging.
2023-04-30 06:12:01 +01:00
Stenzekandrefractionpcsx2 b3e6e28827 x86/iR5900: Fast forward timeout loops 2023-04-30 04:52:50 +01:00
Stenzekandrefractionpcsx2 eaceb27879 x86/microVU: Remove redundant cmp in mVUtestCycles 2023-04-29 18:24:49 +01:00
Stenzekandrefractionpcsx2 cd9b6c7ac3 x86/microVU: Pack VF cycles into bitfields
The VF cycle count doesn't go above 4, across 32 registers that saves 64
bytes.

Also gets rid of blockhasmbit, since save states are getting invalidated
anyway, it was never used.

[SAVEVERSION+] VU struct changes.
2023-04-29 18:24:49 +01:00
TellowKrinkleandrefractionpcsx2 d3e527f2a4 GS:MTL: Always end all encoders on FlushEncoders
Previously, texture upload encoders weren't submitted if no rendering had been done, which would result in an assertion failure if the device was destroyed in that state, as the encoders would be released without calling `endEncoding` on them.
2023-04-29 17:37:24 +01:00
TellowKrinkleandrefractionpcsx2 b47fdcdfab GS: Fix crash when looking up color textures with depth lookups 2023-04-29 17:02:16 +01:00
Stenzekandrefractionpcsx2 2550ad7fd1 GS/HW: Detect clears spanning multiple sprites
Fixes GT4 rendering to >1000x1000 targets.
2023-04-29 17:01:15 +01:00
Stenzekandrefractionpcsx2 1717f584a0 GS/HW: Add flush reason to draw tracing 2023-04-29 17:01:15 +01:00
Stenzekandrefractionpcsx2 0822d3e3e5 GS/HW: Cache possible mem clear value 2023-04-29 17:01:15 +01:00
Stenzekandrefractionpcsx2 ec41af760a GS/Vulkan: Make primid not require barycentric extension 2023-04-29 16:23:09 +01:00
Stenzekandrefractionpcsx2 a5ed24ca88 Perf: Support instruction-level profiling with jitdump on Linux 2023-04-29 16:22:37 +01:00
Stenzekandrefractionpcsx2 b3697579c0 GS/Vulkan: Simplify GPU selection
Hopefully stops a crash on broken drivers.
2023-04-29 16:20:01 +01:00
JordanTheToasterandrefractionpcsx2 388da2058b GameDB: FFXII texture fixes
Fixes for broken textures on player model.
2023-04-29 08:01:59 +01:00
Stenzekandlightningterror aa9a0dca4b GS/HW: Fix HW move debug message 2023-04-28 13:34:45 +02:00
Stenzekandlightningterror 2a892da0da GS/HW: Improve split shuffle detection
Fixes transition effects in DBZ BT3 PAL.
2023-04-28 13:34:45 +02:00
Stenzekandlightningterror 9237bf9429 GS/HW: Relax PSM match requirement for move targets
Fixes broken car preview in Tokyo Xtreme Racer Zero.
2023-04-28 13:34:45 +02:00
Stenzekandlightningterror 10533dce02 GS/HW: Swap xyxy() for upld()
In theory more efficient.
2023-04-28 13:34:45 +02:00
Stenzekandlightningterror b5ebc19eff GS/HW: Don't mess with ZMSK for no_ds
Fixes broken depth in Superman Returns.
2023-04-28 13:34:45 +02:00
Stenzekandrefractionpcsx2 6535e7e43a GS: Add natvis for vector types 2023-04-28 10:22:45 +01:00
Ty Lamontagneandrefractionpcsx2 5f9473ef02 ci: Update labeler debugger directories 2023-04-28 06:15:27 +01:00
Stenzekandrefractionpcsx2 fbb1c7cb8e GS/OGL: Don't reuse targets when they're the texture
I don't trust drivers to insert a barrier here. At least one of them
gets it wrong.

Also moves the masking of depth/colour to the common renderer for
consistency.
2023-04-27 23:22:09 +01:00
lightningterror 2d97d85ca5 GS-hw: Use correct format specifier for blend log, use constants for mergesprite log. 2023-04-27 21:20:31 +02:00
Stenzekandrefractionpcsx2 ecd7d0fc35 GS/HW: Fix pipeline/shader duplication 2023-04-27 12:01:34 +01:00
Stenzekandrefractionpcsx2 0c389789f3 GS: Fix hang when switching renderer while fullscreen 2023-04-27 09:17:27 +01:00
Stenzekandrefractionpcsx2 d8239664a8 GS/Vulkan: Re-enable async presentation 2023-04-27 09:17:16 +01:00
rayanHappyandrefractionpcsx2 c06d4f477a Misc: remove unneeded file and clean up a 32bit check 2023-04-27 09:09:04 +01:00
refractionpcsx2 cdd88a6e5c GS-HW: Fix std::sort comparator for purging hash cache 2023-04-27 09:07:21 +01:00
refractionpcsx2 5a73fa2d23 GS-TC: Update dirty read overlap on local mem invalidate 2023-04-27 09:07:05 +01:00
Stenzekandrefractionpcsx2 0367851b8e GS: Make TEXFLUSH a flag instead 2023-04-26 16:00:59 +01:00
Stenzekandrefractionpcsx2 33b2f6331c GS/HW: Allow auto flush to be applied only to sprites 2023-04-26 16:00:59 +01:00
Stenzekandrefractionpcsx2 befbf57191 GS: Refactor exclusive fullscreen yet again
Also acquire render window as late as possible.
Limits the duration that the main window isn't displaying anything.
2023-04-26 16:00:39 +01:00
JordanTheToasterandrefractionpcsx2 20d040d5d1 GameDB: Disney Golf Fixes
Fixes for grass rendering to match software with mipmapping and trilinear filtering.
2023-04-26 02:07:15 +01:00
TellowKrinkleandrefractionpcsx2 06fdc75945 CMake: Properly fail on windeployqt failure 2023-04-26 02:06:58 +01:00
refractionpcsx2 ded971a3ec Build: Fix Qtdir for windows build workdflows 2023-04-25 22:57:05 +01:00
Stenzekandrefractionpcsx2 abc0f99ddd Qt: Move themes to its own file
It's getting a bit out of hand.
2023-04-25 21:53:30 +01:00
Stenzekandrefractionpcsx2 b3a88d6ea7 Qt: Migrate to 6.5.0 on Windows 2023-04-25 21:53:30 +01:00
refractionpcsx2 76014b7cb9 GS-TC: Use the expected rect to expand the target when Tex is RT. 2023-04-25 20:53:31 +01:00
Stenzekandrefractionpcsx2 0ab6eb6587 GS: Rework texture pooling behavior
- Split into texture/target pools.
 - Keep textures around when they're used recently regardless of size
   (saves work in the backend/driver).
 - Don't boot textures out of the pool when it's an idle frame.
2023-04-25 20:53:21 +01:00
Stenzekandrefractionpcsx2 a4e99366fb GS/HW: Put a cap on the hash cache count
As well as VRAM usage. Stops Corvette allocating 16,000+ textures.

Also reduce max age for hash cache sources, since they get kept around
in the latter for another 30 frames.
2023-04-25 20:53:21 +01:00
Stenzekandrefractionpcsx2 a32ab4cc97 GS: Refactor ResizeTexture() to ResizeRenderTarget() 2023-04-25 20:53:21 +01:00
JordanTheToasterandrefractionpcsx2 e7f3c42f9d GameDB: Various FIFA 2001-2004 fixes
Fixes for broken player textures and some missing fixes.
2023-04-25 20:53:05 +01:00
Ty Lamontagneandrefractionpcsx2 d76a0d7416 Debugger: Implement BC0XY branches & their condition evaluation 2023-04-25 17:28:31 +01:00
Stuart Kennyandrefractionpcsx2 79f4af8ab5 Qt: Delete SDLRawInput on non win32 builds 2023-04-25 15:05:30 +01:00
Stuart Kennyandrefractionpcsx2 a5f83329cb FullscreenUI: Only show SDL Raw on win32 builds. 2023-04-25 15:05:30 +01:00
rayanHappyandrefractionpcsx2 267479f31d Misc: Cmake and GCC compiler flags cleanups 2023-04-25 15:04:39 +01:00
rayanHappyandrefractionpcsx2 164462e510 Misc: Remove ICC compiler support 2023-04-25 15:04:39 +01:00
TellowKrinkleandrefractionpcsx2 6331df306f qt:resources: Use black and white icon for forum menu entry 2023-04-25 15:04:26 +01:00
TellowKrinkleandrefractionpcsx2 027ceebcbd qt:resources: Use black and white icons for discord menu icon 2023-04-25 15:04:26 +01:00
TellowKrinkleandrefractionpcsx2 edb2c0080c qt:resources: Use separate black/white github icon 2023-04-25 15:04:26 +01:00
TellowKrinkleandrefractionpcsx2 caafc87b29 qt:resources: Sort qrc filenames
Many filesystems (e.g. btrfs, apfs) return results in some internal non-alphabetical ordering, which isn't great for minimizing changes to files
2023-04-25 15:04:26 +01:00
TellowKrinkleandrefractionpcsx2 5d37cac4a0 qt:resources: Skip dotfiles when generating qrc 2023-04-25 15:04:26 +01:00
Stenzekandrefractionpcsx2 8f68e096d4 GS/HW: Avoid render pass restarts to turn off RT
Significantly reduces render passes in Sly 2.
2023-04-24 22:17:25 +01:00
Stenzekandrefractionpcsx2 430cad48e3 GS/Metal: Get rid of redundant pointer 2023-04-24 22:17:04 +01:00
Stenzekandrefractionpcsx2 757a9532e6 GS: Add Render Pass stats 2023-04-24 22:17:04 +01:00
KamFretoZandlightningterror f26f8cafa9 Qt: Even more fixes to the Cobalt Theme 2023-04-24 19:24:19 +02:00
KamFretoZandlightningterror 128a79e355 Qt: Help menu icon fix for macOS user 2023-04-24 19:24:19 +02:00
PCSX2 Botandlightningterror cc2d99db3a PAD: Update to latest controller database. 2023-04-24 19:21:18 +02:00
KamFretoZandrefractionpcsx2 30a31d931a Qt: Add extra icons to the help menu 2023-04-23 03:56:36 +01:00
KamFretoZandrefractionpcsx2 1c30d449bf Tools: Fix filename lookup error on the python glyph updater script 2023-04-23 03:56:36 +01:00
refractionpcsx2 dc4ce58248 VU-JIT: Avoid writeReg stealing loadReg GPR 2023-04-23 03:54:53 +01:00
Mrlinkwiiandrefractionpcsx2 dc93e861c7 GameDB: various fixes 2023-04-22 23:58:58 +01:00
refractionpcsx2 960daf27e2 GameDB: Add FullVU0SyncHack to the linter 2023-04-22 23:38:05 +01:00
Goatman13andrefractionpcsx2 844f21344d GameDB: Add patch for Michigan: Report from Hell 2023-04-22 16:55:27 +01:00
refractionpcsx2 535ad110e3 VU-JIT: Backup non cached VI before writing to it when load != write 2023-04-22 15:15:25 +01:00
JordanTheToasterandrefractionpcsx2 0e0d7a5441 GameDB: Various fixes
Fixes for vertical lines in Ring of Red and invisible text in Dynasty Warriors 2.
2023-04-22 03:03:27 +01:00
SeruranBlueandGitHub ed63221c7e GameDB: Fixes for Air Ranger: Rescue Helicopter (#8711) 2023-04-22 03:02:46 +01:00
seta-sanandrefractionpcsx2 f9c2d7767d CDVD: Fix Error Message in InputIsoFile.cpp 2023-04-21 10:53:48 +01:00
Berylskidandrefractionpcsx2 cb91478590 UI: Correct Recommended Value for Show Indicators 2023-04-20 10:18:25 +01:00
Mrlinkwiiandrefractionpcsx2 5dec7fe27d GameDB : fixes for Hanjuku Hero 4 2023-04-19 23:30:31 +01:00
BerylskidandGitHub 575d487c65 GameDB: Fix Armored Core water and game names (#8702) 2023-04-19 19:14:37 +01:00
Stenzekandrefractionpcsx2 2b9289f402 GS/HW: Fix missing init of non-CLUT replacement textures 2023-04-19 13:38:20 +01:00
Mrlinkwiiandrefractionpcsx2 9273683d3c GameDB: fixes for Dark cloud 2023-04-17 21:06:48 +01:00
PCSX2 Botandlightningterror 88f8465e7e PAD: Update to latest controller database. 2023-04-17 20:02:50 +02:00
refractionpcsx2 f26031cada Vif: Fix up Instant DMA behaviour 2023-04-16 21:15:26 +01:00
JordanTheToasterandlightningterror 3352d71515 GameDB: Various fixes
Fixes for a potential slowdown in Super Robot Taisen and replace disabling Instant VU with InstantDMA in MGS 3 Subsistence.
2023-04-16 21:10:31 +02:00
Connor McLaughlinandrefractionpcsx2 999f9532ee GS: Warning fix 2023-04-16 06:43:22 +01:00
Stenzekandrefractionpcsx2 d1f62ca9bf GS: Remove GSVertexList
It doesn't appear to be used anywhere.
2023-04-16 06:35:05 +01:00
Stenzekandrefractionpcsx2 ef9f0cf635 GS: Replace magic alignment number with constant
And ensure it gets used in None preloading.
2023-04-16 06:35:05 +01:00
Stenzekandrefractionpcsx2 d745564451 GS/HW: Adjust Black/Burnout sky CRC hack
Apparently some stages use a sky height of 128 instead of 256?
2023-04-15 22:01:38 +01:00
Stenzekandrefractionpcsx2 d37ac992fc GS/HW: Use bitfield extract for VS expand (GL/VK) 2023-04-15 20:10:25 +01:00
Stenzekandrefractionpcsx2 e7fc3de90c GS/HW: Ensure region texture mipmaps don't go out of bounds 2023-04-15 20:10:15 +01:00
Stenzekandrefractionpcsx2 bde81380c3 GS/SW: Stop C rasterizer crashing with AA1 2023-04-15 20:10:03 +01:00
Stenzekandrefractionpcsx2 839b482cb5 GS: Use 16-bit indices instead of 32-bit
Save some bandwidth.
2023-04-15 20:10:03 +01:00
Stenzekandrefractionpcsx2 72f70d4789 GS/Vulkan: Clear textures/RTs at end of frame
Prevents us from updating potentially changed-state descriptors.
2023-04-15 20:09:48 +01:00
Stenzekandrefractionpcsx2 d646bbf5c1 GS/Vulkan: Prioritize VK_EXT_rasterization_order_attachment_access
.. over the ARM version. But continue to support both.
2023-04-15 20:09:48 +01:00
Stenzekandrefractionpcsx2 e68aaf6540 GS/Vulkan: Saturate ImGui scissor to zero 2023-04-15 20:09:48 +01:00
Stenzekandrefractionpcsx2 20ab5ed0fa GS/Vulkan: Don't assume opaque composite alpha is supported 2023-04-15 20:09:48 +01:00
Stenzekandrefractionpcsx2 8590e390a2 GS/Vulkan: Don't enable geometryShader 2023-04-15 20:09:48 +01:00
Stenzekandrefractionpcsx2 ab1d558420 GS/Vulkan: Make provoking vertex consistent across pipelines 2023-04-15 20:09:48 +01:00
Stenzekandrefractionpcsx2 53c9021455 GS/HW: Don't attempt to colour copy into depth target 2023-04-15 20:09:26 +01:00
Stenzekandrefractionpcsx2 8bd00e2433 GS: Remove unused scissor variables 2023-04-15 18:01:52 +01:00
Stenzekandrefractionpcsx2 c045feae50 GS/HW: Skip draws on reset until scissor is set 2023-04-15 18:01:52 +01:00
Stenzekandrefractionpcsx2 7531080e51 GS/HW: Only force shader sampling for non-32bit targets
Not sources.
2023-04-15 17:37:34 +01:00
TellowKrinkleandrefractionpcsx2 bf57ab3e39 GS:OGL: Support vs expand on older GL with SSBO extension 2023-04-15 04:29:10 +01:00
JordanTheToasterandrefractionpcsx2 dfcb96a4b6 GameDB: Various fixes
Fixes for bloom alignment in Dogz and Catz and broken sun in Ace Combat 4.
2023-04-14 23:01:26 +01:00
refractionpcsx2 5c4fad6725 GameDB: Remove no longer needed Spyro patches 2023-04-14 18:17:44 +01:00
refractionpcsx2 988b1ad03b SPU2: Don't make end IRQ positions inclusive 2023-04-14 18:17:44 +01:00
refractionpcsx2 79705a2514 SPU2: Increase maximum ADSR rate from 0x3FFF to 0x4000 2023-04-14 18:17:44 +01:00
JordanTheToasterandrefractionpcsx2 0919b15183 GameDB: Various fixes
Fixes for Dogz and Catz vertical lines and black squares and a workaround for FMVs causing screen shaking in NFS U2.
2023-04-14 13:13:35 +01:00
kenshen112andrefractionpcsx2 8162c87884 GameIndex: Added Boss Hang Fix to more regions.
Added Kirie hang fix to Fatal Frame Korea and Asia.
2023-04-14 09:23:35 +01:00
Stuart Kennyandrefractionpcsx2 09394ee4b7 Qt: Hide SDL Raw option on non win32 builds 2023-04-13 12:14:15 +01:00
Stenzekandrefractionpcsx2 7f7dd60587 GS/HW: VS expand instead of GS for DX/GL/Vulkan 2023-04-13 11:12:11 +01:00
Stenzekandrefractionpcsx2 6877abb2ec GS/HW: Remove FFXII CRC hack
No longer needed, and it causes issues with splitting point draws.
2023-04-13 11:12:11 +01:00
Stenzekandrefractionpcsx2 ce5dd88790 GS/OGL: Fix GL error on shutdown 2023-04-13 11:12:11 +01:00
Stenzekandrefractionpcsx2 5bc9d625e7 GL/StreamBuffer: Align CPU side fallback buffers 2023-04-13 11:12:11 +01:00
Connor McLaughlinandrefractionpcsx2 1d7a69ad40 AppImage: Include libxcb-cursor 2023-04-13 10:51:09 +01:00
JordanTheToasterandrefractionpcsx2 f7d87076a3 Qt: Adjust MTVU core count text
The wording here was causing confusion and unneeded arguments over what it actually means.
2023-04-13 09:39:02 +01:00
JordanTheToasterandrefractionpcsx2 9d20b4d6a6 GameDB: Soulcalibur 2&3 blending recommendations
Fixes menu transparency when using high blending.
2023-04-13 09:39:02 +01:00
TellowKrinkleandrefractionpcsx2 128cf9b57d 3rdparty:macOS: Update to Qt 6.4.3
Gives us 5 more months to decide whether we want to use 6.2 LTS or drop macOS 10.14 and macOS 10.15 support
2023-04-13 08:27:49 +01:00
TellowKrinkleandrefractionpcsx2 e5b7adb228 3rdparty:linux: Update to Qt 6.5.0 2023-04-13 08:27:49 +01:00
TellowKrinkleandrefractionpcsx2 bd5ae66fbe 3rdparty: Update SDL to 2.26.5 2023-04-13 08:27:49 +01:00
Romain Tisserandandrefractionpcsx2 a3af4155f8 3rdparty: Bump libchdr to support raw DVD ISO as CHD 2023-04-12 09:37:46 +01:00
refractionpcsx2 1ec83dc790 SPU2: Fix savestate loading setting incorrect variable 2023-04-11 18:45:27 +01:00
Stenzekandrefractionpcsx2 f26cc38b80 SPU2: Store DMA pointers as offsets in save state
[SAVEVERSION+] Sadly need to bump save state, don't want to have a mess
of different version handling here.
2023-04-11 15:30:54 +01:00
lightningterror d9f537e9dc GS-hw: Fix Wsign-compare warning. 2023-04-11 01:06:15 +02:00
PCSX2 Botandlightningterror 94c75df0d0 PAD: Update to latest controller database. 2023-04-10 20:35:28 +02:00
Stenzekandrefractionpcsx2 423a8884e8 GS/Vulkan: Don't try to render out of bounds in Interlace() 2023-04-10 16:51:01 +01:00
Stenzekandrefractionpcsx2 1f26502c64 GS/HW: Always convert float depth to integer on readback
Even if it's been reinterpreted as a colour format.
2023-04-10 16:51:01 +01:00
dependabot[bot]andlightningterror f61f7bb711 Bump peter-evans/create-pull-request from 4 to 5
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4 to 5.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](https://github.com/peter-evans/create-pull-request/compare/v4...v5)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-10 16:13:04 +02:00
KamFretoZandrefractionpcsx2 971acd3fdb Qt: Fills in the settings help description fields 2023-04-09 19:13:09 +01:00
JordanTheToasterandrefractionpcsx2 bba070bdbf GameDB: PAL ZoE 2 Text fix
Fixes cut off text in PAL versions of Zone of the Enders 2
2023-04-09 19:12:56 +01:00
Connor McLaughlinandrefractionpcsx2 6c4152a7e0 GS/HW: Update 32-bit flag for depth buffers too
Jackie Chan Adventures re-uses a previous C32 target pointer as a Z16S
depth buffer, but it does clear it inbetween. So we need to remove the
32-bit flag on the clear.
2023-04-09 17:56:49 +01:00
Stenzekandrefractionpcsx2 f569ad0970 GS/HW: Allow translating targets for depth sources
Fixes broken half screen in Miami Vice and 10 Pin - Champions Alley.
2023-04-09 17:56:49 +01:00
Stenzekandrefractionpcsx2 f16a291412 GS/HW: Adjust TextureMinMax end coordinate when point sampling 2023-04-09 17:56:49 +01:00
refractionpcsx2 e0cfa2dff3 EE/COP2: Increase likely clear sync 2023-04-09 17:23:09 +01:00
Stenzekandrefractionpcsx2 bf9d087e74 GS/HW: Adjust Burnout CRC to fully skip broken post effect 2023-04-09 16:28:57 +01:00
JordanTheToasterandrefractionpcsx2 b245dd55d6 Github: Change emu bug report template
Missed when changing the other template.
2023-04-09 16:26:23 +01:00
JordanTheToasterandrefractionpcsx2 1e3f429169 GameDB: Various fixes
Alieviates high VU % usage in Pilot Down Behind Enemy Lines and sets max blending level to minimum for other Monster Hunter games to fix heavy GPU usage for no reason.
2023-04-09 16:26:23 +01:00
refractionpcsx2 8d429c7e5a GameDB: Update the VU clamp mode on Ultimate Spider-Man 2023-04-09 16:24:46 +01:00
Stenzekandrefractionpcsx2 b9be3ad3b8 GS/HW: Tiny optimization in source lookup
Don't want to do divides per-target.
2023-04-09 06:01:54 +01:00
refractionpcsx2 3099090e6a GameDB: Add InstantDMA to Jak 3 for holes in face geometry 2023-04-09 05:56:58 +01:00
refractionpcsx2 5e27c65615 EE/COP2: Check for likely zero clears in COP2 synced ops 2023-04-09 05:55:15 +01:00
refractionpcsx2 8b32382e1b GameDB: Add Autoflush and HPO Special to Ultimate Spider-Man 2023-04-09 03:31:41 +01:00
arcum42andrefractionpcsx2 60047e8029 common: Remove some unneeded includes. 2023-04-08 20:26:39 +01:00
arcum42andrefractionpcsx2 e37fff1213 common: Remove SafeList and SafeAllignedArray as unused. 2023-04-08 20:26:39 +01:00
JordanTheToasterandrefractionpcsx2 64a6d8027b GS: Reset performance counters on renderer switch
Resets performance counters on renderer switch.
2023-04-08 13:37:21 +01:00
Stenzekandrefractionpcsx2 cd4434135e GSRunner: Don't skip dumps with dots in their filename 2023-04-08 13:36:45 +01:00
Stenzekandrefractionpcsx2 747e11d7dd GS/HW: Allow region targets for half-right fix 2023-04-08 12:44:33 +01:00
Stenzekandlightningterror 3cae728aba Qt: Recreate new window immediately when switching APIs 2023-04-08 12:42:34 +02:00
Stenzekandrefractionpcsx2 7f24a5cf82 GS: Fix crash when resizing window 2023-04-08 04:05:45 +01:00
refractionpcsx2 1b8f5f232a GS-HW: Fix bug with looping invalidation 2023-04-08 00:08:08 +01:00
refractionpcsx2 77d37de18c GameDB: Add mipmapping to Hasbro Family Game Night 2023-04-07 20:34:03 +01:00
Mrlinkwiiandrefractionpcsx2 5ea3fb8e1e Github: Update issue template 2023-04-07 19:52:50 +01:00
refractionpcsx2 d683aa43d8 GS: Clean up Host->Local code 2023-04-07 17:18:33 +01:00
refractionpcsx2 d4c3501bb8 GS: Retool downloads to buffer full read 2023-04-07 17:18:33 +01:00
Stenzekandrefractionpcsx2 f2229a0007 GS/OGL: Don't leak shader objects when compiling 2023-04-07 17:18:21 +01:00
Stenzekandrefractionpcsx2 2a06bb6e2c GS/OGL: Use VS/GS selectors from base class 2023-04-07 17:18:21 +01:00
lightningterror a06f890ab9 GS: Fix Wunused-variable warning. 2023-04-07 01:26:00 +02:00
refractionpcsx2 bbe22f95d1 GS: Avoid modifying single QW downloads as they go to a register
Also avoid downloading more than requested
2023-04-06 23:26:59 +01:00
Stenzekandrefractionpcsx2 631f75a79c GS/HW: Don't break out of target search loop on dirty target 2023-04-06 14:28:19 +01:00
Stenzekandrefractionpcsx2 c121aae8f1 GS: Add VS natvis files for FastList and TC Targets 2023-04-06 14:27:36 +01:00
refractionpcsx2 fed7629632 GS: Fix typo in ResizeTexture which was causing a crash 2023-04-06 14:27:08 +01:00
Stenzekandrefractionpcsx2 0825ca736f GS/HW: Add other StretchRect() calls to texture copies counter
Better reflects GPU work.
2023-04-06 14:20:20 +01:00
Stenzekandrefractionpcsx2 660974c9d1 GS/HW: Update target in new format when reinterpreting
Fixes block scrambling in Budokai 3 during screen transitions.
2023-04-06 14:20:20 +01:00
Stenzekandrefractionpcsx2 4404b06d2a Qt: Fix lockup when cancelling shutdown and fullscreen 2023-04-06 08:48:07 +01:00
Stenzekandrefractionpcsx2 daef69099b Qt: Fix improper shutdown with CTRL+C 2023-04-06 08:48:07 +01:00
Stenzekandrefractionpcsx2 6362994fd8 GS: Default to Vulkan for suitable GPUs on Linux 2023-04-06 08:48:07 +01:00
Stenzekandrefractionpcsx2 398cf43782 GS: Combine HostDisplay with GSDevice
GS/DX11: Don't throw bad_alloc on surface creation fail

GS: Link device and host display construction/destruction

FullscreenUI: Replace HostDisplayTexture with GSTexture

GS: Purge HostDisplayTexture

GS: Move everything in HostDisplay to GSDevice

GS: Move ImGui rendering to GSDevice

GS: Get rid of reset/store API state
2023-04-06 08:48:07 +01:00
refractionpcsx2 77f8a0f5f6 Counters: Retool UpdateVSyncRate 2023-04-06 08:47:35 +01:00
lightningterror d7e54ccbed CDVD: Fix struct member variables not used.
Codacy.
2023-04-05 20:15:18 +02:00
lightningterror 53a8855696 INISettingsInterface: Fix scope of variable warning.
Codacy.
2023-04-05 20:15:18 +02:00
lightningterror bd16ed1340 iR5900: Fix scope of variable warning.
Codacy.
2023-04-05 20:15:18 +02:00
lightningterror dd365fe334 GS-hw/tc: Fix Wsign-compare warnings. 2023-04-05 20:15:18 +02:00
refractionpcsx2 2a6ba739bc GS-HW: Fix stretch rects errantly discarding data 2023-04-05 16:29:36 +01:00
refractionpcsx2 a863466f70 GS-HW: Better handle double half clears + masked channels + invalidate
Also add Auto Flush to Power Drome US, apparently it wasn't there.
2023-04-05 16:29:36 +01:00
refractionpcsx2 32f07f4aae GS-HW: Read back TC on GS CSR Reset 2023-04-05 16:29:36 +01:00
refractionpcsx2 3ed0e010be GS-TC: Improve handing of wrapping targets in tex in rt 2023-04-05 16:29:36 +01:00
GiladNirandrefractionpcsx2 fb3c0c8138 GameDB: Added fixes for Fatal Frame and Siren 2023-04-05 15:10:48 +01:00
Stenzekandrefractionpcsx2 58ded2e0d0 GS/HW: Fix incorrect hashing of non-palette textures 2023-04-05 15:01:42 +01:00
Stenzekandrefractionpcsx2 369b9a4808 Misc: Fix up a few recent clang warnings 2023-04-05 12:43:45 +01:00
Stenzekandrefractionpcsx2 0bd57986a9 GS/HW: Don't try to use forced trilinear on shuffles 2023-04-05 12:43:45 +01:00
484 changed files with 30322 additions and 32582 deletions
+21 -9
View File
@@ -12,19 +12,22 @@ body:
## Important: Read First
Please do not make support requests on GitHub. Our issue tracker is for tracking bugs and feature requests only
If you need help configuring the emulator please make a request on our forums or contact us on discord
If you need help configuring the emulator please make a request on our forums or contact us on discord.
If you are unsure, start with [discord](https://discord.com/invite/TCz3t9k) or the [forums](https://forums.pcsx2.net/index.php)
If you are unsure, start with [discord](https://discord.com/invite/TCz3t9k) or the [forums](https://forums.pcsx2.net/index.php).
Please make an effort to make sure your issue isn't already reported
Please make an effort to make sure your issue isn't already reported.
### Please Avoid Issues Pertaining to the Following:
- We are **not** accepting bug reports for **PSX mode** at this time
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use a [proper PSX emulator](https://emulation.gametechwiki.com/index.php/PlayStation_emulators)
- We do **not** accept issues relating to **upscaling** at this time
- We are aware of the various problems with upscaling. The issue spans many games and having hundreds of issues for the same fundamental issues isn't particularly helpful. There are several workarounds for graphical problems that come as a result of upscaling
- Please try your game at native resolution before creating an issue
- If your bug is the result of upscaling please use the forums or discord for assistance with various upscaling workarounds. Additionally, the unofficial PCSX2 [Wiki](https://wiki.pcsx2.net/Main_Page) often lists various fixes for upscaling issues
- We are **not** accepting bug reports for **PSX mode** at this time.
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use [Duckstation](https://github.com/stenzek/duckstation/releases/tag/latest).
- We do **not** accept issues relating to **upscaling** at this time.
- We are aware of the various problems with upscaling. The issue spans many games and having hundreds of issues for the same fundamental issues isn't particularly helpful. There are several workarounds for graphical problems that come as a result of upscaling.
- Please try your game at native resolution before creating an issue.
- If your bug is the result of upscaling please use the forums or discord for assistance with various upscaling workarounds. Additionally, the unofficial PCSX2 [Wiki](https://wiki.pcsx2.net/Main_Page) often lists various fixes for upscaling issues.
- We do **not** accept issues relating to Widescreen/no-interlace patches at this time.
- Any issues pertaining to Widescreen/no-interlace patches please forward them to the [patches repository](https://github.com/PCSX2/pcsx2_patches).
- type: textarea
id: desc
attributes:
@@ -76,3 +79,12 @@ body:
placeholder: "Example: Arch"
validations:
required: false
- type: textarea
id: logsDumps
attributes:
label: "Logs & Dumps"
description: |
Please feel free to attach any logs here.
If PCSX2 crashed, please post crash logs and the .dmp file (in a zip file) if appropriate.
validations:
required: false
+21 -18
View File
@@ -12,19 +12,22 @@ body:
## Important: Read First
Please do not make support requests on GitHub. Our issue tracker is for tracking bugs and feature requests only
If you need help configuring the emulator please make a request on our forums or contact us on discord
If you need help configuring the emulator please make a request on our forums or contact us on discord.
If you are unsure, start with [discord](https://discord.com/invite/TCz3t9k) or the [forums](https://forums.pcsx2.net/index.php)
If you are unsure, start with [discord](https://discord.com/invite/TCz3t9k) or the [forums](https://forums.pcsx2.net/index.php).
Please make an effort to make sure your issue isn't already reported
Please make an effort to make sure your issue isn't already reported.
### Please Avoid Issues Pertaining to the Following:
- We are **not** accepting bug reports for **PSX mode** at this time
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use a [proper PSX emulator](https://emulation.gametechwiki.com/index.php/PlayStation_emulators)
- We do **not** accept issues relating to **upscaling** at this time
- We are aware of the various problems with upscaling. The issue spans many games and having hundreds of issues for the same fundamental issues isn't particularly helpful. There are several workarounds for graphical problems that come as a result of upscaling
- Please try your game at native resolution before creating an issue
- If your bug is the result of upscaling please use the forums or discord for assistance with various upscaling workarounds. Additionally, the unofficial PCSX2 [Wiki](https://wiki.pcsx2.net/Main_Page) often lists various fixes for upscaling issues
- We are **not** accepting bug reports for **PSX mode** at this time.
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use [Duckstation](https://github.com/stenzek/duckstation/releases/tag/latest).
- We do **not** accept issues relating to **upscaling** at this time.
- We are aware of the various problems with upscaling. The issue spans many games and having hundreds of issues for the same fundamental issues isn't particularly helpful. There are several workarounds for graphical problems that come as a result of upscaling.
- Please try your game at native resolution before creating an issue.
- If your bug is the result of upscaling please use the forums or discord for assistance with various upscaling workarounds. Additionally, the unofficial PCSX2 [Wiki](https://wiki.pcsx2.net/Main_Page) often lists various fixes for upscaling issues.
- We do **not** accept issues relating to Widescreen/no-interlace patches at this time.
- Any issues pertaining to Widescreen/no-interlace patches please forward them to the [patches repository](https://github.com/PCSX2/pcsx2_patches).
- type: textarea
id: desc
attributes:
@@ -52,13 +55,13 @@ body:
## System Info
Please make sure your system meets our requirements for OS version, CPU and GPU
- [System Requirements](https://github.com/PCSX2/pcsx2#system-requirements)
- [System Requirements](https://github.com/PCSX2/pcsx2#system-requirements).
Performance issues as a result of not meeting our hardware requirements are not valid
Performance issues as a result of not meeting our hardware requirements are not valid.
Please read our known issues pages for AMD and Intel drivers.
- [Intel Drivers](https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-Intel-GPUs-All-you-need-to-know)
- [AMD Drivers](https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-AMD-GPUs---All-you-need-to-know)
- [Intel Drivers](https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-Intel-GPUs-All-you-need-to-know).
- [AMD Drivers](https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-AMD-GPUs---All-you-need-to-know).
We are **not** accepting issues related to the **libretro** core. The libretro core is being maintained separately at this time
- type: input
@@ -117,11 +120,11 @@ body:
attributes:
label: Emulation Settings
description: |
Any non-default core settings. If you don't want to list them out, please provide screenshots of your configuration window
Any non-default core settings. If you don't want to list them out, please provide screenshots of your configuration window.
Please note that the safe preset works for most games. MTVU can have some compatibility issues so please disable it before making a report
Please note that the safe preset works for most games. MTVU can have some compatibility issues so please disable it before making a report.
If you need to modify the settings manually because a game requires you to do so to work, please state that explicitly
If you need to modify the settings manually because a game requires you to do so to work, please state that explicitly.
validations:
required: false
- type: textarea
@@ -136,8 +139,8 @@ body:
attributes:
label: "Logs & Dumps"
description: |
Please feel free to attach any logs, block dumps, GSdump, etc here
Please feel free to attach any logs, block dumps, GSdump, etc here.
If PCSX2 crashed, please post crash logs and the .dmp file (in a zip file) if appropriate.
If your problem is graphical in nature it is highly recommended that you provide a GSdump. [GSdump Guide](https://forums.pcsx2.net/Thread-How-to-create-a-proper-GS-dump)
validations:
required: false
+2 -2
View File
@@ -39,8 +39,8 @@
'Debugger':
- 'pcsx2/DebugTools/*'
- 'pcsx2/DebugTools/**/*'
- 'pcsx2/gui/Debugger/*'
- 'pcsx2/gui/Debugger/**/*'
- 'pcsx2-qt/Debugger/*'
- 'pcsx2-qt/Debugger/**/*'
'IPC':
- 'pcsx2/IPC*'
- 'pcsx2/**/IPC*'
@@ -19,7 +19,7 @@ jobs:
mv ./game_controller_db.txt ${{github.workspace}}/bin/resources/game_controller_db.txt
- name: Create Pull Request
uses: peter-evans/create-pull-request@v4
uses: peter-evans/create-pull-request@v5
with:
title: "PAD: Update to latest controller database"
commit-message: "PAD: Update to latest controller database."
+3 -3
View File
@@ -28,7 +28,7 @@ on:
required: false
type: string
default: ""
cheats_url:
patches_url:
required: false
type: string
default: https://github.com/PCSX2/pcsx2_patches/releases/latest/download
@@ -93,10 +93,10 @@ jobs:
if: steps.cache-deps.outputs.cache-hit != 'true'
run: .github/workflows/scripts/linux/build-dependencies-qt.sh
- name: Download cheats
- name: Download patches
run: |
cd bin/resources
aria2c -Z "${{ inputs.cheats_url }}/cheats_ni.zip" "${{ inputs.cheats_url }}/cheats_ws.zip"
aria2c -Z "${{ inputs.patches_url }}/patches.zip"
- name: Generate CMake
env:
+3 -3
View File
@@ -17,7 +17,7 @@ on:
gui:
required: true
type: string
cheats_url:
patches_url:
required: false
type: string
default: https://github.com/PCSX2/pcsx2_patches/releases/latest/download
@@ -82,10 +82,10 @@ jobs:
GUI: ${{ inputs.gui }}
run: .github/workflows/scripts/macos/build-dependencies.sh
- name: Download cheats
- name: Download patches
run: |
cd bin/resources
aria2c -Z "${{ inputs.cheats_url }}/cheats_ni.zip" "${{ inputs.cheats_url }}/cheats_ws.zip"
aria2c -Z "${{ inputs.patches_url }}/patches.zip"
# -- SETUP CCACHE - https://cristianadam.eu/20200113/speeding-up-c-plus-plus-github-actions-using-ccache/
- name: Prepare ccache timestamp
@@ -87,6 +87,7 @@ declare -a SYSLIBS=(
"libvorbis.so.0"
"libvorbisenc.so.2"
"libxcb.so.1"
"libxcb-cursor.so.0"
"libxcb-render.so.0"
"libxcb-shm.so.0"
"libxkbcommon.so.0"
@@ -157,6 +158,7 @@ declare -a SYSLIBS=(
"libhx509.so.5"
"libsqlite3.so.0"
"libcrypt.so.1"
"libdbus-1.so.3"
)
declare -a DEPLIBS=(
@@ -206,6 +208,9 @@ mkdir "$OUTDIR/usr"
echo "Copying binary and resources..."
cp -a "$BUILDDIR/bin" "$OUTDIR/usr"
# Get rid of unit tests, we don't want them bloating the squashfs.
rm -fv "$OUTDIR"/usr/bin/*_test
# Patch RPATH so the binary goes hunting for shared libraries in the AppDir instead of system.
echo "Patching RPATH in ${BINARY}..."
patchelf --set-rpath '$ORIGIN/../lib' "$OUTDIR/usr/bin/$BINARY"
@@ -4,21 +4,21 @@ set -e
INSTALLDIR="$HOME/deps"
NPROCS="$(getconf _NPROCESSORS_ONLN)"
SDL=SDL2-2.26.4
QT=6.4.3
SDL=SDL2-2.26.5
QT=6.5.0
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
mkdir -p deps-build
cd deps-build
cat > SHASUMS <<EOF
1a0f686498fb768ad9f3f80b39037a7d006eac093aad39cb4ebcc832a8887231 $SDL.tar.gz
ad8fea3da1be64c83c45b1d363a6b4ba8fd60f5bde3b23ec73855709ec5eabf7 $SDL.tar.gz
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
5087c9e5b0165e7bc3c1a4ab176b35d0cd8f52636aea903fa377bdba00891a60 qtbase-everywhere-src-$QT.tar.xz
88315f886cf81898705e487cedba6e6160724359d23c518c92c333c098879a4a qtsvg-everywhere-src-$QT.tar.xz
867df829cd5cd3ae8efe62e825503123542764b13c96953511e567df70c5a091 qttools-everywhere-src-$QT.tar.xz
79e56b7800d49649a8a8010818538c367a829e0b7a09d5f60bd3aecf5abe972c qttranslations-everywhere-src-$QT.tar.xz
c6b161da8f4c01e48c10b7b558a0a01ac07dba9b907b13a98ff5d89f46bc4789 qtwayland-everywhere-src-$QT.tar.xz
fde1aa7b4fbe64ec1b4fc576a57f4688ad1453d2fab59cbadd948a10a6eaf5ef qtbase-everywhere-src-$QT.tar.xz
64ca7e61f44d51e28bcbb4e0509299b53a9a7e38879e00a7fe91643196067a4f qtsvg-everywhere-src-$QT.tar.xz
49c33d96b0a44988be954269b8ce3d1a495b439726e03a6be7c0d50a686369c4 qttools-everywhere-src-$QT.tar.xz
fc85d0fd8393f518653ccada1014177a56df6e73f30f3b64eea0c2e4a0067a3d qttranslations-everywhere-src-$QT.tar.xz
ccc57fa277fc5f1c1c2c4733eae80a60996b67a067233c47809e542aa31759a3 qtwayland-everywhere-src-$QT.tar.xz
EOF
curl -L \
@@ -6,11 +6,11 @@ export MACOSX_DEPLOYMENT_TARGET=10.14
INSTALLDIR="$HOME/deps"
NPROCS="$(getconf _NPROCESSORS_ONLN)"
SDL=SDL2-2.26.0
SDL=SDL2-2.26.5
PNG=1.6.37
JPG=9e
SOUNDTOUCH=soundtouch-2.3.1
QT=6.3.1
QT=6.4.3
mkdir deps-build
cd deps-build
@@ -21,14 +21,14 @@ export CFLAGS="-I$INSTALLDIR/include -Os $CFLAGS"
export CXXFLAGS="-I$INSTALLDIR/include -Os $CXXFLAGS"
cat > SHASUMS <<EOF
8000d7169febce93c84b6bdf376631f8179132fd69f7015d4dadb8b9c2bdb295 $SDL.tar.gz
ad8fea3da1be64c83c45b1d363a6b4ba8fd60f5bde3b23ec73855709ec5eabf7 $SDL.tar.gz
505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca libpng-$PNG.tar.xz
4077d6a6a75aeb01884f708919d25934c93305e49f7e3f36db9129320e6f4f3d jpegsrc.v$JPG.tar.gz
6900996607258496ce126924a19fe9d598af9d892cf3f33d1e4daaa9b42ae0b1 $SOUNDTOUCH.tar.gz
0a64421d9c2469c2c48490a032ab91d547017c9cc171f3f8070bc31888f24e03 qtbase-everywhere-src-$QT.tar.xz
7b19f418e6f7b8e23344082dd04440aacf5da23c5a73980ba22ae4eba4f87df7 qtsvg-everywhere-src-$QT.tar.xz
c412750f2aa3beb93fce5f30517c607f55daaeb7d0407af206a8adf917e126c1 qttools-everywhere-src-$QT.tar.xz
d7bdd55e2908ded901dcc262157100af2a490bf04d31e32995f6d91d78dfdb97 qttranslations-everywhere-src-$QT.tar.xz
5087c9e5b0165e7bc3c1a4ab176b35d0cd8f52636aea903fa377bdba00891a60 qtbase-everywhere-src-$QT.tar.xz
88315f886cf81898705e487cedba6e6160724359d23c518c92c333c098879a4a qtsvg-everywhere-src-$QT.tar.xz
867df829cd5cd3ae8efe62e825503123542764b13c96953511e567df70c5a091 qttools-everywhere-src-$QT.tar.xz
79e56b7800d49649a8a8010818538c367a829e0b7a09d5f60bd3aecf5abe972c qttranslations-everywhere-src-$QT.tar.xz
EOF
curl -L \
+5 -5
View File
@@ -32,12 +32,12 @@ on:
qt_binary_url:
required: false
type: string
default: https://github.com/PCSX2/pcsx2-windows-dependencies/releases/download/2022-11-20/qt-6.4.0-x64.7z
default: https://github.com/PCSX2/pcsx2-windows-dependencies/releases/download/2023-04-25/qt-6.5.0-x64.7z
qt_dir:
required: false
type: string
default: 3rdparty\qt\6.4.0\msvc2022_64
cheats_url:
default: 3rdparty\qt\6.5.0\msvc2022_64
patches_url:
required: false
type: string
default: https://github.com/PCSX2/pcsx2_patches/releases/latest/download
@@ -84,11 +84,11 @@ jobs:
7z x qt-*-x64.7z
del qt-*-x64.7z
- name: Download cheats
- name: Download patches
shell: cmd
run: |
cd bin/resources
aria2c -Z "${{ inputs.cheats_url }}/cheats_ni.zip" "${{ inputs.cheats_url }}/cheats_ws.zip"
aria2c -Z "${{ inputs.patches_url }}/patches.zip"
- name: Generate CMake
if: inputs.configuration == 'CMake'
+2 -7
View File
@@ -33,14 +33,9 @@
<ClCompile>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>TurnOffAllWarnings</WarningLevel>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\glad\include;$(ProjectDir)include;$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir)include;$(ProjectDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)3rdparty\glad\glad.vcxproj">
<Project>{c0293b32-5acf-40f0-aa6c-e6da6f3bf33a}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\imconfig.h" />
<ClInclude Include="include\imgui.h" />
@@ -60,4 +55,4 @@
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets" />
</Project>
</Project>
+1 -1
View File
@@ -25,7 +25,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpgd", "3rdparty\jpgd\jpgd.
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "common\common.vcxproj", "{4639972E-424E-4E13-8B07-CA403C481346}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2core", "pcsx2\pcsx2core.vcxproj", "{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}"
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pcsx2", "pcsx2\pcsx2.vcxproj", "{6C7986C4-3E4D-4DCC-B3C6-6BB12B238995}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glad", "3rdparty\glad\glad.vcxproj", "{C0293B32-5ACF-40F0-AA6C-E6DA6F3BF33A}"
EndProject
+1670 -741
View File
File diff suppressed because it is too large Load Diff
+18 -3
View File
@@ -186,6 +186,7 @@
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,
03005036852100000000000000000000,Final Fantasy XIV Online 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,
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,
@@ -533,9 +534,11 @@
030000009b2800002300000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,
030000009b2800006900000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,
030000009b2800000800000000000000,Raphnet Dreamcast Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows,
030000009b2800006200000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,
030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,
030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows,
030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
@@ -662,6 +665,7 @@
03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,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,x:b3,y:b4,platform:Windows,
03000000790000002601000000000000,TGZ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,platform:Windows,
030000004f04000015b3000000000000,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:Windows,
030000004f04000023b3000000000000,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:Windows,
030000004f0400000ed0000000000000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -865,7 +869,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f0000ee00000000010000,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:Mac OS X,
03000000242e0000ff0b000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Mac OS X,
03000000790000004e95000000010000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Mac OS X,
03000000830500006020000000000000,iBuffalo Gamepad,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,
03000000830500006020000000000000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,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,
03000000fd0500000030000010010000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Mac OS X,
030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X,
@@ -982,6 +986,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000457500002211000000010000,SZMY Power PC Gamepad,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,
03000000790000001c18000003100000,TGZ Controller,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:Mac OS X,
03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X,
030000004f04000015b3000000000000,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:Mac OS X,
030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,
@@ -1140,6 +1145,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006e0500000720000010010000,Elecom W01U,a:b2,b:b3,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:a3,start:b9,x:b0,y:b1,platform:Linux,
030000007d0400000640000010010000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Linux,
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,
03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
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,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000b40400001224000011010000,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,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,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:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1149,6 +1155,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
03000000ac0500007a05000011010000,GameSir G5,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:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
@@ -1206,7 +1213,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000242e00006a38000010010000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Linux,
03000000242e00008816000001010000,Hyperkin X91,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,
03000000f00300008d03000011010000,HyperX Clutch,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,
03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,
@@ -1268,6 +1275,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000b50700004f00000000010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux,
030000005e0400000300000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
@@ -1328,8 +1336,12 @@ 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 U 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,
030000007e0500001920000011810000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,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,
050000007e0500001920000001800000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux,
030000007e0500001720000011810000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500001720000001800000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,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,
05000000550900001472000001000000,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,
@@ -1501,6 +1513,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
03000000790000001c18000011010000,TGZ Controller,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,
03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,leftshoulder:b4,rightshoulder:b5,x:b3,y:b0,start:b7,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,
@@ -1576,6 +1590,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000130b000015050000,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,
060000005e040000120b000007050000,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,
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,
060000005e040000120b00000f050000,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,
050000005e040000200b000013050000,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,
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,
+36
View File
@@ -0,0 +1,36 @@
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 vs_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;
}
sampler sampler0 : register(s0);
Texture2D texture0 : register(t0);
float4 ps_main(PS_INPUT input) : SV_Target
{
float4 out_col = input.col * texture0.Sample(sampler0, input.uv);
return out_col;
}
+103 -150
View File
@@ -1,5 +1,3 @@
#ifdef SHADER_MODEL // make safe to include in resource file to enforce dependency
#define FMT_32 0
#define FMT_24 1
#define FMT_16 2
@@ -113,6 +111,8 @@ struct PS_INPUT
#endif
};
#ifdef PIXEL_SHADER
struct PS_OUTPUT
{
#if !PS_NO_COLOR
@@ -136,21 +136,6 @@ Texture2D<float4> RtTexture : register(t2);
Texture2D<float> PrimMinTexture : register(t3);
SamplerState TextureSampler : register(s0);
#ifdef DX12
cbuffer cb0 : register(b0)
#else
cbuffer cb0
#endif
{
float2 VertexScale;
float2 VertexOffset;
float2 TextureScale;
float2 TextureOffset;
float2 PointSize;
uint MaxDepth;
uint pad_cb0;
};
#ifdef DX12
cbuffer cb1 : register(b1)
#else
@@ -437,8 +422,12 @@ int2 clamp_wrap_uv_depth(int2 uv)
float4 sample_depth(float2 st, float2 pos)
{
float2 uv_f = (float2)clamp_wrap_uv_depth(int2(st)) * (float2)ScaledScaleFactor;
int2 uv = (int2)uv_f;
#if PS_REGION_RECT == 1
uv_f = clamp(uv_f + STRange.xy, STRange.xy, STRange.zw);
#endif
int2 uv = (int2)uv_f;
float4 t = (float4)(0.0f);
if (PS_TALES_OF_ABYSS_HLE == 1)
@@ -1058,10 +1047,29 @@ PS_OUTPUT ps_main(PS_INPUT input)
return output;
}
#endif // PIXEL_SHADER
//////////////////////////////////////////////////////////////////////
// Vertex Shader
//////////////////////////////////////////////////////////////////////
#ifdef VERTEX_SHADER
#ifdef DX12
cbuffer cb0 : register(b0)
#else
cbuffer cb0
#endif
{
float2 VertexScale;
float2 VertexOffset;
float2 TextureScale;
float2 TextureOffset;
float2 PointSize;
uint MaxDepth;
uint BaseVertex; // Only used in DX11.
};
VS_OUTPUT vs_main(VS_INPUT input)
{
// Clamp to max depth, gs doesn't wrap
@@ -1114,156 +1122,101 @@ VS_OUTPUT vs_main(VS_INPUT input)
return output;
}
//////////////////////////////////////////////////////////////////////
// Geometry Shader
//////////////////////////////////////////////////////////////////////
#if VS_EXPAND != 0
#if GS_FORWARD_PRIMID
#define PRIMID_IN , uint primid : SV_PrimitiveID
#define VS2PS(x) vs2ps_impl(x, primid)
PS_INPUT vs2ps_impl(VS_OUTPUT vs, uint primid)
struct VS_RAW_INPUT
{
PS_INPUT o;
o.p = vs.p;
o.t = vs.t;
o.ti = vs.ti;
o.c = vs.c;
o.primid = primid;
return o;
}
float2 ST;
uint RGBA;
float Q;
uint XY;
uint Z;
uint UV;
uint FOG;
};
StructuredBuffer<VS_RAW_INPUT> vertices : register(t0);
VS_INPUT load_vertex(uint index)
{
#ifdef DX12
VS_RAW_INPUT raw = vertices.Load(index);
#else
#define PRIMID_IN
#define VS2PS(x) vs2ps_impl(x)
PS_INPUT vs2ps_impl(VS_OUTPUT vs)
{
PS_INPUT o;
o.p = vs.p;
o.t = vs.t;
o.ti = vs.ti;
o.c = vs.c;
return o;
}
VS_RAW_INPUT raw = vertices.Load(BaseVertex + index);
#endif
#if GS_PRIM == 0
[maxvertexcount(6)]
void gs_main(point VS_OUTPUT input[1], inout TriangleStream<PS_INPUT> stream PRIMID_IN)
{
// Transform a point to a NxN sprite
PS_INPUT Point = VS2PS(input[0]);
// Get new position
float4 lt_p = input[0].p;
float4 rb_p = input[0].p + float4(PointSize.x, PointSize.y, 0.0f, 0.0f);
float4 lb_p = rb_p;
float4 rt_p = rb_p;
lb_p.x = lt_p.x;
rt_p.y = lt_p.y;
// Triangle 1
Point.p = lt_p;
stream.Append(Point);
Point.p = lb_p;
stream.Append(Point);
Point.p = rt_p;
stream.Append(Point);
// Triangle 2
Point.p = lb_p;
stream.Append(Point);
Point.p = rt_p;
stream.Append(Point);
Point.p = rb_p;
stream.Append(Point);
VS_INPUT vert;
vert.st = raw.ST;
vert.c = uint4(raw.RGBA & 0xFFu, (raw.RGBA >> 8) & 0xFFu, (raw.RGBA >> 16) & 0xFFu, raw.RGBA >> 24);
vert.q = raw.Q;
vert.p = uint2(raw.XY & 0xFFFFu, raw.XY >> 16);
vert.z = raw.Z;
vert.uv = uint2(raw.UV & 0xFFFFu, raw.UV >> 16);
vert.f = float4(float(raw.FOG & 0xFFu), float((raw.FOG >> 8) & 0xFFu), float((raw.FOG >> 16) & 0xFFu), float(raw.FOG >> 24)) / 255.0f;
return vert;
}
#elif GS_PRIM == 1
[maxvertexcount(6)]
void gs_main(line VS_OUTPUT input[2], inout TriangleStream<PS_INPUT> stream PRIMID_IN)
VS_OUTPUT vs_main_expand(uint vid : SV_VertexID)
{
// Transform a line to a thick line-sprite
PS_INPUT left = VS2PS(input[0]);
PS_INPUT right = VS2PS(input[1]);
float2 lt_p = input[0].p.xy;
float2 rt_p = input[1].p.xy;
#if VS_EXPAND == 1 // Point
// Potentially there is faster math
float2 line_vector = normalize(rt_p.xy - lt_p.xy);
VS_OUTPUT vtx = vs_main(load_vertex(vid >> 2));
vtx.p.x += ((vid & 1u) != 0u) ? PointSize.x : 0.0f;
vtx.p.y += ((vid & 2u) != 0u) ? PointSize.y : 0.0f;
return vtx;
#elif VS_EXPAND == 2 // Line
uint vid_base = vid >> 2;
bool is_bottom = vid & 2;
bool is_right = vid & 1;
// All lines will be a pair of vertices next to each other
// Since DirectX uses provoking vertex first, the bottom point will be the lower of the two
uint vid_other = is_bottom ? vid_base + 1 : vid_base - 1;
VS_OUTPUT vtx = vs_main(load_vertex(vid_base));
VS_OUTPUT other = vs_main(load_vertex(vid_other));
float2 line_vector = normalize(vtx.p.xy - other.p.xy);
float2 line_normal = float2(line_vector.y, -line_vector.x);
float2 line_width = (line_normal * PointSize) / 2;
// line_normal is inverted for bottom point
float2 offset = (is_bottom ^ is_right) ? line_width : -line_width;
vtx.p.xy += offset;
lt_p -= line_width;
rt_p -= line_width;
float2 lb_p = input[0].p.xy + line_width;
float2 rb_p = input[1].p.xy + line_width;
// Lines will be run as (0 1 2) (1 2 3)
// This means that both triangles will have a point based off the top line point as their first point
// So we don't have to do anything for !IIP
#if GS_IIP == 0
left.c = right.c;
#endif
return vtx;
// Triangle 1
left.p.xy = lt_p;
stream.Append(left);
#elif VS_EXPAND == 3 // Sprite
left.p.xy = lb_p;
stream.Append(left);
// Sprite points are always in pairs
uint vid_base = vid >> 1;
uint vid_lt = vid_base & ~1u;
uint vid_rb = vid_base | 1u;
right.p.xy = rt_p;
stream.Append(right);
stream.RestartStrip();
VS_OUTPUT lt = vs_main(load_vertex(vid_lt));
VS_OUTPUT rb = vs_main(load_vertex(vid_rb));
VS_OUTPUT vtx = rb;
// Triangle 2
left.p.xy = lb_p;
stream.Append(left);
bool is_right = ((vid & 1u) != 0u);
vtx.p.x = is_right ? lt.p.x : vtx.p.x;
vtx.t.x = is_right ? lt.t.x : vtx.t.x;
vtx.ti.xz = is_right ? lt.ti.xz : vtx.ti.xz;
right.p.xy = rt_p;
stream.Append(right);
bool is_bottom = ((vid & 2u) != 0u);
vtx.p.y = is_bottom ? lt.p.y : vtx.p.y;
vtx.t.y = is_bottom ? lt.t.y : vtx.t.y;
vtx.ti.yw = is_bottom ? lt.ti.yw : vtx.ti.yw;
right.p.xy = rb_p;
stream.Append(right);
stream.RestartStrip();
}
#elif GS_PRIM == 3
[maxvertexcount(4)]
void gs_main(line VS_OUTPUT input[2], inout TriangleStream<PS_INPUT> stream PRIMID_IN)
{
PS_INPUT lt = VS2PS(input[0]);
PS_INPUT rb = VS2PS(input[1]);
// flat depth
lt.p.z = rb.p.z;
// flat fog and texture perspective
lt.t.zw = rb.t.zw;
// flat color
lt.c = rb.c;
// Swap texture and position coordinate
PS_INPUT lb = rb;
lb.p.x = lt.p.x;
lb.t.x = lt.t.x;
lb.ti.x = lt.ti.x;
lb.ti.z = lt.ti.z;
PS_INPUT rt = rb;
rt.p.y = lt.p.y;
rt.t.y = lt.t.y;
rt.ti.y = lt.ti.y;
rt.ti.w = lt.ti.w;
stream.Append(lt);
stream.Append(lb);
stream.Append(rt);
stream.Append(rb);
}
return vtx;
#endif
#endif
}
#endif // VS_EXPAND
#endif // VERTEX_SHADER
+16 -16
View File
@@ -30,7 +30,7 @@ layout(binding=0, rgba8) uniform writeonly image2D imgDst;
AF3 CasLoad(ASU2 p)
{
return texelFetch(imgSrc, srcOffset + ivec2(p), 0).rgb;
return texelFetch(imgSrc, srcOffset + ivec2(p), 0).rgb;
}
// Lets you transform input from the load into a linear color space between 0 and 1. See ffx_cas.h
@@ -42,23 +42,23 @@ void CasInput(inout AF1 r, inout AF1 g, inout AF1 b) {}
layout(local_size_x=64) in;
void main()
{
// Do remapping of local xy in workgroup for a more PS-like swizzle pattern.
AU2 gxy = ARmp8x8(gl_LocalInvocationID.x)+AU2(gl_WorkGroupID.x<<4u,gl_WorkGroupID.y<<4u);
// Do remapping of local xy in workgroup for a more PS-like swizzle pattern.
AU2 gxy = ARmp8x8(gl_LocalInvocationID.x)+AU2(gl_WorkGroupID.x<<4u,gl_WorkGroupID.y<<4u);
// Filter.
AF4 c;
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
imageStore(imgDst, ASU2(gxy), c);
gxy.x += 8u;
// Filter.
AF4 c;
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
imageStore(imgDst, ASU2(gxy), c);
gxy.x += 8u;
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
imageStore(imgDst, ASU2(gxy), c);
gxy.y += 8u;
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
imageStore(imgDst, ASU2(gxy), c);
gxy.y += 8u;
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
imageStore(imgDst, ASU2(gxy), c);
gxy.x -= 8u;
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
imageStore(imgDst, ASU2(gxy), c);
gxy.x -= 8u;
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
imageStore(imgDst, ASU2(gxy), c);
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
imageStore(imgDst, ASU2(gxy), c);
}
+147 -147
View File
@@ -21,10 +21,10 @@ out vec4 PSin_c;
void vs_main()
{
PSin_p = vec4(POSITION, 0.5f, 1.0f);
PSin_t = TEXCOORD0;
PSin_c = COLOR;
gl_Position = vec4(POSITION, 0.5f, 1.0f); // NOTE I don't know if it is possible to merge POSITION_OUT and gl_Position
PSin_p = vec4(POSITION, 0.5f, 1.0f);
PSin_t = TEXCOORD0;
PSin_c = COLOR;
gl_Position = vec4(POSITION, 0.5f, 1.0f); // NOTE I don't know if it is possible to merge POSITION_OUT and gl_Position
}
#endif
@@ -46,13 +46,13 @@ layout(location = 0) out vec4 SV_Target0;
vec4 sample_c()
{
return texture(TextureSampler, PSin_t);
return texture(TextureSampler, PSin_t);
}
#ifdef ps_copy
void ps_copy()
{
SV_Target0 = sample_c();
SV_Target0 = sample_c();
}
#endif
@@ -67,20 +67,20 @@ void ps_depth_copy()
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
void ps_convert_rgba8_16bits()
{
highp uvec4 i = uvec4(sample_c() * vec4(255.5f, 255.5f, 255.5f, 255.5f));
highp uvec4 i = uvec4(sample_c() * vec4(255.5f, 255.5f, 255.5f, 255.5f));
SV_Target1 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
SV_Target1 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
}
#endif
#ifdef ps_convert_float32_32bits
void ps_convert_float32_32bits()
{
// Convert a GL_FLOAT32 depth texture into a 32 bits UINT texture
// Convert a GL_FLOAT32 depth texture into a 32 bits UINT texture
#if HAS_CLIP_CONTROL
SV_Target1 = uint(exp2(32.0f) * sample_c().r);
SV_Target1 = uint(exp2(32.0f) * sample_c().r);
#else
SV_Target1 = uint(exp2(24.0f) * sample_c().r);
SV_Target1 = uint(exp2(24.0f) * sample_c().r);
#endif
}
#endif
@@ -88,150 +88,150 @@ void ps_convert_float32_32bits()
#ifdef ps_convert_float32_rgba8
void ps_convert_float32_rgba8()
{
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
#if HAS_CLIP_CONTROL
uint d = uint(sample_c().r * exp2(32.0f));
uint d = uint(sample_c().r * exp2(32.0f));
#else
uint d = uint(sample_c().r * exp2(24.0f));
uint d = uint(sample_c().r * exp2(24.0f));
#endif
SV_Target0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0);
SV_Target0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0);
}
#endif
#ifdef ps_convert_float16_rgb5a1
void ps_convert_float16_rgb5a1()
{
// Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
// Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
#if HAS_CLIP_CONTROL
uint d = uint(sample_c().r * exp2(32.0f));
uint d = uint(sample_c().r * exp2(32.0f));
#else
uint d = uint(sample_c().r * exp2(24.0f));
uint d = uint(sample_c().r * exp2(24.0f));
#endif
SV_Target0 = vec4(uvec4((d & 0x1Fu), ((d >> 5) & 0x1Fu), ((d >> 10) & 0x1Fu), (d >> 15) & 0x01u)) / vec4(32.0f, 32.0f, 32.0f, 1.0f);
SV_Target0 = vec4(uvec4((d & 0x1Fu), ((d >> 5) & 0x1Fu), ((d >> 10) & 0x1Fu), (d >> 15) & 0x01u)) / vec4(32.0f, 32.0f, 32.0f, 1.0f);
}
#endif
float rgba8_to_depth32(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
uvec4 c = uvec4(unorm * vec4(255.5f));
#if HAS_CLIP_CONTROL
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
#else
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-24.0f);
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-24.0f);
#endif
}
float rgba8_to_depth24(vec4 unorm)
{
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
#if HAS_CLIP_CONTROL
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
#else
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-24.0f);
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-24.0f);
#endif
}
float rgba8_to_depth16(vec4 unorm)
{
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
#if HAS_CLIP_CONTROL
return float(c.r | (c.g << 8)) * exp2(-32.0f);
return float(c.r | (c.g << 8)) * exp2(-32.0f);
#else
return float(c.r | (c.g << 8)) * exp2(-24.0f);
return float(c.r | (c.g << 8)) * exp2(-24.0f);
#endif
}
float rgb5a1_to_depth16(vec4 unorm)
{
uvec4 c = uvec4(unorm * vec4(255.5f));
uvec4 c = uvec4(unorm * vec4(255.5f));
#if HAS_CLIP_CONTROL
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
#else
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-24.0f);
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-24.0f);
#endif
}
#ifdef ps_convert_rgba8_float32
void ps_convert_rgba8_float32()
{
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth32(sample_c());
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth32(sample_c());
}
#endif
#ifdef ps_convert_rgba8_float24
void ps_convert_rgba8_float24()
{
// Same as above but without the alpha channel (24 bits Z)
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth24(sample_c());
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth24(sample_c());
}
#endif
#ifdef ps_convert_rgba8_float16
void ps_convert_rgba8_float16()
{
// Same as above but without the A/B channels (16 bits Z)
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth16(sample_c());
// Convert an RGBA texture into a float depth texture
gl_FragDepth = rgba8_to_depth16(sample_c());
}
#endif
#ifdef ps_convert_rgb5a1_float16
void ps_convert_rgb5a1_float16()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
gl_FragDepth = rgb5a1_to_depth16(sample_c());
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
gl_FragDepth = rgb5a1_to_depth16(sample_c());
}
#endif
#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
ivec2 dims = textureSize(TextureSampler, 0); \
vec2 top_left_f = PSin_t * vec2(dims) - 0.5f; \
ivec2 top_left = ivec2(floor(top_left_f)); \
ivec4 coords = clamp(ivec4(top_left, top_left + 1), ivec4(0), dims.xyxy - 1); \
vec2 mix_vals = fract(top_left_f); \
float depthTL = CONVERT_FN(texelFetch(TextureSampler, coords.xy, 0)); \
float depthTR = CONVERT_FN(texelFetch(TextureSampler, coords.zy, 0)); \
float depthBL = CONVERT_FN(texelFetch(TextureSampler, coords.xw, 0)); \
float depthBR = CONVERT_FN(texelFetch(TextureSampler, coords.zw, 0)); \
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
ivec2 dims = textureSize(TextureSampler, 0); \
vec2 top_left_f = PSin_t * vec2(dims) - 0.5f; \
ivec2 top_left = ivec2(floor(top_left_f)); \
ivec4 coords = clamp(ivec4(top_left, top_left + 1), ivec4(0), dims.xyxy - 1); \
vec2 mix_vals = fract(top_left_f); \
float depthTL = CONVERT_FN(texelFetch(TextureSampler, coords.xy, 0)); \
float depthTR = CONVERT_FN(texelFetch(TextureSampler, coords.zy, 0)); \
float depthBL = CONVERT_FN(texelFetch(TextureSampler, coords.xw, 0)); \
float depthBR = CONVERT_FN(texelFetch(TextureSampler, coords.zw, 0)); \
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
#ifdef ps_convert_rgba8_float32_biln
void ps_convert_rgba8_float32_biln()
{
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
}
#endif
#ifdef ps_convert_rgba8_float24_biln
void ps_convert_rgba8_float24_biln()
{
// Same as above but without the alpha channel (24 bits Z)
// Same as above but without the alpha channel (24 bits Z)
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
}
#endif
#ifdef ps_convert_rgba8_float16_biln
void ps_convert_rgba8_float16_biln()
{
// Same as above but without the A/B channels (16 bits Z)
// Same as above but without the A/B channels (16 bits Z)
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
// Convert an RGBA texture into a float depth texture
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
}
#endif
#ifdef ps_convert_rgb5a1_float16_biln
void ps_convert_rgb5a1_float16_biln()
{
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
}
#endif
@@ -242,51 +242,51 @@ uniform float ScaleFactor;
void ps_convert_rgba_8i()
{
// Convert a RGBA texture into a 8 bits packed texture
// Input column: 8x2 RGBA pixels
// 0: 8 RGBA
// 1: 8 RGBA
// Output column: 16x4 Index pixels
// 0: 8 R | 8 B
// 1: 8 R | 8 B
// 2: 8 G | 8 A
// 3: 8 G | 8 A
uvec2 pos = uvec2(gl_FragCoord.xy);
// Convert a RGBA texture into a 8 bits packed texture
// Input column: 8x2 RGBA pixels
// 0: 8 RGBA
// 1: 8 RGBA
// Output column: 16x4 Index pixels
// 0: 8 R | 8 B
// 1: 8 R | 8 B
// 2: 8 G | 8 A
// 3: 8 G | 8 A
uvec2 pos = uvec2(gl_FragCoord.xy);
// Collapse separate R G B A areas into their base pixel
uvec2 block = (pos & ~uvec2(15u, 3u)) >> 1;
uvec2 subblock = pos & uvec2(7u, 1u);
uvec2 coord = block | subblock;
// Collapse separate R G B A areas into their base pixel
uvec2 block = (pos & ~uvec2(15u, 3u)) >> 1;
uvec2 subblock = pos & uvec2(7u, 1u);
uvec2 coord = block | subblock;
// Compensate for potentially differing page pitch.
// Compensate for potentially differing page pitch.
uvec2 block_xy = coord / uvec2(64u, 32u);
uint block_num = (block_xy.y * (DBW / 128u)) + block_xy.x;
uvec2 block_offset = uvec2((block_num % (SBW / 64u)) * 64u, (block_num / (SBW / 64u)) * 32u);
coord = (coord % uvec2(64u, 32u)) + block_offset;
// Apply offset to cols 1 and 2
uint is_col23 = pos.y & 4u;
uint is_col13 = pos.y & 2u;
uint is_col12 = is_col23 ^ (is_col13 << 1);
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
// Apply offset to cols 1 and 2
uint is_col23 = pos.y & 4u;
uint is_col13 = pos.y & 2u;
uint is_col12 = is_col23 ^ (is_col13 << 1);
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
if (floor(ScaleFactor) != ScaleFactor)
coord = uvec2(vec2(coord) * ScaleFactor);
else
coord *= uvec2(ScaleFactor);
if (floor(ScaleFactor) != ScaleFactor)
coord = uvec2(vec2(coord) * ScaleFactor);
else
coord *= uvec2(ScaleFactor);
vec4 pixel = texelFetch(TextureSampler, ivec2(coord), 0);
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
SV_Target0 = vec4(sel1);
vec4 pixel = texelFetch(TextureSampler, ivec2(coord), 0);
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
SV_Target0 = vec4(sel1);
}
#endif
#ifdef ps_filter_transparency
void ps_filter_transparency()
{
vec4 c = sample_c();
SV_Target0 = vec4(c.rgb, 1.0);
vec4 c = sample_c();
SV_Target0 = vec4(c.rgb, 1.0);
}
#endif
@@ -295,8 +295,8 @@ void ps_filter_transparency()
#ifdef ps_datm1
void ps_datm1()
{
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
discard;
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
discard;
}
#endif
@@ -305,24 +305,24 @@ void ps_datm1()
#ifdef ps_datm0
void ps_datm0()
{
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
discard;
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
discard;
}
#endif
#ifdef ps_hdr_init
void ps_hdr_init()
{
vec4 value = sample_c();
SV_Target0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a);
vec4 value = sample_c();
SV_Target0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a);
}
#endif
#ifdef ps_hdr_resolve
void ps_hdr_resolve()
{
vec4 value = sample_c();
SV_Target0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a);
vec4 value = sample_c();
SV_Target0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a);
}
#endif
@@ -366,51 +366,51 @@ uniform ivec2 EMOD;
void ps_yuv()
{
vec4 i = sample_c();
vec4 o;
vec4 i = sample_c();
vec4 o;
mat3 rgb2yuv; // Value from GS manual
rgb2yuv[0] = vec3(0.587, -0.311, -0.419);
rgb2yuv[1] = vec3(0.114, 0.500, -0.081);
rgb2yuv[2] = vec3(0.299, -0.169, 0.500);
mat3 rgb2yuv; // Value from GS manual
rgb2yuv[0] = vec3(0.587, -0.311, -0.419);
rgb2yuv[1] = vec3(0.114, 0.500, -0.081);
rgb2yuv[2] = vec3(0.299, -0.169, 0.500);
vec3 yuv = rgb2yuv * i.gbr;
vec3 yuv = rgb2yuv * i.gbr;
float Y = float(0xDB)/255.0f * yuv.x + float(0x10)/255.0f;
float Cr = float(0xE0)/255.0f * yuv.y + float(0x80)/255.0f;
float Cb = float(0xE0)/255.0f * yuv.z + float(0x80)/255.0f;
float Y = float(0xDB)/255.0f * yuv.x + float(0x10)/255.0f;
float Cr = float(0xE0)/255.0f * yuv.y + float(0x80)/255.0f;
float Cb = float(0xE0)/255.0f * yuv.z + float(0x80)/255.0f;
switch(EMOD.x) {
case 0:
o.a = i.a;
break;
case 1:
o.a = Y;
break;
case 2:
o.a = Y/2.0f;
break;
case 3:
o.a = 0.0f;
break;
}
switch(EMOD.x) {
case 0:
o.a = i.a;
break;
case 1:
o.a = Y;
break;
case 2:
o.a = Y/2.0f;
break;
case 3:
o.a = 0.0f;
break;
}
switch(EMOD.y) {
case 0:
o.rgb = i.rgb;
break;
case 1:
o.rgb = vec3(Y);
break;
case 2:
o.rgb = vec3(Y, Cb, Cr);
break;
case 3:
o.rgb = vec3(i.a);
break;
}
switch(EMOD.y) {
case 0:
o.rgb = i.rgb;
break;
case 1:
o.rgb = vec3(Y);
break;
case 2:
o.rgb = vec3(Y, Cb, Cr);
break;
case 3:
o.rgb = vec3(i.a);
break;
}
SV_Target0 = o;
SV_Target0 = o;
}
#endif
@@ -418,16 +418,16 @@ void ps_yuv()
void main()
{
SV_Target0 = vec4(0x7FFFFFFF);
SV_Target0 = vec4(0x7FFFFFFF);
#ifdef ps_stencil_image_init_0
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
SV_Target0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_1
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
SV_Target0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_0
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
SV_Target0 = vec4(-1);
#endif
#ifdef ps_stencil_image_init_1
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
SV_Target0 = vec4(-1);
#endif
}
#endif
+35
View File
@@ -0,0 +1,35 @@
#ifdef VERTEX_SHADER
layout(location = 0) in vec2 Position;
layout(location = 1) in vec2 UV;
layout(location = 2) in vec4 Color;
uniform mat4 ProjMtx;
out vec2 Frag_UV;
out vec4 Frag_Color;
void vs_main()
{
Frag_UV = UV;
Frag_Color = Color;
gl_Position = ProjMtx * vec4(Position.xy, 0.0, 1.0);
}
#endif
#ifdef FRAGMENT_SHADER
layout(binding = 0) uniform sampler2D Texture;
in vec2 Frag_UV;
in vec4 Frag_Color;
layout(location = 0) out vec4 Out_Color;
void ps_main()
{
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
}
#endif
+7 -7
View File
@@ -14,17 +14,17 @@ layout(location = 0) out vec4 SV_Target0;
void ps_main0()
{
vec4 c = texture(TextureSampler, PSin_t);
// Note: clamping will be done by fixed unit
c.a *= 2.0f;
SV_Target0 = c;
vec4 c = texture(TextureSampler, PSin_t);
// Note: clamping will be done by fixed unit
c.a *= 2.0f;
SV_Target0 = c;
}
void ps_main1()
{
vec4 c = texture(TextureSampler, PSin_t);
c.a = BGColor.a;
SV_Target0 = c;
vec4 c = texture(TextureSampler, PSin_t);
c.a = BGColor.a;
SV_Target0 = c;
}
#endif
+4 -4
View File
@@ -119,10 +119,10 @@ void ps_filter_triangular() // triangular
#ifdef ps_filter_complex
void ps_filter_complex()
{
const float PI = 3.14159265359f;
vec2 texdim = vec2(textureSize(TextureSampler, 0));
float factor = (0.9f - 0.4f * cos(2.0f * PI * PSin_t.y * texdim.y));
vec4 c = factor * texture(TextureSampler, vec2(PSin_t.x, (floor(PSin_t.y * texdim.y) + 0.5f) / texdim.y));
const float PI = 3.14159265359f;
vec2 texdim = vec2(textureSize(TextureSampler, 0));
float factor = (0.9f - 0.4f * cos(2.0f * PI * PSin_t.y * texdim.y));
vec4 c = factor * texture(TextureSampler, vec2(PSin_t.x, (floor(PSin_t.y * texdim.y) + 0.5f) / texdim.y));
SV_Target0 = c;
}
+18 -18
View File
@@ -24,33 +24,33 @@ layout(location = 0) out vec4 SV_Target0;
// For all settings: 1.0 = 100% 0.5=50% 1.5 = 150%
vec4 ContrastSaturationBrightness(vec4 color)
{
float brt = params.x;
float con = params.y;
float sat = params.z;
float brt = params.x;
float con = params.y;
float sat = params.z;
// Increase or decrease these values to adjust r, g and b color channels separately
const float AvgLumR = 0.5;
const float AvgLumG = 0.5;
const float AvgLumB = 0.5;
// Increase or decrease these values to adjust r, g and b color channels separately
const float AvgLumR = 0.5;
const float AvgLumG = 0.5;
const float AvgLumB = 0.5;
const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
vec3 brtColor = color.rgb * brt;
float dot_intensity = dot(brtColor, LumCoeff);
vec3 intensity = vec3(dot_intensity, dot_intensity, dot_intensity);
vec3 satColor = mix(intensity, brtColor, sat);
vec3 conColor = mix(AvgLumin, satColor, con);
vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
vec3 brtColor = color.rgb * brt;
float dot_intensity = dot(brtColor, LumCoeff);
vec3 intensity = vec3(dot_intensity, dot_intensity, dot_intensity);
vec3 satColor = mix(intensity, brtColor, sat);
vec3 conColor = mix(AvgLumin, satColor, con);
color.rgb = conColor;
return color;
color.rgb = conColor;
return color;
}
void ps_main()
{
vec4 c = texture(TextureSampler, PSin_t);
SV_Target0 = ContrastSaturationBrightness(c);
vec4 c = texture(TextureSampler, PSin_t);
SV_Target0 = ContrastSaturationBrightness(c);
}
File diff suppressed because it is too large Load Diff
+179 -193
View File
@@ -2,18 +2,34 @@
layout(std140, binding = 1) uniform cb20
{
vec2 VertexScale;
vec2 VertexOffset;
vec2 VertexScale;
vec2 VertexOffset;
vec2 TextureScale;
vec2 TextureOffset;
vec2 TextureScale;
vec2 TextureOffset;
vec2 PointSize;
uint MaxDepth;
uint pad_cb20;
vec2 PointSize;
uint MaxDepth;
uint pad_cb20;
};
#ifdef VERTEX_SHADER
out SHADER
{
vec4 t_float;
vec4 t_int;
#if VS_IIP != 0
vec4 c;
#else
flat vec4 c;
#endif
} VSout;
const float exp_min32 = exp2(-32.0f);
#if VS_EXPAND == 0
layout(location = 0) in vec2 i_st;
layout(location = 2) in vec4 i_c;
layout(location = 3) in float i_q;
@@ -22,232 +38,202 @@ layout(location = 5) in uint i_z;
layout(location = 6) in uvec2 i_uv;
layout(location = 7) in vec4 i_f;
out SHADER
{
vec4 t_float;
vec4 t_int;
#if VS_IIP != 0
vec4 c;
#else
flat vec4 c;
#endif
} VSout;
const float exp_min32 = exp2(-32.0f);
void texture_coord()
{
vec2 uv = vec2(i_uv) - TextureOffset;
vec2 st = i_st - TextureOffset;
vec2 uv = vec2(i_uv) - TextureOffset;
vec2 st = i_st - TextureOffset;
// Float coordinate
VSout.t_float.xy = st;
VSout.t_float.w = i_q;
// Float coordinate
VSout.t_float.xy = st;
VSout.t_float.w = i_q;
// Integer coordinate => normalized
VSout.t_int.xy = uv * TextureScale;
#if VS_INT_FST == 1
// Some games uses float coordinate for post-processing effect
VSout.t_int.zw = st / TextureScale;
// Integer coordinate => normalized
VSout.t_int.xy = uv * TextureScale;
#if VS_FST
// Integer coordinate => integral
VSout.t_int.zw = uv;
#else
// Integer coordinate => integral
VSout.t_int.zw = uv;
// Some games uses float coordinate for post-processing effect
VSout.t_int.zw = st / TextureScale;
#endif
}
void vs_main()
{
// Clamp to max depth, gs doesn't wrap
highp uint z = min(i_z, MaxDepth);
// Clamp to max depth, gs doesn't wrap
highp uint z = min(i_z, MaxDepth);
// pos -= 0.05 (1/320 pixel) helps avoiding rounding problems (integral part of pos is usually 5 digits, 0.05 is about as low as we can go)
// example: ceil(afterseveralvertextransformations(y = 133)) => 134 => line 133 stays empty
// input granularity is 1/16 pixel, anything smaller than that won't step drawing up/left by one pixel
// example: 133.0625 (133 + 1/16) should start from line 134, ceil(133.0625 - 0.05) still above 133
vec4 p;
// pos -= 0.05 (1/320 pixel) helps avoiding rounding problems (integral part of pos is usually 5 digits, 0.05 is about as low as we can go)
// example: ceil(afterseveralvertextransformations(y = 133)) => 134 => line 133 stays empty
// input granularity is 1/16 pixel, anything smaller than that won't step drawing up/left by one pixel
// example: 133.0625 (133 + 1/16) should start from line 134, ceil(133.0625 - 0.05) still above 133
vec4 p;
p.xy = vec2(i_p) - vec2(0.05f, 0.05f);
p.xy = p.xy * VertexScale - VertexOffset;
p.w = 1.0f;
p.xy = vec2(i_p) - vec2(0.05f, 0.05f);
p.xy = p.xy * VertexScale - VertexOffset;
p.w = 1.0f;
#if HAS_CLIP_CONTROL
p.z = float(z) * exp_min32;
p.z = float(z) * exp_min32;
#else
// GLES doesn't support ARB_clip_control, so remap it to -1..1. We also reduce the range from 32 bits
// to 24 bits, which means some games with very large depth ranges will not render correctly. But,
// for most, it's okay, and really, the best we can do.
p.z = min(float(z) * exp2(-23.0f), 2.0f) - 1.0f;
// GLES doesn't support ARB_clip_control, so remap it to -1..1. We also reduce the range from 32 bits
// to 24 bits, which means some games with very large depth ranges will not render correctly. But,
// for most, it's okay, and really, the best we can do.
p.z = min(float(z) * exp2(-23.0f), 2.0f) - 1.0f;
#endif
gl_Position = p;
gl_Position = p;
texture_coord();
texture_coord();
VSout.c = i_c;
VSout.t_float.z = i_f.x; // pack for with texture
VSout.c = i_c;
VSout.t_float.z = i_f.x; // pack for with texture
#if VS_POINT_SIZE
gl_PointSize = PointSize.x;
#endif
#if VS_POINT_SIZE
gl_PointSize = PointSize.x;
#endif
}
#endif
#else // VS_EXPAND
#ifdef GEOMETRY_SHADER
in SHADER
struct RawVertex
{
vec4 t_float;
vec4 t_int;
#if GS_IIP != 0
vec4 c;
#else
flat vec4 c;
#endif
} GSin[];
out SHADER
{
vec4 t_float;
vec4 t_int;
#if GS_IIP != 0
vec4 c;
#else
flat vec4 c;
#endif
} GSout;
struct vertex
{
vec4 t_float;
vec4 t_int;
vec4 c;
vec2 ST;
uint RGBA;
float Q;
uint XY;
uint Z;
uint UV;
uint FOG;
};
void out_vertex(in vec4 position, in vertex v)
layout(std140, binding = 2) readonly buffer VertexBuffer {
RawVertex vertex_buffer[];
};
struct ProcessedVertex
{
GSout.t_float = v.t_float;
GSout.t_int = v.t_int;
// Flat output
#if GS_POINT == 1
GSout.c = GSin[0].c;
vec4 p;
vec4 t_float;
vec4 t_int;
vec4 c;
};
ProcessedVertex load_vertex(uint index)
{
#if defined(GL_ARB_shader_draw_parameters) && GL_ARB_shader_draw_parameters
RawVertex rvtx = vertex_buffer[index + gl_BaseVertexARB];
#else
GSout.c = GSin[1].c;
RawVertex rvtx = vertex_buffer[index];
#endif
gl_Position = position;
gl_PrimitiveID = gl_PrimitiveIDIn;
EmitVertex();
}
#if GS_POINT == 1
layout(points) in;
vec2 i_st = rvtx.ST;
vec4 i_c = vec4(uvec4(bitfieldExtract(rvtx.RGBA, 0, 8), bitfieldExtract(rvtx.RGBA, 8, 8),
bitfieldExtract(rvtx.RGBA, 16, 8), bitfieldExtract(rvtx.RGBA, 24, 8)));
float i_q = rvtx.Q;
uvec2 i_p = uvec2(bitfieldExtract(rvtx.XY, 0, 16), bitfieldExtract(rvtx.XY, 16, 16));
uint i_z = rvtx.Z;
uvec2 i_uv = uvec2(bitfieldExtract(rvtx.UV, 0, 16), bitfieldExtract(rvtx.UV, 16, 16));
vec4 i_f = unpackUnorm4x8(rvtx.FOG);
ProcessedVertex vtx;
uint z = min(i_z, MaxDepth);
vtx.p.xy = vec2(i_p) - vec2(0.05f, 0.05f);
vtx.p.xy = vtx.p.xy * VertexScale - VertexOffset;
vtx.p.w = 1.0f;
#if HAS_CLIP_CONTROL
vtx.p.z = float(z) * exp_min32;
#else
layout(lines) in;
vtx.p.z = min(float(z) * exp2(-23.0f), 2.0f) - 1.0f;
#endif
layout(triangle_strip, max_vertices = 4) out;
#if GS_POINT == 1
vec2 uv = vec2(i_uv) - TextureOffset;
vec2 st = i_st - TextureOffset;
void gs_main()
{
// Transform a point to a NxN sprite
vertex point = vertex(GSin[0].t_float, GSin[0].t_int, GSin[0].c);
// Get new position
vec4 lt_p = gl_in[0].gl_Position;
vec4 rb_p = gl_in[0].gl_Position + vec4(PointSize.x, PointSize.y, 0.0f, 0.0f);
vec4 lb_p = rb_p;
vec4 rt_p = rb_p;
lb_p.x = lt_p.x;
rt_p.y = lt_p.y;
out_vertex(lt_p, point);
out_vertex(lb_p, point);
out_vertex(rt_p, point);
out_vertex(rb_p, point);
EndPrimitive();
}
#elif GS_LINE == 1
void gs_main()
{
// Transform a line to a thick line-sprite
vertex left = vertex(GSin[0].t_float, GSin[0].t_int, GSin[0].c);
vertex right = vertex(GSin[1].t_float, GSin[1].t_int, GSin[1].c);
vec4 lt_p = gl_in[0].gl_Position;
vec4 rt_p = gl_in[1].gl_Position;
// Potentially there is faster math
vec2 line_vector = normalize(rt_p.xy - lt_p.xy);
vec2 line_normal = vec2(line_vector.y, -line_vector.x);
vec2 line_width = (line_normal * PointSize) / 2.0f;
lt_p.xy -= line_width;
rt_p.xy -= line_width;
vec4 lb_p = gl_in[0].gl_Position + vec4(line_width, 0.0f, 0.0f);
vec4 rb_p = gl_in[1].gl_Position + vec4(line_width, 0.0f, 0.0f);
out_vertex(lt_p, left);
out_vertex(lb_p, left);
out_vertex(rt_p, right);
out_vertex(rb_p, right);
EndPrimitive();
}
vtx.t_float.xy = st;
vtx.t_float.w = i_q;
vtx.t_int.xy = uv * TextureScale;
#if VS_FST
vtx.t_int.zw = uv;
#else
vtx.t_int.zw = st / TextureScale;
#endif
void gs_main()
{
// left top => GSin[0];
// right bottom => GSin[1];
vertex rb = vertex(GSin[1].t_float, GSin[1].t_int, GSin[1].c);
vertex lt = vertex(GSin[0].t_float, GSin[0].t_int, GSin[0].c);
vtx.c = i_c;
vtx.t_float.z = i_f.x;
vec4 rb_p = gl_in[1].gl_Position;
vec4 lb_p = rb_p;
vec4 rt_p = rb_p;
vec4 lt_p = gl_in[0].gl_Position;
// flat depth
lt_p.z = rb_p.z;
// flat fog and texture perspective
lt.t_float.zw = rb.t_float.zw;
// flat color
lt.c = rb.c;
// Swap texture and position coordinate
vertex lb = rb;
lb.t_float.x = lt.t_float.x;
lb.t_int.x = lt.t_int.x;
lb.t_int.z = lt.t_int.z;
lb_p.x = lt_p.x;
vertex rt = rb;
rt_p.y = lt_p.y;
rt.t_float.y = lt.t_float.y;
rt.t_int.y = lt.t_int.y;
rt.t_int.w = lt.t_int.w;
out_vertex(lt_p, lt);
out_vertex(lb_p, lb);
out_vertex(rt_p, rt);
out_vertex(rb_p, rb);
EndPrimitive();
return vtx;
}
void main()
{
ProcessedVertex vtx;
#if defined(GL_ARB_shader_draw_parameters) && GL_ARB_shader_draw_parameters
uint vid = uint(gl_VertexID - gl_BaseVertexARB);
#else
uint vid = uint(gl_VertexID);
#endif
#if VS_EXPAND == 1 // Point
vtx = load_vertex(vid >> 2);
vtx.p.x += ((vid & 1u) != 0u) ? PointSize.x : 0.0f;
vtx.p.y += ((vid & 2u) != 0u) ? PointSize.y : 0.0f;
#elif VS_EXPAND == 2 // Line
uint vid_base = vid >> 2;
bool is_bottom = (vid & 2u) != 0u;
bool is_right = (vid & 1u) != 0u;
uint vid_other = is_bottom ? vid_base - 1 : vid_base + 1;
vtx = load_vertex(vid_base);
ProcessedVertex other = load_vertex(vid_other);
vec2 line_vector = normalize(vtx.p.xy - other.p.xy);
vec2 line_normal = vec2(line_vector.y, -line_vector.x);
vec2 line_width = (line_normal * PointSize) / 2;
// line_normal is inverted for bottom point
vec2 offset = ((uint(is_bottom) ^ uint(is_right)) != 0u) ? line_width : -line_width;
vtx.p.xy += offset;
// Lines will be run as (0 1 2) (1 2 3)
// This means that both triangles will have a point based off the top line point as their first point
// So we don't have to do anything for !IIP
#elif VS_EXPAND == 3 // Sprite
// Sprite points are always in pairs
uint vid_base = vid >> 1;
uint vid_lt = vid_base & ~1u;
uint vid_rb = vid_base | 1u;
ProcessedVertex lt = load_vertex(vid_lt);
ProcessedVertex rb = load_vertex(vid_rb);
vtx = rb;
bool is_right = ((vid & 1u) != 0u);
vtx.p.x = is_right ? lt.p.x : vtx.p.x;
vtx.t_float.x = is_right ? lt.t_float.x : vtx.t_float.x;
vtx.t_int.xz = is_right ? lt.t_int.xz : vtx.t_int.xz;
bool is_bottom = ((vid & 2u) != 0u);
vtx.p.y = is_bottom ? lt.p.y : vtx.p.y;
vtx.t_float.y = is_bottom ? lt.t_float.y : vtx.t_float.y;
vtx.t_int.yw = is_bottom ? lt.t_int.yw : vtx.t_int.yw;
#endif
gl_Position = vtx.p;
VSout.t_float = vtx.t_float;
VSout.t_int = vtx.t_int;
VSout.c = vtx.c;
}
#endif // VS_EXPAND
#endif // VERTEX_SHADER
+39
View File
@@ -0,0 +1,39 @@
#ifdef VERTEX_SHADER
layout(location = 0) in vec2 Position;
layout(location = 1) in vec2 UV;
layout(location = 2) in vec4 Color;
layout(push_constant) uniform PushConstants
{
vec2 uScale;
vec2 uTranslate;
};
layout(location = 0) out vec2 Frag_UV;
layout(location = 1) out vec4 Frag_Color;
void vs_main()
{
Frag_UV = UV;
Frag_Color = Color;
gl_Position = vec4(Position * uScale + uTranslate, 0.0f, 1.0f);
}
#endif
#ifdef FRAGMENT_SHADER
layout(binding = 0) uniform sampler2D Texture;
layout(location = 0) in vec2 Frag_UV;
layout(location = 1) in vec4 Frag_Color;
layout(location = 0) out vec4 Out_Color;
void ps_main()
{
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
}
#endif
+129 -191
View File
@@ -2,7 +2,7 @@
// Vertex Shader
//////////////////////////////////////////////////////////////////////
#if defined(VERTEX_SHADER) || defined(GEOMETRY_SHADER)
#if defined(VERTEX_SHADER)
layout(std140, set = 0, binding = 0) uniform cb0
{
@@ -15,18 +15,6 @@ layout(std140, set = 0, binding = 0) uniform cb0
uint pad_cb0;
};
#endif
#ifdef VERTEX_SHADER
layout(location = 0) in vec2 a_st;
layout(location = 1) in uvec4 a_c;
layout(location = 2) in float a_q;
layout(location = 3) in uvec2 a_p;
layout(location = 4) in uint a_z;
layout(location = 5) in uvec2 a_uv;
layout(location = 6) in vec4 a_f;
layout(location = 0) out VSOutput
{
vec4 t;
@@ -39,17 +27,27 @@ layout(location = 0) out VSOutput
#endif
} vsOut;
#if VS_EXPAND == 0
layout(location = 0) in vec2 a_st;
layout(location = 1) in uvec4 a_c;
layout(location = 2) in float a_q;
layout(location = 3) in uvec2 a_p;
layout(location = 4) in uint a_z;
layout(location = 5) in uvec2 a_uv;
layout(location = 6) in vec4 a_f;
void main()
{
// Clamp to max depth, gs doesn't wrap
float z = min(a_z, MaxDepth);
uint z = min(a_z, MaxDepth);
// pos -= 0.05 (1/320 pixel) helps avoiding rounding problems (integral part of pos is usually 5 digits, 0.05 is about as low as we can go)
// example: ceil(afterseveralvertextransformations(y = 133)) => 134 => line 133 stays empty
// input granularity is 1/16 pixel, anything smaller than that won't step drawing up/left by one pixel
// example: 133.0625 (133 + 1/16) should start from line 134, ceil(133.0625 - 0.05) still above 133
gl_Position = vec4(a_p, z, 1.0f) - vec4(0.05f, 0.05f, 0, 0);
gl_Position = vec4(a_p, float(z), 1.0f) - vec4(0.05f, 0.05f, 0, 0);
gl_Position.xy = gl_Position.xy * vec2(VertexScale.x, -VertexScale.y) - vec2(VertexOffset.x, -VertexOffset.y);
gl_Position.z *= exp2(-32.0f); // integer->float depth
gl_Position.y = -gl_Position.y;
@@ -81,214 +79,150 @@ void main()
gl_PointSize = PointSize.x;
#endif
vsOut.c = a_c;
vsOut.c = vec4(a_c);
vsOut.t.z = a_f.r;
}
#endif
#else // VS_EXPAND
#ifdef GEOMETRY_SHADER
layout(location = 0) in VSOutput
struct RawVertex
{
vec2 ST;
uint RGBA;
float Q;
uint XY;
uint Z;
uint UV;
uint FOG;
};
layout(std140, set = 0, binding = 2) readonly buffer VertexBuffer {
RawVertex vertex_buffer[];
};
struct ProcessedVertex
{
vec4 p;
vec4 t;
vec4 ti;
#if GS_IIP != 0
vec4 c;
vec4 c;
};
ProcessedVertex load_vertex(uint index)
{
RawVertex rvtx = vertex_buffer[gl_BaseVertexARB + index];
vec2 a_st = rvtx.ST;
uvec4 a_c = uvec4(bitfieldExtract(rvtx.RGBA, 0, 8), bitfieldExtract(rvtx.RGBA, 8, 8),
bitfieldExtract(rvtx.RGBA, 16, 8), bitfieldExtract(rvtx.RGBA, 24, 8));
float a_q = rvtx.Q;
uvec2 a_p = uvec2(bitfieldExtract(rvtx.XY, 0, 16), bitfieldExtract(rvtx.XY, 16, 16));
uint a_z = rvtx.Z;
uvec2 a_uv = uvec2(bitfieldExtract(rvtx.UV, 0, 16), bitfieldExtract(rvtx.UV, 16, 16));
vec4 a_f = unpackUnorm4x8(rvtx.FOG);
ProcessedVertex vtx;
uint z = min(a_z, MaxDepth);
vtx.p = vec4(a_p, float(z), 1.0f) - vec4(0.05f, 0.05f, 0, 0);
vtx.p.xy = vtx.p.xy * vec2(VertexScale.x, -VertexScale.y) - vec2(VertexOffset.x, -VertexOffset.y);
vtx.p.z *= exp2(-32.0f); // integer->float depth
vtx.p.y = -vtx.p.y;
#if VS_TME
vec2 uv = a_uv - TextureOffset;
vec2 st = a_st - TextureOffset;
vtx.ti.xy = uv * TextureScale;
#if VS_FST
vtx.ti.zw = uv;
#else
vtx.ti.zw = st / TextureScale;
#endif
vtx.t.xy = st;
vtx.t.w = a_q;
#else
flat vec4 c;
vtx.t = vec4(0.0f, 0.0f, 0.0f, 1.0f);
vtx.ti = vec4(0.0f);
#endif
} gsIn[];
layout(location = 0) out GSOutput
{
vec4 t;
vec4 ti;
#if GS_IIP != 0
vec4 c;
#else
flat vec4 c;
#endif
} gsOut;
vtx.c = a_c;
vtx.t.z = a_f.r;
void WriteVertex(vec4 pos, vec4 t, vec4 ti, vec4 c)
{
#if GS_FORWARD_PRIMID
gl_PrimitiveID = gl_PrimitiveIDIn;
#endif
gl_Position = pos;
gsOut.t = t;
gsOut.ti = ti;
gsOut.c = c;
EmitVertex();
return vtx;
}
//////////////////////////////////////////////////////////////////////
// Geometry Shader
//////////////////////////////////////////////////////////////////////
#if GS_PRIM == 0 && GS_POINT == 0
layout(points) in;
layout(points, max_vertices = 1) out;
void main()
{
WriteVertex(gl_in[0].gl_Position, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
EndPrimitive();
}
#elif GS_PRIM == 0 && GS_POINT == 1
layout(points) in;
layout(triangle_strip, max_vertices = 4) out;
void main()
{
// Transform a point to a NxN sprite
ProcessedVertex vtx;
uint vid = uint(gl_VertexIndex - gl_BaseVertexARB);
// Get new position
vec4 lt_p = gl_in[0].gl_Position;
vec4 rb_p = gl_in[0].gl_Position + vec4(PointSize.x, PointSize.y, 0.0f, 0.0f);
vec4 lb_p = rb_p;
vec4 rt_p = rb_p;
lb_p.x = lt_p.x;
rt_p.y = lt_p.y;
#if VS_EXPAND == 1 // Point
WriteVertex(lt_p, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
WriteVertex(lb_p, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
WriteVertex(rt_p, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
WriteVertex(rb_p, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
vtx = load_vertex(vid >> 2);
EndPrimitive();
}
vtx.p.x += ((vid & 1u) != 0u) ? PointSize.x : 0.0f;
vtx.p.y += ((vid & 2u) != 0u) ? PointSize.y : 0.0f;
#elif GS_PRIM == 1 && GS_LINE == 0
#elif VS_EXPAND == 2 // Line
layout(lines) in;
layout(line_strip, max_vertices = 2) out;
uint vid_base = vid >> 2;
void main()
{
#if GS_IIP == 0
WriteVertex(gl_in[0].gl_Position, gsIn[0].t, gsIn[0].ti, gsIn[1].c);
WriteVertex(gl_in[1].gl_Position, gsIn[1].t, gsIn[1].ti, gsIn[1].c);
bool is_bottom = (vid & 2u) != 0u;
bool is_right = (vid & 1u) != 0u;
#ifdef VS_PROVOKING_VERTEX_LAST
uint vid_other = is_bottom ? vid_base - 1 : vid_base + 1;
#else
WriteVertex(gl_in[0].gl_Position, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
WriteVertex(gl_in[1].gl_Position, gsIn[1].t, gsIn[1].ti, gsIn[1].c);
uint vid_other = is_bottom ? vid_base + 1 : vid_base - 1;
#endif
EndPrimitive();
}
vtx = load_vertex(vid_base);
ProcessedVertex other = load_vertex(vid_other);
#elif GS_PRIM == 1 && GS_LINE == 1
layout(lines) in;
layout(triangle_strip, max_vertices = 4) out;
void main()
{
// Transform a line to a thick line-sprite
vec4 left_t = gsIn[0].t;
vec4 left_ti = gsIn[0].ti;
vec4 left_c = gsIn[0].c;
vec4 right_t = gsIn[1].t;
vec4 right_ti = gsIn[1].ti;
vec4 right_c = gsIn[1].c;
vec4 lt_p = gl_in[0].gl_Position;
vec4 rt_p = gl_in[1].gl_Position;
// Potentially there is faster math
vec2 line_vector = normalize(rt_p.xy - lt_p.xy);
vec2 line_vector = normalize(vtx.p.xy - other.p.xy);
vec2 line_normal = vec2(line_vector.y, -line_vector.x);
vec2 line_width = (line_normal * PointSize) / 2.0;
vec2 line_width = (line_normal * PointSize) / 2;
// line_normal is inverted for bottom point
vec2 offset = ((uint(is_bottom) ^ uint(is_right)) != 0u) ? line_width : -line_width;
vtx.p.xy += offset;
lt_p.xy -= line_width;
rt_p.xy -= line_width;
vec4 lb_p = gl_in[0].gl_Position + vec4(line_width, 0.0, 0.0);
vec4 rb_p = gl_in[1].gl_Position + vec4(line_width, 0.0, 0.0);
// Lines will be run as (0 1 2) (1 2 3)
// This means that both triangles will have a point based off the top line point as their first point
// So we don't have to do anything for !IIP
#if GS_IIP == 0
left_c = right_c;
#endif
#elif VS_EXPAND == 3 // Sprite
WriteVertex(lt_p, left_t, left_ti, left_c);
WriteVertex(lb_p, left_t, left_ti, left_c);
WriteVertex(rt_p, right_t, right_ti, right_c);
WriteVertex(rb_p, right_t, right_ti, right_c);
EndPrimitive();
}
// Sprite points are always in pairs
uint vid_base = vid >> 1;
uint vid_lt = vid_base & ~1u;
uint vid_rb = vid_base | 1u;
#elif GS_PRIM == 2
ProcessedVertex lt = load_vertex(vid_lt);
ProcessedVertex rb = load_vertex(vid_rb);
vtx = rb;
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
bool is_right = ((vid & 1u) != 0u);
vtx.p.x = is_right ? lt.p.x : vtx.p.x;
vtx.t.x = is_right ? lt.t.x : vtx.t.x;
vtx.ti.xz = is_right ? lt.ti.xz : vtx.ti.xz;
void main()
{
#if GS_IIP == 0
WriteVertex(gl_in[0].gl_Position, gsIn[0].t, gsIn[0].ti, gsIn[2].c);
WriteVertex(gl_in[1].gl_Position, gsIn[1].t, gsIn[1].ti, gsIn[2].c);
WriteVertex(gl_in[2].gl_Position, gsIn[2].t, gsIn[2].ti, gsIn[2].c);
#else
WriteVertex(gl_in[0].gl_Position, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
WriteVertex(gl_in[1].gl_Position, gsIn[1].t, gsIn[1].ti, gsIn[0].c);
WriteVertex(gl_in[2].gl_Position, gsIn[2].t, gsIn[2].ti, gsIn[0].c);
#endif
EndPrimitive();
}
#elif GS_PRIM == 3
layout(lines) in;
layout(triangle_strip, max_vertices = 4) out;
void main()
{
vec4 lt_p = gl_in[0].gl_Position;
vec4 lt_t = gsIn[0].t;
vec4 lt_ti = gsIn[0].ti;
vec4 lt_c = gsIn[0].c;
vec4 rb_p = gl_in[1].gl_Position;
vec4 rb_t = gsIn[1].t;
vec4 rb_ti = gsIn[1].ti;
vec4 rb_c = gsIn[1].c;
// flat depth
lt_p.z = rb_p.z;
// flat fog and texture perspective
lt_t.zw = rb_t.zw;
// flat color
lt_c = rb_c;
// Swap texture and position coordinate
vec4 lb_p = rb_p;
vec4 lb_t = rb_t;
vec4 lb_ti = rb_ti;
vec4 lb_c = rb_c;
lb_p.x = lt_p.x;
lb_t.x = lt_t.x;
lb_ti.x = lt_ti.x;
lb_ti.z = lt_ti.z;
vec4 rt_p = rb_p;
vec4 rt_t = rb_t;
vec4 rt_ti = rb_ti;
vec4 rt_c = rb_c;
rt_p.y = lt_p.y;
rt_t.y = lt_t.y;
rt_ti.y = lt_ti.y;
rt_ti.w = lt_ti.w;
WriteVertex(lt_p, lt_t, lt_ti, lt_c);
WriteVertex(lb_p, lb_t, lb_ti, lb_c);
WriteVertex(rt_p, rt_t, rt_ti, rt_c);
WriteVertex(rb_p, rb_t, rb_ti, rb_c);
EndPrimitive();
}
bool is_bottom = ((vid & 2u) != 0u);
vtx.p.y = is_bottom ? lt.p.y : vtx.p.y;
vtx.t.y = is_bottom ? lt.t.y : vtx.t.y;
vtx.ti.yw = is_bottom ? lt.ti.yw : vtx.ti.yw;
#endif
#endif
gl_Position = vtx.p;
vsOut.t = vtx.t;
vsOut.ti = vtx.ti;
vsOut.c = vtx.c;
}
#endif // VS_EXPAND
#endif // VERTEX_SHADER
#ifdef FRAGMENT_SHADER
@@ -684,8 +618,12 @@ ivec2 clamp_wrap_uv_depth(ivec2 uv)
vec4 sample_depth(vec2 st, ivec2 pos)
{
vec2 uv_f = vec2(clamp_wrap_uv_depth(ivec2(st))) * vec2(ScaledScaleFactor);
ivec2 uv = ivec2(uv_f);
#if PS_REGION_RECT == 1
uv_f = clamp(uv_f + STRange.xy, STRange.xy, STRange.zw);
#endif
ivec2 uv = ivec2(uv_f);
vec4 t = vec4(0.0f);
#if (PS_TALES_OF_ABYSS_HLE == 1)
-113
View File
@@ -1,113 +0,0 @@
set(wx_sdl_c_code "
#include <wx/setup.h>
#if (wxUSE_LIBSDL == 0)
#error cmake_WX_SDL
#endif
int main()
{
return 0;
}
")
set(gcc7_mmx_code "
#include <stdio.h>
#include <stdint.h>
#include <xmmintrin.h>
#include <emmintrin.h>
class alignas(16) GSVector4i
{
public:
__m128i m;
explicit GSVector4i(__m128i m)
{
this->m = m;
}
static void storel(void* p, const GSVector4i& v)
{
_mm_storel_epi64((__m128i*)p, v.m);
}
static GSVector4i loadl(const void* p)
{
return GSVector4i(_mm_loadl_epi64((__m128i*)p));
}
bool eq(const GSVector4i& v) const
{
return _mm_movemask_epi8(_mm_cmpeq_epi32(m, v.m)) == 0xffff;
}
};
union GIFRegTRXPOS
{
unsigned long long u64;
void operator = (const GSVector4i& v) {GSVector4i::storel(this, v);}
bool operator != (const union GIFRegTRXPOS& r) const {return !((GSVector4i)r).eq(*this);}
operator GSVector4i() const {return GSVector4i::loadl(this);}
};
extern GIFRegTRXPOS TRXPOS;
GIFRegTRXPOS TRXPOS = {};
void GIFRegHandlerTRXPOS(const GIFRegTRXPOS& p)
{
if(p != TRXPOS)
{
printf(\"foo\");
}
TRXPOS = (GSVector4i)p;
}
int main()
{
GIFRegTRXPOS r = {};
GIFRegHandlerTRXPOS(r);
uint16_t fpu[16] = {0};
__asm__ __volatile__(\"fstenv %0\" : \"=m\"(fpu));
bool ok = fpu[4] == 0xFFFF;
if (!ok) {
printf(\"Wrong MMX state !\");
exit(1);
}
return 0;
}
")
function(GCC7_BUG)
# try_run doesn't work when cross-compiling is enabled. It is completely silly in our case
# as i386 binaries are 100% fine on x64.
set(OLD_CMAKE_CROSSCOMPILING ${CMAKE_CROSSCOMPILING})
set(CMAKE_CROSSCOMPILING 0)
set(IN "${CMAKE_BINARY_DIR}/gcc7_mmx.cpp")
file(WRITE "${IN}" "${gcc7_mmx_code}")
enable_language(CXX)
try_run(
run_result
compile_result_unused
"${CMAKE_BINARY_DIR}"
"${IN}"
CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=-msse -msse2 -O2 -m32 -march=i686"
)
if (${run_result})
message(FATAL_ERROR "GCC 7.0/7.1 generates invalid code => https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80799\n"
"You can either backport the fix or swith to another version of GCC.")
endif()
set(CMAKE_CROSSCOMPILING ${OLD_CMAKE_CROSSCOMPILING})
endfunction()
+12 -34
View File
@@ -34,6 +34,7 @@ if(UNIX AND NOT APPLE)
option(USE_LEGACY_USER_DIRECTORY "Use legacy home/PCSX2 user directory instead of XDG standard" OFF)
option(X11_API "Enable X11 support" ON)
option(WAYLAND_API "Enable Wayland support" ON)
option(DBUS_API "Enable DBus support for screensaver inhibiting" ON)
endif()
if(APPLE)
@@ -52,9 +53,6 @@ if(MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
set(USE_CLANG TRUE)
message(STATUS "Building with Clang/LLVM.")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
set(USE_ICC TRUE)
message(STATUS "Building with Intel's ICC.")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(USE_GCC TRUE)
message(STATUS "Building with GNU GCC")
@@ -106,21 +104,13 @@ include(TargetArch)
target_architecture(PCSX2_TARGET_ARCHITECTURES)
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
message(STATUS "Compiling a ${PCSX2_TARGET_ARCHITECTURES} build on a ${CMAKE_HOST_SYSTEM_PROCESSOR} host.")
else()
message(FATAL_ERROR "Unsupported architecture: ${PCSX2_TARGET_ARCHITECTURES}")
endif()
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
# x86_64 requires -fPIC
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if(NOT DEFINED ARCH_FLAG AND NOT MSVC)
if (DISABLE_ADVANCE_SIMD)
if (USE_ICC)
set(ARCH_FLAG "-msse2 -msse4.1")
else()
set(ARCH_FLAG "-msse -msse2 -msse4.1 -mfxsr")
endif()
set(ARCH_FLAG "-msse -msse2 -msse4.1 -mfxsr")
else()
#set(ARCH_FLAG "-march=native -fabi-version=6")
set(ARCH_FLAG "-march=native")
@@ -128,13 +118,9 @@ if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
elseif(NOT DEFINED ARCH_FLAG AND USE_CLANG_CL)
set(ARCH_FLAG "-msse4.1")
endif()
list(APPEND PCSX2_DEFS _ARCH_64=1 _M_X86=1)
set(_ARCH_64 1)
list(APPEND PCSX2_DEFS _M_X86=1)
set(_M_X86 1)
else()
# All but i386 requires -fPIC
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
message(FATAL_ERROR "Unsupported architecture: ${PCSX2_TARGET_ARCHITECTURES}")
endif()
string(REPLACE " " ";" ARCH_FLAG_LIST "${ARCH_FLAG}")
@@ -149,12 +135,15 @@ option(USE_PGO_OPTIMIZE "Enable PGO optimization (use profile)")
# Note1: Builtin strcmp/memcmp was proved to be slower on Mesa than stdlib version.
# Note2: float operation SSE is impacted by the PCSX2 SSE configuration. In particular, flush to zero denormal.
if(MSVC AND NOT USE_CLANG_CL)
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/Zc:externConstexpr>")
add_compile_options(
"$<$<COMPILE_LANGUAGE:CXX>:/Zc:externConstexpr>"
"$<$<COMPILE_LANGUAGE:CXX>:/Zc:__cplusplus>"
"$<$<COMPILE_LANGUAGE:CXX>:/permissive->"
"/Zo"
"/utf-8"
)
elseif(NOT MSVC)
add_compile_options(-pipe -fvisibility=hidden -pthread -fno-builtin-strcmp -fno-builtin-memcmp -mfpmath=sse)
# -fno-operator-names should only be for C++ files, not C files.
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-operator-names>)
endif()
set(CONFIG_REL_NO_DEB $<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>>)
@@ -220,24 +209,13 @@ endif()
if (MSVC)
set(DEFAULT_WARNINGS)
else()
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-attributes -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers -Wno-format -Wno-format-security)
if (NOT USE_ICC)
list(APPEND DEFAULT_WARNINGS -Wno-unused-value)
endif()
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-attributes -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers -Wno-format -Wno-format-security -Wno-unused-value)
endif()
if (USE_GCC)
list(APPEND DEFAULT_WARNINGS -Wno-stringop-truncation -Wno-stringop-overflow -Wno-maybe-uninitialized )
endif()
# -Wstrict-aliasing=n: to fix one day aliasing issue. n=1/2/3
if (USE_ICC)
set(AGGRESSIVE_WARNING -Wstrict-aliasing)
elseif(NOT MSVC)
set(AGGRESSIVE_WARNING -Wstrict-aliasing -Wstrict-overflow=1)
endif()
if (USE_PGO_GENERATE OR USE_PGO_OPTIMIZE)
add_compile_options("-fprofile-dir=${CMAKE_SOURCE_DIR}/profile")
endif()
@@ -264,7 +242,7 @@ if(USE_CLANG AND TIMETRACE)
add_compile_options(-ftime-trace)
endif()
set(PCSX2_WARNINGS ${DEFAULT_WARNINGS} ${AGGRESSIVE_WARNING})
set(PCSX2_WARNINGS ${DEFAULT_WARNINGS})
if(DISABLE_BUILD_DATE)
message(STATUS "Disabling the inclusion of the binary compile date.")
+13 -21
View File
@@ -5,28 +5,21 @@
# VTUNE_INCLUDE_DIRS include path to jitprofiling.h
# VTUNE_LIBRARIES path to vtune libs
find_path(VTUNE_INCLUDE_DIRS NAMES jitprofiling.h PATHS
/opt/intel/oneapi/vtune/latest/include
/opt/intel/vtune_amplifier_xe_2018/include
/opt/intel/vtune_amplifier_xe_2017/include
/opt/intel/vtune_amplifier_xe_2016/include
set(VTUNE_PATHS
/opt/intel/oneapi/vtune/latest
/opt/intel/vtune_amplifier_xe_2018
/opt/intel/vtune_amplifier_xe_2017
/opt/intel/vtune_amplifier_xe_2016
"C:\\Program Files (x86)\\Intel\\oneAPI\\vtune\\latest"
)
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "i386")
find_library(VTUNE_LIBRARIES NAMES libjitprofiling.a PATHS
/opt/intel/oneapi/vtune/latest/lib32
/opt/intel/vtune_amplifier_xe_2018/lib32
/opt/intel/vtune_amplifier_xe_2017/lib32
/opt/intel/vtune_amplifier_xe_2016/lib32
)
else()
find_library(VTUNE_LIBRARIES NAMES libjitprofiling.a PATHS
/opt/intel/oneapi/vtune/latest/lib64
/opt/intel/vtune_amplifier_xe_2018/lib64
/opt/intel/vtune_amplifier_xe_2017/lib64
/opt/intel/vtune_amplifier_xe_2016/lib64
)
endif()
find_path(VTUNE_INCLUDE_DIRS NAMES jitprofiling.h PATHS ${VTUNE_PATHS} PATH_SUFFIXES include)
find_library(VTUNE_LIBRARIES
NAMES ${CMAKE_STATIC_LIBRARY_PREFIX}jitprofiling${CMAKE_STATIC_LIBRARY_SUFFIX}
PATHS ${VTUNE_PATHS}
PATH_SUFFIXES lib64
)
# handle the QUIETLY and REQUIRED arguments and set VTUNE_FOUND to TRUE if
# all listed variables are TRUE
@@ -41,4 +34,3 @@ if(VTUNE_LIBRARIES AND NOT TARGET Vtune::Vtune)
endif()
mark_as_advanced(VTUNE_FOUND VTUNE_INCLUDE_DIRS VTUNE_LIBRARIES)
+3 -13
View File
@@ -14,6 +14,7 @@ if (WIN32)
add_subdirectory(3rdparty/xz EXCLUDE_FROM_ALL)
add_subdirectory(3rdparty/D3D12MemAlloc EXCLUDE_FROM_ALL)
set(FFMPEG_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/3rdparty/ffmpeg/include")
find_package(Vtune)
else()
find_package(PCAP REQUIRED)
find_package(LibLZMA REQUIRED)
@@ -102,18 +103,7 @@ if(ENABLE_TESTS)
endif()
endif()
#----------------------------------------
# Check correctness of the parameter
# Note: wxWidgets_INCLUDE_DIRS must be defined
#----------------------------------------
include(ApiValidation)
# Blacklist bad GCC
if(GCC_VERSION VERSION_EQUAL "7.0" OR GCC_VERSION VERSION_EQUAL "7.1")
GCC7_BUG()
endif()
if((GCC_VERSION VERSION_EQUAL "9.0" OR GCC_VERSION VERSION_GREATER "9.0") AND GCC_VERSION LESS "9.2")
if(GCC_VERSION VERSION_GREATER_EQUAL "9.0" AND GCC_VERSION VERSION_LESS "9.2")
message(WARNING "
It looks like you are compiling with 9.0.x or 9.1.x. Using these versions is not recommended,
as there is a bug known to cause the compiler to segfault while compiling. See patch
@@ -134,7 +124,7 @@ find_optional_system_library(libzip 3rdparty/libzip 1.8.0)
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.4.0/msvc2022_64/lib/cmake/Qt6)
set(Qt6_DIR ${CMAKE_SOURCE_DIR}/3rdparty/qt/6.5.0/msvc2022_64/lib/cmake/Qt6)
endif()
# Find the Qt components that we need.
+56
View File
@@ -0,0 +1,56 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
#include <type_traits>
#ifdef _MSC_VER
#include <stdlib.h>
#endif
template <typename T>
T ByteSwap(T value)
{
if constexpr (std::is_signed_v<T>)
{
return static_cast<T>(ByteSwap(std::make_unsigned_t<T>(value)));
}
else if constexpr (std::is_same_v<T, std::uint16_t>)
{
#ifdef _MSC_VER
return _byteswap_ushort(value);
#else
return __builtin_bswap16(value);
#endif
}
else if constexpr (std::is_same_v<T, std::uint32_t>)
{
#ifdef _MSC_VER
return _byteswap_ulong(value);
#else
return __builtin_bswap32(value);
#endif
}
else if constexpr (std::is_same_v<T, std::uint64_t>)
{
#ifdef _MSC_VER
return _byteswap_uint64(value);
#else
return __builtin_bswap64(value);
#endif
}
}
+16 -115
View File
@@ -64,6 +64,7 @@ target_sources(common PRIVATE
AlignedMalloc.h
Assertions.h
boost_spsc_queue.hpp
ByteSwap.h
Console.h
CrashHandler.h
DynamicLibrary.h
@@ -126,52 +127,9 @@ target_sources(common PRIVATE
emitter/tools.h
emitter/x86emitter.h
emitter/x86types.h
Darwin/DarwinMisc.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
)
target_sources(common PRIVATE
Vulkan/ShaderCache.cpp
Vulkan/Texture.cpp
Vulkan/Loader.cpp
Vulkan/ShaderCompiler.cpp
Vulkan/Util.cpp
Vulkan/SwapChain.cpp
Vulkan/StreamBuffer.cpp
Vulkan/Context.cpp
Vulkan/Builders.cpp
Vulkan/vk_mem_alloc.cpp
Vulkan/Context.h
Vulkan/Texture.h
Vulkan/ShaderCompiler.h
Vulkan/SwapChain.h
Vulkan/Builders.h
Vulkan/StreamBuffer.h
Vulkan/ShaderCache.h
Vulkan/EntryPoints.h
Vulkan/Loader.h
Vulkan/Util.h
)
endif()
if(USE_VTUNE)
target_link_libraries(common PUBLIC Vtune::Vtune)
endif()
@@ -179,7 +137,7 @@ endif()
if(WIN32)
enable_language(ASM_MASM)
target_sources(common PRIVATE FastJmp.asm)
target_link_libraries(common PUBLIC WIL::WIL D3D12MemAlloc winmm)
target_link_libraries(common PUBLIC WIL::WIL winmm)
target_sources(common PRIVATE
CrashHandler.cpp
CrashHandler.h
@@ -188,24 +146,6 @@ if(WIN32)
HTTPDownloaderWinHTTP.h
StackWalker.cpp
StackWalker.h
D3D11/ShaderCache.cpp
D3D11/ShaderCache.h
D3D11/ShaderCompiler.cpp
D3D11/ShaderCompiler.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
)
endif()
@@ -216,62 +156,23 @@ if(APPLE)
)
target_compile_options(common PRIVATE -fobjc-arc)
target_link_options(common PRIVATE -fobjc-link-runtime)
target_link_libraries(common PRIVATE
"-framework Foundation"
"-framework IOKit"
)
endif()
if(USE_OPENGL)
if(WIN32)
target_sources(common PRIVATE
GL/ContextWGL.cpp
GL/ContextWGL.h
)
target_link_libraries(common PUBLIC opengl32.lib)
elseif(APPLE)
target_sources(common PRIVATE
GL/ContextAGL.mm
GL/ContextAGL.h
)
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()
if(DBUS_API)
target_compile_definitions(common PRIVATE DBUS_API)
find_package(PkgConfig REQUIRED)
pkg_check_modules(DBUS REQUIRED dbus-1)
target_include_directories(common PRIVATE ${DBUS_INCLUDE_DIRS})
target_link_libraries(common PRIVATE ${DBUS_LINK_LIBRARIES})
endif()
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()
if(X11_API AND TARGET PkgConfig::XRANDR)
target_link_libraries(common PRIVATE PkgConfig::XRANDR)
target_compile_definitions(common PRIVATE "HAS_XRANDR=1")
endif()
if (USE_GCC AND CMAKE_INTERPROCEDURAL_OPTIMIZATION)
-120
View File
@@ -1,120 +0,0 @@
/* 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 "common/RedtapeWilCom.h"
#include "common/D3D11/ShaderCompiler.h"
#include <cstdio>
#include <d3d11.h>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace D3D11
{
class ShaderCache
{
public:
ShaderCache();
~ShaderCache();
D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; }
bool UsingDebugShaders() const { return m_debug; }
bool Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_level, u32 version, bool debug);
wil::com_ptr_nothrow<ID3DBlob> GetShaderBlob(ShaderCompiler::Type type, const std::string_view& shader_code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
wil::com_ptr_nothrow<ID3D11VertexShader> GetVertexShader(ID3D11Device* device, const std::string_view& shader_code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
bool GetVertexShaderAndInputLayout(ID3D11Device* device,
ID3D11VertexShader** vs, ID3D11InputLayout** il,
const D3D11_INPUT_ELEMENT_DESC* layout, size_t layout_size,
const std::string_view& shader_code, const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
wil::com_ptr_nothrow<ID3D11GeometryShader> GetGeometryShader(ID3D11Device* device, const std::string_view& shader_code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
wil::com_ptr_nothrow<ID3D11PixelShader> GetPixelShader(ID3D11Device* device, const std::string_view& shader_code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
wil::com_ptr_nothrow<ID3D11ComputeShader> GetComputeShader(ID3D11Device* device, const std::string_view& shader_code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
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;
ShaderCompiler::Type shader_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.shader_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, D3D_FEATURE_LEVEL feature_level,
bool debug);
static CacheIndexKey GetCacheKey(ShaderCompiler::Type type, const std::string_view& shader_code,
const D3D_SHADER_MACRO* macros, const char* entry_point);
bool CreateNew(const std::string& index_filename, const std::string& blob_filename);
bool ReadExisting(const std::string& index_filename, const std::string& blob_filename);
void Close();
wil::com_ptr_nothrow<ID3DBlob> CompileAndAddShaderBlob(const CacheIndexKey& key, const std::string_view& shader_code,
const D3D_SHADER_MACRO* macros, const char* entry_point);
std::FILE* m_index_file = nullptr;
std::FILE* m_blob_file = nullptr;
CacheIndex m_index;
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0;
u32 m_version = 0;
bool m_debug = false;
};
} // namespace D3D11
-215
View File
@@ -1,215 +0,0 @@
/* 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/D3D11/ShaderCompiler.h"
#include "common/Console.h"
#include "common/StringUtil.h"
#include <array>
#include <d3dcompiler.h>
#include <fstream>
static unsigned s_next_bad_shader_id = 1;
wil::com_ptr_nothrow<ID3DBlob> D3D11::ShaderCompiler::CompileShader(Type type, D3D_FEATURE_LEVEL feature_level, bool debug,
const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */)
{
const char* target;
switch (feature_level)
{
case D3D_FEATURE_LEVEL_10_0:
{
static constexpr std::array<const char*, 4> targets = {{"vs_4_0", "gs_4_0", "ps_4_0", "cs_4_0"}};
target = targets[static_cast<int>(type)];
}
break;
case D3D_FEATURE_LEVEL_10_1:
{
static constexpr std::array<const char*, 4> targets = {{"vs_4_1", "gs_4_1", "ps_4_1", "cs_4_1"}};
target = targets[static_cast<int>(type)];
}
break;
case D3D_FEATURE_LEVEL_11_0:
{
static constexpr std::array<const char*, 4> targets = {{"vs_5_0", "gs_5_0", "ps_5_0", "cs_5_0"}};
target = targets[static_cast<int>(type)];
}
break;
case D3D_FEATURE_LEVEL_11_1:
default:
{
static constexpr std::array<const char*, 4> targets = {{"vs_5_1", "gs_5_1", "ps_5_1", "cs_5_1"}};
target = targets[static_cast<int>(type)];
}
break;
}
static constexpr UINT flags_non_debug = D3DCOMPILE_OPTIMIZATION_LEVEL3;
static constexpr UINT flags_debug = D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG;
wil::com_ptr_nothrow<ID3DBlob> blob;
wil::com_ptr_nothrow<ID3DBlob> error_blob;
const HRESULT hr =
D3DCompile(code.data(), code.size(), "0", macros, nullptr, entry_point, target, debug ? flags_debug : flags_non_debug,
0, blob.put(), error_blob.put());
std::string error_string;
if (error_blob)
{
error_string.append(static_cast<const char*>(error_blob->GetBufferPointer()), error_blob->GetBufferSize());
error_blob.reset();
}
if (FAILED(hr))
{
Console.WriteLn("Failed to compile '%s':\n%s", target, error_string.c_str());
std::ofstream ofs(StringUtil::StdStringFromFormat("pcsx2_bad_shader_%u.txt", s_next_bad_shader_id++).c_str(),
std::ofstream::out | std::ofstream::binary);
if (ofs.is_open())
{
ofs << code;
ofs << "\n\nCompile as " << target << " failed: " << hr << "\n";
ofs.write(error_string.c_str(), error_string.size());
ofs.close();
}
return {};
}
if (!error_string.empty())
Console.Warning("'%s' compiled with warnings:\n%s", target, error_string.c_str());
return blob;
}
wil::com_ptr_nothrow<ID3D11VertexShader> D3D11::ShaderCompiler::CompileAndCreateVertexShader(ID3D11Device* device, bool debug,
const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */)
{
wil::com_ptr_nothrow<ID3DBlob> blob = CompileShader(Type::Vertex, device->GetFeatureLevel(), debug, code, macros, entry_point);
if (!blob)
return {};
return CreateVertexShader(device, blob.get());
}
wil::com_ptr_nothrow<ID3D11GeometryShader> D3D11::ShaderCompiler::CompileAndCreateGeometryShader(ID3D11Device* device, bool debug,
const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */)
{
wil::com_ptr_nothrow<ID3DBlob> blob = CompileShader(Type::Geometry, device->GetFeatureLevel(), debug, code, macros, entry_point);
if (!blob)
return {};
return CreateGeometryShader(device, blob.get());
}
wil::com_ptr_nothrow<ID3D11PixelShader> D3D11::ShaderCompiler::CompileAndCreatePixelShader(ID3D11Device* device, bool debug,
const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */)
{
wil::com_ptr_nothrow<ID3DBlob> blob = CompileShader(Type::Pixel, device->GetFeatureLevel(), debug, code, macros, entry_point);
if (!blob)
return {};
return CreatePixelShader(device, blob.get());
}
wil::com_ptr_nothrow<ID3D11ComputeShader> D3D11::ShaderCompiler::CompileAndCreateComputeShader(ID3D11Device* device, bool debug,
const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */)
{
wil::com_ptr_nothrow<ID3DBlob> blob = CompileShader(Type::Compute, device->GetFeatureLevel(), debug, code, macros, entry_point);
if (!blob)
return {};
return CreateComputeShader(device, blob.get());
}
wil::com_ptr_nothrow<ID3D11VertexShader> D3D11::ShaderCompiler::CreateVertexShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length)
{
wil::com_ptr_nothrow<ID3D11VertexShader> shader;
const HRESULT hr = device->CreateVertexShader(bytecode, bytecode_length, nullptr, shader.put());
if (FAILED(hr))
{
Console.Error("Failed to create vertex shader: 0x%08X", hr);
return {};
}
return shader;
}
wil::com_ptr_nothrow<ID3D11VertexShader> D3D11::ShaderCompiler::CreateVertexShader(ID3D11Device* device, const ID3DBlob* blob)
{
return CreateVertexShader(device, const_cast<ID3DBlob*>(blob)->GetBufferPointer(),
const_cast<ID3DBlob*>(blob)->GetBufferSize());
}
wil::com_ptr_nothrow<ID3D11GeometryShader> D3D11::ShaderCompiler::CreateGeometryShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length)
{
wil::com_ptr_nothrow<ID3D11GeometryShader> shader;
const HRESULT hr = device->CreateGeometryShader(bytecode, bytecode_length, nullptr, shader.put());
if (FAILED(hr))
{
Console.Error("Failed to create geometry shader: 0x%08X", hr);
return {};
}
return shader;
}
wil::com_ptr_nothrow<ID3D11GeometryShader> D3D11::ShaderCompiler::CreateGeometryShader(ID3D11Device* device, const ID3DBlob* blob)
{
return CreateGeometryShader(device, const_cast<ID3DBlob*>(blob)->GetBufferPointer(),
const_cast<ID3DBlob*>(blob)->GetBufferSize());
}
wil::com_ptr_nothrow<ID3D11PixelShader> D3D11::ShaderCompiler::CreatePixelShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length)
{
wil::com_ptr_nothrow<ID3D11PixelShader> shader;
const HRESULT hr = device->CreatePixelShader(bytecode, bytecode_length, nullptr, shader.put());
if (FAILED(hr))
{
Console.Error("Failed to create pixel shader: 0x%08X", hr);
return {};
}
return shader;
}
wil::com_ptr_nothrow<ID3D11PixelShader> D3D11::ShaderCompiler::CreatePixelShader(ID3D11Device* device, const ID3DBlob* blob)
{
return CreatePixelShader(device, const_cast<ID3DBlob*>(blob)->GetBufferPointer(),
const_cast<ID3DBlob*>(blob)->GetBufferSize());
}
wil::com_ptr_nothrow<ID3D11ComputeShader> D3D11::ShaderCompiler::CreateComputeShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length)
{
wil::com_ptr_nothrow<ID3D11ComputeShader> shader;
const HRESULT hr = device->CreateComputeShader(bytecode, bytecode_length, nullptr, shader.put());
if (FAILED(hr))
{
Console.Error("Failed to create compute shader: 0x%08X", hr);
return {};
}
return shader;
}
wil::com_ptr_nothrow<ID3D11ComputeShader> D3D11::ShaderCompiler::CreateComputeShader(ID3D11Device* device, const ID3DBlob* blob)
{
return CreateComputeShader(device, const_cast<ID3DBlob*>(blob)->GetBufferPointer(),
const_cast<ID3DBlob*>(blob)->GetBufferSize());
}
-55
View File
@@ -1,55 +0,0 @@
/* 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/RedtapeWindows.h"
#include "common/RedtapeWilCom.h"
#include <d3d11.h>
#include <string_view>
#include <type_traits>
namespace D3D11::ShaderCompiler
{
enum class Type
{
Vertex,
Geometry,
Pixel,
Compute
};
wil::com_ptr_nothrow<ID3DBlob> CompileShader(Type type, D3D_FEATURE_LEVEL feature_level, bool debug, const std::string_view& code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
wil::com_ptr_nothrow<ID3D11VertexShader> CompileAndCreateVertexShader(ID3D11Device* device, bool debug, const std::string_view& code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
wil::com_ptr_nothrow<ID3D11GeometryShader> CompileAndCreateGeometryShader(ID3D11Device* device, bool debug, const std::string_view& code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
wil::com_ptr_nothrow<ID3D11PixelShader> CompileAndCreatePixelShader(ID3D11Device* device, bool debug, const std::string_view& code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
wil::com_ptr_nothrow<ID3D11ComputeShader> CompileAndCreateComputeShader(ID3D11Device* device, bool debug, const std::string_view& code,
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
wil::com_ptr_nothrow<ID3D11VertexShader> CreateVertexShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length);
wil::com_ptr_nothrow<ID3D11VertexShader> CreateVertexShader(ID3D11Device* device, const ID3DBlob* blob);
wil::com_ptr_nothrow<ID3D11GeometryShader> CreateGeometryShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length);
wil::com_ptr_nothrow<ID3D11GeometryShader> CreateGeometryShader(ID3D11Device* device, const ID3DBlob* blob);
wil::com_ptr_nothrow<ID3D11PixelShader> CreatePixelShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length);
wil::com_ptr_nothrow<ID3D11PixelShader> CreatePixelShader(ID3D11Device* device, const ID3DBlob* blob);
wil::com_ptr_nothrow<ID3D11ComputeShader> CreateComputeShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length);
wil::com_ptr_nothrow<ID3D11ComputeShader> CreateComputeShader(ID3D11Device* device, const ID3DBlob* blob);
}; // namespace D3D11::ShaderCompiler
-215
View File
@@ -1,215 +0,0 @@
/* 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 <dxgi1_5.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(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, 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);
enum class WaitType
{
None, ///< Don't wait (async)
Sleep, ///< Wait normally
Spin, ///< Wait by spinning
};
/// Executes the current command list.
bool ExecuteCommandList(WaitType wait_for_completion);
/// Waits for a specific fence.
void WaitForFence(u64 fence, bool spin);
/// 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(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, 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;
-269
View File
@@ -1,269 +0,0 @@
/* 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 "common/RedtapeWilCom.h"
#include <bitset>
#include <cstring>
#include <d3d12.h>
#include <unordered_map>
#include <vector>
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;
bool m_shader_visible = false;
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
-156
View File
@@ -1,156 +0,0 @@
/* 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 "common/RedtapeWilCom.h"
#include <cstdio>
#include <d3d12.h>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace D3D12
{
class ShaderCache
{
public:
template <typename T>
using ComPtr = wil::com_ptr_nothrow<T>;
enum class EntryType
{
VertexShader,
GeometryShader,
PixelShader,
ComputeShader,
GraphicsPipeline,
ComputePipeline,
};
ShaderCache();
~ShaderCache();
__fi D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; }
__fi u32 GetDataVersion() const { return m_data_version; }
__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);
ComPtr<ID3D12PipelineState> GetPipelineState(ID3D12Device* device, const D3D12_COMPUTE_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);
static CacheIndexKey GetPipelineCacheKey(const D3D12_COMPUTE_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);
ComPtr<ID3D12PipelineState> CompileAndAddPipeline(ID3D12Device* device, const CacheIndexKey& key,
const D3D12_COMPUTE_PIPELINE_STATE_DESC& gpdesc);
bool AddPipelineToBlob(const CacheIndexKey& key, ID3D12PipelineState* pso);
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_debug = false;
};
} // namespace D3D12
-77
View File
@@ -1,77 +0,0 @@
/* 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/RedtapeWilCom.h"
#include <d3d12.h>
#include <deque>
#include <utility>
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
-506
View File
@@ -1,506 +0,0 @@
/* 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;
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_write_descriptor(texture.m_write_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_write_descriptor_type(texture.m_write_descriptor_type)
{
texture.m_srv_descriptor = {};
texture.m_write_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_write_descriptor_type = WriteDescriptorType::None;
}
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_write_descriptor = texture.m_write_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_write_descriptor_type = texture.m_write_descriptor_type;
texture.m_srv_descriptor = {};
texture.m_write_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_write_descriptor_type = WriteDescriptorType::None;
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, write_descriptor;
WriteDescriptorType write_descriptor_type = WriteDescriptorType::None;
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 && !(flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS));
write_descriptor_type = Texture::WriteDescriptorType::RTV;
if (!CreateRTVDescriptor(resource.get(), rtv_format, &write_descriptor))
{
g_d3d12_context->GetRTVHeapManager().Free(&srv_descriptor);
return false;
}
}
else if (dsv_format != DXGI_FORMAT_UNKNOWN && !(flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS))
{
write_descriptor_type = Texture::WriteDescriptorType::DSV;
if (!CreateDSVDescriptor(resource.get(), dsv_format, &write_descriptor))
{
g_d3d12_context->GetDSVHeapManager().Free(&srv_descriptor);
return false;
}
}
else if (flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
{
write_descriptor_type = Texture::WriteDescriptorType::UAV;
if (!CreateUAVDescriptor(resource.get(), dsv_format, &write_descriptor))
{
g_d3d12_context->GetDescriptorHeapManager().Free(&srv_descriptor);
return false;
}
}
Destroy(true);
m_resource = std::move(resource);
m_allocation = std::move(allocation);
m_srv_descriptor = std::move(srv_descriptor);
m_write_descriptor = std::move(write_descriptor);
m_width = width;
m_height = height;
m_levels = levels;
m_format = format;
m_state = state;
m_write_descriptor_type = write_descriptor_type;
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, write_descriptor;
WriteDescriptorType write_descriptor_type = WriteDescriptorType::None;
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);
write_descriptor_type = Texture::WriteDescriptorType::RTV;
if (!CreateRTVDescriptor(texture.get(), rtv_format, &write_descriptor))
{
g_d3d12_context->GetRTVHeapManager().Free(&srv_descriptor);
return false;
}
}
else if (dsv_format != DXGI_FORMAT_UNKNOWN)
{
write_descriptor_type = Texture::WriteDescriptorType::DSV;
if (!CreateDSVDescriptor(texture.get(), dsv_format, &write_descriptor))
{
g_d3d12_context->GetDSVHeapManager().Free(&srv_descriptor);
return false;
}
}
else if (desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)
{
write_descriptor_type = Texture::WriteDescriptorType::UAV;
if (!CreateUAVDescriptor(texture.get(), srv_format, &write_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_write_descriptor = std::move(write_descriptor);
m_write_descriptor_type = write_descriptor_type;
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);
switch (m_write_descriptor_type)
{
case Texture::WriteDescriptorType::RTV:
g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetRTVHeapManager(), &m_write_descriptor);
break;
case Texture::WriteDescriptorType::DSV:
g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDSVHeapManager(), &m_write_descriptor);
break;
case Texture::WriteDescriptorType::UAV:
g_d3d12_context->DeferDescriptorDestruction(g_d3d12_context->GetDescriptorHeapManager(), &m_write_descriptor);
break;
case Texture::WriteDescriptorType::None:
default:
break;
}
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);
switch (m_write_descriptor_type)
{
case Texture::WriteDescriptorType::RTV:
g_d3d12_context->GetRTVHeapManager().Free(&m_write_descriptor);
break;
case Texture::WriteDescriptorType::DSV:
g_d3d12_context->GetDSVHeapManager().Free(&m_write_descriptor);
break;
case Texture::WriteDescriptorType::UAV:
g_d3d12_context->GetDescriptorHeapManager().Free(&m_write_descriptor);
break;
case Texture::WriteDescriptorType::None:
default:
break;
}
m_resource.reset();
m_allocation.reset();
}
m_width = 0;
m_height = 0;
m_levels = 0;
m_format = DXGI_FORMAT_UNKNOWN;
m_write_descriptor_type = WriteDescriptorType::None;
}
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);
}
ID3D12GraphicsCommandList* Texture::BeginStreamUpdate(ID3D12GraphicsCommandList* cmdlist, 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(Context::WaitType::None);
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 nullptr;
}
// cmdlist change
cmdlist = g_d3d12_context->GetInitCommandList();
}
*out_data = g_d3d12_context->GetTextureStreamBuffer().GetCurrentHostPointer();
*out_data_pitch = copy_pitch;
return cmdlist;
}
void Texture::EndStreamUpdate(ID3D12GraphicsCommandList* cmdlist, 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(cmdlist, level, x, y, width, height, copy_pitch, sb.GetBuffer(), sb_offset);
}
void Texture::CopyFromBuffer(ID3D12GraphicsCommandList* cmdlist, 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;
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_GENERIC_READ,
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(ID3D12GraphicsCommandList* cmdlist, 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(cmdlist, level, x, y, width, height, upload_pitch, staging_buffer, 0);
return true;
}
void* write_ptr;
u32 write_pitch;
if (!(cmdlist = BeginStreamUpdate(cmdlist, 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(cmdlist, 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;
}
bool Texture::CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh)
{
if (!g_d3d12_context->GetDescriptorHeapManager().Allocate(dh))
{
Console.Error("Failed to allocate UAV descriptor");
return false;
}
const D3D12_UNORDERED_ACCESS_VIEW_DESC desc = {format, D3D12_UAV_DIMENSION_TEXTURE2D};
g_d3d12_context->GetDevice()->CreateUnorderedAccessView(resource, nullptr, &desc, dh->cpu_handle);
return true;
}
-109
View File
@@ -1,109 +0,0 @@
/* 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& GetWriteDescriptor() const { return m_write_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.
ID3D12GraphicsCommandList* BeginStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch);
void EndStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height);
bool LoadData(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch);
void CopyFromBuffer(ID3D12GraphicsCommandList* cmdlist, 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);
static bool CreateUAVDescriptor(ID3D12Resource* resource, DXGI_FORMAT format, DescriptorHandle* dh);
enum class WriteDescriptorType : u8
{
None,
RTV,
DSV,
UAV
};
ComPtr<ID3D12Resource> m_resource;
ComPtr<D3D12MA::Allocation> m_allocation;
DescriptorHandle m_srv_descriptor = {};
DescriptorHandle m_write_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;
WriteDescriptorType m_write_descriptor_type = WriteDescriptorType::None;
};
} // namespace D3D12
-93
View File
@@ -1,93 +0,0 @@
/* 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
@@ -1,77 +0,0 @@
/* 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
+60
View File
@@ -15,8 +15,11 @@
#if defined(__APPLE__)
#include "common/Darwin/DarwinMisc.h"
#include <cstring>
#include <cstdlib>
#include <optional>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <time.h>
@@ -24,6 +27,7 @@
#include <IOKit/pwr_mgt/IOPMLib.h>
#include "common/Pcsx2Types.h"
#include "common/Console.h"
#include "common/General.h"
#include "common/Threading.h"
#include "common/WindowInfo.h"
@@ -89,6 +93,20 @@ static std::string sysctl_str(int category, int name)
return std::string(buf, len > 0 ? len - 1 : 0);
}
static std::optional<u32> sysctlbyname_u32(const char* name)
{
u32 output;
size_t output_size = sizeof(output);
if (0 != sysctlbyname(name, &output, &output_size, nullptr, 0))
return std::nullopt;
if (output_size != sizeof(output))
{
DevCon.WriteLn("(DarwinMisc) sysctl %s gave unexpected size %zd", name, output_size);
return std::nullopt;
}
return output;
}
std::string GetOSVersionString()
{
std::string type = sysctl_str(CTL_KERN, KERN_OSTYPE);
@@ -135,4 +153,46 @@ void Threading::SleepUntil(u64 ticks)
nanosleep(&ts, nullptr);
}
std::vector<DarwinMisc::CPUClass> DarwinMisc::GetCPUClasses()
{
std::vector<CPUClass> out;
if (std::optional<u32> nperflevels = sysctlbyname_u32("hw.nperflevels"))
{
char name[64];
for (u32 i = 0; i < *nperflevels; i++)
{
snprintf(name, sizeof(name), "hw.perflevel%u.physicalcpu", i);
std::optional<u32> physicalcpu = sysctlbyname_u32(name);
snprintf(name, sizeof(name), "hw.perflevel%u.logicalcpu", i);
std::optional<u32> logicalcpu = sysctlbyname_u32(name);
char levelname[64];
size_t levelname_size = sizeof(levelname);
snprintf(name, sizeof(name), "hw.perflevel%u.name", i);
if (0 != sysctlbyname(name, levelname, &levelname_size, nullptr, 0))
strcpy(levelname, "???");
if (!physicalcpu.has_value() || !logicalcpu.has_value())
{
Console.Warning("(DarwinMisc) Perf level %u is missing data on %s cpus!",
i, !physicalcpu.has_value() ? "physical" : "logical");
continue;
}
out.push_back({levelname, *physicalcpu, *logicalcpu});
}
}
else if (std::optional<u32> physcpu = sysctlbyname_u32("hw.physicalcpu"))
{
out.push_back({"Default", *physcpu, sysctlbyname_u32("hw.logicalcpu").value_or(0)});
}
else
{
Console.Warning("(DarwinMisc) Couldn't get cpu core count!");
}
return out;
}
#endif
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
* Copyright (C) 2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -13,5 +13,24 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "GSVertexList.h"
#pragma once
#ifdef __APPLE__
#include <string>
#include <vector>
#include "common/Pcsx2Types.h"
namespace DarwinMisc {
struct CPUClass {
std::string name;
u32 num_physical;
u32 num_logical;
};
std::vector<CPUClass> GetCPUClasses();
}
#endif
-171
View File
@@ -1,171 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/PrecompiledHeader.h"
#include "common/Console.h"
#include "common/GL/Context.h"
#include "glad.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#ifdef __APPLE__
#include <stdlib.h>
#else
#include <malloc.h>
#endif
#if defined(_WIN32) && !defined(_M_ARM64)
#include "common/GL/ContextWGL.h"
#elif defined(__APPLE__)
#include "common/GL/ContextAGL.h"
#else
#ifdef X11_API
#include "common/GL/ContextEGLX11.h"
#endif
#ifdef WAYLAND_API
#include "common/GL/ContextEGLWayland.h"
#endif
#endif
namespace GL
{
static bool ShouldPreferESContext()
{
#ifndef _MSC_VER
const char* value = std::getenv("PREFER_GLES_CONTEXT");
return (value && std::strcmp(value, "1") == 0);
#else
char buffer[2] = {};
size_t buffer_size = sizeof(buffer);
getenv_s(&buffer_size, buffer, "PREFER_GLES_CONTEXT");
return (std::strcmp(buffer, "1") == 0);
#endif
}
Context::Context(const WindowInfo& wi)
: m_wi(wi)
{
}
Context::~Context() = default;
std::vector<Context::FullscreenModeInfo> Context::EnumerateFullscreenModes()
{
return {};
}
std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try)
{
if (ShouldPreferESContext())
{
// move ES versions to the front
Version* new_versions_to_try = static_cast<Version*>(alloca(sizeof(Version) * versions_to_try.size()));
size_t count = 0;
for (size_t i = 0; i < versions_to_try.size(); i++)
{
if (versions_to_try[i].profile == Profile::ES)
new_versions_to_try[count++] = versions_to_try[i];
}
for (size_t i = 0; i < versions_to_try.size(); i++)
{
if (versions_to_try[i].profile != Profile::ES)
new_versions_to_try[count++] = versions_to_try[i];
}
versions_to_try = gsl::span<const Version>(new_versions_to_try, versions_to_try.size());
}
std::unique_ptr<Context> context;
#if defined(_WIN32) && !defined(_M_ARM64)
context = ContextWGL::Create(wi, versions_to_try);
#elif defined(__APPLE__)
context = ContextAGL::Create(wi, versions_to_try);
#endif
#if defined(X11_API)
if (wi.type == WindowInfo::Type::X11)
context = ContextEGLX11::Create(wi, versions_to_try);
#endif
#if defined(WAYLAND_API)
if (wi.type == WindowInfo::Type::Wayland)
context = ContextEGLWayland::Create(wi, versions_to_try);
#endif
if (!context)
return nullptr;
Console.WriteLn("Created an %s context", context->IsGLES() ? "OpenGL ES" : "OpenGL");
// NOTE: Not thread-safe. But this is okay, since we're not going to be creating more than one context at a time.
static Context* context_being_created;
context_being_created = context.get();
// load up glad
if (!context->IsGLES())
{
if (!gladLoadGLLoader([](const char* name) { return context_being_created->GetProcAddress(name); }))
{
Console.Error("Failed to load GL functions for GLAD");
return nullptr;
}
}
else
{
if (!gladLoadGLES2Loader([](const char* name) { return context_being_created->GetProcAddress(name); }))
{
Console.Error("Failed to load GLES functions for GLAD");
return nullptr;
}
}
context_being_created = nullptr;
const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
const char* gl_renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
const char* gl_version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
const char* gl_shading_language_version = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
DevCon.WriteLn(Color_Magenta, "GL_VENDOR: %s", gl_vendor);
DevCon.WriteLn(Color_Magenta, "GL_RENDERER: %s", gl_renderer);
DevCon.WriteLn(Color_Magenta, "GL_VERSION: %s", gl_version);
DevCon.WriteLn(Color_Magenta, "GL_SHADING_LANGUAGE_VERSION: %s", gl_shading_language_version);
return context;
}
gsl::span<const Context::Version> Context::GetAllVersionsList()
{
static constexpr Version vlist[] = {
{Profile::Core, 4, 6},
{Profile::Core, 4, 5},
{Profile::Core, 4, 4},
{Profile::Core, 4, 3},
{Profile::Core, 4, 2},
{Profile::Core, 4, 1},
{Profile::Core, 4, 0},
{Profile::Core, 3, 3},
{Profile::Core, 3, 2},
{Profile::Core, 3, 1},
{Profile::Core, 3, 0},
{Profile::ES, 3, 2},
{Profile::ES, 3, 1},
{Profile::ES, 3, 0},
{Profile::ES, 2, 0},
{Profile::NoProfile, 0, 0}
};
return vlist;
}
} // namespace GL
-80
View File
@@ -1,80 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/WindowInfo.h"
#include <gsl/span>
#include <array>
#include <memory>
#include <vector>
namespace GL {
class Context
{
public:
Context(const WindowInfo& wi);
virtual ~Context();
enum class Profile
{
NoProfile,
Core,
ES
};
struct Version
{
Profile profile;
int major_version;
int minor_version;
};
struct FullscreenModeInfo
{
u32 width;
u32 height;
float refresh_rate;
};
__fi const WindowInfo& GetWindowInfo() const { return m_wi; }
__fi bool IsGLES() const { return (m_version.profile == Profile::ES); }
__fi u32 GetSurfaceWidth() const { return m_wi.surface_width; }
__fi u32 GetSurfaceHeight() const { return m_wi.surface_height; }
virtual void* GetProcAddress(const char* name) = 0;
virtual bool ChangeSurface(const WindowInfo& new_wi) = 0;
virtual void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) = 0;
virtual bool SwapBuffers() = 0;
virtual bool MakeCurrent() = 0;
virtual bool DoneCurrent() = 0;
virtual bool SetSwapInterval(s32 interval) = 0;
virtual std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) = 0;
virtual std::vector<FullscreenModeInfo> EnumerateFullscreenModes();
static std::unique_ptr<Context> Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try);
static std::unique_ptr<Context> Create(const WindowInfo& wi) { return Create(wi, GetAllVersionsList()); }
static gsl::span<const Version> GetAllVersionsList();
protected:
WindowInfo m_wi;
Version m_version = {};
};
} // namespace GL
-62
View File
@@ -1,62 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/GL/Context.h"
#include "glad.h"
#if defined(__APPLE__) && defined(__OBJC__)
#import <AppKit/AppKit.h>
#else
struct NSView;
struct NSOpenGLContext;
struct NSOpenGLPixelFormat;
#endif
namespace GL
{
class ContextAGL final : public Context
{
public:
ContextAGL(const WindowInfo& wi);
~ContextAGL() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try);
void* GetProcAddress(const char* name) override;
bool ChangeSurface(const WindowInfo& new_wi) override;
void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;
bool SwapBuffers() override;
bool MakeCurrent() override;
bool DoneCurrent() override;
bool SetSwapInterval(s32 interval) override;
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
private:
bool Initialize(gsl::span<const Version> versions_to_try);
bool CreateContext(NSOpenGLContext* share_context, int profile, bool make_current);
void BindContextToView();
void CleanupView();
// returns true if dimensions have changed
bool UpdateDimensions();
NSView* m_view = nullptr;
NSOpenGLContext* m_context = nullptr;
NSOpenGLPixelFormat* m_pixel_format = nullptr;
void* m_opengl_module_handle = nullptr;
};
} // namespace GL
-243
View File
@@ -1,243 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/GL/ContextAGL.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "glad.h"
#include <dlfcn.h>
#if ! __has_feature(objc_arc)
#error "Compile this with -fobjc-arc"
#endif
namespace GL
{
ContextAGL::ContextAGL(const WindowInfo& wi)
: Context(wi)
{
m_opengl_module_handle = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_NOW);
if (!m_opengl_module_handle)
Console.Error("Could not open OpenGL.framework, function lookups will probably fail");
}
ContextAGL::~ContextAGL()
{
if ([NSOpenGLContext currentContext] == m_context)
[NSOpenGLContext clearCurrentContext];
CleanupView();
if (m_opengl_module_handle)
dlclose(m_opengl_module_handle);
}
std::unique_ptr<Context> ContextAGL::Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try)
{
std::unique_ptr<ContextAGL> context = std::make_unique<ContextAGL>(wi);
if (!context->Initialize(versions_to_try))
return nullptr;
return context;
}
bool ContextAGL::Initialize(gsl::span<const Version> versions_to_try)
{
for (const Version& cv : versions_to_try)
{
if (cv.profile == Profile::NoProfile && CreateContext(nullptr, NSOpenGLProfileVersionLegacy, true))
{
// we already have the dummy context, so just use that
m_version = cv;
return true;
}
else if (cv.profile == Profile::Core)
{
if (cv.major_version > 4 || cv.minor_version > 1)
continue;
const NSOpenGLPixelFormatAttribute profile = (cv.major_version > 3 || cv.minor_version > 2) ? NSOpenGLProfileVersion4_1Core : NSOpenGLProfileVersion3_2Core;
if (CreateContext(nullptr, static_cast<int>(profile), true))
{
m_version = cv;
return true;
}
}
}
return false;
}
void* ContextAGL::GetProcAddress(const char* name)
{
void* addr = m_opengl_module_handle ? dlsym(m_opengl_module_handle, name) : nullptr;
if (addr)
return addr;
return dlsym(RTLD_NEXT, name);
}
bool ContextAGL::ChangeSurface(const WindowInfo& new_wi)
{
m_wi = new_wi;
BindContextToView();
return true;
}
void ContextAGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/)
{
UpdateDimensions();
}
bool ContextAGL::UpdateDimensions()
{
if (![NSThread isMainThread])
{
bool ret;
dispatch_sync(dispatch_get_main_queue(), [this, &ret]{ ret = UpdateDimensions(); });
return ret;
}
const NSSize window_size = [m_view frame].size;
const CGFloat window_scale = [[m_view window] backingScaleFactor];
const u32 new_width = static_cast<u32>(window_size.width * window_scale);
const u32 new_height = static_cast<u32>(window_size.height * window_scale);
if (m_wi.surface_width == new_width && m_wi.surface_height == new_height)
return false;
m_wi.surface_width = new_width;
m_wi.surface_height = new_height;
[m_context update];
return true;
}
bool ContextAGL::SwapBuffers()
{
[m_context flushBuffer];
return true;
}
bool ContextAGL::MakeCurrent()
{
[m_context makeCurrentContext];
return true;
}
bool ContextAGL::DoneCurrent()
{
[NSOpenGLContext clearCurrentContext];
return true;
}
bool ContextAGL::SetSwapInterval(s32 interval)
{
GLint gl_interval = static_cast<GLint>(interval);
[m_context setValues:&gl_interval forParameter:NSOpenGLCPSwapInterval];
return true;
}
std::unique_ptr<Context> ContextAGL::CreateSharedContext(const WindowInfo& wi)
{
std::unique_ptr<ContextAGL> context = std::make_unique<ContextAGL>(wi);
context->m_context = [[NSOpenGLContext alloc] initWithFormat:m_pixel_format shareContext:m_context];
if (context->m_context == nil)
return nullptr;
context->m_version = m_version;
context->m_pixel_format = m_pixel_format;
if (wi.type == WindowInfo::Type::MacOS)
context->BindContextToView();
return context;
}
bool ContextAGL::CreateContext(NSOpenGLContext* share_context, int profile, bool make_current)
{
if (m_context)
m_context = nullptr;
const NSOpenGLPixelFormatAttribute attribs[] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAOpenGLProfile, static_cast<NSOpenGLPixelFormatAttribute>(profile),
NSOpenGLPFAAccelerated,
0
};
m_pixel_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
if (m_pixel_format == nil)
{
Console.Error("(ContextAGL) Failed to initialize pixel format");
return false;
}
m_context = [[NSOpenGLContext alloc] initWithFormat:m_pixel_format shareContext:nil];
if (m_context == nil)
return false;
if (m_wi.type == WindowInfo::Type::MacOS)
BindContextToView();
if (make_current)
[m_context makeCurrentContext];
return true;
}
void ContextAGL::BindContextToView()
{
if (![NSThread isMainThread])
{
dispatch_sync(dispatch_get_main_queue(), [this]{ BindContextToView(); });
return;
}
#ifdef PCSX2_CORE
m_view = (__bridge NSView*)m_wi.window_handle;
#else
// Drawing to wx's wxView somehow causes fighting between us and wx, resulting in massive CPU usage on the main thread and no image
// Avoid that by adding our own subview
CleanupView();
NSView* const superview = (__bridge NSView*)m_wi.window_handle;
m_view = [[NSView alloc] initWithFrame:[superview frame]];
[superview addSubview:m_view];
[m_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
#endif
[m_view setWantsBestResolutionOpenGLSurface:YES];
UpdateDimensions();
[m_context setView:m_view];
}
void ContextAGL::CleanupView()
{
#ifndef PCSX2_CORE
if (![NSThread isMainThread])
{
dispatch_sync(dispatch_get_main_queue(), [this]{ CleanupView(); });
return;
}
if (m_view)
[m_view removeFromSuperview];
#endif
m_view = nullptr;
}
} // namespace GL
-391
View File
@@ -1,391 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/PrecompiledHeader.h"
#include "common/Console.h"
#include "ContextEGL.h"
#include <algorithm>
#include <cstring>
#include <optional>
#include <vector>
namespace GL
{
ContextEGL::ContextEGL(const WindowInfo& wi)
: Context(wi)
{
}
ContextEGL::~ContextEGL()
{
DestroySurface();
DestroyContext();
}
std::unique_ptr<Context> ContextEGL::Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try)
{
std::unique_ptr<ContextEGL> context = std::make_unique<ContextEGL>(wi);
if (!context->Initialize(versions_to_try))
return nullptr;
return context;
}
bool ContextEGL::Initialize(gsl::span<const Version> versions_to_try)
{
if (!gladLoadEGL())
{
Console.Error("Loading GLAD EGL functions failed");
return false;
}
if (!SetDisplay())
return false;
int egl_major, egl_minor;
if (!eglInitialize(m_display, &egl_major, &egl_minor))
{
Console.Error("eglInitialize() failed: %d", eglGetError());
return false;
}
Console.WriteLn("EGL Version: %d.%d", egl_major, egl_minor);
const char* extensions = eglQueryString(m_display, EGL_EXTENSIONS);
if (extensions)
{
Console.WriteLn("EGL Extensions: %s", extensions);
m_supports_surfaceless = std::strstr(extensions, "EGL_KHR_surfaceless_context") != nullptr;
}
if (!m_supports_surfaceless)
Console.Warning("EGL implementation does not support surfaceless contexts, emulating with pbuffers");
for (const Version& version : versions_to_try)
{
if (CreateContextAndSurface(version, nullptr, true))
return true;
}
return false;
}
bool ContextEGL::SetDisplay()
{
m_display = eglGetDisplay(static_cast<EGLNativeDisplayType>(m_wi.display_connection));
if (!m_display)
{
Console.Error("eglGetDisplay() failed: %d", eglGetError());
return false;
}
return true;
}
void* ContextEGL::GetProcAddress(const char* name)
{
return reinterpret_cast<void*>(eglGetProcAddress(name));
}
bool ContextEGL::ChangeSurface(const WindowInfo& new_wi)
{
const bool was_current = (eglGetCurrentContext() == m_context);
if (was_current)
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_surface != EGL_NO_SURFACE)
{
eglDestroySurface(m_display, m_surface);
m_surface = EGL_NO_SURFACE;
}
m_wi = new_wi;
if (!CreateSurface())
return false;
if (was_current && !eglMakeCurrent(m_display, m_surface, m_surface, m_context))
{
Console.Error("Failed to make context current again after surface change");
return false;
}
return true;
}
void ContextEGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/)
{
if (new_surface_width == 0 && new_surface_height == 0)
{
EGLint surface_width, surface_height;
if (eglQuerySurface(m_display, m_surface, EGL_WIDTH, &surface_width) &&
eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &surface_height))
{
m_wi.surface_width = static_cast<u32>(surface_width);
m_wi.surface_height = static_cast<u32>(surface_height);
return;
}
else
{
Console.Error("eglQuerySurface() failed: %d", eglGetError());
}
}
m_wi.surface_width = new_surface_width;
m_wi.surface_height = new_surface_height;
}
bool ContextEGL::SwapBuffers()
{
return eglSwapBuffers(m_display, m_surface);
}
bool ContextEGL::MakeCurrent()
{
if (!eglMakeCurrent(m_display, m_surface, m_surface, m_context))
{
Console.Error("eglMakeCurrent() failed: %d", eglGetError());
return false;
}
return true;
}
bool ContextEGL::DoneCurrent()
{
return eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
bool ContextEGL::SetSwapInterval(s32 interval)
{
return eglSwapInterval(m_display, interval);
}
std::unique_ptr<Context> ContextEGL::CreateSharedContext(const WindowInfo& wi)
{
std::unique_ptr<ContextEGL> context = std::make_unique<ContextEGL>(wi);
context->m_display = m_display;
context->m_supports_surfaceless = m_supports_surfaceless;
if (!context->CreateContextAndSurface(m_version, m_context, false))
return nullptr;
return context;
}
EGLNativeWindowType ContextEGL::GetNativeWindow(EGLConfig config)
{
return {};
}
bool ContextEGL::CreateSurface()
{
if (m_wi.type == WindowInfo::Type::Surfaceless)
{
if (m_supports_surfaceless)
return true;
else
return CreatePBufferSurface();
}
EGLNativeWindowType native_window = GetNativeWindow(m_config);
m_surface = eglCreateWindowSurface(m_display, m_config, native_window, nullptr);
if (!m_surface)
{
Console.Error("eglCreateWindowSurface() failed: %d", eglGetError());
return false;
}
// Some implementations may require the size to be queried at runtime.
EGLint surface_width, surface_height;
if (eglQuerySurface(m_display, m_surface, EGL_WIDTH, &surface_width) &&
eglQuerySurface(m_display, m_surface, EGL_HEIGHT, &surface_height))
{
m_wi.surface_width = static_cast<u32>(surface_width);
m_wi.surface_height = static_cast<u32>(surface_height);
}
else
{
Console.Error("eglQuerySurface() failed: %d", eglGetError());
}
return true;
}
bool ContextEGL::CreatePBufferSurface()
{
const u32 width = std::max<u32>(m_wi.surface_width, 1);
const u32 height = std::max<u32>(m_wi.surface_height, 1);
EGLint attrib_list[] = {
EGL_WIDTH, static_cast<EGLint>(width),
EGL_HEIGHT, static_cast<EGLint>(height),
EGL_NONE,
};
m_surface = eglCreatePbufferSurface(m_display, m_config, attrib_list);
if (!m_surface)
{
Console.Error("eglCreatePbufferSurface() failed: %d", eglGetError());
return false;
}
Console.WriteLn("Created %ux%u pbuffer surface", width, height);
return true;
}
bool ContextEGL::CheckConfigSurfaceFormat(EGLConfig config) const
{
int red_size, green_size, blue_size;
if (!eglGetConfigAttrib(m_display, config, EGL_RED_SIZE, &red_size) ||
!eglGetConfigAttrib(m_display, config, EGL_GREEN_SIZE, &green_size) ||
!eglGetConfigAttrib(m_display, config, EGL_BLUE_SIZE, &blue_size))
{
return false;
}
return (red_size == 8 && green_size == 8 && blue_size == 8);
}
void ContextEGL::DestroyContext()
{
if (eglGetCurrentContext() == m_context)
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_context != EGL_NO_CONTEXT)
{
eglDestroyContext(m_display, m_context);
m_context = EGL_NO_CONTEXT;
}
}
void ContextEGL::DestroySurface()
{
if (eglGetCurrentSurface(EGL_DRAW) == m_surface)
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (m_surface != EGL_NO_SURFACE)
{
eglDestroySurface(m_display, m_surface);
m_surface = EGL_NO_SURFACE;
}
}
bool ContextEGL::CreateContext(const Version& version, EGLContext share_context)
{
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"));
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)
{
Console.Error("eglChooseConfig() failed: %d", eglGetError());
return false;
}
std::vector<EGLConfig> configs(static_cast<u32>(num_configs));
if (!eglChooseConfig(m_display, surface_attribs, configs.data(), num_configs, &num_configs))
{
Console.Error("eglChooseConfig() failed: %d", eglGetError());
return false;
}
configs.resize(static_cast<u32>(num_configs));
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))
{
Console.Warning("No EGL configs matched exactly, using first.");
return configs.front();
}
else
{
return *found_config;
}
}();
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))
{
Console.Error("eglBindAPI(%s) failed", (version.profile == Profile::ES) ? "EGL_OPENGL_ES_API" : "EGL_OPENGL_API");
return false;
}
m_context = eglCreateContext(m_display, m_config, share_context, attribs.data());
if (!m_context)
{
Console.Error("eglCreateContext() failed: %d", eglGetError());
return false;
}
Console.WriteLn(
"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_version = version;
return true;
}
bool ContextEGL::CreateContextAndSurface(const Version& version, EGLContext share_context, bool make_current)
{
if (!CreateContext(version, share_context))
return false;
if (!CreateSurface())
{
Console.Error("Failed to create surface for context");
eglDestroyContext(m_display, m_context);
m_context = EGL_NO_CONTEXT;
return false;
}
if (make_current && !eglMakeCurrent(m_display, m_surface, m_surface, m_context))
{
Console.Error("eglMakeCurrent() failed: %d", eglGetError());
if (m_surface != EGL_NO_SURFACE)
{
eglDestroySurface(m_display, m_surface);
m_surface = EGL_NO_SURFACE;
}
eglDestroyContext(m_display, m_context);
m_context = EGL_NO_CONTEXT;
return false;
}
return true;
}
} // namespace GL
-63
View File
@@ -1,63 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/GL/Context.h"
#include "glad_egl.h"
namespace GL
{
class ContextEGL : public Context
{
public:
ContextEGL(const WindowInfo& wi);
~ContextEGL() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try);
void* GetProcAddress(const char* name) override;
virtual bool ChangeSurface(const WindowInfo& new_wi) override;
virtual void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;
bool SwapBuffers() override;
bool MakeCurrent() override;
bool DoneCurrent() override;
bool SetSwapInterval(s32 interval) override;
virtual std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
protected:
virtual bool SetDisplay();
virtual EGLNativeWindowType GetNativeWindow(EGLConfig config);
bool Initialize(gsl::span<const Version> versions_to_try);
bool CreateDisplay();
bool CreateContext(const Version& version, EGLContext share_context);
bool CreateContextAndSurface(const Version& version, EGLContext share_context, bool make_current);
bool CreateSurface();
bool CreatePBufferSurface();
bool CheckConfigSurfaceFormat(EGLConfig config) const;
void DestroyContext();
void DestroySurface();
EGLDisplay m_display = EGL_NO_DISPLAY;
EGLSurface m_surface = EGL_NO_SURFACE;
EGLContext m_context = EGL_NO_CONTEXT;
EGLConfig m_config = {};
bool m_supports_surfaceless = false;
};
} // namespace GL
-104
View File
@@ -1,104 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/PrecompiledHeader.h"
#include "common/Console.h"
#include "ContextEGLWayland.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)
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, gsl::span<const Version> versions_to_try)
{
std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi);
if (!context->LoadModule() || !context->Initialize(versions_to_try))
return nullptr;
return context;
}
std::unique_ptr<Context> ContextEGLWayland::CreateSharedContext(const WindowInfo& wi)
{
std::unique_ptr<ContextEGLWayland> context = std::make_unique<ContextEGLWayland>(wi);
context->m_display = m_display;
if (!context->LoadModule() || !context->CreateContextAndSurface(m_version, m_context, false))
return nullptr;
return context;
}
void ContextEGLWayland::ResizeSurface(u32 new_surface_width, u32 new_surface_height)
{
if (m_wl_window)
m_wl_egl_window_resize(m_wl_window, new_surface_width, new_surface_height, 0, 0);
ContextEGL::ResizeSurface(new_surface_width, new_surface_height);
}
EGLNativeWindowType ContextEGLWayland::GetNativeWindow(EGLConfig config)
{
if (m_wl_window)
{
m_wl_egl_window_destroy(m_wl_window);
m_wl_window = nullptr;
}
m_wl_window =
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
-49
View File
@@ -1,49 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/GL/ContextEGL.h"
struct wl_egl_window;
struct wl_surface;
namespace GL
{
class ContextEGLWayland final : public ContextEGL
{
public:
ContextEGLWayland(const WindowInfo& wi);
~ContextEGLWayland() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try);
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;
protected:
EGLNativeWindowType GetNativeWindow(EGLConfig config) override;
private:
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
-59
View File
@@ -1,59 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/PrecompiledHeader.h"
#include "common/GL/ContextEGLX11.h"
#include <X11/Xlib.h>
namespace GL
{
ContextEGLX11::ContextEGLX11(const WindowInfo& wi)
: ContextEGL(wi)
{
}
ContextEGLX11::~ContextEGLX11() = default;
std::unique_ptr<Context> ContextEGLX11::Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try)
{
std::unique_ptr<ContextEGLX11> context = std::make_unique<ContextEGLX11>(wi);
if (!context->Initialize(versions_to_try))
return nullptr;
return context;
}
std::unique_ptr<Context> ContextEGLX11::CreateSharedContext(const WindowInfo& wi)
{
std::unique_ptr<ContextEGLX11> context = std::make_unique<ContextEGLX11>(wi);
context->m_display = m_display;
if (!context->CreateContextAndSurface(m_version, m_context, false))
return nullptr;
return context;
}
void ContextEGLX11::ResizeSurface(u32 new_surface_width, u32 new_surface_height)
{
ContextEGL::ResizeSurface(new_surface_width, new_surface_height);
}
EGLNativeWindowType ContextEGLX11::GetNativeWindow(EGLConfig config)
{
return (EGLNativeWindowType)reinterpret_cast<Window>(m_wi.window_handle);
}
} // namespace GL
-487
View File
@@ -1,487 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/GL/ContextWGL.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/ScopedGuard.h"
static void* GetProcAddressCallback(const char* name)
{
void* addr = reinterpret_cast<void*>(wglGetProcAddress(name));
if (addr)
return addr;
// try opengl32.dll
return reinterpret_cast<void*>(::GetProcAddress(GetModuleHandleA("opengl32.dll"), name));
}
static bool ReloadWGL(HDC dc)
{
if (!gladLoadWGLLoader([](const char* name) -> void* { return reinterpret_cast<void*>(wglGetProcAddress(name)); }, dc))
{
Console.Error("Loading GLAD WGL functions failed");
return false;
}
return true;
}
namespace GL
{
ContextWGL::ContextWGL(const WindowInfo& wi)
: Context(wi)
{
}
ContextWGL::~ContextWGL()
{
if (wglGetCurrentContext() == m_rc)
wglMakeCurrent(m_dc, nullptr);
if (m_rc)
wglDeleteContext(m_rc);
ReleaseDC();
}
std::unique_ptr<Context> ContextWGL::Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try)
{
std::unique_ptr<ContextWGL> context = std::make_unique<ContextWGL>(wi);
if (!context->Initialize(versions_to_try))
return nullptr;
return context;
}
bool ContextWGL::Initialize(gsl::span<const Version> versions_to_try)
{
if (m_wi.type == WindowInfo::Type::Win32)
{
if (!InitializeDC())
return false;
}
else
{
if (!CreatePBuffer())
return false;
}
// Everything including core/ES requires a dummy profile to load the WGL extensions.
if (!CreateAnyContext(nullptr, true))
return false;
for (const Version& cv : versions_to_try)
{
if (cv.profile == Profile::NoProfile)
{
// we already have the dummy context, so just use that
m_version = cv;
return true;
}
else if (CreateVersionContext(cv, nullptr, true))
{
m_version = cv;
return true;
}
}
return false;
}
void* ContextWGL::GetProcAddress(const char* name)
{
return GetProcAddressCallback(name);
}
bool ContextWGL::ChangeSurface(const WindowInfo& new_wi)
{
const bool was_current = (wglGetCurrentContext() == m_rc);
ReleaseDC();
m_wi = new_wi;
if (!InitializeDC())
return false;
if (was_current && !wglMakeCurrent(m_dc, m_rc))
{
Console.Error("Failed to make context current again after surface change: 0x%08X", GetLastError());
return false;
}
return true;
}
void ContextWGL::ResizeSurface(u32 new_surface_width /*= 0*/, u32 new_surface_height /*= 0*/)
{
RECT client_rc = {};
GetClientRect(GetHWND(), &client_rc);
m_wi.surface_width = static_cast<u32>(client_rc.right - client_rc.left);
m_wi.surface_height = static_cast<u32>(client_rc.bottom - client_rc.top);
}
bool ContextWGL::SwapBuffers()
{
return ::SwapBuffers(m_dc);
}
bool ContextWGL::MakeCurrent()
{
if (!wglMakeCurrent(m_dc, m_rc))
{
Console.Error("wglMakeCurrent() failed: 0x%08X", GetLastError());
return false;
}
return true;
}
bool ContextWGL::DoneCurrent()
{
return wglMakeCurrent(m_dc, nullptr);
}
bool ContextWGL::SetSwapInterval(s32 interval)
{
if (!GLAD_WGL_EXT_swap_control)
return false;
return wglSwapIntervalEXT(interval);
}
std::unique_ptr<Context> ContextWGL::CreateSharedContext(const WindowInfo& wi)
{
std::unique_ptr<ContextWGL> context = std::make_unique<ContextWGL>(wi);
if (wi.type == WindowInfo::Type::Win32)
{
if (!context->InitializeDC())
return nullptr;
}
else
{
if (!context->CreatePBuffer())
return nullptr;
}
if (m_version.profile == Profile::NoProfile)
{
if (!context->CreateAnyContext(m_rc, false))
return nullptr;
}
else
{
if (!context->CreateVersionContext(m_version, m_rc, false))
return nullptr;
}
context->m_version = m_version;
return context;
}
HDC ContextWGL::GetDCAndSetPixelFormat(HWND hwnd)
{
PIXELFORMATDESCRIPTOR pfd = {};
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.dwLayerMask = PFD_MAIN_PLANE;
pfd.cRedBits = 8;
pfd.cGreenBits = 8;
pfd.cBlueBits = 8;
pfd.cColorBits = 24;
HDC hDC = ::GetDC(hwnd);
if (!hDC)
{
Console.Error("GetDC() failed: 0x%08X", GetLastError());
return {};
}
if (!m_pixel_format.has_value())
{
const int pf = ChoosePixelFormat(hDC, &pfd);
if (pf == 0)
{
Console.Error("ChoosePixelFormat() failed: 0x%08X", GetLastError());
::ReleaseDC(hwnd, hDC);
return {};
}
m_pixel_format = pf;
}
if (!SetPixelFormat(hDC, m_pixel_format.value(), &pfd))
{
Console.Error("SetPixelFormat() failed: 0x%08X", GetLastError());
::ReleaseDC(hwnd, hDC);
return {};
}
return hDC;
}
bool ContextWGL::InitializeDC()
{
if (m_wi.type == WindowInfo::Type::Win32)
{
m_dc = GetDCAndSetPixelFormat(GetHWND());
if (!m_dc)
{
Console.Error("Failed to get DC for window");
return false;
}
return true;
}
else if (m_wi.type == WindowInfo::Type::Surfaceless)
{
return CreatePBuffer();
}
else
{
Console.Error("Unknown window info type %u", static_cast<unsigned>(m_wi.type));
return false;
}
}
void ContextWGL::ReleaseDC()
{
if (m_pbuffer)
{
wglReleasePbufferDCARB(m_pbuffer, m_dc);
m_dc = {};
wglDestroyPbufferARB(m_pbuffer);
m_pbuffer = {};
::ReleaseDC(m_dummy_window, m_dummy_dc);
m_dummy_dc = {};
DestroyWindow(m_dummy_window);
m_dummy_window = {};
}
else if (m_dc)
{
::ReleaseDC(GetHWND(), m_dc);
m_dc = {};
}
}
bool ContextWGL::CreatePBuffer()
{
static bool window_class_registered = false;
static const wchar_t* window_class_name = L"ContextWGLPBuffer";
if (!window_class_registered)
{
WNDCLASSEXW wc = {};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.style = 0;
wc.lpfnWndProc = DefWindowProcW;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(nullptr);
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = window_class_name;
wc.hIconSm = NULL;
if (!RegisterClassExW(&wc))
{
Console.Error("(ContextWGL::CreatePBuffer) RegisterClassExW() failed");
return false;
}
window_class_registered = true;
}
HWND hwnd = CreateWindowExW(0, window_class_name, window_class_name, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
if (!hwnd)
{
Console.Error("(ContextWGL::CreatePBuffer) CreateWindowEx() failed");
return false;
}
ScopedGuard hwnd_guard([hwnd]() { DestroyWindow(hwnd); });
HDC hdc = GetDCAndSetPixelFormat(hwnd);
if (!hdc)
return false;
ScopedGuard hdc_guard([hdc, hwnd]() { ::ReleaseDC(hwnd, hdc); });
static constexpr const int pb_attribs[] = {0, 0};
HGLRC temp_rc = nullptr;
ScopedGuard temp_rc_guard([&temp_rc, hdc]() { if (temp_rc) {
wglMakeCurrent(hdc, nullptr);
wglDeleteContext(temp_rc);
} });
if (!GLAD_WGL_ARB_pbuffer)
{
// we're probably running completely surfaceless... need a temporary context.
temp_rc = wglCreateContext(hdc);
if (!temp_rc || !wglMakeCurrent(hdc, temp_rc))
{
Console.Error("Failed to create temporary context to load WGL for pbuffer.");
return false;
}
if (!ReloadWGL(hdc) || !GLAD_WGL_ARB_pbuffer)
{
Console.Error("Missing WGL_ARB_pbuffer");
return false;
}
}
pxAssertRel(m_pixel_format.has_value(), "Has pixel format for pbuffer");
HPBUFFERARB pbuffer = wglCreatePbufferARB(hdc, m_pixel_format.value(), 1, 1, pb_attribs);
if (!pbuffer)
{
Console.Error("(ContextWGL::CreatePBuffer) wglCreatePbufferARB() failed");
return false;
}
ScopedGuard pbuffer_guard([pbuffer]() { wglDestroyPbufferARB(pbuffer); });
m_dc = wglGetPbufferDCARB(pbuffer);
if (!m_dc)
{
Console.Error("(ContextWGL::CreatePbuffer) wglGetPbufferDCARB() failed");
return false;
}
m_dummy_window = hwnd;
m_dummy_dc = hdc;
m_pbuffer = pbuffer;
temp_rc_guard.Run();
pbuffer_guard.Cancel();
hdc_guard.Cancel();
hwnd_guard.Cancel();
return true;
}
bool ContextWGL::CreateAnyContext(HGLRC share_context, bool make_current)
{
m_rc = wglCreateContext(m_dc);
if (!m_rc)
{
Console.Error("wglCreateContext() failed: 0x%08X", GetLastError());
return false;
}
if (make_current)
{
if (!wglMakeCurrent(m_dc, m_rc))
{
Console.Error("wglMakeCurrent() failed: 0x%08X", GetLastError());
return false;
}
// re-init glad-wgl
if (!gladLoadWGLLoader([](const char* name) -> void* { return reinterpret_cast<void*>(wglGetProcAddress(name)); }, m_dc))
{
Console.Error("Loading GLAD WGL functions failed");
return false;
}
}
if (share_context && !wglShareLists(share_context, m_rc))
{
Console.Error("wglShareLists() failed: 0x%08X", GetLastError());
return false;
}
return true;
}
bool ContextWGL::CreateVersionContext(const Version& version, HGLRC share_context, bool make_current)
{
// we need create context attribs
if (!GLAD_WGL_ARB_create_context)
{
Console.Error("Missing GLAD_WGL_ARB_create_context.");
return false;
}
HGLRC new_rc;
if (version.profile == Profile::Core)
{
const int attribs[] = {
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
WGL_CONTEXT_MAJOR_VERSION_ARB, version.major_version,
WGL_CONTEXT_MINOR_VERSION_ARB, version.minor_version,
#ifdef _DEBUG
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB,
#else
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
#endif
0, 0};
new_rc = wglCreateContextAttribsARB(m_dc, share_context, attribs);
}
else if (version.profile == Profile::ES)
{
if ((version.major_version >= 2 && !GLAD_WGL_EXT_create_context_es2_profile) ||
(version.major_version < 2 && !GLAD_WGL_EXT_create_context_es_profile))
{
Console.Error("WGL_EXT_create_context_es_profile not supported");
return false;
}
const int attribs[] = {
WGL_CONTEXT_PROFILE_MASK_ARB, ((version.major_version >= 2) ? WGL_CONTEXT_ES2_PROFILE_BIT_EXT : WGL_CONTEXT_ES_PROFILE_BIT_EXT),
WGL_CONTEXT_MAJOR_VERSION_ARB, version.major_version,
WGL_CONTEXT_MINOR_VERSION_ARB, version.minor_version,
0, 0};
new_rc = wglCreateContextAttribsARB(m_dc, share_context, attribs);
}
else
{
Console.Error("Unknown profile");
return false;
}
if (!new_rc)
return false;
// destroy and swap contexts
if (m_rc)
{
if (!wglMakeCurrent(m_dc, make_current ? new_rc : nullptr))
{
Console.Error("wglMakeCurrent() failed: 0x%08X", GetLastError());
wglDeleteContext(new_rc);
return false;
}
// re-init glad-wgl
if (make_current && !ReloadWGL(m_dc))
return false;
wglDeleteContext(m_rc);
}
m_rc = new_rc;
return true;
}
} // namespace GL
-71
View File
@@ -1,71 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/GL/Context.h"
#include "glad_wgl.h"
#include "glad.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <optional>
namespace GL
{
class ContextWGL final : public Context
{
public:
ContextWGL(const WindowInfo& wi);
~ContextWGL() override;
static std::unique_ptr<Context> Create(const WindowInfo& wi, gsl::span<const Version> versions_to_try);
void* GetProcAddress(const char* name) override;
bool ChangeSurface(const WindowInfo& new_wi) override;
void ResizeSurface(u32 new_surface_width = 0, u32 new_surface_height = 0) override;
bool SwapBuffers() override;
bool MakeCurrent() override;
bool DoneCurrent() override;
bool SetSwapInterval(s32 interval) override;
std::unique_ptr<Context> CreateSharedContext(const WindowInfo& wi) override;
private:
__fi HWND GetHWND() const { return static_cast<HWND>(m_wi.window_handle); }
HDC GetDCAndSetPixelFormat(HWND hwnd);
bool Initialize(gsl::span<const Version> versions_to_try);
bool InitializeDC();
void ReleaseDC();
bool CreatePBuffer();
bool CreateAnyContext(HGLRC share_context, bool make_current);
bool CreateVersionContext(const Version& version, HGLRC share_context, bool make_current);
HDC m_dc = {};
HGLRC m_rc = {};
// Can't change pixel format once it's set for a RC.
std::optional<int> m_pixel_format;
// Dummy window for creating a PBuffer off when we're surfaceless.
HWND m_dummy_window = {};
HDC m_dummy_dc = {};
HPBUFFERARB m_pbuffer = {};
};
} // namespace GL
-673
View File
@@ -1,673 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/PrecompiledHeader.h"
#include "common/GL/Program.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/StringUtil.h"
#include <array>
#include <fstream>
namespace GL
{
GLuint Program::s_last_program_id = 0;
static GLuint s_next_bad_shader_id = 1;
Program::Program() = default;
Program::Program(Program&& prog)
{
m_program_id = prog.m_program_id;
prog.m_program_id = 0;
m_vertex_shader_id = prog.m_vertex_shader_id;
prog.m_vertex_shader_id = 0;
m_fragment_shader_id = prog.m_fragment_shader_id;
prog.m_fragment_shader_id = 0;
m_uniform_locations = std::move(prog.m_uniform_locations);
}
Program::~Program()
{
Destroy();
}
GLuint Program::CompileShader(GLenum type, const std::string_view source)
{
GLuint id = glCreateShader(type);
std::array<const GLchar*, 1> sources = {{source.data()}};
std::array<GLint, 1> source_lengths = {{static_cast<GLint>(source.size())}};
glShaderSource(id, static_cast<GLsizei>(sources.size()), sources.data(), source_lengths.data());
glCompileShader(id);
GLint status = GL_FALSE;
glGetShaderiv(id, GL_COMPILE_STATUS, &status);
GLint info_log_length = 0;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
// Log will create a new line when there are no warnings so let's set a minimum log length of 1.
constexpr int info_log_min_length = 1;
if (status == GL_FALSE || info_log_length > info_log_min_length)
{
std::string info_log;
info_log.resize(info_log_length + 1);
glGetShaderInfoLog(id, info_log_length, &info_log_length, &info_log[0]);
if (status == GL_TRUE)
{
Console.Warning("Shader compiled with warnings:\n%s", info_log.c_str());
}
else
{
Console.Error("Shader failed to compile:\n%s", info_log.c_str());
std::ofstream ofs(StringUtil::StdStringFromFormat("pcsx2_bad_shader_%u.txt", s_next_bad_shader_id++).c_str(),
std::ofstream::out | std::ofstream::binary);
if (ofs.is_open())
{
ofs.write(sources[0], source_lengths[0]);
ofs << "\n\nCompile failed, info log:\n";
ofs << info_log;
ofs.close();
}
glDeleteShader(id);
return 0;
}
}
return id;
}
void Program::ResetLastProgram()
{
s_last_program_id = 0;
}
bool Program::Compile(const std::string_view vertex_shader, const std::string_view geometry_shader,
const std::string_view fragment_shader)
{
GLuint vertex_shader_id = 0;
if (!vertex_shader.empty())
{
vertex_shader_id = CompileShader(GL_VERTEX_SHADER, vertex_shader);
if (vertex_shader_id == 0)
return false;
}
GLuint geometry_shader_id = 0;
if (!geometry_shader.empty())
{
geometry_shader_id = CompileShader(GL_GEOMETRY_SHADER, geometry_shader);
if (geometry_shader_id == 0)
return false;
}
GLuint fragment_shader_id = 0;
if (!fragment_shader.empty())
{
fragment_shader_id = CompileShader(GL_FRAGMENT_SHADER, fragment_shader);
if (fragment_shader_id == 0)
{
glDeleteShader(vertex_shader_id);
return false;
}
}
m_program_id = glCreateProgram();
if (vertex_shader_id != 0)
glAttachShader(m_program_id, vertex_shader_id);
if (geometry_shader_id != 0)
glAttachShader(m_program_id, geometry_shader_id);
if (fragment_shader_id != 0)
glAttachShader(m_program_id, fragment_shader_id);
return true;
}
bool Program::CompileCompute(const std::string_view glsl)
{
GLuint id = CompileShader(GL_COMPUTE_SHADER, glsl);
if (id == 0)
return false;
m_program_id = glCreateProgram();
glAttachShader(m_program_id, id);
return true;
}
bool Program::CreateFromBinary(const void* data, u32 data_length, u32 data_format)
{
GLuint prog = glCreateProgram();
glProgramBinary(prog, static_cast<GLenum>(data_format), data, data_length);
GLint link_status;
glGetProgramiv(prog, GL_LINK_STATUS, &link_status);
if (link_status != GL_TRUE)
{
Console.Error("Failed to create GL program from binary: status %d", link_status);
glDeleteProgram(prog);
return false;
}
m_program_id = prog;
return true;
}
bool Program::GetBinary(std::vector<u8>* out_data, u32* out_data_format)
{
GLint binary_size = 0;
glGetProgramiv(m_program_id, GL_PROGRAM_BINARY_LENGTH, &binary_size);
if (binary_size == 0)
{
Console.Warning("glGetProgramiv(GL_PROGRAM_BINARY_LENGTH) returned 0");
return false;
}
GLenum format = 0;
out_data->resize(static_cast<size_t>(binary_size));
glGetProgramBinary(m_program_id, binary_size, &binary_size, &format, out_data->data());
if (binary_size == 0)
{
Console.Warning("glGetProgramBinary() failed");
return false;
}
else if (static_cast<size_t>(binary_size) != out_data->size())
{
Console.Warning("Size changed from %zu to %d after glGetProgramBinary()", out_data->size(), binary_size);
out_data->resize(static_cast<size_t>(binary_size));
}
*out_data_format = static_cast<u32>(format);
DevCon.WriteLn("Program binary retrieved, %zu bytes, format %u", out_data->size(), *out_data_format);
return true;
}
void Program::SetBinaryRetrievableHint()
{
glProgramParameteri(m_program_id, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE);
}
void Program::BindAttribute(GLuint index, const char* name)
{
glBindAttribLocation(m_program_id, index, name);
}
void Program::BindDefaultAttributes()
{
BindAttribute(0, "a_position");
BindAttribute(1, "a_texcoord");
BindAttribute(2, "a_color");
}
void Program::BindFragData(GLuint index /*= 0*/, const char* name /*= "o_col0"*/)
{
glBindFragDataLocation(m_program_id, index, name);
}
void Program::BindFragDataIndexed(GLuint color_number /*= 0*/, const char* name /*= "o_col0"*/)
{
if (GLAD_GL_VERSION_3_3 || GLAD_GL_ARB_blend_func_extended)
{
glBindFragDataLocationIndexed(m_program_id, color_number, 0, name);
return;
}
else if (GLAD_GL_EXT_blend_func_extended)
{
glBindFragDataLocationIndexedEXT(m_program_id, color_number, 0, name);
return;
}
Console.Error("BindFragDataIndexed() called without ARB or EXT extension, we'll probably crash.");
glBindFragDataLocationIndexed(m_program_id, color_number, 0, name);
}
bool Program::Link()
{
glLinkProgram(m_program_id);
if (m_vertex_shader_id != 0)
glDeleteShader(m_vertex_shader_id);
m_vertex_shader_id = 0;
if (m_fragment_shader_id != 0)
glDeleteShader(m_fragment_shader_id);
m_fragment_shader_id = 0;
GLint status = GL_FALSE;
glGetProgramiv(m_program_id, GL_LINK_STATUS, &status);
GLint info_log_length = 0;
// Log will create a new line when there are no warnings so let's set a minimum log length of 1.
constexpr int info_log_min_length = 1;
glGetProgramiv(m_program_id, GL_INFO_LOG_LENGTH, &info_log_length);
if (status == GL_FALSE || info_log_length > info_log_min_length)
{
std::string info_log;
info_log.resize(info_log_length + 1);
glGetProgramInfoLog(m_program_id, info_log_length, &info_log_length, &info_log[0]);
if (status == GL_TRUE)
{
Console.Error("Program linked with warnings:\n%s", info_log.c_str());
}
else
{
Console.Error("Program failed to link:\n%s", info_log.c_str());
glDeleteProgram(m_program_id);
m_program_id = 0;
return false;
}
}
return true;
}
void Program::Bind() const
{
if (s_last_program_id == m_program_id)
return;
glUseProgram(m_program_id);
s_last_program_id = m_program_id;
}
void Program::Destroy()
{
if (m_vertex_shader_id != 0)
{
glDeleteShader(m_vertex_shader_id);
m_vertex_shader_id = 0;
}
if (m_fragment_shader_id != 0)
{
glDeleteShader(m_fragment_shader_id);
m_fragment_shader_id = 0;
}
if (m_program_id != 0)
{
glDeleteProgram(m_program_id);
m_program_id = 0;
}
m_uniform_locations.clear();
}
int Program::RegisterUniform(const char* name)
{
int id = static_cast<int>(m_uniform_locations.size());
m_uniform_locations.push_back(glGetUniformLocation(m_program_id, name));
return id;
}
void Program::Uniform1ui(int index, u32 x) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform1ui(location, x);
}
void Program::Uniform2ui(int index, u32 x, u32 y) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2ui(location, x, y);
}
void Program::Uniform3ui(int index, u32 x, u32 y, u32 z) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3ui(location, x, y, z);
}
void Program::Uniform4ui(int index, u32 x, u32 y, u32 z, u32 w) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4ui(location, x, y, z, w);
}
void Program::Uniform1i(int index, s32 x) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform1i(location, x);
}
void Program::Uniform2i(int index, s32 x, s32 y) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2i(location, x, y);
}
void Program::Uniform3i(int index, s32 x, s32 y, s32 z) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3i(location, x, y, z);
}
void Program::Uniform4i(int index, s32 x, s32 y, s32 z, s32 w) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4i(location, x, y, z, w);
}
void Program::Uniform1f(int index, float x) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform1f(location, x);
}
void Program::Uniform2f(int index, float x, float y) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2f(location, x, y);
}
void Program::Uniform3f(int index, float x, float y, float z) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3f(location, x, y, z);
}
void Program::Uniform4f(int index, float x, float y, float z, float w) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4f(location, x, y, z, w);
}
void Program::Uniform2uiv(int index, const u32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2uiv(location, 1, v);
}
void Program::Uniform3uiv(int index, const u32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3uiv(location, 1, v);
}
void Program::Uniform4uiv(int index, const u32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4uiv(location, 1, v);
}
void Program::Uniform2iv(int index, const s32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2iv(location, 1, v);
}
void Program::Uniform3iv(int index, const s32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3iv(location, 1, v);
}
void Program::Uniform4iv(int index, const s32* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4iv(location, 1, v);
}
void Program::Uniform2fv(int index, const float* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform2fv(location, 1, v);
}
void Program::Uniform3fv(int index, const float* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform3fv(location, 1, v);
}
void Program::Uniform4fv(int index, const float* v) const
{
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
const GLint location = m_uniform_locations[index];
if (location >= 0)
glUniform4fv(location, 1, v);
}
void Program::Uniform1ui(const char* name, u32 x) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform1ui(location, x);
}
void Program::Uniform2ui(const char* name, u32 x, u32 y) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2ui(location, x, y);
}
void Program::Uniform3ui(const char* name, u32 x, u32 y, u32 z) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3ui(location, x, y, z);
}
void Program::Uniform4ui(const char* name, u32 x, u32 y, u32 z, u32 w) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4ui(location, x, y, z, w);
}
void Program::Uniform1i(const char* name, s32 x) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform1i(location, x);
}
void Program::Uniform2i(const char* name, s32 x, s32 y) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2i(location, x, y);
}
void Program::Uniform3i(const char* name, s32 x, s32 y, s32 z) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3i(location, x, y, z);
}
void Program::Uniform4i(const char* name, s32 x, s32 y, s32 z, s32 w) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4i(location, x, y, z, w);
}
void Program::Uniform1f(const char* name, float x) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform1f(location, x);
}
void Program::Uniform2f(const char* name, float x, float y) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2f(location, x, y);
}
void Program::Uniform3f(const char* name, float x, float y, float z) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3f(location, x, y, z);
}
void Program::Uniform4f(const char* name, float x, float y, float z, float w) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4f(location, x, y, z, w);
}
void Program::Uniform2uiv(const char* name, const u32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2uiv(location, 1, v);
}
void Program::Uniform3uiv(const char* name, const u32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3uiv(location, 1, v);
}
void Program::Uniform4uiv(const char* name, const u32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4uiv(location, 1, v);
}
void Program::Uniform2iv(const char* name, const s32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2iv(location, 1, v);
}
void Program::Uniform3iv(const char* name, const s32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3iv(location, 1, v);
}
void Program::Uniform4iv(const char* name, const s32* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4iv(location, 1, v);
}
void Program::Uniform2fv(const char* name, const float* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform2fv(location, 1, v);
}
void Program::Uniform3fv(const char* name, const float* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform3fv(location, 1, v);
}
void Program::Uniform4fv(const char* name, const float* v) const
{
const GLint location = glGetUniformLocation(m_program_id, name);
if (location >= 0)
glUniform4fv(location, 1, v);
}
void Program::BindUniformBlock(const char* name, u32 index)
{
const GLint location = glGetUniformBlockIndex(m_program_id, name);
if (location >= 0)
glUniformBlockBinding(m_program_id, location, index);
}
void Program::SetName(const std::string_view& name)
{
if (name.empty())
return;
#ifdef _DEBUG
glObjectLabel(GL_PROGRAM, m_program_id, name.length(), name.data());
#endif
}
void Program::SetFormattedName(const char* format, ...)
{
va_list ap;
va_start(ap, format);
std::string n = StringUtil::StdStringFromFormatV(format, ap);
va_end(ap);
SetName(n);
}
Program& Program::operator=(Program&& prog)
{
Destroy();
m_program_id = prog.m_program_id;
prog.m_program_id = 0;
m_vertex_shader_id = prog.m_vertex_shader_id;
prog.m_vertex_shader_id = 0;
m_fragment_shader_id = prog.m_fragment_shader_id;
prog.m_fragment_shader_id = 0;
m_uniform_locations = std::move(prog.m_uniform_locations);
return *this;
}
} // namespace GL
-124
View File
@@ -1,124 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "../Pcsx2Defs.h"
#include "glad.h"
#include <string_view>
#include <vector>
namespace GL
{
class Program
{
public:
Program();
Program(const Program&) = delete;
Program(Program&& prog);
~Program();
static GLuint CompileShader(GLenum type, const std::string_view source);
static void ResetLastProgram();
bool IsValid() const { return m_program_id != 0; }
bool Compile(const std::string_view vertex_shader, const std::string_view geometry_shader,
const std::string_view fragment_shader);
bool CompileCompute(const std::string_view glsl);
bool CreateFromBinary(const void* data, u32 data_length, u32 data_format);
bool GetBinary(std::vector<u8>* out_data, u32* out_data_format);
void SetBinaryRetrievableHint();
void BindAttribute(GLuint index, const char* name);
void BindDefaultAttributes();
void BindFragData(GLuint index = 0, const char* name = "o_col0");
void BindFragDataIndexed(GLuint color_number = 0, const char* name = "o_col0");
bool Link();
void Bind() const;
void Destroy();
int RegisterUniform(const char* name);
void Uniform1ui(int index, u32 x) const;
void Uniform2ui(int index, u32 x, u32 y) const;
void Uniform3ui(int index, u32 x, u32 y, u32 z) const;
void Uniform4ui(int index, u32 x, u32 y, u32 z, u32 w) const;
void Uniform1i(int index, s32 x) const;
void Uniform2i(int index, s32 x, s32 y) const;
void Uniform3i(int index, s32 x, s32 y, s32 z) const;
void Uniform4i(int index, s32 x, s32 y, s32 z, s32 w) const;
void Uniform1f(int index, float x) const;
void Uniform2f(int index, float x, float y) const;
void Uniform3f(int index, float x, float y, float z) const;
void Uniform4f(int index, float x, float y, float z, float w) const;
void Uniform2uiv(int index, const u32* v) const;
void Uniform3uiv(int index, const u32* v) const;
void Uniform4uiv(int index, const u32* v) const;
void Uniform2iv(int index, const s32* v) const;
void Uniform3iv(int index, const s32* v) const;
void Uniform4iv(int index, const s32* v) const;
void Uniform2fv(int index, const float* v) const;
void Uniform3fv(int index, const float* v) const;
void Uniform4fv(int index, const float* v) const;
void Uniform1ui(const char* name, u32 x) const;
void Uniform2ui(const char* name, u32 x, u32 y) const;
void Uniform3ui(const char* name, u32 x, u32 y, u32 z) const;
void Uniform4ui(const char* name, u32 x, u32 y, u32 z, u32 w) const;
void Uniform1i(const char* name, s32 x) const;
void Uniform2i(const char* name, s32 x, s32 y) const;
void Uniform3i(const char* name, s32 x, s32 y, s32 z) const;
void Uniform4i(const char* name, s32 x, s32 y, s32 z, s32 w) const;
void Uniform1f(const char* name, float x) const;
void Uniform2f(const char* name, float x, float y) const;
void Uniform3f(const char* name, float x, float y, float z) const;
void Uniform4f(const char* name, float x, float y, float z, float w) const;
void Uniform2uiv(const char* name, const u32* v) const;
void Uniform3uiv(const char* name, const u32* v) const;
void Uniform4uiv(const char* name, const u32* v) const;
void Uniform2iv(const char* name, const s32* v) const;
void Uniform3iv(const char* name, const s32* v) const;
void Uniform4iv(const char* name, const s32* v) const;
void Uniform2fv(const char* name, const float* v) const;
void Uniform3fv(const char* name, const float* v) const;
void Uniform4fv(const char* name, const float* v) const;
void BindUniformBlock(const char* name, u32 index);
void SetName(const std::string_view& name);
void SetFormattedName(const char* format, ...);
Program& operator=(const Program&) = delete;
Program& operator=(Program&& prog);
__fi bool operator==(const Program& rhs) const { return m_program_id == rhs.m_program_id; }
__fi bool operator!=(const Program& rhs) const { return m_program_id != rhs.m_program_id; }
private:
static u32 s_last_program_id;
GLuint m_program_id = 0;
GLuint m_vertex_shader_id = 0;
GLuint m_fragment_shader_id = 0;
std::vector<GLint> m_uniform_locations;
};
} // namespace GL
-566
View File
@@ -1,566 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/GL/ShaderCache.h"
#include "common/FileSystem.h"
#include "common/Console.h"
#include "common/MD5Digest.h"
#include "common/StringUtil.h"
#include "common/Timer.h"
namespace GL
{
#pragma pack(push, 1)
struct CacheIndexEntry
{
u64 vertex_source_hash_low;
u64 vertex_source_hash_high;
u32 vertex_source_length;
u64 geometry_source_hash_low;
u64 geometry_source_hash_high;
u32 geometry_source_length;
u64 fragment_source_hash_low;
u64 fragment_source_hash_high;
u32 fragment_source_length;
u32 file_offset;
u32 blob_size;
u32 blob_format;
};
#pragma pack(pop)
ShaderCache::ShaderCache() = default;
ShaderCache::~ShaderCache()
{
Close();
}
bool ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const
{
return (
vertex_source_hash_low == key.vertex_source_hash_low && vertex_source_hash_high == key.vertex_source_hash_high &&
vertex_source_length == key.vertex_source_length && geometry_source_hash_low == key.geometry_source_hash_low &&
geometry_source_hash_high == key.geometry_source_hash_high &&
geometry_source_length == key.geometry_source_length && fragment_source_hash_low == key.fragment_source_hash_low &&
fragment_source_hash_high == key.fragment_source_hash_high && fragment_source_length == key.fragment_source_length);
}
bool ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const
{
return (
vertex_source_hash_low != key.vertex_source_hash_low || vertex_source_hash_high != key.vertex_source_hash_high ||
vertex_source_length != key.vertex_source_length || geometry_source_hash_low != key.geometry_source_hash_low ||
geometry_source_hash_high != key.geometry_source_hash_high ||
geometry_source_length != key.geometry_source_length || fragment_source_hash_low != key.fragment_source_hash_low ||
fragment_source_hash_high != key.fragment_source_hash_high || fragment_source_length != key.fragment_source_length);
}
bool ShaderCache::Open(bool is_gles, std::string_view base_path, u32 version)
{
m_base_path = base_path;
m_version = version;
m_program_binary_supported = is_gles || GLAD_GL_ARB_get_program_binary;
if (m_program_binary_supported)
{
// check that there's at least one format and the extension isn't being "faked"
GLint num_formats = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &num_formats);
Console.WriteLn("%u program binary formats supported by driver", num_formats);
m_program_binary_supported = (num_formats > 0);
}
if (!m_program_binary_supported)
{
Console.Warning("Your GL driver does not support program binaries. Hopefully it has a built-in cache.");
return true;
}
if (!base_path.empty())
{
const std::string index_filename = GetIndexFileName();
const std::string blob_filename = GetBlobFileName();
if (ReadExisting(index_filename, blob_filename))
return true;
return CreateNew(index_filename, blob_filename);
}
return true;
}
bool ShaderCache::CreateNew(const std::string& index_filename, const std::string& blob_filename)
{
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());
}
m_index_file = FileSystem::OpenCFile(index_filename.c_str(), "wb");
if (!m_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, m_index_file) != 1 ||
std::fwrite(&m_version, sizeof(m_version), 1, m_index_file) != 1)
{
Console.Error("Failed to write version to index file '%s'", index_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
FileSystem::DeleteFilePath(index_filename.c_str());
return false;
}
m_blob_file = FileSystem::OpenCFile(blob_filename.c_str(), "w+b");
if (!m_blob_file)
{
Console.Error("Failed to open blob file '%s' for writing", blob_filename.c_str());
std::fclose(m_index_file);
m_index_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)
{
m_index_file = FileSystem::OpenCFile(index_filename.c_str(), "r+b");
if (!m_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 = 0;
u32 data_version = 0;
if (std::fread(&file_version, sizeof(file_version), 1, m_index_file) != 1 || file_version != FILE_VERSION ||
std::fread(&data_version, sizeof(data_version), 1, m_index_file) != 1 || data_version != m_version)
{
Console.Error("Bad file/data version in '%s'", index_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
return false;
}
m_blob_file = FileSystem::OpenCFile(blob_filename.c_str(), "a+b");
if (!m_blob_file)
{
Console.Error("Blob file '%s' is missing", blob_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
return false;
}
std::fseek(m_blob_file, 0, SEEK_END);
const u32 blob_file_size = static_cast<u32>(std::ftell(m_blob_file));
for (;;)
{
CacheIndexEntry entry;
if (std::fread(&entry, sizeof(entry), 1, m_index_file) != 1 ||
(entry.file_offset + entry.blob_size) > blob_file_size)
{
if (std::feof(m_index_file))
break;
Console.Error("Failed to read entry from '%s', corrupt file?", index_filename.c_str());
m_index.clear();
std::fclose(m_blob_file);
m_blob_file = nullptr;
std::fclose(m_index_file);
m_index_file = nullptr;
return false;
}
const CacheIndexKey key{
entry.vertex_source_hash_low, entry.vertex_source_hash_high, entry.vertex_source_length,
entry.geometry_source_hash_low, entry.geometry_source_hash_high, entry.geometry_source_length,
entry.fragment_source_hash_low, entry.fragment_source_hash_high, entry.fragment_source_length};
const CacheIndexData data{entry.file_offset, entry.blob_size, entry.blob_format};
m_index.emplace(key, data);
}
Console.WriteLn("Read %zu entries from '%s'", m_index.size(), index_filename.c_str());
return true;
}
void ShaderCache::Close()
{
m_index.clear();
if (m_index_file)
std::fclose(m_index_file);
if (m_blob_file)
std::fclose(m_blob_file);
}
bool ShaderCache::Recreate()
{
Close();
const std::string index_filename = GetIndexFileName();
const std::string blob_filename = GetBlobFileName();
return CreateNew(index_filename, blob_filename);
}
ShaderCache::CacheIndexKey ShaderCache::GetCacheKey(const std::string_view& vertex_shader,
const std::string_view& geometry_shader,
const std::string_view& fragment_shader)
{
union ShaderHash
{
struct
{
u64 low;
u64 high;
};
u8 bytes[16];
};
ShaderHash vertex_hash = {};
ShaderHash geometry_hash = {};
ShaderHash fragment_hash = {};
MD5Digest digest;
if (!vertex_shader.empty())
{
digest.Update(vertex_shader.data(), static_cast<u32>(vertex_shader.length()));
digest.Final(vertex_hash.bytes);
}
if (!geometry_shader.empty())
{
digest.Reset();
digest.Update(geometry_shader.data(), static_cast<u32>(geometry_shader.length()));
digest.Final(geometry_hash.bytes);
}
if (!fragment_shader.empty())
{
digest.Reset();
digest.Update(fragment_shader.data(), static_cast<u32>(fragment_shader.length()));
digest.Final(fragment_hash.bytes);
}
return CacheIndexKey{vertex_hash.low, vertex_hash.high, static_cast<u32>(vertex_shader.length()),
geometry_hash.low, geometry_hash.high, static_cast<u32>(geometry_shader.length()),
fragment_hash.low, fragment_hash.high, static_cast<u32>(fragment_shader.length())};
}
std::string ShaderCache::GetIndexFileName() const
{
return StringUtil::StdStringFromFormat("%s/gl_programs.idx", m_base_path.c_str());
}
std::string ShaderCache::GetBlobFileName() const
{
return StringUtil::StdStringFromFormat("%s/gl_programs.bin", m_base_path.c_str());
}
std::optional<Program> ShaderCache::GetProgram(const std::string_view vertex_shader,
const std::string_view geometry_shader,
const std::string_view fragment_shader, const PreLinkCallback& callback)
{
if (!m_program_binary_supported || !m_blob_file)
{
#ifdef PCSX2_DEVBUILD
Common::Timer timer;
#endif
std::optional<Program> res = CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, false);
#ifdef PCSX2_DEVBUILD
Console.WriteLn("Time to compile shader without caching: %.2fms", timer.GetTimeMilliseconds());
#endif
return res;
}
const auto key = GetCacheKey(vertex_shader, geometry_shader, fragment_shader);
auto iter = m_index.find(key);
if (iter == m_index.end())
return CompileAndAddProgram(key, vertex_shader, geometry_shader, fragment_shader, callback);
std::vector<u8> data(iter->second.blob_size);
if (std::fseek(m_blob_file, iter->second.file_offset, SEEK_SET) != 0 ||
std::fread(data.data(), 1, iter->second.blob_size, m_blob_file) != iter->second.blob_size)
{
Console.Error("Read blob from file failed");
return {};
}
#ifdef PCSX2_DEVBUILD
Common::Timer timer;
#endif
Program prog;
if (prog.CreateFromBinary(data.data(), static_cast<u32>(data.size()), iter->second.blob_format))
{
#ifdef PCSX2_DEVBUILD
Console.WriteLn("Time to create program from binary: %.2fms", timer.GetTimeMilliseconds());
#endif
return std::optional<Program>(std::move(prog));
}
Console.Warning(
"Failed to create program from binary, this may be due to a driver or GPU Change. Recreating cache.");
if (!Recreate())
return CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, false);
else
return CompileAndAddProgram(key, vertex_shader, geometry_shader, fragment_shader, callback);
}
bool ShaderCache::GetProgram(Program* out_program, const std::string_view vertex_shader,
const std::string_view geometry_shader, const std::string_view fragment_shader,
const PreLinkCallback& callback /* = */)
{
auto prog = GetProgram(vertex_shader, geometry_shader, fragment_shader, callback);
if (!prog)
return false;
*out_program = std::move(*prog);
return true;
}
bool ShaderCache::WriteToBlobFile(const CacheIndexKey& key, const std::vector<u8>& prog_data, u32 prog_format)
{
if (!m_blob_file || std::fseek(m_blob_file, 0, SEEK_END) != 0)
return false;
CacheIndexData data;
data.file_offset = static_cast<u32>(std::ftell(m_blob_file));
data.blob_size = static_cast<u32>(prog_data.size());
data.blob_format = prog_format;
CacheIndexEntry entry = {};
entry.vertex_source_hash_low = key.vertex_source_hash_low;
entry.vertex_source_hash_high = key.vertex_source_hash_high;
entry.vertex_source_length = key.vertex_source_length;
entry.geometry_source_hash_low = key.geometry_source_hash_low;
entry.geometry_source_hash_high = key.geometry_source_hash_high;
entry.geometry_source_length = key.geometry_source_length;
entry.fragment_source_hash_low = key.fragment_source_hash_low;
entry.fragment_source_hash_high = key.fragment_source_hash_high;
entry.fragment_source_length = key.fragment_source_length;
entry.file_offset = data.file_offset;
entry.blob_size = data.blob_size;
entry.blob_format = data.blob_format;
if (std::fwrite(prog_data.data(), 1, entry.blob_size, m_blob_file) != entry.blob_size ||
std::fflush(m_blob_file) != 0 || std::fwrite(&entry, sizeof(entry), 1, m_index_file) != 1 ||
std::fflush(m_index_file) != 0)
{
Console.Error("Failed to write shader blob to file");
return false;
}
m_index.emplace(key, data);
return true;
}
std::optional<Program> ShaderCache::CompileProgram(const std::string_view& vertex_shader,
const std::string_view& geometry_shader,
const std::string_view& fragment_shader,
const PreLinkCallback& callback, bool set_retrievable)
{
Program prog;
if (!prog.Compile(vertex_shader, geometry_shader, fragment_shader))
return std::nullopt;
if (callback)
callback(prog);
if (set_retrievable)
prog.SetBinaryRetrievableHint();
if (!prog.Link())
return std::nullopt;
return std::optional<Program>(std::move(prog));
}
std::optional<Program> ShaderCache::CompileComputeProgram(const std::string_view& glsl,
const PreLinkCallback& callback, bool set_retrievable)
{
Program prog;
if (!prog.CompileCompute(glsl))
return std::nullopt;
if (callback)
callback(prog);
if (set_retrievable)
prog.SetBinaryRetrievableHint();
if (!prog.Link())
return std::nullopt;
return std::optional<Program>(std::move(prog));
}
std::optional<Program> ShaderCache::CompileAndAddProgram(const CacheIndexKey& key,
const std::string_view& vertex_shader,
const std::string_view& geometry_shader,
const std::string_view& fragment_shader,
const PreLinkCallback& callback)
{
#ifdef PCSX2_DEVBUILD
Common::Timer timer;
#endif
std::optional<Program> prog = CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, true);
if (!prog)
return std::nullopt;
#ifdef PCSX2_DEVBUILD
const float compile_time = timer.GetTimeMilliseconds();
timer.Reset();
#endif
std::vector<u8> prog_data;
u32 prog_format = 0;
if (!prog->GetBinary(&prog_data, &prog_format))
return std::nullopt;
#ifdef PCSX2_DEVBUILD
const float binary_time = timer.GetTimeMilliseconds();
timer.Reset();
#endif
WriteToBlobFile(key, prog_data, prog_format);
#ifdef PCSX2_DEVBUILD
const float write_time = timer.GetTimeMilliseconds();
Console.WriteLn("Compiled and cached shader: Compile: %.2fms, Binary: %.2fms, Write: %.2fms", compile_time, binary_time, write_time);
#endif
return prog;
}
std::optional<Program> ShaderCache::GetComputeProgram(const std::string_view glsl, const PreLinkCallback& callback)
{
if (!m_program_binary_supported || !m_blob_file)
{
#ifdef PCSX2_DEVBUILD
Common::Timer timer;
#endif
std::optional<Program> res = CompileComputeProgram(glsl, callback, false);
#ifdef PCSX2_DEVBUILD
Console.WriteLn("Time to compile shader without caching: %.2fms", timer.GetTimeMilliseconds());
#endif
return res;
}
const auto key = GetCacheKey(glsl, std::string_view(), std::string_view());
auto iter = m_index.find(key);
if (iter == m_index.end())
return CompileAndAddComputeProgram(key, glsl, callback);
std::vector<u8> data(iter->second.blob_size);
if (std::fseek(m_blob_file, iter->second.file_offset, SEEK_SET) != 0 ||
std::fread(data.data(), 1, iter->second.blob_size, m_blob_file) != iter->second.blob_size)
{
Console.Error("Read blob from file failed");
return {};
}
#ifdef PCSX2_DEVBUILD
Common::Timer timer;
#endif
Program prog;
if (prog.CreateFromBinary(data.data(), static_cast<u32>(data.size()), iter->second.blob_format))
{
#ifdef PCSX2_DEVBUILD
Console.WriteLn("Time to create program from binary: %.2fms", timer.GetTimeMilliseconds());
#endif
return std::optional<Program>(std::move(prog));
}
Console.Warning(
"Failed to create program from binary, this may be due to a driver or GPU Change. Recreating cache.");
if (!Recreate())
return CompileComputeProgram(glsl, callback, false);
else
return CompileAndAddComputeProgram(key, glsl, callback);
}
bool ShaderCache::GetComputeProgram(Program* out_program, const std::string_view glsl, const PreLinkCallback& callback)
{
auto prog = GetComputeProgram(glsl, callback);
if (!prog)
return false;
*out_program = std::move(*prog);
return true;
}
std::optional<Program> ShaderCache::CompileAndAddComputeProgram(
const CacheIndexKey& key, const std::string_view& glsl, const PreLinkCallback& callback)
{
#ifdef PCSX2_DEVBUILD
Common::Timer timer;
#endif
std::optional<Program> prog = CompileComputeProgram(glsl, callback, true);
if (!prog)
return std::nullopt;
#ifdef PCSX2_DEVBUILD
const float compile_time = timer.GetTimeMilliseconds();
timer.Reset();
#endif
std::vector<u8> prog_data;
u32 prog_format = 0;
if (!prog->GetBinary(&prog_data, &prog_format))
return std::nullopt;
#ifdef PCSX2_DEVBUILD
const float binary_time = timer.GetTimeMilliseconds();
timer.Reset();
#endif
WriteToBlobFile(key, prog_data, prog_format);
#ifdef PCSX2_DEVBUILD
const float write_time = timer.GetTimeMilliseconds();
Console.WriteLn("Compiled and cached compute shader: Compile: %.2fms, Binary: %.2fms, Write: %.2fms", compile_time, binary_time, write_time);
#endif
return prog;
}
} // namespace GL
-120
View File
@@ -1,120 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/HashCombine.h"
#include "common/GL/Program.h"
#include <cstdio>
#include <functional>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace GL
{
class ShaderCache
{
public:
using PreLinkCallback = std::function<void(Program&)>;
ShaderCache();
~ShaderCache();
bool Open(bool is_gles, std::string_view base_path, u32 version);
std::optional<Program> GetProgram(const std::string_view vertex_shader, const std::string_view geometry_shader,
const std::string_view fragment_shader, const PreLinkCallback& callback = {});
bool GetProgram(Program* out_program, const std::string_view vertex_shader, const std::string_view geometry_shader,
const std::string_view fragment_shader, const PreLinkCallback& callback = {});
std::optional<Program> GetComputeProgram(const std::string_view glsl, const PreLinkCallback& callback = {});
bool GetComputeProgram(Program* out_program, const std::string_view glsl, const PreLinkCallback& callback = {});
private:
static constexpr u32 FILE_VERSION = 1;
struct CacheIndexKey
{
u64 vertex_source_hash_low;
u64 vertex_source_hash_high;
u32 vertex_source_length;
u64 geometry_source_hash_low;
u64 geometry_source_hash_high;
u32 geometry_source_length;
u64 fragment_source_hash_low;
u64 fragment_source_hash_high;
u32 fragment_source_length;
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.vertex_source_hash_low, e.vertex_source_hash_high, e.vertex_source_length,
e.geometry_source_hash_low, e.geometry_source_hash_high, e.geometry_source_length,
e.fragment_source_hash_low, e.fragment_source_hash_high, e.fragment_source_length);
return h;
}
};
struct CacheIndexData
{
u32 file_offset;
u32 blob_size;
u32 blob_format;
};
using CacheIndex = std::unordered_map<CacheIndexKey, CacheIndexData, CacheIndexEntryHasher>;
static CacheIndexKey GetCacheKey(const std::string_view& vertex_shader, const std::string_view& geometry_shader,
const std::string_view& fragment_shader);
std::string GetIndexFileName() const;
std::string GetBlobFileName() const;
bool CreateNew(const std::string& index_filename, const std::string& blob_filename);
bool ReadExisting(const std::string& index_filename, const std::string& blob_filename);
void Close();
bool Recreate();
bool WriteToBlobFile(const CacheIndexKey& key, const std::vector<u8>& prog_data, u32 prog_format);
std::optional<Program> CompileProgram(const std::string_view& vertex_shader, const std::string_view& geometry_shader,
const std::string_view& fragment_shader, const PreLinkCallback& callback,
bool set_retrievable);
std::optional<Program> CompileAndAddProgram(const CacheIndexKey& key, const std::string_view& vertex_shader,
const std::string_view& geometry_shader,
const std::string_view& fragment_shader, const PreLinkCallback& callback);
std::optional<Program> CompileComputeProgram(const std::string_view& glsl, const PreLinkCallback& callback, bool set_retrievable);
std::optional<Program> CompileAndAddComputeProgram(const CacheIndexKey& key, const std::string_view& glsl, const PreLinkCallback& callback);
std::string m_base_path;
std::FILE* m_index_file = nullptr;
std::FILE* m_blob_file = nullptr;
CacheIndex m_index;
u32 m_version = 0;
bool m_program_binary_supported = false;
};
} // namespace GL
-346
View File
@@ -1,346 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "StreamBuffer.h"
#include "common/Align.h"
#include "common/Assertions.h"
#include <array>
#include <cstring>
namespace GL
{
StreamBuffer::StreamBuffer(GLenum target, GLuint buffer_id, u32 size)
: m_target(target)
, m_buffer_id(buffer_id)
, m_size(size)
{
}
StreamBuffer::~StreamBuffer()
{
glDeleteBuffers(1, &m_buffer_id);
}
void StreamBuffer::Bind()
{
glBindBuffer(m_target, m_buffer_id);
}
void StreamBuffer::Unbind()
{
glBindBuffer(m_target, 0);
}
namespace detail
{
// Uses glBufferSubData() to update. Preferred for drivers which don't support {ARB,EXT}_buffer_storage.
class BufferSubDataStreamBuffer final : public StreamBuffer
{
public:
~BufferSubDataStreamBuffer() override = default;
MappingResult Map(u32 alignment, u32 min_size) override
{
return MappingResult{static_cast<void*>(m_cpu_buffer.data()), 0, 0, m_size / alignment};
}
void Unmap(u32 used_size) override
{
if (used_size == 0)
return;
glBindBuffer(m_target, m_buffer_id);
glBufferSubData(m_target, 0, used_size, m_cpu_buffer.data());
}
u32 GetChunkSize() const override
{
return m_size;
}
static std::unique_ptr<StreamBuffer> Create(GLenum target, u32 size)
{
glGetError();
GLuint buffer_id;
glGenBuffers(1, &buffer_id);
glBindBuffer(target, buffer_id);
glBufferData(target, size, nullptr, GL_STREAM_DRAW);
GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
glBindBuffer(target, 0);
glDeleteBuffers(1, &buffer_id);
return {};
}
return std::unique_ptr<StreamBuffer>(new BufferSubDataStreamBuffer(target, buffer_id, size));
}
private:
BufferSubDataStreamBuffer(GLenum target, GLuint buffer_id, u32 size)
: StreamBuffer(target, buffer_id, size)
, m_cpu_buffer(size)
{
}
std::vector<u8> m_cpu_buffer;
};
// Uses BufferData() to orphan the buffer after every update. Used on Mali where BufferSubData forces a sync.
class BufferDataStreamBuffer final : public StreamBuffer
{
public:
~BufferDataStreamBuffer() override = default;
MappingResult Map(u32 alignment, u32 min_size) override
{
return MappingResult{static_cast<void*>(m_cpu_buffer.data()), 0, 0, m_size / alignment};
}
void Unmap(u32 used_size) override
{
if (used_size == 0)
return;
glBindBuffer(m_target, m_buffer_id);
glBufferData(m_target, used_size, m_cpu_buffer.data(), GL_STREAM_DRAW);
}
u32 GetChunkSize() const override
{
return m_size;
}
static std::unique_ptr<StreamBuffer> Create(GLenum target, u32 size)
{
glGetError();
GLuint buffer_id;
glGenBuffers(1, &buffer_id);
glBindBuffer(target, buffer_id);
glBufferData(target, size, nullptr, GL_STREAM_DRAW);
GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
glBindBuffer(target, 0);
glDeleteBuffers(1, &buffer_id);
return {};
}
return std::unique_ptr<StreamBuffer>(new BufferDataStreamBuffer(target, buffer_id, size));
}
private:
BufferDataStreamBuffer(GLenum target, GLuint buffer_id, u32 size)
: StreamBuffer(target, buffer_id, size)
, m_cpu_buffer(size)
{
}
std::vector<u8> m_cpu_buffer;
};
// Base class for implementations which require syncing.
class SyncingStreamBuffer : public StreamBuffer
{
public:
enum : u32
{
NUM_SYNC_POINTS = 16
};
virtual ~SyncingStreamBuffer() override
{
for (u32 i = m_available_block_index; i <= m_used_block_index; i++)
{
pxAssert(m_sync_objects[i]);
glDeleteSync(m_sync_objects[i]);
}
}
protected:
SyncingStreamBuffer(GLenum target, GLuint buffer_id, u32 size)
: StreamBuffer(target, buffer_id, size)
, m_bytes_per_block((size + (NUM_SYNC_POINTS)-1) / NUM_SYNC_POINTS)
{
}
__fi u32 GetSyncIndexForOffset(u32 offset) { return offset / m_bytes_per_block; }
__fi void AddSyncsForOffset(u32 offset)
{
const u32 end = GetSyncIndexForOffset(offset);
for (; m_used_block_index < end; m_used_block_index++)
{
pxAssert(!m_sync_objects[m_used_block_index]);
m_sync_objects[m_used_block_index] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
}
__fi void WaitForSync(GLsync& sync)
{
glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
glDeleteSync(sync);
sync = nullptr;
}
__fi void EnsureSyncsWaitedForOffset(u32 offset)
{
const u32 end = std::min<u32>(GetSyncIndexForOffset(offset) + 1, NUM_SYNC_POINTS);
for (; m_available_block_index < end; m_available_block_index++)
{
pxAssert(m_sync_objects[m_available_block_index]);
WaitForSync(m_sync_objects[m_available_block_index]);
}
}
void AllocateSpace(u32 size)
{
// add sync objects for writes since the last allocation
AddSyncsForOffset(m_position);
// wait for sync objects for the space we want to use
EnsureSyncsWaitedForOffset(m_position + size);
// wrap-around?
if ((m_position + size) > m_size)
{
// current position ... buffer end
AddSyncsForOffset(m_size);
// rewind, and try again
m_position = 0;
// wait for the sync at the start of the buffer
WaitForSync(m_sync_objects[0]);
m_available_block_index = 1;
// and however much more we need to satisfy the allocation
EnsureSyncsWaitedForOffset(size);
m_used_block_index = 0;
}
}
u32 GetChunkSize() const override
{
return m_size / NUM_SYNC_POINTS;
}
u32 m_position = 0;
u32 m_used_block_index = 0;
u32 m_available_block_index = NUM_SYNC_POINTS;
u32 m_bytes_per_block;
std::array<GLsync, NUM_SYNC_POINTS> m_sync_objects{};
};
class BufferStorageStreamBuffer : public SyncingStreamBuffer
{
public:
~BufferStorageStreamBuffer() override
{
glBindBuffer(m_target, m_buffer_id);
glUnmapBuffer(m_target);
glBindBuffer(m_target, 0);
}
MappingResult Map(u32 alignment, u32 min_size) override
{
if (m_position > 0)
m_position = Common::AlignUp(m_position, alignment);
AllocateSpace(min_size);
pxAssert((m_position + min_size) <= (m_available_block_index * m_bytes_per_block));
const u32 free_space_in_block = ((m_available_block_index * m_bytes_per_block) - m_position);
return MappingResult{static_cast<void*>(m_mapped_ptr + m_position), m_position, m_position / alignment,
free_space_in_block / alignment};
}
void Unmap(u32 used_size) override
{
pxAssert((m_position + used_size) <= m_size);
if (!m_coherent)
{
Bind();
glFlushMappedBufferRange(m_target, m_position, used_size);
}
m_position += used_size;
}
static std::unique_ptr<StreamBuffer> Create(GLenum target, u32 size, bool coherent = true)
{
glGetError();
GLuint buffer_id;
glGenBuffers(1, &buffer_id);
glBindBuffer(target, buffer_id);
const u32 flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? GL_MAP_COHERENT_BIT : 0);
const u32 map_flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | (coherent ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT);
if (GLAD_GL_VERSION_4_4 || GLAD_GL_ARB_buffer_storage)
glBufferStorage(target, size, nullptr, flags);
else if (GLAD_GL_EXT_buffer_storage)
glBufferStorageEXT(target, size, nullptr, flags);
GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
glBindBuffer(target, 0);
glDeleteBuffers(1, &buffer_id);
return {};
}
u8* mapped_ptr = static_cast<u8*>(glMapBufferRange(target, 0, size, map_flags));
pxAssertRel(mapped_ptr, "Persistent buffer was mapped");
return std::unique_ptr<StreamBuffer>(new BufferStorageStreamBuffer(target, buffer_id, size, mapped_ptr, coherent));
}
private:
BufferStorageStreamBuffer(GLenum target, GLuint buffer_id, u32 size, u8* mapped_ptr, bool coherent)
: SyncingStreamBuffer(target, buffer_id, size)
, m_mapped_ptr(mapped_ptr)
, m_coherent(coherent)
{
}
u8* m_mapped_ptr;
bool m_coherent;
};
} // namespace detail
std::unique_ptr<StreamBuffer> StreamBuffer::Create(GLenum target, u32 size)
{
std::unique_ptr<StreamBuffer> buf;
if (GLAD_GL_VERSION_4_4 || GLAD_GL_ARB_buffer_storage || GLAD_GL_EXT_buffer_storage)
{
buf = detail::BufferStorageStreamBuffer::Create(target, size);
if (buf)
return buf;
}
// BufferSubData is slower on all drivers except NVIDIA...
const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
if (std::strstr(vendor, "NVIDIA"))
return detail::BufferSubDataStreamBuffer::Create(target, size);
else
return detail::BufferDataStreamBuffer::Create(target, size);
}
} // namespace GL
-61
View File
@@ -1,61 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "glad.h"
#include <memory>
#include <tuple>
#include <vector>
namespace GL
{
/// Provides a buffer for streaming data to the GPU, ideally in write-combined memory.
class StreamBuffer
{
public:
virtual ~StreamBuffer();
__fi GLuint GetGLBufferId() const { return m_buffer_id; }
__fi GLenum GetGLTarget() const { return m_target; }
__fi u32 GetSize() const { return m_size; }
void Bind();
void Unbind();
struct MappingResult
{
void* pointer;
u32 buffer_offset;
u32 index_aligned; // offset / alignment, suitable for base vertex
u32 space_aligned; // remaining space / alignment
};
virtual MappingResult Map(u32 alignment, u32 min_size) = 0;
virtual void Unmap(u32 used_size) = 0;
/// Returns the minimum granularity of blocks which sync objects will be created around.
virtual u32 GetChunkSize() const = 0;
static std::unique_ptr<StreamBuffer> Create(GLenum target, u32 size);
protected:
StreamBuffer(GLenum target, GLuint buffer_id, u32 size);
GLenum m_target;
GLuint m_buffer_id;
u32 m_size;
};
} // namespace GL
+85 -4
View File
@@ -31,6 +31,10 @@
#include "common/Threading.h"
#include "common/WindowInfo.h"
#ifdef DBUS_API
#include <dbus/dbus.h>
#endif
// Returns 0 on failure (not supported by the operating system).
u64 GetPhysicalMemory()
{
@@ -69,11 +73,77 @@ std::string GetOSVersionString()
#endif
}
#ifdef X11_API
#ifdef DBUS_API
bool ChangeScreenSaverStateDBus(const bool inhibit_requested, const char* program_name, const char* reason)
{
static dbus_uint32_t s_cookie;
// "error_dbus" doesn't need to be cleared in the end with "dbus_message_unref" at least if there is
// no error set, since calling "dbus_error_free" reinitializes it like "dbus_error_init" after freeing.
DBusError error_dbus;
dbus_error_init(&error_dbus);
DBusConnection* connection = nullptr;
DBusMessage* message = nullptr;
DBusMessage* response = nullptr;
// Initialized here because initializations should be before "goto" statements.
const char* bus_method = (inhibit_requested) ? "Inhibit" : "UnInhibit";
// "dbus_bus_get" gets a pointer to the same connection in libdbus, if exists, without creating a new connection.
// this doesn't need to be deleted, except if there's an error then calling "dbus_connection_unref", to free it,
// might be better so a new connection is established on the next try.
if (!(connection = dbus_bus_get(DBUS_BUS_SESSION, &error_dbus)) || (dbus_error_is_set(&error_dbus)))
goto cleanup;
if (!(message = dbus_message_new_method_call("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", bus_method)))
goto cleanup;
// Initialize an append iterator for the message, gets freed with the message.
DBusMessageIter message_itr;
dbus_message_iter_init_append(message, &message_itr);
if (inhibit_requested)
{
// Append process/window name.
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_STRING, &program_name))
goto cleanup;
// Append reason for inhibiting the screensaver.
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_STRING, &reason))
goto cleanup;
}
else
{
// Only Append the cookie.
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_UINT32, &s_cookie))
goto cleanup;
}
// Send message and get response.
if (!(response = dbus_connection_send_with_reply_and_block(connection, message, DBUS_TIMEOUT_USE_DEFAULT, &error_dbus))
|| dbus_error_is_set(&error_dbus))
goto cleanup;
if (inhibit_requested)
{
// Get the cookie from the response message.
if (!dbus_message_get_args(response, &error_dbus, DBUS_TYPE_UINT32, &s_cookie, DBUS_TYPE_INVALID))
goto cleanup;
}
dbus_message_unref(message);
dbus_message_unref(response);
return true;
cleanup:
if (dbus_error_is_set(&error_dbus))
dbus_error_free(&error_dbus);
if (connection)
dbus_connection_unref(connection);
if (message)
dbus_message_unref(message);
if (response)
dbus_message_unref(response);
return false;
}
#endif
#if !defined(DBUS_API) && defined(X11_API)
static bool SetScreensaverInhibitX11(const WindowInfo& wi, bool inhibit)
{
extern char **environ;
extern char** environ;
const char* command = "xdg-screensaver";
const char* operation = inhibit ? "suspend" : "resume";
@@ -88,8 +158,6 @@ static bool SetScreensaverInhibitX11(const WindowInfo& wi, bool inhibit)
return (res == 0);
}
#endif
static bool SetScreensaverInhibit(const WindowInfo& wi, bool inhibit)
{
switch (wi.type)
@@ -106,8 +174,18 @@ static bool SetScreensaverInhibit(const WindowInfo& wi, bool inhibit)
static std::optional<WindowInfo> s_inhibit_window_info;
#endif
bool WindowInfo::InhibitScreensaver(const WindowInfo& wi, bool inhibit)
{
#ifdef DBUS_API
return ChangeScreenSaverStateDBus(inhibit, "PCSX2", "PCSX2 VM is running.");
#else
//ChangeScreenSaverStateDBus
if (s_inhibit_window_info.has_value())
{
// Bit of extra logic here, because wx spams it and we don't want to
@@ -132,6 +210,9 @@ bool WindowInfo::InhibitScreensaver(const WindowInfo& wi, bool inhibit)
s_inhibit_window_info = wi;
return true;
#endif
}
bool Common::PlaySoundAsync(const char* path)
+164 -154
View File
@@ -15,197 +15,207 @@
#include "common/Perf.h"
#include "common/Pcsx2Defs.h"
#ifdef __unix__
#include <unistd.h>
#endif
#include "common/Assertions.h"
#include "common/StringUtil.h"
#ifdef ENABLE_VTUNE
#include "jitprofiling.h"
#endif
#include <string> // std::string
#include <cstring> // strncpy
#include <algorithm> // std::remove_if
#include <array>
#include <cstring>
#ifdef __linux__
#include <atomic>
#include <ctime>
#include <mutex>
#include <elf.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#endif
//#define ProfileWithPerf
#define MERGE_BLOCK_RESULT
//#define ProfileWithPerfJitDump
#ifdef ENABLE_VTUNE
#ifdef _WIN32
#if defined(ENABLE_VTUNE) && defined(_WIN32)
#pragma comment(lib, "jitprofiling.lib")
#endif
#endif
namespace Perf
{
// Warning object aren't thread safe
InfoVector any("");
InfoVector ee("EE");
InfoVector iop("IOP");
InfoVector vu("VU");
InfoVector vif("VIF");
Group any("");
Group ee("EE");
Group iop("IOP");
Group vu0("VU0");
Group vu1("VU1");
Group vif("VIF");
// Perf is only supported on linux
#if defined(__linux__) && (defined(ProfileWithPerf) || defined(ENABLE_VTUNE))
////////////////////////////////////////////////////////////////////////////////
// Implementation of the Info object
////////////////////////////////////////////////////////////////////////////////
Info::Info(uptr x86, u32 size, const char* symbol)
: m_x86(x86)
, m_size(size)
, m_dynamic(false)
#if defined(__linux__) && defined(ProfileWithPerf)
static std::FILE* s_map_file = nullptr;
static bool s_map_file_opened = false;
static std::mutex s_mutex;
static void RegisterMethod(const void* ptr, size_t size, const char* symbol)
{
strncpy(m_symbol, symbol, sizeof(m_symbol));
}
std::unique_lock lock(s_mutex);
Info::Info(uptr x86, u32 size, const char* symbol, u32 pc)
: m_x86(x86)
, m_size(size)
, m_dynamic(true)
{
snprintf(m_symbol, sizeof(m_symbol), "%s_0x%08x", symbol, pc);
}
void Info::Print(FILE* fp)
{
fprintf(fp, "%x %x %s\n", m_x86, m_size, m_symbol);
}
////////////////////////////////////////////////////////////////////////////////
// Implementation of the InfoVector object
////////////////////////////////////////////////////////////////////////////////
InfoVector::InfoVector(const char* prefix)
{
strncpy(m_prefix, prefix, sizeof(m_prefix));
#ifdef ENABLE_VTUNE
m_vtune_id = iJIT_GetNewMethodID();
#else
m_vtune_id = 0;
#endif
}
void InfoVector::print(FILE* fp)
{
for (auto&& it : m_v)
it.Print(fp);
}
void InfoVector::map(uptr x86, u32 size, const char* symbol)
{
// This function is typically used for dispatcher and recompiler.
// Dispatchers are on a page and must always be kept.
// Recompilers are much bigger (TODO check VIF) and are only
// useful when MERGE_BLOCK_RESULT is defined
#if defined(ENABLE_VTUNE) || !defined(MERGE_BLOCK_RESULT)
u32 max_code_size = 16 * _1kb;
#else
u32 max_code_size = _1gb;
#endif
if (size < max_code_size)
if (!s_map_file)
{
m_v.emplace_back(x86, size, symbol);
if (s_map_file_opened)
return;
#ifdef ENABLE_VTUNE
std::string name = std::string(symbol);
iJIT_Method_Load ml;
memset(&ml, 0, sizeof(ml));
ml.method_id = iJIT_GetNewMethodID();
ml.method_name = (char*)name.c_str();
ml.method_load_address = (void*)x86;
ml.method_size = size;
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ml);
//fprintf(stderr, "mapF %s: %p size %dKB\n", ml.method_name, ml.method_load_address, ml.method_size / 1024u);
#endif
char file[256];
snprintf(file, std::size(file), "/tmp/perf-%d.map", getpid());
s_map_file = std::fopen(file, "wb");
s_map_file_opened = true;
if (!s_map_file)
return;
}
std::fprintf(s_map_file, "%" PRIx64 " %zx %s\n", static_cast<u64>(reinterpret_cast<uintptr_t>(ptr)), size, symbol);
std::fflush(s_map_file);
}
#elif defined(__linux__) && defined(ProfileWithPerfJitDump)
enum : u32
{
JIT_CODE_LOAD = 0,
JIT_CODE_MOVE = 1,
JIT_CODE_DEBUG_INFO = 2,
JIT_CODE_CLOSE = 3,
JIT_CODE_UNWINDING_INFO = 4
};
#pragma pack(push, 1)
struct JITDUMP_HEADER
{
u32 magic = 0x4A695444; // JiTD
u32 version = 1;
u32 header_size = sizeof(JITDUMP_HEADER);
u32 elf_mach;
u32 pad1 = 0;
u32 pid;
u64 timestamp;
u64 flags = 0;
};
struct JITDUMP_RECORD_HEADER
{
u32 id;
u32 total_size;
u64 timestamp;
};
struct JITDUMP_CODE_LOAD
{
JITDUMP_RECORD_HEADER header;
u32 pid;
u32 tid;
u64 vma;
u64 code_addr;
u64 code_size;
u64 code_index;
// name
};
#pragma pack(pop)
static u64 JitDumpTimestamp()
{
struct timespec ts = {};
clock_gettime(CLOCK_MONOTONIC, &ts);
return (static_cast<u64>(ts.tv_sec) * 1000000000ULL) + static_cast<u64>(ts.tv_nsec);
}
void InfoVector::map(uptr x86, u32 size, u32 pc)
static FILE* s_jitdump_file = nullptr;
static bool s_jitdump_file_opened = false;
static std::mutex s_jitdump_mutex;
static u32 s_jitdump_record_id;
static void RegisterMethod(const void* ptr, size_t size, const char* symbol)
{
#ifndef MERGE_BLOCK_RESULT
m_v.emplace_back(x86, size, m_prefix, pc);
#endif
const u32 namelen = std::strlen(symbol) + 1;
#ifdef ENABLE_VTUNE
iJIT_Method_Load_V2 ml;
std::unique_lock lock(s_jitdump_mutex);
if (!s_jitdump_file)
{
if (!s_jitdump_file_opened)
{
char file[256];
snprintf(file, std::size(file), "jit-%d.dump", getpid());
s_jitdump_file = fopen(file, "w+b");
s_jitdump_file_opened = true;
if (!s_jitdump_file)
return;
}
memset(&ml, 0, sizeof(ml));
void* perf_marker = mmap(nullptr, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno(s_jitdump_file), 0);
pxAssertRel(perf_marker != MAP_FAILED, "Map perf marker");
#ifdef MERGE_BLOCK_RESULT
ml.method_id = m_vtune_id;
ml.method_name = m_prefix;
#else
std::string name = std::string(m_prefix) + "_" + std::to_string(pc);
JITDUMP_HEADER jh = {};
jh.elf_mach = EM_X86_64;
jh.pid = getpid();
jh.timestamp = JitDumpTimestamp();
std::fwrite(&jh, sizeof(jh), 1, s_jitdump_file);
}
JITDUMP_CODE_LOAD cl = {};
cl.header.id = JIT_CODE_LOAD;
cl.header.total_size = sizeof(cl) + namelen + static_cast<u32>(size);
cl.header.timestamp = JitDumpTimestamp();
cl.pid = getpid();
cl.tid = syscall(SYS_gettid);
cl.vma = 0;
cl.code_addr = static_cast<u64>(reinterpret_cast<uintptr_t>(ptr));
cl.code_size = static_cast<u64>(size);
cl.code_index = s_jitdump_record_id++;
std::fwrite(&cl, sizeof(cl), 1, s_jitdump_file);
std::fwrite(symbol, namelen, 1, s_jitdump_file);
std::fwrite(ptr, size, 1, s_jitdump_file);
std::fflush(s_jitdump_file);
}
#elif defined(ENABLE_VTUNE)
static void RegisterMethod(const void* ptr, size_t size, const char* symbol)
{
iJIT_Method_Load_V2 ml = {};
ml.method_id = iJIT_GetNewMethodID();
ml.method_name = (char*)name.c_str();
#endif
ml.method_load_address = (void*)x86;
ml.method_size = size;
ml.method_name = const_cast<char*>(symbol);
ml.method_load_address = const_cast<void*>(ptr);
ml.method_size = static_cast<unsigned int>(size);
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, &ml);
//fprintf(stderr, "mapB %s: %p size %d\n", ml.method_name, ml.method_load_address, ml.method_size);
}
#endif
}
void InfoVector::reset()
#if (defined(__linux__) && (defined(ProfileWithPerf) || defined(ProfileWithPerfJitDump))) || defined(ENABLE_VTUNE)
void Group::Register(const void* ptr, size_t size, const char* symbol)
{
auto dynamic = std::remove_if(m_v.begin(), m_v.end(), [](Info i) { return i.m_dynamic; });
m_v.erase(dynamic, m_v.end());
char full_symbol[128];
if (HasPrefix())
std::snprintf(full_symbol, std::size(full_symbol), "%s_%s", m_prefix, symbol);
else
StringUtil::Strlcpy(full_symbol, symbol, std::size(full_symbol));
RegisterMethod(ptr, size, full_symbol);
}
////////////////////////////////////////////////////////////////////////////////
// Global function
////////////////////////////////////////////////////////////////////////////////
void dump()
void Group::RegisterPC(const void* ptr, size_t size, u32 pc)
{
char file[256];
snprintf(file, 250, "/tmp/perf-%d.map", getpid());
FILE* fp = fopen(file, "w");
any.print(fp);
ee.print(fp);
iop.print(fp);
vu.print(fp);
if (fp)
fclose(fp);
char full_symbol[128];
if (HasPrefix())
std::snprintf(full_symbol, std::size(full_symbol), "%s_%08X", m_prefix, pc);
else
std::snprintf(full_symbol, std::size(full_symbol), "%08X", pc);
RegisterMethod(ptr, size, full_symbol);
}
void dump_and_reset()
void Group::RegisterKey(const void* ptr, size_t size, const char* prefix, u64 key)
{
dump();
any.reset();
ee.reset();
iop.reset();
vu.reset();
char full_symbol[128];
if (HasPrefix())
std::snprintf(full_symbol, std::size(full_symbol), "%s_%s%016" PRIX64, m_prefix, prefix, key);
else
std::snprintf(full_symbol, std::size(full_symbol), "%s%016" PRIX64, prefix, key);
RegisterMethod(ptr, size, full_symbol);
}
#else
////////////////////////////////////////////////////////////////////////////////
// Dummy implementation
////////////////////////////////////////////////////////////////////////////////
InfoVector::InfoVector(const char* prefix)
: m_vtune_id(0)
{
}
void InfoVector::map(uptr x86, u32 size, const char* symbol) {}
void InfoVector::map(uptr x86, u32 size, u32 pc) {}
void InfoVector::reset() {}
void dump() {}
void dump_and_reset() {}
void Group::Register(const void* ptr, size_t size, const char* symbol) {}
void Group::RegisterPC(const void* ptr, size_t size, u32 pc) {}
void Group::RegisterKey(const void* ptr, size_t size, const char* prefix, u64 key) {}
#endif
} // namespace Perf
+13 -32
View File
@@ -21,42 +21,23 @@
namespace Perf
{
struct Info
class Group
{
uptr m_x86;
u32 m_size;
char m_symbol[20];
// The idea is to keep static zones that are set only
// once.
bool m_dynamic;
Info(uptr x86, u32 size, const char* symbol);
Info(uptr x86, u32 size, const char* symbol, u32 pc);
void Print(FILE* fp);
};
class InfoVector
{
std::vector<Info> m_v;
char m_prefix[20];
unsigned int m_vtune_id;
const char* m_prefix;
public:
InfoVector(const char* prefix);
constexpr Group(const char* prefix) : m_prefix(prefix) {}
bool HasPrefix() const { return (m_prefix && m_prefix[0]); }
void print(FILE* fp);
void map(uptr x86, u32 size, const char* symbol);
void map(uptr x86, u32 size, u32 pc);
void reset();
void Register(const void* ptr, size_t size, const char* symbol);
void RegisterPC(const void* ptr, size_t size, u32 pc);
void RegisterKey(const void* ptr, size_t size, const char* prefix, u64 key);
};
void dump();
void dump_and_reset();
extern InfoVector any;
extern InfoVector ee;
extern InfoVector iop;
extern InfoVector vu;
extern InfoVector vif;
extern Group any;
extern Group ee;
extern Group iop;
extern Group vu0;
extern Group vu1;
extern Group vif;
} // namespace Perf
-111
View File
@@ -97,114 +97,3 @@ public:
virtual SafeArray<T>* Clone() const;
};
//////////////////////////////////////////////////////////////////////////////////////////
// SafeList - Simple growable container without all the mess or hassle of std containers.
//
// This container is intended for reasonably simple class types only. Things which this
// container does not handle with desired robustness:
//
// * Classes with non-trivial constructors (such that construction creates much overhead)
// * Classes with copy constructors (copying is done using performance memcpy)
// * Classes with destructors (they're not called, sorry!)
//
template <typename T>
class SafeList
{
DeclareNoncopyableObject(SafeList);
public:
static const int DefaultChunkSize = 0x80 * sizeof(T);
public:
std::string Name; // user-assigned block name
int ChunkSize; // assigned DefaultChunkSize on init, reconfigurable at any time.
protected:
T* m_ptr;
int m_allocsize; // size of the allocation of memory
uint m_length; // length of the array (active items, not buffer allocation)
protected:
virtual T* _virtual_realloc(int newsize);
void _MakeRoomFor_threshold(int newsize);
T* _getPtr(uint i) const;
public:
virtual ~SafeList();
explicit SafeList(const char* name = "Unnamed");
explicit SafeList(int initialSize, const char* name = "Unnamed");
virtual SafeList<T>* Clone() const;
void Remove(int index);
void MakeRoomFor(int blockSize);
T& New();
int Add(const T& src);
T& AddNew(const T& src);
// Returns the size of the list, as according to the array type. This includes
// mapped items only. The actual size of the allocation may differ.
int GetLength() const { return m_length; }
// Returns the size of the list, in bytes. This includes mapped items only.
// The actual size of the allocation may differ.
int GetSizeInBytes() const { return m_length * sizeof(T); }
void MatchLengthToAllocatedSize()
{
m_length = m_allocsize;
}
void GrowBy(int items)
{
MakeRoomFor(m_length + ChunkSize + items + 1);
}
// Sets the item length to zero. Does not free memory allocations.
void Clear()
{
m_length = 0;
}
// Gets an element of this memory allocation much as if it were an array.
// DevBuilds : Generates assertion if the index is invalid.
T& operator[](int idx) { return *_getPtr((uint)idx); }
const T& operator[](int idx) const { return *_getPtr((uint)idx); }
T* GetPtr() { return m_ptr; }
const T* GetPtr() const { return m_ptr; }
T& GetLast() { return m_ptr[m_length - 1]; }
const T& GetLast() const { return m_ptr[m_length - 1]; }
};
// --------------------------------------------------------------------------------------
// SafeAlignedArray<T>
// --------------------------------------------------------------------------------------
// Handy little class for allocating a resizable memory block, complete with
// exception-based error handling and automatic cleanup.
// This one supports aligned data allocations too!
template <typename T, uint Alignment>
class SafeAlignedArray : public SafeArray<T>
{
typedef SafeArray<T> _parent;
protected:
T* _virtual_realloc(int newsize);
public:
using _parent::operator[];
virtual ~SafeAlignedArray();
explicit SafeAlignedArray(std::string name = "Unnamed")
: SafeArray<T>::SafeArray(name)
{
}
explicit SafeAlignedArray(int initialSize, std::string name = "Unnamed");
virtual SafeAlignedArray<T, Alignment>* Clone() const;
};
-166
View File
@@ -15,13 +15,9 @@
#pragma once
#include "common/AlignedMalloc.h"
#include "common/Assertions.h"
#include "common/Exceptions.h"
#include "common/SafeArray.h"
#include "fmt/core.h"
// Internal constructor for use by derived classes. This allows a derived class to
// use its own memory allocation (with an aligned memory, for example).
// Throws:
@@ -123,165 +119,3 @@ SafeArray<T>* SafeArray<T>::Clone() const
memcpy(retval->GetPtr(), m_ptr, sizeof(T) * m_size);
return retval;
}
// --------------------------------------------------------------------------------------
// SafeAlignedArray<T> (implementations)
// --------------------------------------------------------------------------------------
template <typename T, uint Alignment>
T* SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize)
{
return (T*)((this->m_ptr == NULL) ?
_aligned_malloc(newsize * sizeof(T), Alignment) :
pcsx2_aligned_realloc(this->m_ptr, newsize * sizeof(T), Alignment, this->m_size * sizeof(T)));
}
// Appends "(align: xx)" to the name of the allocation in devel builds.
// Maybe useful,maybe not... no harm in attaching it. :D
template <typename T, uint Alignment>
SafeAlignedArray<T, Alignment>::~SafeAlignedArray()
{
safe_aligned_free(this->m_ptr);
// mptr is set to null, so the parent class's destructor won't re-free it.
}
template <typename T, uint Alignment>
SafeAlignedArray<T, Alignment>::SafeAlignedArray(int initialSize, std::string name)
: SafeArray<T>::SafeArray(
std::move(name),
(T*)_aligned_malloc(initialSize * sizeof(T), Alignment),
initialSize)
{
}
template <typename T, uint Alignment>
SafeAlignedArray<T, Alignment>* SafeAlignedArray<T, Alignment>::Clone() const
{
SafeAlignedArray<T, Alignment>* retval = new SafeAlignedArray<T, Alignment>(this->m_size);
memcpy(retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size);
return retval;
}
// --------------------------------------------------------------------------------------
// SafeList<T> (implementations)
// --------------------------------------------------------------------------------------
template <typename T>
T* SafeList<T>::_virtual_realloc(int newsize)
{
return (T*)realloc(m_ptr, newsize * sizeof(T));
}
template <typename T>
SafeList<T>::~SafeList()
{
safe_free(m_ptr);
}
template <typename T>
SafeList<T>::SafeList(const char* name)
: Name(name)
{
ChunkSize = DefaultChunkSize;
m_ptr = NULL;
m_allocsize = 0;
m_length = 0;
}
template <typename T>
SafeList<T>::SafeList(int initialSize, const char* name)
: Name(name)
{
ChunkSize = DefaultChunkSize;
m_allocsize = initialSize;
m_length = 0;
m_ptr = (T*)malloc(initialSize * sizeof(T));
if (m_ptr == NULL)
pxFailRel("SafeList exact alloc failed");
for (int i = 0; i < m_allocsize; ++i)
{
new (&m_ptr[i]) T();
}
}
template <typename T>
T* SafeList<T>::_getPtr(uint i) const
{
pxAssumeDev(i < m_length, "Index in bounds");
return &m_ptr[i];
}
// Ensures that the allocation is large enough to fit data of the
// amount requested. The memory allocation is not resized smaller.
template <typename T>
void SafeList<T>::MakeRoomFor(int blockSize)
{
if (blockSize > m_allocsize)
{
const int newalloc = blockSize + ChunkSize;
m_ptr = _virtual_realloc(newalloc);
if (m_ptr == NULL)
pxFailRel("SafeList MakeRoomFor failed");
for (; m_allocsize < newalloc; ++m_allocsize)
{
new (&m_ptr[m_allocsize]) T();
}
}
}
// Appends an item to the end of the list and returns a handle to it.
template <typename T>
T& SafeList<T>::New()
{
_MakeRoomFor_threshold(m_length + 1);
return m_ptr[m_length++];
}
template <typename T>
int SafeList<T>::Add(const T& src)
{
_MakeRoomFor_threshold(m_length + 1);
m_ptr[m_length] = src;
return m_length++;
}
// Same as Add, but returns the handle of the new object instead of it's array index.
template <typename T>
T& SafeList<T>::AddNew(const T& src)
{
_MakeRoomFor_threshold(m_length + 1);
m_ptr[m_length] = src;
return m_ptr[m_length];
}
// Performs a standard array-copy removal of the given item. All items past the
// given item are copied over.
// DevBuilds : Generates assertion if the index is invalid.
template <typename T>
void SafeList<T>::Remove(int index)
{
pxAssert(index < m_length);
int copylen = m_length - index;
if (copylen > 0)
memcpy(&m_ptr[index], &m_ptr[index + 1], copylen);
}
template <typename T>
SafeList<T>* SafeList<T>::Clone() const
{
SafeList<T>* retval = new SafeList<T>(m_length);
memcpy(retval->m_ptr, m_ptr, sizeof(T) * m_length);
return retval;
}
template <typename T>
void SafeList<T>::_MakeRoomFor_threshold(int newsize)
{
MakeRoomFor(newsize + ChunkSize);
}
+2 -8
View File
@@ -100,10 +100,7 @@ namespace StringUtil
return std::nullopt;
if (endptr)
{
const size_t remaining_len = end - ptr - 1;
*endptr = (remaining_len > 0) ? std::string_view(result.ptr, remaining_len) : std::string_view();
}
*endptr = (result.ptr < end) ? std::string_view(result.ptr, end - result.ptr) : std::string_view();
return value;
}
@@ -131,10 +128,7 @@ namespace StringUtil
return std::nullopt;
if (endptr)
{
const size_t remaining_len = end - ptr - 1;
*endptr = (remaining_len > 0) ? std::string_view(result.ptr, remaining_len) : std::string_view();
}
*endptr = (result.ptr < end) ? std::string_view(result.ptr, end - result.ptr) : std::string_view();
return value;
}
-957
View File
@@ -1,957 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/Vulkan/Builders.h"
#include "common/Vulkan/Util.h"
#include "common/Assertions.h"
#include <limits>
namespace Vulkan
{
DescriptorSetLayoutBuilder::DescriptorSetLayoutBuilder() { Clear(); }
void DescriptorSetLayoutBuilder::Clear()
{
m_ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
m_ci.pNext = nullptr;
m_ci.flags = 0;
m_ci.pBindings = nullptr;
m_ci.bindingCount = 0;
}
VkDescriptorSetLayout DescriptorSetLayoutBuilder::Create(VkDevice device)
{
VkDescriptorSetLayout layout;
VkResult res = vkCreateDescriptorSetLayout(device, &m_ci, nullptr, &layout);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateDescriptorSetLayout() failed: ");
return VK_NULL_HANDLE;
}
Clear();
return layout;
}
void DescriptorSetLayoutBuilder::AddBinding(
u32 binding, VkDescriptorType dtype, u32 dcount, VkShaderStageFlags stages)
{
pxAssert(m_ci.bindingCount < MAX_BINDINGS);
VkDescriptorSetLayoutBinding& b = m_bindings[m_ci.bindingCount];
b.binding = binding;
b.descriptorType = dtype;
b.descriptorCount = dcount;
b.stageFlags = stages;
b.pImmutableSamplers = nullptr;
m_ci.pBindings = m_bindings.data();
m_ci.bindingCount++;
}
PipelineLayoutBuilder::PipelineLayoutBuilder() { Clear(); }
void PipelineLayoutBuilder::Clear()
{
m_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
m_ci.pNext = nullptr;
m_ci.flags = 0;
m_ci.pSetLayouts = nullptr;
m_ci.setLayoutCount = 0;
m_ci.pPushConstantRanges = nullptr;
m_ci.pushConstantRangeCount = 0;
}
VkPipelineLayout PipelineLayoutBuilder::Create(VkDevice device)
{
VkPipelineLayout layout;
VkResult res = vkCreatePipelineLayout(device, &m_ci, nullptr, &layout);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreatePipelineLayout() failed: ");
return VK_NULL_HANDLE;
}
Clear();
return layout;
}
void PipelineLayoutBuilder::AddDescriptorSet(VkDescriptorSetLayout layout)
{
pxAssert(m_ci.setLayoutCount < MAX_SETS);
m_sets[m_ci.setLayoutCount] = layout;
m_ci.setLayoutCount++;
m_ci.pSetLayouts = m_sets.data();
}
void PipelineLayoutBuilder::AddPushConstants(VkShaderStageFlags stages, u32 offset, u32 size)
{
pxAssert(m_ci.pushConstantRangeCount < MAX_PUSH_CONSTANTS);
VkPushConstantRange& r = m_push_constants[m_ci.pushConstantRangeCount];
r.stageFlags = stages;
r.offset = offset;
r.size = size;
m_ci.pushConstantRangeCount++;
m_ci.pPushConstantRanges = m_push_constants.data();
}
GraphicsPipelineBuilder::GraphicsPipelineBuilder() { Clear(); }
void GraphicsPipelineBuilder::Clear()
{
m_ci = {};
m_ci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
m_shader_stages = {};
m_vertex_input_state = {};
m_vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
m_ci.pVertexInputState = &m_vertex_input_state;
m_vertex_attributes = {};
m_vertex_buffers = {};
m_input_assembly = {};
m_input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
m_rasterization_state = {};
m_rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
m_rasterization_state.lineWidth = 1.0f;
m_depth_state = {};
m_depth_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
m_blend_state = {};
m_blend_state.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
m_blend_attachments = {};
m_viewport_state = {};
m_viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
m_viewport = {};
m_scissor = {};
m_dynamic_state = {};
m_dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
m_dynamic_state_values = {};
m_multisample_state = {};
m_multisample_state.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
m_provoking_vertex = {};
m_provoking_vertex.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT;
m_line_rasterization_state = {};
m_line_rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
// set defaults
SetNoCullRasterizationState();
SetNoDepthTestState();
SetNoBlendingState();
SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
// have to be specified even if dynamic
SetViewport(0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f);
SetScissorRect(0, 0, 1, 1);
SetMultisamples(VK_SAMPLE_COUNT_1_BIT);
}
VkPipeline GraphicsPipelineBuilder::Create(VkDevice device, VkPipelineCache pipeline_cache, bool clear /* = true */)
{
VkPipeline pipeline;
VkResult res = vkCreateGraphicsPipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateGraphicsPipelines() failed: ");
return VK_NULL_HANDLE;
}
if (clear)
Clear();
return pipeline;
}
void GraphicsPipelineBuilder::SetShaderStage(
VkShaderStageFlagBits stage, VkShaderModule module, const char* entry_point)
{
pxAssert(m_ci.stageCount < MAX_SHADER_STAGES);
u32 index = 0;
for (; index < m_ci.stageCount; index++)
{
if (m_shader_stages[index].stage == stage)
break;
}
if (index == m_ci.stageCount)
{
m_ci.stageCount++;
m_ci.pStages = m_shader_stages.data();
}
VkPipelineShaderStageCreateInfo& s = m_shader_stages[index];
s.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
s.stage = stage;
s.module = module;
s.pName = entry_point;
}
void GraphicsPipelineBuilder::AddVertexBuffer(
u32 binding, u32 stride, VkVertexInputRate input_rate /*= VK_VERTEX_INPUT_RATE_VERTEX*/)
{
pxAssert(m_vertex_input_state.vertexAttributeDescriptionCount < MAX_VERTEX_BUFFERS);
VkVertexInputBindingDescription& b = m_vertex_buffers[m_vertex_input_state.vertexBindingDescriptionCount];
b.binding = binding;
b.stride = stride;
b.inputRate = input_rate;
m_vertex_input_state.vertexBindingDescriptionCount++;
m_vertex_input_state.pVertexBindingDescriptions = m_vertex_buffers.data();
m_ci.pVertexInputState = &m_vertex_input_state;
}
void GraphicsPipelineBuilder::AddVertexAttribute(u32 location, u32 binding, VkFormat format, u32 offset)
{
pxAssert(m_vertex_input_state.vertexAttributeDescriptionCount < MAX_VERTEX_BUFFERS);
VkVertexInputAttributeDescription& a =
m_vertex_attributes[m_vertex_input_state.vertexAttributeDescriptionCount];
a.location = location;
a.binding = binding;
a.format = format;
a.offset = offset;
m_vertex_input_state.vertexAttributeDescriptionCount++;
m_vertex_input_state.pVertexAttributeDescriptions = m_vertex_attributes.data();
m_ci.pVertexInputState = &m_vertex_input_state;
}
void GraphicsPipelineBuilder::SetPrimitiveTopology(
VkPrimitiveTopology topology, bool enable_primitive_restart /*= false*/)
{
m_input_assembly.topology = topology;
m_input_assembly.primitiveRestartEnable = enable_primitive_restart;
m_ci.pInputAssemblyState = &m_input_assembly;
}
void GraphicsPipelineBuilder::SetRasterizationState(
VkPolygonMode polygon_mode, VkCullModeFlags cull_mode, VkFrontFace front_face)
{
m_rasterization_state.polygonMode = polygon_mode;
m_rasterization_state.cullMode = cull_mode;
m_rasterization_state.frontFace = front_face;
m_ci.pRasterizationState = &m_rasterization_state;
}
void GraphicsPipelineBuilder::SetLineWidth(float width)
{
m_rasterization_state.lineWidth = width;
}
void GraphicsPipelineBuilder::SetLineRasterizationMode(VkLineRasterizationModeEXT mode)
{
Util::AddPointerToChain(&m_rasterization_state, &m_line_rasterization_state);
m_line_rasterization_state.lineRasterizationMode = mode;
}
void GraphicsPipelineBuilder::SetMultisamples(u32 multisamples, bool per_sample_shading)
{
m_multisample_state.rasterizationSamples = static_cast<VkSampleCountFlagBits>(multisamples);
m_multisample_state.sampleShadingEnable = per_sample_shading;
m_multisample_state.minSampleShading = (multisamples > 1) ? 1.0f : 0.0f;
}
void GraphicsPipelineBuilder::SetNoCullRasterizationState()
{
SetRasterizationState(VK_POLYGON_MODE_FILL, VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE);
}
void GraphicsPipelineBuilder::SetDepthState(bool depth_test, bool depth_write, VkCompareOp compare_op)
{
m_depth_state.depthTestEnable = depth_test;
m_depth_state.depthWriteEnable = depth_write;
m_depth_state.depthCompareOp = compare_op;
m_ci.pDepthStencilState = &m_depth_state;
}
void GraphicsPipelineBuilder::SetStencilState(
bool stencil_test, const VkStencilOpState& front, const VkStencilOpState& back)
{
m_depth_state.stencilTestEnable = stencil_test;
m_depth_state.front = front;
m_depth_state.back = back;
}
void GraphicsPipelineBuilder::SetNoStencilState()
{
m_depth_state.stencilTestEnable = VK_FALSE;
m_depth_state.front = {};
m_depth_state.back = {};
}
void GraphicsPipelineBuilder::SetNoDepthTestState() { SetDepthState(false, false, VK_COMPARE_OP_ALWAYS); }
void GraphicsPipelineBuilder::SetBlendConstants(float r, float g, float b, float a)
{
m_blend_state.blendConstants[0] = r;
m_blend_state.blendConstants[1] = g;
m_blend_state.blendConstants[2] = b;
m_blend_state.blendConstants[3] = a;
m_ci.pColorBlendState = &m_blend_state;
}
void GraphicsPipelineBuilder::AddBlendAttachment(bool blend_enable, VkBlendFactor src_factor,
VkBlendFactor dst_factor, VkBlendOp op, VkBlendFactor alpha_src_factor, VkBlendFactor alpha_dst_factor,
VkBlendOp alpha_op,
VkColorComponentFlags
write_mask /* = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT */)
{
pxAssert(m_blend_state.attachmentCount < MAX_ATTACHMENTS);
VkPipelineColorBlendAttachmentState& bs = m_blend_attachments[m_blend_state.attachmentCount];
bs.blendEnable = blend_enable;
bs.srcColorBlendFactor = src_factor;
bs.dstColorBlendFactor = dst_factor;
bs.colorBlendOp = op;
bs.srcAlphaBlendFactor = alpha_src_factor;
bs.dstAlphaBlendFactor = alpha_dst_factor;
bs.alphaBlendOp = alpha_op;
bs.colorWriteMask = write_mask;
m_blend_state.attachmentCount++;
m_blend_state.pAttachments = m_blend_attachments.data();
m_ci.pColorBlendState = &m_blend_state;
}
void GraphicsPipelineBuilder::SetBlendAttachment(u32 attachment, bool blend_enable, VkBlendFactor src_factor,
VkBlendFactor dst_factor, VkBlendOp op, VkBlendFactor alpha_src_factor, VkBlendFactor alpha_dst_factor,
VkBlendOp alpha_op,
VkColorComponentFlags
write_mask /*= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT*/)
{
pxAssert(attachment < MAX_ATTACHMENTS);
VkPipelineColorBlendAttachmentState& bs = m_blend_attachments[attachment];
bs.blendEnable = blend_enable;
bs.srcColorBlendFactor = src_factor;
bs.dstColorBlendFactor = dst_factor;
bs.colorBlendOp = op;
bs.srcAlphaBlendFactor = alpha_src_factor;
bs.dstAlphaBlendFactor = alpha_dst_factor;
bs.alphaBlendOp = alpha_op;
bs.colorWriteMask = write_mask;
if (attachment >= m_blend_state.attachmentCount)
{
m_blend_state.attachmentCount = attachment + 1u;
m_blend_state.pAttachments = m_blend_attachments.data();
m_ci.pColorBlendState = &m_blend_state;
}
}
void GraphicsPipelineBuilder::AddBlendFlags(u32 flags)
{
m_blend_state.flags |= flags;
}
void GraphicsPipelineBuilder::ClearBlendAttachments()
{
m_blend_attachments = {};
m_blend_state.attachmentCount = 0;
}
void GraphicsPipelineBuilder::SetNoBlendingState()
{
ClearBlendAttachments();
SetBlendAttachment(0, false, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE,
VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD,
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
}
void GraphicsPipelineBuilder::AddDynamicState(VkDynamicState state)
{
pxAssert(m_dynamic_state.dynamicStateCount < MAX_DYNAMIC_STATE);
m_dynamic_state_values[m_dynamic_state.dynamicStateCount] = state;
m_dynamic_state.dynamicStateCount++;
m_dynamic_state.pDynamicStates = m_dynamic_state_values.data();
m_ci.pDynamicState = &m_dynamic_state;
}
void GraphicsPipelineBuilder::SetDynamicViewportAndScissorState()
{
AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT);
AddDynamicState(VK_DYNAMIC_STATE_SCISSOR);
}
void GraphicsPipelineBuilder::SetViewport(
float x, float y, float width, float height, float min_depth, float max_depth)
{
m_viewport.x = x;
m_viewport.y = y;
m_viewport.width = width;
m_viewport.height = height;
m_viewport.minDepth = min_depth;
m_viewport.maxDepth = max_depth;
m_viewport_state.pViewports = &m_viewport;
m_viewport_state.viewportCount = 1u;
m_ci.pViewportState = &m_viewport_state;
}
void GraphicsPipelineBuilder::SetScissorRect(s32 x, s32 y, u32 width, u32 height)
{
m_scissor.offset.x = x;
m_scissor.offset.y = y;
m_scissor.extent.width = width;
m_scissor.extent.height = height;
m_viewport_state.pScissors = &m_scissor;
m_viewport_state.scissorCount = 1u;
m_ci.pViewportState = &m_viewport_state;
}
void GraphicsPipelineBuilder::SetMultisamples(VkSampleCountFlagBits samples)
{
m_multisample_state.rasterizationSamples = samples;
m_ci.pMultisampleState = &m_multisample_state;
}
void GraphicsPipelineBuilder::SetPipelineLayout(VkPipelineLayout layout) { m_ci.layout = layout; }
void GraphicsPipelineBuilder::SetRenderPass(VkRenderPass render_pass, u32 subpass)
{
m_ci.renderPass = render_pass;
m_ci.subpass = subpass;
}
void GraphicsPipelineBuilder::SetProvokingVertex(VkProvokingVertexModeEXT mode)
{
Util::AddPointerToChain(&m_rasterization_state, &m_provoking_vertex);
m_provoking_vertex.provokingVertexMode = mode;
}
ComputePipelineBuilder::ComputePipelineBuilder() { Clear(); }
void ComputePipelineBuilder::Clear()
{
m_ci = {};
m_ci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
m_si = {};
m_smap_entries = {};
m_smap_constants = {};
}
VkPipeline ComputePipelineBuilder::Create(VkDevice device, VkPipelineCache pipeline_cache /*= VK_NULL_HANDLE*/, bool clear /*= true*/)
{
VkPipeline pipeline;
VkResult res = vkCreateComputePipelines(device, pipeline_cache, 1, &m_ci, nullptr, &pipeline);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateComputePipelines() failed: ");
return VK_NULL_HANDLE;
}
if (clear)
Clear();
return pipeline;
}
void ComputePipelineBuilder::SetShader(VkShaderModule module, const char* entry_point)
{
m_ci.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
m_ci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
m_ci.stage.module = module;
m_ci.stage.pName = entry_point;
}
void ComputePipelineBuilder::SetPipelineLayout(VkPipelineLayout layout)
{
m_ci.layout = layout;
}
void ComputePipelineBuilder::SetSpecializationBool(u32 index, bool value)
{
const u32 u32_value = static_cast<u32>(value);
SetSpecializationValue(index, u32_value);
}
void ComputePipelineBuilder::SetSpecializationValue(u32 index, u32 value)
{
if (m_si.mapEntryCount == 0)
{
m_si.pMapEntries = m_smap_entries.data();
m_si.pData = m_smap_constants.data();
m_ci.stage.pSpecializationInfo = &m_si;
}
m_smap_entries[m_si.mapEntryCount++] = {index, index * SPECIALIZATION_CONSTANT_SIZE, SPECIALIZATION_CONSTANT_SIZE};
m_si.dataSize += SPECIALIZATION_CONSTANT_SIZE;
}
SamplerBuilder::SamplerBuilder() { Clear(); }
void SamplerBuilder::Clear()
{
m_ci = {};
m_ci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
}
VkSampler SamplerBuilder::Create(VkDevice device, bool clear /* = true */)
{
VkSampler sampler;
VkResult res = vkCreateSampler(device, &m_ci, nullptr, &sampler);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateSampler() failed: ");
return VK_NULL_HANDLE;
}
return sampler;
}
void SamplerBuilder::SetFilter(VkFilter mag_filter, VkFilter min_filter, VkSamplerMipmapMode mip_filter)
{
m_ci.magFilter = mag_filter;
m_ci.minFilter = min_filter;
m_ci.mipmapMode = mip_filter;
}
void SamplerBuilder::SetAddressMode(VkSamplerAddressMode u, VkSamplerAddressMode v, VkSamplerAddressMode w)
{
m_ci.addressModeU = u;
m_ci.addressModeV = v;
m_ci.addressModeW = w;
}
void SamplerBuilder::SetPointSampler(
VkSamplerAddressMode address_mode /* = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER */)
{
Clear();
SetFilter(VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST);
SetAddressMode(address_mode, address_mode, address_mode);
}
void SamplerBuilder::SetLinearSampler(
bool mipmaps, VkSamplerAddressMode address_mode /* = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER */)
{
Clear();
SetFilter(VK_FILTER_LINEAR, VK_FILTER_LINEAR,
mipmaps ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST);
SetAddressMode(address_mode, address_mode, address_mode);
if (mipmaps)
{
m_ci.minLod = std::numeric_limits<float>::min();
m_ci.maxLod = std::numeric_limits<float>::max();
}
}
DescriptorSetUpdateBuilder::DescriptorSetUpdateBuilder() { Clear(); }
void DescriptorSetUpdateBuilder::Clear()
{
m_writes = {};
m_num_writes = 0;
}
void DescriptorSetUpdateBuilder::Update(VkDevice device, bool clear /*= true*/)
{
pxAssert(m_num_writes > 0);
vkUpdateDescriptorSets(device, m_num_writes, (m_num_writes > 0) ? m_writes.data() : nullptr, 0, nullptr);
if (clear)
Clear();
}
void DescriptorSetUpdateBuilder::AddImageDescriptorWrite(VkDescriptorSet set, u32 binding, VkImageView view,
VkImageLayout layout /*= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/)
{
pxAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
ii.imageView = view;
ii.imageLayout = layout;
ii.sampler = VK_NULL_HANDLE;
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dw.dstSet = set;
dw.dstBinding = binding;
dw.descriptorCount = 1;
dw.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
dw.pImageInfo = &ii;
}
void DescriptorSetUpdateBuilder::AddImageDescriptorWrites(VkDescriptorSet set, u32 binding,
const VkImageView* views, u32 num_views, VkImageLayout layout /*= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/)
{
pxAssert(m_num_writes < MAX_WRITES && (m_num_image_infos + num_views) < MAX_IMAGE_INFOS);
#if 1
// NOTE: This is deliberately split up - updating multiple descriptors in one write is broken on Adreno.
for (u32 i = 0; i < num_views; i++)
AddImageDescriptorWrite(set, binding + i, views[i], layout);
#else
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dw.dstSet = set;
dw.dstBinding = binding;
dw.descriptorCount = num_views;
dw.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
dw.pImageInfo = &m_image_infos[m_num_image_infos];
for (u32 i = 0; i < num_views; i++)
{
VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
ii.imageView = views[i];
ii.imageLayout = layout;
ii.sampler = VK_NULL_HANDLE;
}
#endif
}
void DescriptorSetUpdateBuilder::AddSamplerDescriptorWrite(VkDescriptorSet set, u32 binding, VkSampler sampler)
{
pxAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
ii.imageView = VK_NULL_HANDLE;
ii.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
ii.sampler = sampler;
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dw.dstSet = set;
dw.dstBinding = binding;
dw.descriptorCount = 1;
dw.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
dw.pImageInfo = &ii;
}
void DescriptorSetUpdateBuilder::AddSamplerDescriptorWrites(
VkDescriptorSet set, u32 binding, const VkSampler* samplers, u32 num_samplers)
{
pxAssert(m_num_writes < MAX_WRITES && (m_num_image_infos + num_samplers) < MAX_IMAGE_INFOS);
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dw.dstSet = set;
dw.dstBinding = binding;
dw.descriptorCount = num_samplers;
dw.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER;
dw.pImageInfo = &m_image_infos[m_num_image_infos];
for (u32 i = 0; i < num_samplers; i++)
{
VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
ii.imageView = VK_NULL_HANDLE;
ii.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
ii.sampler = samplers[i];
}
}
void DescriptorSetUpdateBuilder::AddCombinedImageSamplerDescriptorWrite(VkDescriptorSet set, u32 binding,
VkImageView view, VkSampler sampler, VkImageLayout layout /*= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/)
{
pxAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
ii.imageView = view;
ii.imageLayout = layout;
ii.sampler = sampler;
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dw.dstSet = set;
dw.dstBinding = binding;
dw.descriptorCount = 1;
dw.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
dw.pImageInfo = &ii;
}
void DescriptorSetUpdateBuilder::AddCombinedImageSamplerDescriptorWrites(VkDescriptorSet set, u32 binding,
const VkImageView* views, const VkSampler* samplers, u32 num_views,
VkImageLayout layout /* = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL */)
{
pxAssert(m_num_writes < MAX_WRITES && (m_num_image_infos + num_views) < MAX_IMAGE_INFOS);
#if 1
// NOTE: This is deliberately split up - updating multiple descriptors in one write is broken on Adreno.
for (u32 i = 0; i < num_views; i++)
AddCombinedImageSamplerDescriptorWrite(set, binding + i, views[i], samplers[i], layout);
#else
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dw.dstSet = set;
dw.dstBinding = binding;
dw.descriptorCount = num_views;
dw.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
dw.pImageInfo = &m_image_infos[m_num_image_infos];
for (u32 i = 0; i < num_views; i++)
{
VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
ii.imageView = views[i];
ii.sampler = samplers[i];
ii.imageLayout = layout;
}
#endif
}
void DescriptorSetUpdateBuilder::AddBufferDescriptorWrite(
VkDescriptorSet set, u32 binding, VkDescriptorType dtype, VkBuffer buffer, u32 offset, u32 size)
{
pxAssert(m_num_writes < MAX_WRITES && m_num_buffer_infos < MAX_BUFFER_INFOS);
VkDescriptorBufferInfo& bi = m_buffer_infos[m_num_buffer_infos++];
bi.buffer = buffer;
bi.offset = offset;
bi.range = size;
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dw.dstSet = set;
dw.dstBinding = binding;
dw.descriptorCount = 1;
dw.descriptorType = dtype;
dw.pBufferInfo = &bi;
}
void DescriptorSetUpdateBuilder::AddBufferViewDescriptorWrite(
VkDescriptorSet set, u32 binding, VkDescriptorType dtype, VkBufferView view)
{
pxAssert(m_num_writes < MAX_WRITES && m_num_views < MAX_VIEWS);
VkBufferView& bi = m_views[m_num_views++];
bi = view;
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dw.dstSet = set;
dw.dstBinding = binding;
dw.descriptorCount = 1;
dw.descriptorType = dtype;
dw.pTexelBufferView = &bi;
}
void DescriptorSetUpdateBuilder::AddInputAttachmentDescriptorWrite(
VkDescriptorSet set, u32 binding, VkImageView view, VkImageLayout layout /*= VK_IMAGE_LAYOUT_GENERAL*/)
{
pxAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dw.dstSet = set;
dw.dstBinding = binding;
dw.descriptorCount = 1;
dw.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
dw.pImageInfo = &m_image_infos[m_num_image_infos];
VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
ii.imageView = view;
ii.imageLayout = layout;
ii.sampler = VK_NULL_HANDLE;
}
void DescriptorSetUpdateBuilder::AddStorageImageDescriptorWrite(
VkDescriptorSet set, u32 binding, VkImageView view, VkImageLayout layout /*= VK_IMAGE_LAYOUT_GENERAL*/)
{
pxAssert(m_num_writes < MAX_WRITES && m_num_image_infos < MAX_IMAGE_INFOS);
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
dw.dstSet = set;
dw.dstBinding = binding;
dw.descriptorCount = 1;
dw.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
dw.pImageInfo = &m_image_infos[m_num_image_infos];
VkDescriptorImageInfo& ii = m_image_infos[m_num_image_infos++];
ii.imageView = view;
ii.imageLayout = layout;
ii.sampler = VK_NULL_HANDLE;
}
FramebufferBuilder::FramebufferBuilder() { Clear(); }
void FramebufferBuilder::Clear()
{
m_ci = {};
m_ci.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
m_images = {};
}
VkFramebuffer FramebufferBuilder::Create(VkDevice device, bool clear /*= true*/)
{
VkFramebuffer fb;
VkResult res = vkCreateFramebuffer(device, &m_ci, nullptr, &fb);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateFramebuffer() failed: ");
return VK_NULL_HANDLE;
}
if (clear)
Clear();
return fb;
}
void FramebufferBuilder::AddAttachment(VkImageView image)
{
pxAssert(m_ci.attachmentCount < MAX_ATTACHMENTS);
m_images[m_ci.attachmentCount] = image;
m_ci.attachmentCount++;
m_ci.pAttachments = m_images.data();
}
void FramebufferBuilder::SetSize(u32 width, u32 height, u32 layers)
{
m_ci.width = width;
m_ci.height = height;
m_ci.layers = layers;
}
void FramebufferBuilder::SetRenderPass(VkRenderPass render_pass) { m_ci.renderPass = render_pass; }
RenderPassBuilder::RenderPassBuilder() { Clear(); }
void RenderPassBuilder::Clear()
{
m_ci = {};
m_ci.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
m_attachments = {};
m_attachment_references = {};
m_num_attachment_references = 0;
m_subpasses = {};
}
VkRenderPass RenderPassBuilder::Create(VkDevice device, bool clear /*= true*/)
{
VkRenderPass rp;
VkResult res = vkCreateRenderPass(device, &m_ci, nullptr, &rp);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass() failed: ");
return VK_NULL_HANDLE;
}
return rp;
}
u32 RenderPassBuilder::AddAttachment(VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp load_op,
VkAttachmentStoreOp store_op, VkImageLayout initial_layout, VkImageLayout final_layout)
{
pxAssert(m_ci.attachmentCount < MAX_ATTACHMENTS);
const u32 index = m_ci.attachmentCount;
VkAttachmentDescription& ad = m_attachments[index];
ad.format = format;
ad.samples = samples;
ad.loadOp = load_op;
ad.storeOp = store_op;
ad.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
ad.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
ad.initialLayout = initial_layout;
ad.finalLayout = final_layout;
m_ci.attachmentCount++;
m_ci.pAttachments = m_attachments.data();
return index;
}
u32 RenderPassBuilder::AddSubpass()
{
pxAssert(m_ci.subpassCount < MAX_SUBPASSES);
const u32 index = m_ci.subpassCount;
VkSubpassDescription& sp = m_subpasses[index];
sp.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
m_ci.subpassCount++;
m_ci.pSubpasses = m_subpasses.data();
return index;
}
void RenderPassBuilder::AddSubpassColorAttachment(u32 subpass, u32 attachment, VkImageLayout layout)
{
pxAssert(subpass < m_ci.subpassCount && m_num_attachment_references < MAX_ATTACHMENT_REFERENCES);
VkAttachmentReference& ar = m_attachment_references[m_num_attachment_references++];
ar.attachment = attachment;
ar.layout = layout;
VkSubpassDescription& sp = m_subpasses[subpass];
if (sp.colorAttachmentCount == 0)
sp.pColorAttachments = &ar;
sp.colorAttachmentCount++;
}
void RenderPassBuilder::AddSubpassDepthAttachment(u32 subpass, u32 attachment, VkImageLayout layout)
{
pxAssert(subpass < m_ci.subpassCount && m_num_attachment_references < MAX_ATTACHMENT_REFERENCES);
VkAttachmentReference& ar = m_attachment_references[m_num_attachment_references++];
ar.attachment = attachment;
ar.layout = layout;
VkSubpassDescription& sp = m_subpasses[subpass];
sp.pDepthStencilAttachment = &ar;
}
BufferViewBuilder::BufferViewBuilder() { Clear(); }
void BufferViewBuilder::Clear()
{
m_ci = {};
m_ci.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
}
VkBufferView BufferViewBuilder::Create(VkDevice device, bool clear /*= true*/)
{
VkBufferView bv;
VkResult res = vkCreateBufferView(device, &m_ci, nullptr, &bv);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateBufferView() failed: ");
return VK_NULL_HANDLE;
}
return bv;
}
void BufferViewBuilder::Set(VkBuffer buffer, VkFormat format, u32 offset, u32 size)
{
m_ci.buffer = buffer;
m_ci.format = format;
m_ci.offset = offset;
m_ci.range = size;
}
} // namespace Vulkan
File diff suppressed because it is too large Load Diff
-412
View File
@@ -1,412 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/ReadbackSpinManager.h"
#include "common/Vulkan/Loader.h"
#include "common/Vulkan/StreamBuffer.h"
#include <array>
#include <atomic>
#include <condition_variable>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
struct WindowInfo;
namespace Vulkan
{
class SwapChain;
class Context
{
public:
enum : u32
{
NUM_COMMAND_BUFFERS = 3,
TEXTURE_BUFFER_SIZE = 64 * 1024 * 1024,
};
struct OptionalExtensions
{
bool vk_ext_provoking_vertex : 1;
bool vk_ext_memory_budget : 1;
bool vk_ext_calibrated_timestamps : 1;
bool vk_ext_line_rasterization : 1;
bool vk_khr_driver_properties : 1;
bool vk_arm_rasterization_order_attachment_access : 1;
bool vk_khr_fragment_shader_barycentric : 1;
};
~Context();
// Helper method to create a Vulkan instance.
static VkInstance CreateVulkanInstance(
const WindowInfo* wi, bool enable_debug_utils, bool enable_validation_layer);
// Returns a list of Vulkan-compatible GPUs.
using GPUList = std::vector<VkPhysicalDevice>;
using GPUNameList = std::vector<std::string>;
static GPUList EnumerateGPUs(VkInstance instance);
static GPUNameList EnumerateGPUNames(VkInstance instance);
// Creates a new context and sets it up as global.
static bool Create(std::string_view gpu_name, const WindowInfo* wi, std::unique_ptr<SwapChain>* out_swap_chain,
VkPresentModeKHR preferred_present_mode, bool threaded_presentation, bool enable_debug_utils,
bool enable_validation_layer);
// Destroys context.
static void Destroy();
// Enable/disable debug message runtime.
bool EnableDebugUtils();
void DisableDebugUtils();
// Global state accessors
__fi VkInstance GetVulkanInstance() const { return m_instance; }
__fi VkPhysicalDevice GetPhysicalDevice() const { return m_physical_device; }
__fi VkDevice GetDevice() const { return m_device; }
__fi VmaAllocator GetAllocator() const { return m_allocator; }
__fi VkQueue GetGraphicsQueue() const { return m_graphics_queue; }
__fi u32 GetGraphicsQueueFamilyIndex() const { return m_graphics_queue_family_index; }
__fi VkQueue GetPresentQueue() const { return m_present_queue; }
__fi u32 GetPresentQueueFamilyIndex() const { return m_present_queue_family_index; }
__fi const VkQueueFamilyProperties& GetGraphicsQueueProperties() const { return m_graphics_queue_properties; }
__fi const VkPhysicalDeviceMemoryProperties& GetDeviceMemoryProperties() const
{
return m_device_memory_properties;
}
__fi const VkPhysicalDeviceProperties& GetDeviceProperties() const { return m_device_properties; }
__fi const VkPhysicalDeviceFeatures& GetDeviceFeatures() const { return m_device_features; }
__fi const VkPhysicalDeviceLimits& GetDeviceLimits() const { return m_device_properties.limits; }
__fi const VkPhysicalDeviceDriverProperties& GetDeviceDriverProperties() const { return m_device_driver_properties; }
__fi const OptionalExtensions& GetOptionalExtensions() const { return m_optional_extensions; }
// Helpers for getting constants
__fi u32 GetUniformBufferAlignment() const
{
return static_cast<u32>(m_device_properties.limits.minUniformBufferOffsetAlignment);
}
__fi u32 GetTexelBufferAlignment() const
{
return static_cast<u32>(m_device_properties.limits.minTexelBufferOffsetAlignment);
}
__fi u32 GetStorageBufferAlignment() const
{
return static_cast<u32>(m_device_properties.limits.minStorageBufferOffsetAlignment);
}
__fi u32 GetBufferImageGranularity() const
{
return static_cast<u32>(m_device_properties.limits.bufferImageGranularity);
}
__fi u32 GetBufferCopyOffsetAlignment() const
{
return static_cast<u32>(m_device_properties.limits.optimalBufferCopyOffsetAlignment);
}
__fi u32 GetBufferCopyRowPitchAlignment() const
{
return static_cast<u32>(m_device_properties.limits.optimalBufferCopyRowPitchAlignment);
}
__fi u32 GetMaxImageDimension2D() const
{
return m_device_properties.limits.maxImageDimension2D;
}
// Creates a simple render pass.
__ri VkRenderPass GetRenderPass(VkFormat color_format, VkFormat depth_format,
VkAttachmentLoadOp color_load_op = VK_ATTACHMENT_LOAD_OP_LOAD,
VkAttachmentStoreOp color_store_op = VK_ATTACHMENT_STORE_OP_STORE,
VkAttachmentLoadOp depth_load_op = VK_ATTACHMENT_LOAD_OP_LOAD,
VkAttachmentStoreOp depth_store_op = VK_ATTACHMENT_STORE_OP_STORE,
VkAttachmentLoadOp stencil_load_op = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VkAttachmentStoreOp stencil_store_op = VK_ATTACHMENT_STORE_OP_DONT_CARE,
bool color_feedback_loop = false, bool depth_sampling = false)
{
RenderPassCacheKey key = {};
key.color_format = color_format;
key.depth_format = depth_format;
key.color_load_op = color_load_op;
key.color_store_op = color_store_op;
key.depth_load_op = depth_load_op;
key.depth_store_op = depth_store_op;
key.stencil_load_op = stencil_load_op;
key.stencil_store_op = stencil_store_op;
key.color_feedback_loop = color_feedback_loop;
key.depth_sampling = depth_sampling;
auto it = m_render_pass_cache.find(key.key);
if (it != m_render_pass_cache.end())
return it->second;
return CreateCachedRenderPass(key);
}
// These command buffers are allocated per-frame. They are valid until the command buffer
// is submitted, after that you should call these functions again.
__fi u32 GetCurrentCommandBufferIndex() const { return m_current_frame; }
__fi VkDescriptorPool GetGlobalDescriptorPool() const { return m_global_descriptor_pool; }
__fi VkCommandBuffer GetCurrentCommandBuffer() const { return m_current_command_buffer; }
__fi StreamBuffer& GetTextureUploadBuffer() { return m_texture_upload_buffer; }
__fi VkDescriptorPool GetCurrentDescriptorPool() const
{
return m_frame_resources[m_current_frame].descriptor_pool;
}
VkCommandBuffer GetCurrentInitCommandBuffer();
/// Allocates a descriptor set from the pool reserved for the current frame.
VkDescriptorSet AllocateDescriptorSet(VkDescriptorSetLayout set_layout);
/// Allocates a descriptor set from the pool reserved for the current frame.
VkDescriptorSet AllocatePersistentDescriptorSet(VkDescriptorSetLayout set_layout);
/// Frees a descriptor set allocated from the global pool.
void FreeGlobalDescriptorSet(VkDescriptorSet set);
// Gets the fence that will be signaled when the currently executing command buffer is
// queued and executed. Do not wait for this fence before the buffer is executed.
__fi VkFence GetCurrentCommandBufferFence() const { return m_frame_resources[m_current_frame].fence; }
// Fence "counters" are used to track which commands have been completed by the GPU.
// If the last completed fence counter is greater or equal to N, it means that the work
// associated counter N has been completed by the GPU. The value of N to associate with
// commands can be retreived by calling GetCurrentFenceCounter().
u64 GetCompletedFenceCounter() const { return m_completed_fence_counter; }
// Gets the fence that will be signaled when the currently executing command buffer is
// queued and executed. Do not wait for this fence before the buffer is executed.
u64 GetCurrentFenceCounter() const { return m_frame_resources[m_current_frame].fence_counter; }
void SubmitCommandBuffer(SwapChain* present_swap_chain = nullptr, bool submit_on_thread = false);
void MoveToNextCommandBuffer();
enum class WaitType
{
None,
Sleep,
Spin,
};
void ExecuteCommandBuffer(WaitType wait_for_completion);
void WaitForPresentComplete();
// Was the last present submitted to the queue a failure? If so, we must recreate our swapchain.
bool CheckLastPresentFail();
bool CheckLastSubmitFail();
// Schedule a vulkan resource for destruction later on. This will occur when the command buffer
// is next re-used, and the GPU has finished working with the specified resource.
void DeferBufferDestruction(VkBuffer object);
void DeferBufferDestruction(VkBuffer object, VmaAllocation allocation);
void DeferBufferViewDestruction(VkBufferView object);
void DeferDeviceMemoryDestruction(VkDeviceMemory object);
void DeferFramebufferDestruction(VkFramebuffer object);
void DeferImageDestruction(VkImage object);
void DeferImageDestruction(VkImage object, VmaAllocation allocation);
void DeferImageViewDestruction(VkImageView object);
void DeferPipelineDestruction(VkPipeline pipeline);
void DeferSamplerDestruction(VkSampler sampler);
// Wait for a fence to be completed.
// Also invokes callbacks for completion.
void WaitForFenceCounter(u64 fence_counter);
void WaitForGPUIdle();
float GetAndResetAccumulatedGPUTime();
bool SetEnableGPUTiming(bool enabled);
void CountRenderPass() { m_command_buffer_render_passes++; }
void NotifyOfReadback();
private:
Context(VkInstance instance, VkPhysicalDevice physical_device);
union RenderPassCacheKey
{
struct
{
u32 color_format : 8;
u32 depth_format : 8;
u32 color_load_op : 2;
u32 color_store_op : 1;
u32 depth_load_op : 2;
u32 depth_store_op : 1;
u32 stencil_load_op : 2;
u32 stencil_store_op : 1;
u32 color_feedback_loop : 1;
u32 depth_sampling : 1;
};
u32 key;
};
using ExtensionList = std::vector<const char*>;
static bool SelectInstanceExtensions(
ExtensionList* extension_list, const WindowInfo* wi, bool enable_debug_utils);
bool SelectDeviceExtensions(ExtensionList* extension_list, bool enable_surface);
bool SelectDeviceFeatures(const VkPhysicalDeviceFeatures* required_features);
bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer, const char** required_device_extensions,
u32 num_required_device_extensions, const char** required_device_layers, u32 num_required_device_layers,
const VkPhysicalDeviceFeatures* required_features);
void ProcessDeviceExtensions();
bool CreateAllocator();
void DestroyAllocator();
bool CreateCommandBuffers();
void DestroyCommandBuffers();
bool CreateGlobalDescriptorPool();
void DestroyGlobalDescriptorPool();
bool CreateTextureStreamBuffer();
VkRenderPass CreateCachedRenderPass(RenderPassCacheKey key);
void DestroyRenderPassCache();
void CommandBufferCompleted(u32 index);
void ActivateCommandBuffer(u32 index);
void ScanForCommandBufferCompletion();
void WaitForCommandBufferCompletion(u32 index);
void DoSubmitCommandBuffer(u32 index, SwapChain* present_swap_chain, u32 spin_cycles);
void DoPresent(SwapChain* present_swap_chain);
void WaitForPresentComplete(std::unique_lock<std::mutex>& lock);
void PresentThread();
void StartPresentThread();
void StopPresentThread();
bool InitSpinResources();
void DestroySpinResources();
void WaitForSpinCompletion(u32 index);
void SpinCommandCompleted(u32 index);
void SubmitSpinCommand(u32 index, u32 cycles);
void CalibrateSpinTimestamp();
u64 GetCPUTimestamp();
struct FrameResources
{
// [0] - Init (upload) command buffer, [1] - draw command buffer
VkCommandPool command_pool = VK_NULL_HANDLE;
std::array<VkCommandBuffer, 2> command_buffers{VK_NULL_HANDLE, VK_NULL_HANDLE};
VkDescriptorPool descriptor_pool = VK_NULL_HANDLE;
VkFence fence = VK_NULL_HANDLE;
u64 fence_counter = 0;
s32 spin_id = -1;
u32 submit_timestamp = 0;
bool init_buffer_used = false;
bool needs_fence_wait = false;
bool timestamp_written = false;
std::vector<std::function<void()>> cleanup_resources;
};
struct SpinResources
{
VkCommandPool command_pool = VK_NULL_HANDLE;
VkCommandBuffer command_buffer = VK_NULL_HANDLE;
VkSemaphore semaphore = VK_NULL_HANDLE;
VkFence fence = VK_NULL_HANDLE;
u32 cycles = 0;
bool in_progress = false;
};
VkInstance m_instance = VK_NULL_HANDLE;
VkPhysicalDevice m_physical_device = VK_NULL_HANDLE;
VkDevice m_device = VK_NULL_HANDLE;
VmaAllocator m_allocator = VK_NULL_HANDLE;
VkCommandBuffer m_current_command_buffer = VK_NULL_HANDLE;
VkDescriptorPool m_global_descriptor_pool = VK_NULL_HANDLE;
VkQueue m_graphics_queue = VK_NULL_HANDLE;
VkQueue m_present_queue = VK_NULL_HANDLE;
u32 m_graphics_queue_family_index = 0;
u32 m_present_queue_family_index = 0;
ReadbackSpinManager m_spin_manager;
VkQueue m_spin_queue = VK_NULL_HANDLE;
VkDescriptorSetLayout m_spin_descriptor_set_layout = VK_NULL_HANDLE;
VkPipelineLayout m_spin_pipeline_layout = VK_NULL_HANDLE;
VkPipeline m_spin_pipeline = VK_NULL_HANDLE;
VkBuffer m_spin_buffer = VK_NULL_HANDLE;
VmaAllocation m_spin_buffer_allocation = VK_NULL_HANDLE;
VkDescriptorSet m_spin_descriptor_set = VK_NULL_HANDLE;
std::array<SpinResources, NUM_COMMAND_BUFFERS> m_spin_resources;
#ifdef _WIN32
double m_queryperfcounter_to_ns = 0;
#endif
double m_spin_timestamp_scale = 0;
double m_spin_timestamp_offset = 0;
u32 m_spin_queue_family_index = 0;
u32 m_command_buffer_render_passes = 0;
u32 m_spin_timer = 0;
bool m_spinning_supported = false;
bool m_spin_queue_is_graphics_queue = false;
bool m_spin_buffer_initialized = false;
VkQueryPool m_timestamp_query_pool = VK_NULL_HANDLE;
float m_accumulated_gpu_time = 0.0f;
bool m_gpu_timing_enabled = false;
bool m_gpu_timing_supported = false;
bool m_wants_new_timestamp_calibration = false;
VkTimeDomainEXT m_calibrated_timestamp_type = VK_TIME_DOMAIN_DEVICE_EXT;
std::array<FrameResources, NUM_COMMAND_BUFFERS> m_frame_resources;
u64 m_next_fence_counter = 1;
u64 m_completed_fence_counter = 0;
u32 m_current_frame = 0;
StreamBuffer m_texture_upload_buffer;
std::atomic_bool m_last_submit_failed{false};
std::atomic_bool m_last_present_failed{false};
std::atomic_bool m_present_done{true};
std::mutex m_present_mutex;
std::condition_variable m_present_queued_cv;
std::condition_variable m_present_done_cv;
std::thread m_present_thread;
std::atomic_bool m_present_thread_done{false};
struct QueuedPresent
{
SwapChain* swap_chain;
u32 command_buffer_index;
u32 spin_cycles;
};
QueuedPresent m_queued_present = {};
std::map<u32, VkRenderPass> m_render_pass_cache;
VkDebugUtilsMessengerEXT m_debug_messenger_callback = VK_NULL_HANDLE;
VkQueueFamilyProperties m_graphics_queue_properties = {};
VkPhysicalDeviceFeatures m_device_features = {};
VkPhysicalDeviceProperties m_device_properties = {};
VkPhysicalDeviceMemoryProperties m_device_memory_properties = {};
VkPhysicalDeviceDriverPropertiesKHR m_device_driver_properties = {};
OptionalExtensions m_optional_extensions = {};
};
} // namespace Vulkan
extern std::unique_ptr<Vulkan::Context> g_vulkan_context;
-237
View File
@@ -1,237 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
// We abuse the preprocessor here to only need to specify function names once.
// Function names are prefixed so to not conflict with system symbols at runtime.
#define VULKAN_MODULE_ENTRY_POINT(name, required) extern PFN_##name pcsx2_##name;
#define VULKAN_INSTANCE_ENTRY_POINT(name, required) extern PFN_##name pcsx2_##name;
#define VULKAN_DEVICE_ENTRY_POINT(name, required) extern PFN_##name pcsx2_##name;
#define VULKAN_DEFINE_NAME_PREFIX pcsx2_
#include "EntryPoints.inl"
#undef VULKAN_DEFINE_NAME_PREFIX
#undef VULKAN_DEVICE_ENTRY_POINT
#undef VULKAN_INSTANCE_ENTRY_POINT
#undef VULKAN_MODULE_ENTRY_POINT
#ifdef __cplusplus
}
#endif
#define vkCreateInstance pcsx2_vkCreateInstance
#define vkGetInstanceProcAddr pcsx2_vkGetInstanceProcAddr
#define vkEnumerateInstanceExtensionProperties pcsx2_vkEnumerateInstanceExtensionProperties
#define vkEnumerateInstanceLayerProperties pcsx2_vkEnumerateInstanceLayerProperties
#define vkEnumerateInstanceVersion pcsx2_vkEnumerateInstanceVersion
#define vkGetDeviceProcAddr pcsx2_vkGetDeviceProcAddr
#define vkDestroyInstance pcsx2_vkDestroyInstance
#define vkEnumeratePhysicalDevices pcsx2_vkEnumeratePhysicalDevices
#define vkGetPhysicalDeviceFeatures pcsx2_vkGetPhysicalDeviceFeatures
#define vkGetPhysicalDeviceFormatProperties pcsx2_vkGetPhysicalDeviceFormatProperties
#define vkGetPhysicalDeviceImageFormatProperties pcsx2_vkGetPhysicalDeviceImageFormatProperties
#define vkGetPhysicalDeviceProperties pcsx2_vkGetPhysicalDeviceProperties
#define vkGetPhysicalDeviceQueueFamilyProperties pcsx2_vkGetPhysicalDeviceQueueFamilyProperties
#define vkGetPhysicalDeviceMemoryProperties pcsx2_vkGetPhysicalDeviceMemoryProperties
#define vkCreateDevice pcsx2_vkCreateDevice
#define vkEnumerateDeviceExtensionProperties pcsx2_vkEnumerateDeviceExtensionProperties
#define vkEnumerateDeviceLayerProperties pcsx2_vkEnumerateDeviceLayerProperties
#define vkGetPhysicalDeviceSparseImageFormatProperties pcsx2_vkGetPhysicalDeviceSparseImageFormatProperties
#define vkDestroySurfaceKHR pcsx2_vkDestroySurfaceKHR
#define vkGetPhysicalDeviceSurfaceSupportKHR pcsx2_vkGetPhysicalDeviceSurfaceSupportKHR
#define vkGetPhysicalDeviceSurfaceCapabilitiesKHR pcsx2_vkGetPhysicalDeviceSurfaceCapabilitiesKHR
#define vkGetPhysicalDeviceSurfaceFormatsKHR pcsx2_vkGetPhysicalDeviceSurfaceFormatsKHR
#define vkGetPhysicalDeviceSurfacePresentModesKHR pcsx2_vkGetPhysicalDeviceSurfacePresentModesKHR
#define vkCreateWin32SurfaceKHR pcsx2_vkCreateWin32SurfaceKHR
#define vkGetPhysicalDeviceWin32PresentationSupportKHR pcsx2_vkGetPhysicalDeviceWin32PresentationSupportKHR
#define vkCreateXlibSurfaceKHR pcsx2_vkCreateXlibSurfaceKHR
#define vkGetPhysicalDeviceXlibPresentationSupportKHR pcsx2_vkGetPhysicalDeviceXlibPresentationSupportKHR
#define vkCreateWaylandSurfaceKHR pcsx2_vkCreateWaylandSurfaceKHR
#define vkCreateAndroidSurfaceKHR pcsx2_vkCreateAndroidSurfaceKHR
#define vkCreateMacOSSurfaceMVK pcsx2_vkCreateMacOSSurfaceMVK
#define vkCreateMetalSurfaceEXT pcsx2_vkCreateMetalSurfaceEXT
// VK_EXT_debug_utils
#define vkCmdBeginDebugUtilsLabelEXT pcsx2_vkCmdBeginDebugUtilsLabelEXT
#define vkCmdEndDebugUtilsLabelEXT pcsx2_vkCmdEndDebugUtilsLabelEXT
#define vkCmdInsertDebugUtilsLabelEXT pcsx2_vkCmdInsertDebugUtilsLabelEXT
#define vkCreateDebugUtilsMessengerEXT pcsx2_vkCreateDebugUtilsMessengerEXT
#define vkDestroyDebugUtilsMessengerEXT pcsx2_vkDestroyDebugUtilsMessengerEXT
#define vkQueueBeginDebugUtilsLabelEXT pcsx2_vkQueueBeginDebugUtilsLabelEXT
#define vkQueueEndDebugUtilsLabelEXT pcsx2_vkQueueEndDebugUtilsLabelEXT
#define vkQueueInsertDebugUtilsLabelEXT pcsx2_vkQueueInsertDebugUtilsLabelEXT
#define vkSetDebugUtilsObjectNameEXT pcsx2_vkSetDebugUtilsObjectNameEXT
#define vkSetDebugUtilsObjectTagEXT pcsx2_vkSetDebugUtilsObjectTagEXT
#define vkSubmitDebugUtilsMessageEXT pcsx2_vkSubmitDebugUtilsMessageEXT
#define vkGetPhysicalDeviceSurfaceCapabilities2KHR pcsx2_vkGetPhysicalDeviceSurfaceCapabilities2KHR
#define vkGetPhysicalDeviceDisplayPropertiesKHR pcsx2_vkGetPhysicalDeviceDisplayPropertiesKHR
#define vkGetPhysicalDeviceDisplayPlanePropertiesKHR pcsx2_vkGetPhysicalDeviceDisplayPlanePropertiesKHR
#define vkGetDisplayPlaneSupportedDisplaysKHR pcsx2_vkGetDisplayPlaneSupportedDisplaysKHR
#define vkGetDisplayModePropertiesKHR pcsx2_vkGetDisplayModePropertiesKHR
#define vkCreateDisplayModeKHR pcsx2_vkCreateDisplayModeKHR
#define vkGetDisplayPlaneCapabilitiesKHR pcsx2_vkGetDisplayPlaneCapabilitiesKHR
#define vkCreateDisplayPlaneSurfaceKHR pcsx2_vkCreateDisplayPlaneSurfaceKHR
// Vulkan 1.1 functions.
#define vkGetPhysicalDeviceFeatures2 pcsx2_vkGetPhysicalDeviceFeatures2
#define vkGetPhysicalDeviceProperties2 pcsx2_vkGetPhysicalDeviceProperties2
#define vkGetPhysicalDeviceMemoryProperties2 pcsx2_vkGetPhysicalDeviceMemoryProperties2
#define vkDestroyDevice pcsx2_vkDestroyDevice
#define vkGetDeviceQueue pcsx2_vkGetDeviceQueue
#define vkQueueSubmit pcsx2_vkQueueSubmit
#define vkQueueWaitIdle pcsx2_vkQueueWaitIdle
#define vkDeviceWaitIdle pcsx2_vkDeviceWaitIdle
#define vkAllocateMemory pcsx2_vkAllocateMemory
#define vkFreeMemory pcsx2_vkFreeMemory
#define vkMapMemory pcsx2_vkMapMemory
#define vkUnmapMemory pcsx2_vkUnmapMemory
#define vkFlushMappedMemoryRanges pcsx2_vkFlushMappedMemoryRanges
#define vkInvalidateMappedMemoryRanges pcsx2_vkInvalidateMappedMemoryRanges
#define vkGetDeviceMemoryCommitment pcsx2_vkGetDeviceMemoryCommitment
#define vkBindBufferMemory pcsx2_vkBindBufferMemory
#define vkBindImageMemory pcsx2_vkBindImageMemory
#define vkGetBufferMemoryRequirements pcsx2_vkGetBufferMemoryRequirements
#define vkGetImageMemoryRequirements pcsx2_vkGetImageMemoryRequirements
#define vkGetImageSparseMemoryRequirements pcsx2_vkGetImageSparseMemoryRequirements
#define vkQueueBindSparse pcsx2_vkQueueBindSparse
#define vkCreateFence pcsx2_vkCreateFence
#define vkDestroyFence pcsx2_vkDestroyFence
#define vkResetFences pcsx2_vkResetFences
#define vkGetFenceStatus pcsx2_vkGetFenceStatus
#define vkWaitForFences pcsx2_vkWaitForFences
#define vkCreateSemaphore pcsx2_vkCreateSemaphore
#define vkDestroySemaphore pcsx2_vkDestroySemaphore
#define vkCreateEvent pcsx2_vkCreateEvent
#define vkDestroyEvent pcsx2_vkDestroyEvent
#define vkGetEventStatus pcsx2_vkGetEventStatus
#define vkSetEvent pcsx2_vkSetEvent
#define vkResetEvent pcsx2_vkResetEvent
#define vkCreateQueryPool pcsx2_vkCreateQueryPool
#define vkDestroyQueryPool pcsx2_vkDestroyQueryPool
#define vkGetQueryPoolResults pcsx2_vkGetQueryPoolResults
#define vkCreateBuffer pcsx2_vkCreateBuffer
#define vkDestroyBuffer pcsx2_vkDestroyBuffer
#define vkCreateBufferView pcsx2_vkCreateBufferView
#define vkDestroyBufferView pcsx2_vkDestroyBufferView
#define vkCreateImage pcsx2_vkCreateImage
#define vkDestroyImage pcsx2_vkDestroyImage
#define vkGetImageSubresourceLayout pcsx2_vkGetImageSubresourceLayout
#define vkCreateImageView pcsx2_vkCreateImageView
#define vkDestroyImageView pcsx2_vkDestroyImageView
#define vkCreateShaderModule pcsx2_vkCreateShaderModule
#define vkDestroyShaderModule pcsx2_vkDestroyShaderModule
#define vkCreatePipelineCache pcsx2_vkCreatePipelineCache
#define vkDestroyPipelineCache pcsx2_vkDestroyPipelineCache
#define vkGetPipelineCacheData pcsx2_vkGetPipelineCacheData
#define vkMergePipelineCaches pcsx2_vkMergePipelineCaches
#define vkCreateGraphicsPipelines pcsx2_vkCreateGraphicsPipelines
#define vkCreateComputePipelines pcsx2_vkCreateComputePipelines
#define vkDestroyPipeline pcsx2_vkDestroyPipeline
#define vkCreatePipelineLayout pcsx2_vkCreatePipelineLayout
#define vkDestroyPipelineLayout pcsx2_vkDestroyPipelineLayout
#define vkCreateSampler pcsx2_vkCreateSampler
#define vkDestroySampler pcsx2_vkDestroySampler
#define vkCreateDescriptorSetLayout pcsx2_vkCreateDescriptorSetLayout
#define vkDestroyDescriptorSetLayout pcsx2_vkDestroyDescriptorSetLayout
#define vkCreateDescriptorPool pcsx2_vkCreateDescriptorPool
#define vkDestroyDescriptorPool pcsx2_vkDestroyDescriptorPool
#define vkResetDescriptorPool pcsx2_vkResetDescriptorPool
#define vkAllocateDescriptorSets pcsx2_vkAllocateDescriptorSets
#define vkFreeDescriptorSets pcsx2_vkFreeDescriptorSets
#define vkUpdateDescriptorSets pcsx2_vkUpdateDescriptorSets
#define vkCreateFramebuffer pcsx2_vkCreateFramebuffer
#define vkDestroyFramebuffer pcsx2_vkDestroyFramebuffer
#define vkCreateRenderPass pcsx2_vkCreateRenderPass
#define vkDestroyRenderPass pcsx2_vkDestroyRenderPass
#define vkGetRenderAreaGranularity pcsx2_vkGetRenderAreaGranularity
#define vkCreateCommandPool pcsx2_vkCreateCommandPool
#define vkDestroyCommandPool pcsx2_vkDestroyCommandPool
#define vkResetCommandPool pcsx2_vkResetCommandPool
#define vkAllocateCommandBuffers pcsx2_vkAllocateCommandBuffers
#define vkFreeCommandBuffers pcsx2_vkFreeCommandBuffers
#define vkBeginCommandBuffer pcsx2_vkBeginCommandBuffer
#define vkEndCommandBuffer pcsx2_vkEndCommandBuffer
#define vkResetCommandBuffer pcsx2_vkResetCommandBuffer
#define vkCmdBindPipeline pcsx2_vkCmdBindPipeline
#define vkCmdSetViewport pcsx2_vkCmdSetViewport
#define vkCmdSetScissor pcsx2_vkCmdSetScissor
#define vkCmdSetLineWidth pcsx2_vkCmdSetLineWidth
#define vkCmdSetDepthBias pcsx2_vkCmdSetDepthBias
#define vkCmdSetBlendConstants pcsx2_vkCmdSetBlendConstants
#define vkCmdSetDepthBounds pcsx2_vkCmdSetDepthBounds
#define vkCmdSetStencilCompareMask pcsx2_vkCmdSetStencilCompareMask
#define vkCmdSetStencilWriteMask pcsx2_vkCmdSetStencilWriteMask
#define vkCmdSetStencilReference pcsx2_vkCmdSetStencilReference
#define vkCmdBindDescriptorSets pcsx2_vkCmdBindDescriptorSets
#define vkCmdBindIndexBuffer pcsx2_vkCmdBindIndexBuffer
#define vkCmdBindVertexBuffers pcsx2_vkCmdBindVertexBuffers
#define vkCmdDraw pcsx2_vkCmdDraw
#define vkCmdDrawIndexed pcsx2_vkCmdDrawIndexed
#define vkCmdDrawIndirect pcsx2_vkCmdDrawIndirect
#define vkCmdDrawIndexedIndirect pcsx2_vkCmdDrawIndexedIndirect
#define vkCmdDispatch pcsx2_vkCmdDispatch
#define vkCmdDispatchIndirect pcsx2_vkCmdDispatchIndirect
#define vkCmdCopyBuffer pcsx2_vkCmdCopyBuffer
#define vkCmdCopyImage pcsx2_vkCmdCopyImage
#define vkCmdBlitImage pcsx2_vkCmdBlitImage
#define vkCmdCopyBufferToImage pcsx2_vkCmdCopyBufferToImage
#define vkCmdCopyImageToBuffer pcsx2_vkCmdCopyImageToBuffer
#define vkCmdUpdateBuffer pcsx2_vkCmdUpdateBuffer
#define vkCmdFillBuffer pcsx2_vkCmdFillBuffer
#define vkCmdClearColorImage pcsx2_vkCmdClearColorImage
#define vkCmdClearDepthStencilImage pcsx2_vkCmdClearDepthStencilImage
#define vkCmdClearAttachments pcsx2_vkCmdClearAttachments
#define vkCmdResolveImage pcsx2_vkCmdResolveImage
#define vkCmdSetEvent pcsx2_vkCmdSetEvent
#define vkCmdResetEvent pcsx2_vkCmdResetEvent
#define vkCmdWaitEvents pcsx2_vkCmdWaitEvents
#define vkCmdPipelineBarrier pcsx2_vkCmdPipelineBarrier
#define vkCmdBeginQuery pcsx2_vkCmdBeginQuery
#define vkCmdEndQuery pcsx2_vkCmdEndQuery
#define vkCmdResetQueryPool pcsx2_vkCmdResetQueryPool
#define vkCmdWriteTimestamp pcsx2_vkCmdWriteTimestamp
#define vkCmdCopyQueryPoolResults pcsx2_vkCmdCopyQueryPoolResults
#define vkCmdPushConstants pcsx2_vkCmdPushConstants
#define vkCmdBeginRenderPass pcsx2_vkCmdBeginRenderPass
#define vkCmdNextSubpass pcsx2_vkCmdNextSubpass
#define vkCmdEndRenderPass pcsx2_vkCmdEndRenderPass
#define vkCmdExecuteCommands pcsx2_vkCmdExecuteCommands
#define vkCreateSwapchainKHR pcsx2_vkCreateSwapchainKHR
#define vkDestroySwapchainKHR pcsx2_vkDestroySwapchainKHR
#define vkGetSwapchainImagesKHR pcsx2_vkGetSwapchainImagesKHR
#define vkAcquireNextImageKHR pcsx2_vkAcquireNextImageKHR
#define vkQueuePresentKHR pcsx2_vkQueuePresentKHR
// Vulkan 1.1 functions.
#define vkGetBufferMemoryRequirements2 pcsx2_vkGetBufferMemoryRequirements2
#define vkGetImageMemoryRequirements2 pcsx2_vkGetImageMemoryRequirements2
#define vkBindBufferMemory2 pcsx2_vkBindBufferMemory2
#define vkBindImageMemory2 pcsx2_vkBindImageMemory2
#ifdef SUPPORTS_VULKAN_EXCLUSIVE_FULLSCREEN
#define vkAcquireFullScreenExclusiveModeEXT pcsx2_vkAcquireFullScreenExclusiveModeEXT
#define vkReleaseFullScreenExclusiveModeEXT pcsx2_vkReleaseFullScreenExclusiveModeEXT
#endif
// VK_EXT_calibrated_timestamps
#define vkGetCalibratedTimestampsEXT pcsx2_vkGetCalibratedTimestampsEXT
#define vkGetPhysicalDeviceCalibrateableTimeDomainsEXT pcsx2_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT
-260
View File
@@ -1,260 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <atomic>
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include "Loader.h"
#ifndef _WIN32
#include <dlfcn.h>
#endif
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
extern "C" {
#define VULKAN_MODULE_ENTRY_POINT(name, required) PFN_##name pcsx2_##name;
#define VULKAN_INSTANCE_ENTRY_POINT(name, required) PFN_##name pcsx2_##name;
#define VULKAN_DEVICE_ENTRY_POINT(name, required) PFN_##name pcsx2_##name;
#include "EntryPoints.inl"
#undef VULKAN_DEVICE_ENTRY_POINT
#undef VULKAN_INSTANCE_ENTRY_POINT
#undef VULKAN_MODULE_ENTRY_POINT
}
namespace Vulkan
{
void ResetVulkanLibraryFunctionPointers()
{
#define VULKAN_MODULE_ENTRY_POINT(name, required) pcsx2_##name = nullptr;
#define VULKAN_INSTANCE_ENTRY_POINT(name, required) pcsx2_##name = nullptr;
#define VULKAN_DEVICE_ENTRY_POINT(name, required) pcsx2_##name = nullptr;
#include "EntryPoints.inl"
#undef VULKAN_DEVICE_ENTRY_POINT
#undef VULKAN_INSTANCE_ENTRY_POINT
#undef VULKAN_MODULE_ENTRY_POINT
}
#if defined(_WIN32)
static HMODULE vulkan_module;
static std::atomic_int vulkan_module_ref_count = {0};
bool LoadVulkanLibrary()
{
// Not thread safe if a second thread calls the loader whilst the first is still in-progress.
if (vulkan_module)
{
vulkan_module_ref_count++;
return true;
}
vulkan_module = LoadLibraryA("vulkan-1.dll");
if (!vulkan_module)
{
std::fprintf(stderr, "Failed to load vulkan-1.dll\n");
return false;
}
bool required_functions_missing = false;
auto LoadFunction = [&](FARPROC* func_ptr, const char* name, bool is_required) {
*func_ptr = GetProcAddress(vulkan_module, name);
if (!(*func_ptr) && is_required)
{
std::fprintf(stderr, "Vulkan: Failed to load required module function %s\n", name);
required_functions_missing = true;
}
};
#define VULKAN_MODULE_ENTRY_POINT(name, required) LoadFunction(reinterpret_cast<FARPROC*>(&name), #name, required);
#include "EntryPoints.inl"
#undef VULKAN_MODULE_ENTRY_POINT
if (required_functions_missing)
{
ResetVulkanLibraryFunctionPointers();
FreeLibrary(vulkan_module);
vulkan_module = nullptr;
return false;
}
vulkan_module_ref_count++;
return true;
}
void UnloadVulkanLibrary()
{
if ((--vulkan_module_ref_count) > 0)
return;
ResetVulkanLibraryFunctionPointers();
FreeLibrary(vulkan_module);
vulkan_module = nullptr;
}
#else
static void* vulkan_module;
static std::atomic_int vulkan_module_ref_count = {0};
bool LoadVulkanLibrary()
{
// Not thread safe if a second thread calls the loader whilst the first is still in-progress.
if (vulkan_module)
{
vulkan_module_ref_count++;
return true;
}
#if defined(__APPLE__)
// Check if a path to a specific Vulkan library has been specified.
char* libvulkan_env = getenv("LIBVULKAN_PATH");
if (libvulkan_env)
vulkan_module = dlopen(libvulkan_env, RTLD_NOW);
if (!vulkan_module)
{
unsigned path_size = 0;
_NSGetExecutablePath(nullptr, &path_size);
std::string path;
path.resize(path_size);
if (_NSGetExecutablePath(path.data(), &path_size) == 0)
{
path[path_size] = 0;
size_t pos = path.rfind('/');
if (pos != std::string::npos)
{
path.erase(pos);
path += "/../Frameworks/libvulkan.dylib";
vulkan_module = dlopen(path.c_str(), RTLD_NOW);
if (!vulkan_module)
{
path.erase(pos);
path += "/../Frameworks/libMoltenVK.dylib";
vulkan_module = dlopen(path.c_str(), RTLD_NOW);
}
}
}
}
if (!vulkan_module)
{
vulkan_module = dlopen("libvulkan.dylib", RTLD_NOW);
if (!vulkan_module)
vulkan_module = dlopen("libMoltenVK.dylib", RTLD_NOW);
}
#else
// Names of libraries to search. Desktop should use libvulkan.so.1 or libvulkan.so.
static const char* search_lib_names[] = {"libvulkan.so.1", "libvulkan.so"};
for (size_t i = 0; i < sizeof(search_lib_names) / sizeof(search_lib_names[0]); i++)
{
vulkan_module = dlopen(search_lib_names[i], RTLD_NOW);
if (vulkan_module)
break;
}
#endif
if (!vulkan_module)
{
std::fprintf(stderr, "Failed to load or locate libvulkan.so\n");
return false;
}
bool required_functions_missing = false;
auto LoadFunction = [&](void** func_ptr, const char* name, bool is_required) {
*func_ptr = dlsym(vulkan_module, name);
if (!(*func_ptr) && is_required)
{
std::fprintf(stderr, "Vulkan: Failed to load required module function %s\n", name);
required_functions_missing = true;
}
};
#define VULKAN_MODULE_ENTRY_POINT(name, required) LoadFunction(reinterpret_cast<void**>(&name), #name, required);
#include "EntryPoints.inl"
#undef VULKAN_MODULE_ENTRY_POINT
if (required_functions_missing)
{
ResetVulkanLibraryFunctionPointers();
dlclose(vulkan_module);
vulkan_module = nullptr;
return false;
}
vulkan_module_ref_count++;
return true;
}
void UnloadVulkanLibrary()
{
if ((--vulkan_module_ref_count) > 0)
return;
ResetVulkanLibraryFunctionPointers();
dlclose(vulkan_module);
vulkan_module = nullptr;
}
#endif
bool LoadVulkanInstanceFunctions(VkInstance instance)
{
bool required_functions_missing = false;
auto LoadFunction = [&](PFN_vkVoidFunction* func_ptr, const char* name, bool is_required) {
*func_ptr = vkGetInstanceProcAddr(instance, name);
if (!(*func_ptr) && is_required)
{
std::fprintf(stderr, "Vulkan: Failed to load required instance function %s\n", name);
required_functions_missing = true;
}
};
#define VULKAN_INSTANCE_ENTRY_POINT(name, required) \
LoadFunction(reinterpret_cast<PFN_vkVoidFunction*>(&name), #name, required);
#include "EntryPoints.inl"
#undef VULKAN_INSTANCE_ENTRY_POINT
return !required_functions_missing;
}
bool LoadVulkanDeviceFunctions(VkDevice device)
{
bool required_functions_missing = false;
auto LoadFunction = [&](PFN_vkVoidFunction* func_ptr, const char* name, bool is_required) {
*func_ptr = vkGetDeviceProcAddr(device, name);
if (!(*func_ptr) && is_required)
{
std::fprintf(stderr, "Vulkan: Failed to load required device function %s\n", name);
required_functions_missing = true;
}
};
#define VULKAN_DEVICE_ENTRY_POINT(name, required) \
LoadFunction(reinterpret_cast<PFN_vkVoidFunction*>(&name), #name, required);
#include "EntryPoints.inl"
#undef VULKAN_DEVICE_ENTRY_POINT
return !required_functions_missing;
}
} // namespace Vulkan
-544
View File
@@ -1,544 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/Vulkan/ShaderCache.h"
#include "common/Vulkan/ShaderCompiler.h"
#include "common/Vulkan/Context.h"
#include "common/Vulkan/Util.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/FileSystem.h"
#include "common/MD5Digest.h"
// TODO: store the driver version and stuff in the shader header
std::unique_ptr<Vulkan::ShaderCache> g_vulkan_shader_cache;
namespace Vulkan
{
using ShaderCompiler::SPIRVCodeType;
using ShaderCompiler::SPIRVCodeVector;
#pragma pack(push, 4)
struct VK_PIPELINE_CACHE_HEADER
{
u32 header_length;
u32 header_version;
u32 vendor_id;
u32 device_id;
u8 uuid[VK_UUID_SIZE];
};
struct CacheIndexEntry
{
u64 source_hash_low;
u64 source_hash_high;
u32 source_length;
u32 shader_type;
u32 file_offset;
u32 blob_size;
};
#pragma pack(pop)
static bool ValidatePipelineCacheHeader(const VK_PIPELINE_CACHE_HEADER& header)
{
if (header.header_length < sizeof(VK_PIPELINE_CACHE_HEADER))
{
Console.Error("Pipeline cache failed validation: Invalid header length");
return false;
}
if (header.header_version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE)
{
Console.Error("Pipeline cache failed validation: Invalid header version");
return false;
}
if (header.vendor_id != g_vulkan_context->GetDeviceProperties().vendorID)
{
Console.Error("Pipeline cache failed validation: Incorrect vendor ID (file: 0x%X, device: 0x%X)",
header.vendor_id, g_vulkan_context->GetDeviceProperties().vendorID);
return false;
}
if (header.device_id != g_vulkan_context->GetDeviceProperties().deviceID)
{
Console.Error("Pipeline cache failed validation: Incorrect device ID (file: 0x%X, device: 0x%X)",
header.device_id, g_vulkan_context->GetDeviceProperties().deviceID);
return false;
}
if (std::memcmp(header.uuid, g_vulkan_context->GetDeviceProperties().pipelineCacheUUID, VK_UUID_SIZE) != 0)
{
Console.Error("Pipeline cache failed validation: Incorrect UUID");
return false;
}
return true;
}
static void FillPipelineCacheHeader(VK_PIPELINE_CACHE_HEADER* header)
{
header->header_length = sizeof(VK_PIPELINE_CACHE_HEADER);
header->header_version = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
header->vendor_id = g_vulkan_context->GetDeviceProperties().vendorID;
header->device_id = g_vulkan_context->GetDeviceProperties().deviceID;
std::memcpy(header->uuid, g_vulkan_context->GetDeviceProperties().pipelineCacheUUID, VK_UUID_SIZE);
}
ShaderCache::ShaderCache() = default;
ShaderCache::~ShaderCache()
{
CloseShaderCache();
FlushPipelineCache();
ClosePipelineCache();
}
bool ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const
{
return (source_hash_low == key.source_hash_low && source_hash_high == key.source_hash_high &&
source_length == key.source_length && shader_type == key.shader_type);
}
bool ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const
{
return (source_hash_low != key.source_hash_low || source_hash_high != key.source_hash_high ||
source_length != key.source_length || shader_type != key.shader_type);
}
void ShaderCache::Create(std::string_view base_path, u32 version, bool debug)
{
pxAssert(!g_vulkan_shader_cache);
g_vulkan_shader_cache.reset(new ShaderCache());
g_vulkan_shader_cache->Open(base_path, version, debug);
}
void ShaderCache::Destroy() { g_vulkan_shader_cache.reset(); }
void ShaderCache::Open(std::string_view directory, u32 version, bool debug)
{
m_version = version;
m_debug = debug;
if (!directory.empty())
{
m_pipeline_cache_filename = GetPipelineCacheBaseFileName(directory, debug);
const std::string base_filename = GetShaderCacheBaseFileName(directory, debug);
const std::string index_filename = base_filename + ".idx";
const std::string blob_filename = base_filename + ".bin";
if (!ReadExistingShaderCache(index_filename, blob_filename))
CreateNewShaderCache(index_filename, blob_filename);
if (!ReadExistingPipelineCache())
CreateNewPipelineCache();
}
else
{
CreateNewPipelineCache();
}
}
VkPipelineCache ShaderCache::GetPipelineCache(bool set_dirty /*= true*/)
{
if (m_pipeline_cache == VK_NULL_HANDLE)
return VK_NULL_HANDLE;
m_pipeline_cache_dirty |= set_dirty;
return m_pipeline_cache;
}
bool ShaderCache::CreateNewShaderCache(const std::string& index_filename, const std::string& blob_filename)
{
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());
}
m_index_file = FileSystem::OpenCFile(index_filename.c_str(), "wb");
if (!m_index_file)
{
Console.Error("Failed to open index file '%s' for writing", index_filename.c_str());
return false;
}
const u32 index_version = FILE_VERSION;
VK_PIPELINE_CACHE_HEADER header;
FillPipelineCacheHeader(&header);
if (std::fwrite(&index_version, sizeof(index_version), 1, m_index_file) != 1 ||
std::fwrite(&m_version, sizeof(m_version), 1, m_index_file) != 1 ||
std::fwrite(&header, sizeof(header), 1, m_index_file) != 1)
{
Console.Error("Failed to write header to index file '%s'", index_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
FileSystem::DeleteFilePath(index_filename.c_str());
return false;
}
m_blob_file = FileSystem::OpenCFile(blob_filename.c_str(), "w+b");
if (!m_blob_file)
{
Console.Error("Failed to open blob file '%s' for writing", blob_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
FileSystem::DeleteFilePath(index_filename.c_str());
return false;
}
return true;
}
bool ShaderCache::ReadExistingShaderCache(const std::string& index_filename, const std::string& blob_filename)
{
m_index_file = FileSystem::OpenCFile(index_filename.c_str(), "r+b");
if (!m_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 = 0;
u32 data_version = 0;
if (std::fread(&file_version, sizeof(file_version), 1, m_index_file) != 1 || file_version != FILE_VERSION ||
std::fread(&data_version, sizeof(data_version), 1, m_index_file) != 1 || data_version != m_version)
{
Console.Error("Bad file/data version in '%s'", index_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
return false;
}
VK_PIPELINE_CACHE_HEADER header;
if (std::fread(&header, sizeof(header), 1, m_index_file) != 1 || !ValidatePipelineCacheHeader(header))
{
Console.Error("Mismatched pipeline cache header in '%s' (GPU/driver changed?)", index_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
return false;
}
m_blob_file = FileSystem::OpenCFile(blob_filename.c_str(), "a+b");
if (!m_blob_file)
{
Console.Error("Blob file '%s' is missing", blob_filename.c_str());
std::fclose(m_index_file);
m_index_file = nullptr;
return false;
}
std::fseek(m_blob_file, 0, SEEK_END);
const u32 blob_file_size = static_cast<u32>(std::ftell(m_blob_file));
for (;;)
{
CacheIndexEntry entry;
if (std::fread(&entry, sizeof(entry), 1, m_index_file) != 1 ||
(entry.file_offset + entry.blob_size) > blob_file_size)
{
if (std::feof(m_index_file))
break;
Console.Error("Failed to read entry from '%s', corrupt file?", index_filename.c_str());
m_index.clear();
std::fclose(m_blob_file);
m_blob_file = nullptr;
std::fclose(m_index_file);
m_index_file = nullptr;
return false;
}
const CacheIndexKey key{entry.source_hash_low, entry.source_hash_high, entry.source_length,
static_cast<ShaderCompiler::Type>(entry.shader_type)};
const CacheIndexData data{entry.file_offset, entry.blob_size};
m_index.emplace(key, data);
}
// ensure we don't write before seeking
std::fseek(m_index_file, 0, SEEK_END);
Console.WriteLn("Read %zu entries from '%s'", m_index.size(), index_filename.c_str());
return true;
}
void ShaderCache::CloseShaderCache()
{
if (m_index_file)
{
std::fclose(m_index_file);
m_index_file = nullptr;
}
if (m_blob_file)
{
std::fclose(m_blob_file);
m_blob_file = nullptr;
}
}
bool ShaderCache::CreateNewPipelineCache()
{
if (!m_pipeline_cache_filename.empty() && FileSystem::FileExists(m_pipeline_cache_filename.c_str()))
{
Console.Warning("Removing existing pipeline cache '%s'", m_pipeline_cache_filename.c_str());
FileSystem::DeleteFilePath(m_pipeline_cache_filename.c_str());
}
const VkPipelineCacheCreateInfo ci{VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, nullptr, 0, 0, nullptr};
VkResult res = vkCreatePipelineCache(g_vulkan_context->GetDevice(), &ci, nullptr, &m_pipeline_cache);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreatePipelineCache() failed: ");
return false;
}
m_pipeline_cache_dirty = true;
return true;
}
bool ShaderCache::ReadExistingPipelineCache()
{
std::optional<std::vector<u8>> data = FileSystem::ReadBinaryFile(m_pipeline_cache_filename.c_str());
if (!data.has_value())
return false;
if (data->size() < sizeof(VK_PIPELINE_CACHE_HEADER))
{
Console.Error("Pipeline cache at '%s' is too small", m_pipeline_cache_filename.c_str());
return false;
}
VK_PIPELINE_CACHE_HEADER header;
std::memcpy(&header, data->data(), sizeof(header));
if (!ValidatePipelineCacheHeader(header))
return false;
const VkPipelineCacheCreateInfo ci{
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, nullptr, 0, data->size(), data->data()};
VkResult res = vkCreatePipelineCache(g_vulkan_context->GetDevice(), &ci, nullptr, &m_pipeline_cache);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreatePipelineCache() failed: ");
return false;
}
return true;
}
bool ShaderCache::FlushPipelineCache()
{
if (m_pipeline_cache == VK_NULL_HANDLE || !m_pipeline_cache_dirty || m_pipeline_cache_filename.empty())
return false;
size_t data_size;
VkResult res = vkGetPipelineCacheData(g_vulkan_context->GetDevice(), m_pipeline_cache, &data_size, nullptr);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkGetPipelineCacheData() failed: ");
return false;
}
std::vector<u8> data(data_size);
res = vkGetPipelineCacheData(g_vulkan_context->GetDevice(), m_pipeline_cache, &data_size, data.data());
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkGetPipelineCacheData() (2) failed: ");
return false;
}
data.resize(data_size);
// Save disk writes if it hasn't changed, think of the poor SSDs.
FILESYSTEM_STAT_DATA sd;
if (!FileSystem::StatFile(m_pipeline_cache_filename.c_str(), &sd) || sd.Size != static_cast<s64>(data_size))
{
Console.WriteLn("Writing %zu bytes to '%s'", data_size, m_pipeline_cache_filename.c_str());
if (!FileSystem::WriteBinaryFile(m_pipeline_cache_filename.c_str(), data.data(), data.size()))
{
Console.Error("Failed to write pipeline cache to '%s'", m_pipeline_cache_filename.c_str());
return false;
}
}
else
{
Console.WriteLn(
"Skipping updating pipeline cache '%s' due to no changes.", m_pipeline_cache_filename.c_str());
}
m_pipeline_cache_dirty = false;
return true;
}
void ShaderCache::ClosePipelineCache()
{
if (m_pipeline_cache == VK_NULL_HANDLE)
return;
vkDestroyPipelineCache(g_vulkan_context->GetDevice(), m_pipeline_cache, nullptr);
m_pipeline_cache = VK_NULL_HANDLE;
}
std::string ShaderCache::GetShaderCacheBaseFileName(const std::string_view& base_path, bool debug)
{
std::string base_filename(base_path);
base_filename += FS_OSPATH_SEPARATOR_STR "vulkan_shaders";
if (debug)
base_filename += "_debug";
return base_filename;
}
std::string ShaderCache::GetPipelineCacheBaseFileName(const std::string_view& base_path, bool debug)
{
std::string base_filename(base_path);
base_filename += FS_OSPATH_SEPARATOR_STR "vulkan_pipelines";
if (debug)
base_filename += "_debug";
base_filename += ".bin";
return base_filename;
}
ShaderCache::CacheIndexKey ShaderCache::GetCacheKey(ShaderCompiler::Type type, const std::string_view& shader_code)
{
union HashParts
{
struct
{
u64 hash_low;
u64 hash_high;
};
u8 hash[16];
};
HashParts h;
MD5Digest digest;
digest.Update(shader_code.data(), static_cast<u32>(shader_code.length()));
digest.Final(h.hash);
return CacheIndexKey{h.hash_low, h.hash_high, static_cast<u32>(shader_code.length()), type};
}
std::optional<ShaderCompiler::SPIRVCodeVector> ShaderCache::GetShaderSPV(
ShaderCompiler::Type type, std::string_view shader_code)
{
const auto key = GetCacheKey(type, shader_code);
auto iter = m_index.find(key);
if (iter == m_index.end())
return CompileAndAddShaderSPV(key, shader_code);
SPIRVCodeVector spv(iter->second.blob_size);
if (std::fseek(m_blob_file, iter->second.file_offset, SEEK_SET) != 0 ||
std::fread(spv.data(), sizeof(SPIRVCodeType), iter->second.blob_size, m_blob_file) !=
iter->second.blob_size)
{
Console.Error("Read blob from file failed, recompiling");
return ShaderCompiler::CompileShader(type, shader_code, m_debug);
}
return spv;
}
VkShaderModule ShaderCache::GetShaderModule(ShaderCompiler::Type type, std::string_view shader_code)
{
std::optional<SPIRVCodeVector> spv = GetShaderSPV(type, shader_code);
if (!spv.has_value())
return VK_NULL_HANDLE;
const VkShaderModuleCreateInfo ci{
VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, nullptr, 0, spv->size() * sizeof(SPIRVCodeType), spv->data()};
VkShaderModule mod;
VkResult res = vkCreateShaderModule(g_vulkan_context->GetDevice(), &ci, nullptr, &mod);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateShaderModule() failed: ");
return VK_NULL_HANDLE;
}
return mod;
}
VkShaderModule ShaderCache::GetVertexShader(std::string_view shader_code)
{
return GetShaderModule(ShaderCompiler::Type::Vertex, std::move(shader_code));
}
VkShaderModule ShaderCache::GetGeometryShader(std::string_view shader_code)
{
return GetShaderModule(ShaderCompiler::Type::Geometry, std::move(shader_code));
}
VkShaderModule ShaderCache::GetFragmentShader(std::string_view shader_code)
{
return GetShaderModule(ShaderCompiler::Type::Fragment, std::move(shader_code));
}
VkShaderModule ShaderCache::GetComputeShader(std::string_view shader_code)
{
return GetShaderModule(ShaderCompiler::Type::Compute, std::move(shader_code));
}
std::optional<ShaderCompiler::SPIRVCodeVector> ShaderCache::CompileAndAddShaderSPV(
const CacheIndexKey& key, std::string_view shader_code)
{
std::optional<SPIRVCodeVector> spv = ShaderCompiler::CompileShader(key.shader_type, shader_code, m_debug);
if (!spv.has_value())
return {};
if (!m_blob_file || std::fseek(m_blob_file, 0, SEEK_END) != 0)
return spv;
CacheIndexData data;
data.file_offset = static_cast<u32>(std::ftell(m_blob_file));
data.blob_size = static_cast<u32>(spv->size());
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.shader_type);
entry.blob_size = data.blob_size;
entry.file_offset = data.file_offset;
if (std::fwrite(spv->data(), sizeof(SPIRVCodeType), entry.blob_size, m_blob_file) != entry.blob_size ||
std::fflush(m_blob_file) != 0 || std::fwrite(&entry, sizeof(entry), 1, m_index_file) != 1 ||
std::fflush(m_index_file) != 0)
{
Console.Error("Failed to write shader blob to file");
return spv;
}
m_index.emplace(key, data);
return spv;
}
} // namespace Vulkan
-118
View File
@@ -1,118 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Vulkan/ShaderCompiler.h"
#include "common/Pcsx2Defs.h"
#include "common/HashCombine.h"
#include "common/Vulkan/Loader.h"
#include <cstdio>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace Vulkan
{
class ShaderCache
{
public:
~ShaderCache();
static void Create(std::string_view directory, u32 version, bool debug);
static void Destroy();
/// Returns a handle to the pipeline cache. Set set_dirty to true if you are planning on writing to it externally.
VkPipelineCache GetPipelineCache(bool set_dirty = true);
/// Writes pipeline cache to file, saving all newly compiled pipelines.
bool FlushPipelineCache();
std::optional<ShaderCompiler::SPIRVCodeVector> GetShaderSPV(
ShaderCompiler::Type type, std::string_view shader_code);
VkShaderModule GetShaderModule(ShaderCompiler::Type type, std::string_view shader_code);
VkShaderModule GetVertexShader(std::string_view shader_code);
VkShaderModule GetGeometryShader(std::string_view shader_code);
VkShaderModule GetFragmentShader(std::string_view shader_code);
VkShaderModule GetComputeShader(std::string_view shader_code);
private:
static constexpr u32 FILE_VERSION = 2;
struct CacheIndexKey
{
u64 source_hash_low;
u64 source_hash_high;
u32 source_length;
ShaderCompiler::Type shader_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.source_hash_low, e.source_hash_high, e.source_length, e.shader_type);
return h;
}
};
struct CacheIndexData
{
u32 file_offset;
u32 blob_size;
};
using CacheIndex = std::unordered_map<CacheIndexKey, CacheIndexData, CacheIndexEntryHasher>;
ShaderCache();
static std::string GetShaderCacheBaseFileName(const std::string_view& base_path, bool debug);
static std::string GetPipelineCacheBaseFileName(const std::string_view& base_path, bool debug);
static CacheIndexKey GetCacheKey(ShaderCompiler::Type type, const std::string_view& shader_code);
void Open(std::string_view base_path, u32 version, bool debug);
bool CreateNewShaderCache(const std::string& index_filename, const std::string& blob_filename);
bool ReadExistingShaderCache(const std::string& index_filename, const std::string& blob_filename);
void CloseShaderCache();
bool CreateNewPipelineCache();
bool ReadExistingPipelineCache();
void ClosePipelineCache();
std::optional<ShaderCompiler::SPIRVCodeVector> CompileAndAddShaderSPV(
const CacheIndexKey& key, std::string_view shader_code);
std::FILE* m_index_file = nullptr;
std::FILE* m_blob_file = nullptr;
std::string m_pipeline_cache_filename;
CacheIndex m_index;
VkPipelineCache m_pipeline_cache = VK_NULL_HANDLE;
u32 m_version = 0;
bool m_debug = false;
bool m_pipeline_cache_dirty = false;
};
} // namespace Vulkan
extern std::unique_ptr<Vulkan::ShaderCache> g_vulkan_shader_cache;
-192
View File
@@ -1,192 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/Vulkan/ShaderCompiler.h"
#include "common/Vulkan/Util.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/StringUtil.h"
#include <cstring>
#include <fstream>
#include <memory>
// glslang includes
#include "SPIRV/GlslangToSpv.h"
#include "StandAlone/ResourceLimits.h"
#include "glslang/Public/ShaderLang.h"
namespace Vulkan::ShaderCompiler
{
// Registers itself for cleanup via atexit
bool InitializeGlslang();
static unsigned s_next_bad_shader_id = 1;
static bool glslang_initialized = false;
static std::optional<SPIRVCodeVector> CompileShaderToSPV(
EShLanguage stage, const char* stage_filename, std::string_view source, bool debug)
{
if (!InitializeGlslang())
return std::nullopt;
std::unique_ptr<glslang::TShader> shader = std::make_unique<glslang::TShader>(stage);
std::unique_ptr<glslang::TProgram> program;
glslang::TShader::ForbidIncluder includer;
const EProfile profile = ECoreProfile;
const EShMessages messages = static_cast<EShMessages>(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules | (debug ? EShMsgDebugInfo : 0));
const int default_version = 450;
std::string full_source_code;
const char* pass_source_code = source.data();
int pass_source_code_length = static_cast<int>(source.size());
shader->setStringsWithLengths(&pass_source_code, &pass_source_code_length, 1);
auto DumpBadShader = [&](const char* msg) {
std::string filename = StringUtil::StdStringFromFormat("pcsx2_bad_shader_%u.txt", s_next_bad_shader_id++);
Console.Error("CompileShaderToSPV: %s, writing to %s", msg, filename.c_str());
std::ofstream ofs(filename.c_str(), std::ofstream::out | std::ofstream::binary);
if (ofs.is_open())
{
ofs << source;
ofs << "\n";
ofs << msg << std::endl;
ofs << "Shader Info Log:" << std::endl;
ofs << shader->getInfoLog() << std::endl;
ofs << shader->getInfoDebugLog() << std::endl;
if (program)
{
ofs << "Program Info Log:" << std::endl;
ofs << program->getInfoLog() << std::endl;
ofs << program->getInfoDebugLog() << std::endl;
}
ofs.close();
}
};
if (!shader->parse(
&glslang::DefaultTBuiltInResource, default_version, profile, false, true, messages, includer))
{
DumpBadShader("Failed to parse shader");
return std::nullopt;
}
// Even though there's only a single shader, we still need to link it to generate SPV
program = std::make_unique<glslang::TProgram>();
program->addShader(shader.get());
if (!program->link(messages))
{
DumpBadShader("Failed to link program");
return std::nullopt;
}
glslang::TIntermediate* intermediate = program->getIntermediate(stage);
if (!intermediate)
{
DumpBadShader("Failed to generate SPIR-V");
return std::nullopt;
}
SPIRVCodeVector out_code;
spv::SpvBuildLogger logger;
glslang::SpvOptions options;
options.generateDebugInfo = debug;
glslang::GlslangToSpv(*intermediate, out_code, &logger, &options);
// Write out messages
if (std::strlen(shader->getInfoLog()) > 0)
Console.Warning("Shader info log: %s", shader->getInfoLog());
if (std::strlen(shader->getInfoDebugLog()) > 0)
Console.Warning("Shader debug info log: %s", shader->getInfoDebugLog());
if (std::strlen(program->getInfoLog()) > 0)
Console.Warning("Program info log: %s", program->getInfoLog());
if (std::strlen(program->getInfoDebugLog()) > 0)
Console.Warning("Program debug info log: %s", program->getInfoDebugLog());
std::string spv_messages = logger.getAllMessages();
if (!spv_messages.empty())
Console.Warning("SPIR-V conversion messages: %s", spv_messages.c_str());
return out_code;
}
bool InitializeGlslang()
{
if (glslang_initialized)
return true;
if (!glslang::InitializeProcess())
{
pxFailRel("Failed to initialize glslang shader compiler");
return false;
}
std::atexit(DeinitializeGlslang);
glslang_initialized = true;
return true;
}
void DeinitializeGlslang()
{
if (!glslang_initialized)
return;
glslang::FinalizeProcess();
glslang_initialized = false;
}
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code, bool debug)
{
return CompileShaderToSPV(EShLangVertex, "vs", source_code, debug);
}
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code, bool debug)
{
return CompileShaderToSPV(EShLangGeometry, "gs", source_code, debug);
}
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code, bool debug)
{
return CompileShaderToSPV(EShLangFragment, "ps", source_code, debug);
}
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code, bool debug)
{
return CompileShaderToSPV(EShLangCompute, "cs", source_code, debug);
}
std::optional<ShaderCompiler::SPIRVCodeVector> CompileShader(Type type, std::string_view source_code, bool debug)
{
switch (type)
{
case Type::Vertex:
return CompileShaderToSPV(EShLangVertex, "vs", source_code, debug);
case Type::Geometry:
return CompileShaderToSPV(EShLangGeometry, "gs", source_code, debug);
case Type::Fragment:
return CompileShaderToSPV(EShLangFragment, "ps", source_code, debug);
case Type::Compute:
return CompileShaderToSPV(EShLangCompute, "cs", source_code, debug);
default:
return std::nullopt;
}
}
} // namespace Vulkan::ShaderCompiler
-53
View File
@@ -1,53 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include <optional>
#include <string_view>
#include <vector>
namespace Vulkan::ShaderCompiler
{
// Shader types
enum class Type
{
Vertex,
Geometry,
Fragment,
Compute
};
void DeinitializeGlslang();
// SPIR-V compiled code type
using SPIRVCodeType = u32;
using SPIRVCodeVector = std::vector<SPIRVCodeType>;
// Compile a vertex shader to SPIR-V.
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code, bool debug);
// Compile a geometry shader to SPIR-V.
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code, bool debug);
// Compile a fragment shader to SPIR-V.
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code, bool debug);
// Compile a compute shader to SPIR-V.
std::optional<SPIRVCodeVector> CompileComputeShader(std::string_view source_code, bool debug);
std::optional<SPIRVCodeVector> CompileShader(Type type, std::string_view source_code, bool debug);
} // namespace Vulkan::ShaderCompiler
-323
View File
@@ -1,323 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/Vulkan/StreamBuffer.h"
#include "common/Vulkan/Context.h"
#include "common/Vulkan/Util.h"
#include "common/Align.h"
#include "common/Assertions.h"
#include "common/Console.h"
namespace Vulkan
{
StreamBuffer::StreamBuffer() = default;
StreamBuffer::StreamBuffer(StreamBuffer&& move)
: m_size(move.m_size)
, m_current_offset(move.m_current_offset)
, m_current_space(move.m_current_space)
, m_current_gpu_position(move.m_current_gpu_position)
, m_allocation(move.m_allocation)
, m_buffer(move.m_buffer)
, m_host_pointer(move.m_host_pointer)
, m_tracked_fences(std::move(move.m_tracked_fences))
{
move.m_size = 0;
move.m_current_offset = 0;
move.m_current_space = 0;
move.m_current_gpu_position = 0;
move.m_allocation = VK_NULL_HANDLE;
move.m_buffer = VK_NULL_HANDLE;
move.m_host_pointer = nullptr;
}
StreamBuffer::~StreamBuffer()
{
if (IsValid())
Destroy(true);
}
StreamBuffer& StreamBuffer::operator=(StreamBuffer&& move)
{
if (IsValid())
Destroy(true);
std::swap(m_size, move.m_size);
std::swap(m_current_offset, move.m_current_offset);
std::swap(m_current_space, move.m_current_space);
std::swap(m_current_gpu_position, move.m_current_gpu_position);
std::swap(m_buffer, move.m_buffer);
std::swap(m_host_pointer, move.m_host_pointer);
std::swap(m_tracked_fences, move.m_tracked_fences);
return *this;
}
bool StreamBuffer::Create(VkBufferUsageFlags usage, u32 size)
{
const VkBufferCreateInfo bci = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, nullptr, 0,
static_cast<VkDeviceSize>(size), usage, VK_SHARING_MODE_EXCLUSIVE, 0, nullptr};
VmaAllocationCreateInfo aci = {};
aci.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
aci.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
aci.preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
VmaAllocationInfo ai = {};
VkBuffer new_buffer = VK_NULL_HANDLE;
VmaAllocation new_allocation = VK_NULL_HANDLE;
VkResult res = vmaCreateBuffer(g_vulkan_context->GetAllocator(), &bci, &aci, &new_buffer, &new_allocation, &ai);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateBuffer failed: ");
return false;
}
if (IsValid())
Destroy(true);
// Replace with the new buffer
m_size = size;
m_current_offset = 0;
m_current_gpu_position = 0;
m_tracked_fences.clear();
m_allocation = new_allocation;
m_buffer = new_buffer;
m_host_pointer = static_cast<u8*>(ai.pMappedData);
return true;
}
void StreamBuffer::Destroy(bool defer)
{
if (m_buffer != VK_NULL_HANDLE)
{
if (defer)
g_vulkan_context->DeferBufferDestruction(m_buffer, m_allocation);
else
vmaDestroyBuffer(g_vulkan_context->GetAllocator(), m_buffer, m_allocation);
}
m_size = 0;
m_current_offset = 0;
m_current_gpu_position = 0;
m_tracked_fences.clear();
m_buffer = VK_NULL_HANDLE;
m_allocation = VK_NULL_HANDLE;
m_host_pointer = nullptr;
}
bool StreamBuffer::ReserveMemory(u32 num_bytes, u32 alignment)
{
const u32 required_bytes = num_bytes + alignment;
// Check for sane allocations
if (required_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;
}
UpdateGPUPosition();
// Is the GPU behind or up to date with our current offset?
if (m_current_offset >= m_current_gpu_position)
{
const u32 remaining_bytes = m_size - m_current_offset;
if (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 - 1;
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 - 1;
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);
// For non-coherent mappings, flush the memory range
vmaFlushAllocation(g_vulkan_context->GetAllocator(), m_allocation, m_current_offset, final_num_bytes);
m_current_offset += final_num_bytes;
m_current_space -= final_num_bytes;
UpdateCurrentFencePosition();
}
void StreamBuffer::UpdateCurrentFencePosition()
{
// Has the offset changed since the last fence?
const u64 counter = g_vulkan_context->GetCurrentFenceCounter();
if (!m_tracked_fences.empty() && m_tracked_fences.back().first == counter)
{
// Still haven't executed a command buffer, so just update the offset.
m_tracked_fences.back().second = m_current_offset;
return;
}
// New buffer, so update the GPU position while we're at it.
m_tracked_fences.emplace_back(counter, m_current_offset);
}
void StreamBuffer::UpdateGPUPosition()
{
auto start = m_tracked_fences.begin();
auto end = start;
const u64 completed_counter = g_vulkan_context->GetCompletedFenceCounter();
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);
if (m_current_offset == m_current_gpu_position)
{
// GPU is all caught up now.
m_current_offset = 0;
m_current_gpu_position = 0;
m_current_space = m_size;
}
}
}
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 - 1;
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 = available_space_inbetween - 1;
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_vulkan_context->GetCurrentFenceCounter())
return false;
// Wait until this fence is signaled. This will fire the callback, updating the GPU position.
g_vulkan_context->WaitForFenceCounter(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;
}
} // namespace Vulkan
-71
View File
@@ -1,71 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/Vulkan/Loader.h"
#include "vk_mem_alloc.h"
#include <deque>
#include <memory>
namespace Vulkan
{
class StreamBuffer
{
public:
StreamBuffer();
StreamBuffer(StreamBuffer&& move);
StreamBuffer(const StreamBuffer&) = delete;
~StreamBuffer();
StreamBuffer& operator=(StreamBuffer&& move);
StreamBuffer& operator=(const StreamBuffer&) = delete;
__fi bool IsValid() const { return (m_buffer != VK_NULL_HANDLE); }
__fi VkBuffer GetBuffer() const { return m_buffer; }
__fi u8* GetHostPointer() const { return m_host_pointer; }
__fi u8* GetCurrentHostPointer() const { return m_host_pointer + m_current_offset; }
__fi u32 GetCurrentSize() const { return m_size; }
__fi u32 GetCurrentSpace() const { return m_current_space; }
__fi u32 GetCurrentOffset() const { return m_current_offset; }
bool Create(VkBufferUsageFlags usage, u32 size);
void Destroy(bool defer);
bool ReserveMemory(u32 num_bytes, u32 alignment);
void CommitMemory(u32 final_num_bytes);
private:
bool AllocateBuffer(VkBufferUsageFlags usage, u32 size);
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;
VmaAllocation m_allocation = VK_NULL_HANDLE;
VkBuffer m_buffer = VK_NULL_HANDLE;
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 Vulkan
-835
View File
@@ -1,835 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/Vulkan/SwapChain.h"
#include "common/Assertions.h"
#include "common/CocoaTools.h"
#include "common/Console.h"
#include "common/Vulkan/Context.h"
#include "common/Vulkan/Util.h"
#include <algorithm>
#include <array>
#include <cmath>
#if defined(VK_USE_PLATFORM_XLIB_KHR)
#include <X11/Xlib.h>
#endif
namespace Vulkan
{
SwapChain::SwapChain(const WindowInfo& wi, VkSurfaceKHR surface, VkPresentModeKHR preferred_present_mode)
: m_window_info(wi)
, m_surface(surface)
, m_preferred_present_mode(preferred_present_mode)
{
}
SwapChain::~SwapChain()
{
DestroySwapChainImages();
DestroySwapChain();
DestroySurface();
}
#if 0
// Unused for now, can be used for nogui
static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo* wi)
{
Console.WriteLn("Trying to create a VK_KHR_display surface of %ux%u", wi->surface_width, wi->surface_height);
u32 num_displays;
VkResult res = vkGetPhysicalDeviceDisplayPropertiesKHR(physical_device, &num_displays, nullptr);
if (res != VK_SUCCESS || num_displays == 0)
{
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPropertiesKHR() failed:");
return {};
}
std::vector<VkDisplayPropertiesKHR> displays(num_displays);
res = vkGetPhysicalDeviceDisplayPropertiesKHR(physical_device, &num_displays, displays.data());
if (res != VK_SUCCESS || num_displays != displays.size())
{
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPropertiesKHR() failed:");
return {};
}
for (u32 display_index = 0; display_index < num_displays; display_index++)
{
const VkDisplayPropertiesKHR& props = displays[display_index];
DevCon.WriteLn("Testing display '%s'", props.displayName);
u32 num_modes;
res = vkGetDisplayModePropertiesKHR(physical_device, props.display, &num_modes, nullptr);
if (res != VK_SUCCESS || num_modes == 0)
{
LOG_VULKAN_ERROR(res, "vkGetDisplayModePropertiesKHR() failed:");
continue;
}
std::vector<VkDisplayModePropertiesKHR> modes(num_modes);
res = vkGetDisplayModePropertiesKHR(physical_device, props.display, &num_modes, modes.data());
if (res != VK_SUCCESS || num_modes != modes.size())
{
LOG_VULKAN_ERROR(res, "vkGetDisplayModePropertiesKHR() failed:");
continue;
}
const VkDisplayModePropertiesKHR* matched_mode = nullptr;
for (const VkDisplayModePropertiesKHR& mode : modes)
{
const float refresh_rate = static_cast<float>(mode.parameters.refreshRate) / 1000.0f;
DevCon.WriteLn(" Mode %ux%u @ %f", mode.parameters.visibleRegion.width,
mode.parameters.visibleRegion.height, refresh_rate);
if (!matched_mode && ((wi->surface_width == 0 && wi->surface_height == 0) ||
(mode.parameters.visibleRegion.width == wi->surface_width &&
mode.parameters.visibleRegion.height == wi->surface_height &&
(wi->surface_refresh_rate == 0.0f ||
std::abs(refresh_rate - wi->surface_refresh_rate) < 0.1f))))
{
matched_mode = &mode;
}
}
if (!matched_mode)
{
DevCon.WriteLn("No modes matched on '%s'", props.displayName);
continue;
}
u32 num_planes;
res = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physical_device, &num_planes, nullptr);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR() failed:");
continue;
}
if (num_planes == 0)
continue;
std::vector<VkDisplayPlanePropertiesKHR> planes(num_planes);
res = vkGetPhysicalDeviceDisplayPlanePropertiesKHR(physical_device, &num_planes, planes.data());
if (res != VK_SUCCESS || num_planes != planes.size())
{
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPlanePropertiesKHR() failed:");
continue;
}
u32 plane_index = 0;
for (; plane_index < num_planes; plane_index++)
{
u32 supported_display_count;
res = vkGetDisplayPlaneSupportedDisplaysKHR(
physical_device, plane_index, &supported_display_count, nullptr);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkGetDisplayPlaneSupportedDisplaysKHR() failed:");
continue;
}
if (supported_display_count == 0)
continue;
std::vector<VkDisplayKHR> supported_displays(supported_display_count);
res = vkGetDisplayPlaneSupportedDisplaysKHR(
physical_device, plane_index, &supported_display_count, supported_displays.data());
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkGetDisplayPlaneSupportedDisplaysKHR() failed:");
continue;
}
const bool is_supported = std::find(supported_displays.begin(), supported_displays.end(),
props.display) != supported_displays.end();
if (!is_supported)
continue;
break;
}
if (plane_index == num_planes)
{
DevCon.WriteLn("No planes matched on '%s'", props.displayName);
continue;
}
VkDisplaySurfaceCreateInfoKHR info = {};
info.sType = VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR;
info.displayMode = matched_mode->displayMode;
info.planeIndex = plane_index;
info.planeStackIndex = planes[plane_index].currentStackIndex;
info.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
info.globalAlpha = 1.0f;
info.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
info.imageExtent = matched_mode->parameters.visibleRegion;
VkSurfaceKHR surface;
res = vkCreateDisplayPlaneSurfaceKHR(instance, &info, nullptr, &surface);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateDisplayPlaneSurfaceKHR() failed: ");
continue;
}
wi->surface_refresh_rate = static_cast<float>(matched_mode->parameters.refreshRate) / 1000.0f;
return surface;
}
return VK_NULL_HANDLE;
}
static std::vector<SwapChain::FullscreenModeInfo> GetDisplayModes(
VkInstance instance, VkPhysicalDevice physical_device, const WindowInfo& wi)
{
u32 num_displays;
VkResult res = vkGetPhysicalDeviceDisplayPropertiesKHR(physical_device, &num_displays, nullptr);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPropertiesKHR() failed:");
return {};
}
if (num_displays == 0)
{
Console.Error("No displays were returned");
return {};
}
std::vector<VkDisplayPropertiesKHR> displays(num_displays);
res = vkGetPhysicalDeviceDisplayPropertiesKHR(physical_device, &num_displays, displays.data());
if (res != VK_SUCCESS || num_displays != displays.size())
{
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceDisplayPropertiesKHR() failed:");
return {};
}
std::vector<SwapChain::FullscreenModeInfo> result;
for (u32 display_index = 0; display_index < num_displays; display_index++)
{
const VkDisplayPropertiesKHR& props = displays[display_index];
u32 num_modes;
res = vkGetDisplayModePropertiesKHR(physical_device, props.display, &num_modes, nullptr);
if (res != VK_SUCCESS || num_modes == 0)
{
LOG_VULKAN_ERROR(res, "vkGetDisplayModePropertiesKHR() failed:");
continue;
}
std::vector<VkDisplayModePropertiesKHR> modes(num_modes);
res = vkGetDisplayModePropertiesKHR(physical_device, props.display, &num_modes, modes.data());
if (res != VK_SUCCESS || num_modes != modes.size())
{
LOG_VULKAN_ERROR(res, "vkGetDisplayModePropertiesKHR() failed:");
continue;
}
for (const VkDisplayModePropertiesKHR& mode : modes)
{
const float refresh_rate = static_cast<float>(mode.parameters.refreshRate) / 1000.0f;
if (std::find_if(
result.begin(), result.end(), [&mode, refresh_rate](const SwapChain::FullscreenModeInfo& mi) {
return (mi.width == mode.parameters.visibleRegion.width &&
mi.height == mode.parameters.visibleRegion.height &&
mode.parameters.refreshRate == refresh_rate);
}) != result.end())
{
continue;
}
result.push_back(SwapChain::FullscreenModeInfo{static_cast<u32>(mode.parameters.visibleRegion.width),
static_cast<u32>(mode.parameters.visibleRegion.height), refresh_rate});
}
}
return result;
}
#endif
VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo* wi)
{
#if defined(VK_USE_PLATFORM_WIN32_KHR)
if (wi->type == WindowInfo::Type::Win32)
{
VkWin32SurfaceCreateInfoKHR surface_create_info = {
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
nullptr, // const void* pNext
0, // VkWin32SurfaceCreateFlagsKHR flags
nullptr, // HINSTANCE hinstance
reinterpret_cast<HWND>(wi->window_handle) // HWND hwnd
};
VkSurfaceKHR surface;
VkResult res = vkCreateWin32SurfaceKHR(instance, &surface_create_info, nullptr, &surface);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateWin32SurfaceKHR failed: ");
return VK_NULL_HANDLE;
}
return surface;
}
#endif
#if defined(VK_USE_PLATFORM_XLIB_KHR)
if (wi->type == WindowInfo::Type::X11)
{
VkXlibSurfaceCreateInfoKHR surface_create_info = {
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
nullptr, // const void* pNext
0, // VkXlibSurfaceCreateFlagsKHR flags
static_cast<Display*>(wi->display_connection), // Display* dpy
reinterpret_cast<Window>(wi->window_handle) // Window window
};
VkSurfaceKHR surface;
VkResult res = vkCreateXlibSurfaceKHR(instance, &surface_create_info, nullptr, &surface);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateXlibSurfaceKHR failed: ");
return VK_NULL_HANDLE;
}
return surface;
}
#endif
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
if (wi->type == WindowInfo::Type::Wayland)
{
VkWaylandSurfaceCreateInfoKHR surface_create_info = {VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
nullptr, 0, static_cast<struct wl_display*>(wi->display_connection),
static_cast<struct wl_surface*>(wi->window_handle)};
VkSurfaceKHR surface;
VkResult res = vkCreateWaylandSurfaceKHR(instance, &surface_create_info, nullptr, &surface);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateWaylandSurfaceEXT failed: ");
return VK_NULL_HANDLE;
}
return surface;
}
#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
if (wi->type == WindowInfo::Type::Android)
{
VkAndroidSurfaceCreateInfoKHR surface_create_info = {
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
nullptr, // const void* pNext
0, // VkAndroidSurfaceCreateFlagsKHR flags
reinterpret_cast<ANativeWindow*>(wi->window_handle) // ANativeWindow* window
};
VkSurfaceKHR surface;
VkResult res = vkCreateAndroidSurfaceKHR(instance, &surface_create_info, nullptr, &surface);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateAndroidSurfaceKHR failed: ");
return VK_NULL_HANDLE;
}
return surface;
}
#endif
#if defined(VK_USE_PLATFORM_METAL_EXT)
if (wi->type == WindowInfo::Type::MacOS)
{
if (!wi->surface_handle && !CocoaTools::CreateMetalLayer(wi))
return VK_NULL_HANDLE;
VkMetalSurfaceCreateInfoEXT surface_create_info = {VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, nullptr,
0, static_cast<const CAMetalLayer*>(wi->surface_handle)};
VkSurfaceKHR surface;
VkResult res = vkCreateMetalSurfaceEXT(instance, &surface_create_info, nullptr, &surface);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateMetalSurfaceEXT failed: ");
return VK_NULL_HANDLE;
}
return surface;
}
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
if (wi->type == WindowInfo::Type::MacOS)
{
VkMacOSSurfaceCreateInfoMVK surface_create_info = {
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, nullptr, 0, wi->window_handle};
VkSurfaceKHR surface;
VkResult res = vkCreateMacOSSurfaceMVK(instance, &surface_create_info, nullptr, &surface);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateMacOSSurfaceMVK failed: ");
return VK_NULL_HANDLE;
}
return surface;
}
#endif
#if 0
if (wi->type == WindowInfo::Type::Display)
return CreateDisplaySurface(instance, physical_device, wi);
#endif
return VK_NULL_HANDLE;
}
void SwapChain::DestroyVulkanSurface(VkInstance instance, WindowInfo* wi, VkSurfaceKHR surface)
{
vkDestroySurfaceKHR(g_vulkan_context->GetVulkanInstance(), surface, nullptr);
#if defined(__APPLE__)
if (wi->type == WindowInfo::Type::MacOS && wi->surface_handle)
CocoaTools::DestroyMetalLayer(wi);
#endif
}
std::vector<SwapChain::FullscreenModeInfo> SwapChain::GetSurfaceFullscreenModes(
VkInstance instance, VkPhysicalDevice physical_device, const WindowInfo& wi)
{
#if 0
if (wi.type == WindowInfo::Type::Display)
return GetDisplayModes(instance, physical_device, wi);
#endif
return {};
}
std::unique_ptr<SwapChain> SwapChain::Create(const WindowInfo& wi, VkSurfaceKHR surface,
VkPresentModeKHR preferred_present_mode)
{
std::unique_ptr<SwapChain> swap_chain = std::make_unique<SwapChain>(wi, surface, preferred_present_mode);
if (!swap_chain->CreateSwapChain() || !swap_chain->SetupSwapChainImages())
return nullptr;
return swap_chain;
}
bool SwapChain::SelectSurfaceFormat()
{
u32 format_count;
VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(
g_vulkan_context->GetPhysicalDevice(), m_surface, &format_count, nullptr);
if (res != VK_SUCCESS || format_count == 0)
{
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceFormatsKHR failed: ");
return false;
}
std::vector<VkSurfaceFormatKHR> surface_formats(format_count);
res = vkGetPhysicalDeviceSurfaceFormatsKHR(
g_vulkan_context->GetPhysicalDevice(), m_surface, &format_count, surface_formats.data());
pxAssert(res == VK_SUCCESS);
// If there is a single undefined surface format, the device doesn't care, so we'll just use RGBA
if (surface_formats[0].format == VK_FORMAT_UNDEFINED)
{
m_surface_format.format = VK_FORMAT_R8G8B8A8_UNORM;
m_surface_format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
return true;
}
// Try to find a suitable format.
for (const VkSurfaceFormatKHR& surface_format : surface_formats)
{
// Some drivers seem to return a SRGB format here (Intel Mesa).
// This results in gamma correction when presenting to the screen, which we don't want.
// Use a linear format instead, if this is the case.
m_surface_format.format = Util::GetLinearFormat(surface_format.format);
m_surface_format.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
return true;
}
pxFailRel("Failed to find a suitable format for swap chain buffers.");
return false;
}
bool SwapChain::SelectPresentMode()
{
VkResult res;
u32 mode_count;
res = vkGetPhysicalDeviceSurfacePresentModesKHR(
g_vulkan_context->GetPhysicalDevice(), m_surface, &mode_count, nullptr);
if (res != VK_SUCCESS || mode_count == 0)
{
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceFormatsKHR failed: ");
return false;
}
std::vector<VkPresentModeKHR> present_modes(mode_count);
res = vkGetPhysicalDeviceSurfacePresentModesKHR(
g_vulkan_context->GetPhysicalDevice(), m_surface, &mode_count, present_modes.data());
pxAssert(res == VK_SUCCESS);
// Checks if a particular mode is supported, if it is, returns that mode.
auto CheckForMode = [&present_modes](VkPresentModeKHR check_mode) {
auto it = std::find_if(present_modes.begin(), present_modes.end(),
[check_mode](VkPresentModeKHR mode) { return check_mode == mode; });
return it != present_modes.end();
};
// Use preferred mode if available.
if (CheckForMode(m_preferred_present_mode))
{
m_present_mode = m_preferred_present_mode;
return true;
}
// Prefer mailbox over fifo for adaptive vsync/no-vsync.
if ((m_preferred_present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR ||
m_preferred_present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) &&
CheckForMode(VK_PRESENT_MODE_MAILBOX_KHR))
{
m_present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
return true;
}
// Fallback to FIFO if we're using any kind of vsync.
if (m_preferred_present_mode == VK_PRESENT_MODE_FIFO_KHR || m_preferred_present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)
{
// This should never fail, FIFO is mandated.
if (CheckForMode(VK_PRESENT_MODE_FIFO_KHR))
{
m_present_mode = VK_PRESENT_MODE_FIFO_KHR;
return true;
}
}
// Fall back to whatever is available.
m_present_mode = present_modes[0];
return true;
}
bool SwapChain::CreateSwapChain()
{
// Look up surface properties to determine image count and dimensions
VkSurfaceCapabilitiesKHR surface_capabilities;
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
g_vulkan_context->GetPhysicalDevice(), m_surface, &surface_capabilities);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed: ");
return false;
}
// Select swap chain format and present mode
if (!SelectSurfaceFormat() || !SelectPresentMode())
return false;
DevCon.WriteLn("(SwapChain) Preferred present mode: %s, selected: %s",
Util::PresentModeToString(m_preferred_present_mode), Util::PresentModeToString(m_present_mode));
// Select number of images in swap chain, we prefer one buffer in the background to work on
u32 image_count = std::max(surface_capabilities.minImageCount + 1u, 2u);
// maxImageCount can be zero, in which case there isn't an upper limit on the number of buffers.
if (surface_capabilities.maxImageCount > 0)
image_count = std::min(image_count, surface_capabilities.maxImageCount);
// Determine the dimensions of the swap chain. Values of -1 indicate the size we specify here
// determines window size?
VkExtent2D size = surface_capabilities.currentExtent;
#ifndef ANDROID
if (size.width == UINT32_MAX)
#endif
{
size.width = m_window_info.surface_width;
size.height = m_window_info.surface_height;
}
size.width = std::clamp(
size.width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width);
size.height = std::clamp(
size.height, surface_capabilities.minImageExtent.height, surface_capabilities.maxImageExtent.height);
// Prefer identity transform if possible
VkSurfaceTransformFlagBitsKHR transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
if (!(surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR))
transform = surface_capabilities.currentTransform;
// Select swap chain flags, we only need a colour attachment
VkImageUsageFlags image_usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
if (!(surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT))
{
Console.Error("Vulkan: Swap chain does not support usage as color attachment");
return false;
}
// Store the old/current swap chain when recreating for resize
VkSwapchainKHR old_swap_chain = m_swap_chain;
m_swap_chain = VK_NULL_HANDLE;
// Now we can actually create the swap chain
VkSwapchainCreateInfoKHR swap_chain_info = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, nullptr, 0, m_surface,
image_count, m_surface_format.format, m_surface_format.colorSpace, size, 1u, image_usage,
VK_SHARING_MODE_EXCLUSIVE, 0, nullptr, transform, VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, m_present_mode,
VK_TRUE, old_swap_chain};
std::array<uint32_t, 2> indices = {{
g_vulkan_context->GetGraphicsQueueFamilyIndex(),
g_vulkan_context->GetPresentQueueFamilyIndex(),
}};
if (g_vulkan_context->GetGraphicsQueueFamilyIndex() != g_vulkan_context->GetPresentQueueFamilyIndex())
{
swap_chain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
swap_chain_info.queueFamilyIndexCount = 2;
swap_chain_info.pQueueFamilyIndices = indices.data();
}
if (m_swap_chain == VK_NULL_HANDLE)
{
res = vkCreateSwapchainKHR(g_vulkan_context->GetDevice(), &swap_chain_info, nullptr, &m_swap_chain);
}
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateSwapchainKHR failed: ");
return false;
}
// Now destroy the old swap chain, since it's been recreated.
// We can do this immediately since all work should have been completed before calling resize.
if (old_swap_chain != VK_NULL_HANDLE)
vkDestroySwapchainKHR(g_vulkan_context->GetDevice(), old_swap_chain, nullptr);
m_window_info.surface_width = std::max(1u, size.width);
m_window_info.surface_height = std::max(1u, size.height);
return true;
}
bool SwapChain::SetupSwapChainImages()
{
pxAssert(m_images.empty());
u32 image_count;
VkResult res = vkGetSwapchainImagesKHR(g_vulkan_context->GetDevice(), m_swap_chain, &image_count, nullptr);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkGetSwapchainImagesKHR failed: ");
return false;
}
std::vector<VkImage> images(image_count);
res = vkGetSwapchainImagesKHR(g_vulkan_context->GetDevice(), m_swap_chain, &image_count, images.data());
pxAssert(res == VK_SUCCESS);
m_load_render_pass =
g_vulkan_context->GetRenderPass(m_surface_format.format, VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_LOAD);
m_clear_render_pass =
g_vulkan_context->GetRenderPass(m_surface_format.format, VK_FORMAT_UNDEFINED, VK_ATTACHMENT_LOAD_OP_CLEAR);
if (m_load_render_pass == VK_NULL_HANDLE || m_clear_render_pass == VK_NULL_HANDLE)
{
pxFailRel("Failed to get swap chain render passes.");
return false;
}
m_images.reserve(image_count);
m_current_image = 0;
for (u32 i = 0; i < image_count; i++)
{
SwapChainImage image;
image.image = images[i];
// Create texture object, which creates a view of the backbuffer
if (!image.texture.Adopt(image.image, VK_IMAGE_VIEW_TYPE_2D, m_window_info.surface_width,
m_window_info.surface_height, 1, 1, m_surface_format.format, VK_SAMPLE_COUNT_1_BIT))
{
return false;
}
image.framebuffer = image.texture.CreateFramebuffer(m_load_render_pass);
if (image.framebuffer == VK_NULL_HANDLE)
return false;
m_images.emplace_back(std::move(image));
}
m_semaphores.reserve(image_count);
m_current_semaphore = (image_count - 1);
for (u32 i = 0; i < image_count; i++)
{
ImageSemaphores sema;
const VkSemaphoreCreateInfo semaphore_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0};
res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &sema.available_semaphore);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
return false;
}
res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &sema.rendering_finished_semaphore);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
vkDestroySemaphore(g_vulkan_context->GetDevice(), sema.available_semaphore, nullptr);
return false;
}
m_semaphores.push_back(sema);
}
return true;
}
void SwapChain::DestroySwapChainImages()
{
for (auto& it : m_images)
{
// Images themselves are cleaned up by the swap chain object
vkDestroyFramebuffer(g_vulkan_context->GetDevice(), it.framebuffer, nullptr);
}
m_images.clear();
for (auto& it : m_semaphores)
{
vkDestroySemaphore(g_vulkan_context->GetDevice(), it.rendering_finished_semaphore, nullptr);
vkDestroySemaphore(g_vulkan_context->GetDevice(), it.available_semaphore, nullptr);
}
m_semaphores.clear();
m_image_acquire_result.reset();
}
void SwapChain::DestroySwapChain()
{
if (m_swap_chain == VK_NULL_HANDLE)
return;
vkDestroySwapchainKHR(g_vulkan_context->GetDevice(), m_swap_chain, nullptr);
m_swap_chain = VK_NULL_HANDLE;
m_window_info.surface_width = 0;
m_window_info.surface_height = 0;
}
VkResult SwapChain::AcquireNextImage()
{
if (m_image_acquire_result.has_value())
return m_image_acquire_result.value();
if (!m_swap_chain)
return VK_ERROR_SURFACE_LOST_KHR;
// Use a different semaphore for each image.
m_current_semaphore = (m_current_semaphore + 1) % static_cast<u32>(m_semaphores.size());
const VkResult res = vkAcquireNextImageKHR(g_vulkan_context->GetDevice(), m_swap_chain, UINT64_MAX,
m_semaphores[m_current_semaphore].available_semaphore, VK_NULL_HANDLE, &m_current_image);
m_image_acquire_result = res;
return res;
}
void SwapChain::ReleaseCurrentImage()
{
m_image_acquire_result.reset();
}
bool SwapChain::ResizeSwapChain(u32 new_width, u32 new_height, float new_scale)
{
DestroySwapChainImages();
if (new_width != 0 && new_height != 0)
{
m_window_info.surface_width = new_width;
m_window_info.surface_height = new_height;
}
m_window_info.surface_scale = new_scale;
if (!CreateSwapChain() || !SetupSwapChainImages())
{
DestroySwapChainImages();
DestroySwapChain();
return false;
}
return true;
}
bool SwapChain::RecreateSwapChain()
{
DestroySwapChainImages();
if (!CreateSwapChain() || !SetupSwapChainImages())
{
DestroySwapChainImages();
DestroySwapChain();
return false;
}
return true;
}
bool SwapChain::SetVSync(VkPresentModeKHR preferred_mode)
{
if (m_preferred_present_mode == preferred_mode)
return true;
// Recreate the swap chain with the new present mode.
m_preferred_present_mode = preferred_mode;
return RecreateSwapChain();
}
bool SwapChain::RecreateSurface(const WindowInfo& new_wi)
{
// Destroy the old swap chain, images, and surface.
DestroySwapChainImages();
DestroySwapChain();
DestroySurface();
// Re-create the surface with the new native handle
m_window_info = new_wi;
m_surface = CreateVulkanSurface(
g_vulkan_context->GetVulkanInstance(), g_vulkan_context->GetPhysicalDevice(), &m_window_info);
if (m_surface == VK_NULL_HANDLE)
return false;
// The validation layers get angry at us if we don't call this before creating the swapchain.
VkBool32 present_supported = VK_TRUE;
VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_vulkan_context->GetPhysicalDevice(),
g_vulkan_context->GetPresentQueueFamilyIndex(), m_surface, &present_supported);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkGetPhysicalDeviceSurfaceSupportKHR failed: ");
return false;
}
if (!present_supported)
{
pxFailRel("Recreated surface does not support presenting.");
return false;
}
// Finally re-create the swap chain
if (!CreateSwapChain())
return false;
if (!SetupSwapChainImages())
{
DestroySwapChain();
DestroySurface();
return false;
}
return true;
}
void SwapChain::DestroySurface()
{
if (m_surface == VK_NULL_HANDLE)
return;
DestroyVulkanSurface(g_vulkan_context->GetVulkanInstance(), &m_window_info, m_surface);
m_surface = VK_NULL_HANDLE;
}
} // namespace Vulkan
-135
View File
@@ -1,135 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/WindowInfo.h"
#include "common/Vulkan/Texture.h"
#include "common/Vulkan/Loader.h"
#include <memory>
#include <optional>
#include <vector>
namespace Vulkan
{
class SwapChain
{
public:
SwapChain(const WindowInfo& wi, VkSurfaceKHR surface, VkPresentModeKHR preferred_present_mode);
~SwapChain();
// Creates a vulkan-renderable surface for the specified window handle.
static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo* wi);
// Destroys a previously-created surface.
static void DestroyVulkanSurface(VkInstance instance, WindowInfo* wi, VkSurfaceKHR surface);
// Enumerates fullscreen modes for window info.
struct FullscreenModeInfo
{
u32 width;
u32 height;
float refresh_rate;
};
static std::vector<FullscreenModeInfo> GetSurfaceFullscreenModes(
VkInstance instance, VkPhysicalDevice physical_device, const WindowInfo& wi);
// Create a new swap chain from a pre-existing surface.
static std::unique_ptr<SwapChain> Create(const WindowInfo& wi, VkSurfaceKHR surface,
VkPresentModeKHR preferred_present_mode);
__fi VkSurfaceKHR GetSurface() const { return m_surface; }
__fi VkSurfaceFormatKHR GetSurfaceFormat() const { return m_surface_format; }
__fi VkFormat GetTextureFormat() const { return m_surface_format.format; }
__fi VkPresentModeKHR GetPreferredPresentMode() const { return m_preferred_present_mode; }
__fi VkSwapchainKHR GetSwapChain() const { return m_swap_chain; }
__fi const VkSwapchainKHR* GetSwapChainPtr() const { return &m_swap_chain; }
__fi const WindowInfo& GetWindowInfo() const { return m_window_info; }
__fi u32 GetWidth() const { return m_window_info.surface_width; }
__fi u32 GetHeight() const { return m_window_info.surface_height; }
__fi float GetScale() const { return m_window_info.surface_scale; }
__fi u32 GetCurrentImageIndex() const { return m_current_image; }
__fi const u32* GetCurrentImageIndexPtr() const { return &m_current_image; }
__fi u32 GetImageCount() const { return static_cast<u32>(m_images.size()); }
__fi VkImage GetCurrentImage() const { return m_images[m_current_image].image; }
__fi const Texture& GetCurrentTexture() const { return m_images[m_current_image].texture; }
__fi Texture& GetCurrentTexture() { return m_images[m_current_image].texture; }
__fi VkFramebuffer GetCurrentFramebuffer() const { return m_images[m_current_image].framebuffer; }
__fi VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; }
__fi VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; }
__fi VkSemaphore GetImageAvailableSemaphore() const { return m_semaphores[m_current_semaphore].available_semaphore; }
__fi const VkSemaphore* GetImageAvailableSemaphorePtr() const { return &m_semaphores[m_current_semaphore].available_semaphore; }
__fi VkSemaphore GetRenderingFinishedSemaphore() const { return m_semaphores[m_current_semaphore].rendering_finished_semaphore; }
__fi const VkSemaphore* GetRenderingFinishedSemaphorePtr() const { return &m_semaphores[m_current_semaphore].rendering_finished_semaphore; }
VkResult AcquireNextImage();
void ReleaseCurrentImage();
bool RecreateSurface(const WindowInfo& new_wi);
bool ResizeSwapChain(u32 new_width = 0, u32 new_height = 0, float new_scale = 1.0f);
bool RecreateSwapChain();
// Change vsync enabled state. This may fail as it causes a swapchain recreation.
bool SetVSync(VkPresentModeKHR preferred_mode);
// Returns true if the current present mode is synchronizing (adaptive or hard).
bool IsPresentModeSynchronizing() const
{
return (m_present_mode == VK_PRESENT_MODE_FIFO_KHR || m_present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR);
}
private:
bool SelectSurfaceFormat();
bool SelectPresentMode();
bool CreateSwapChain();
void DestroySwapChain();
bool SetupSwapChainImages();
void DestroySwapChainImages();
void DestroySurface();
struct SwapChainImage
{
VkImage image;
Texture texture;
VkFramebuffer framebuffer;
};
struct ImageSemaphores
{
VkSemaphore available_semaphore;
VkSemaphore rendering_finished_semaphore;
};
WindowInfo m_window_info;
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
VkSurfaceFormatKHR m_surface_format = {};
VkPresentModeKHR m_preferred_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
VkPresentModeKHR m_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
VkRenderPass m_load_render_pass = VK_NULL_HANDLE;
VkRenderPass m_clear_render_pass = VK_NULL_HANDLE;
VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE;
std::vector<SwapChainImage> m_images;
std::vector<ImageSemaphores> m_semaphores;
u32 m_current_image = 0;
u32 m_current_semaphore = 0;
std::optional<VkResult> m_image_acquire_result;
};
} // namespace Vulkan
-395
View File
@@ -1,395 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/Vulkan/Texture.h"
#include "common/Vulkan/Context.h"
#include "common/Vulkan/Util.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include <algorithm>
static constexpr VkComponentMapping s_identity_swizzle{VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
namespace Vulkan
{
Texture::Texture() = default;
Texture::Texture(Texture&& move)
: m_width(move.m_width)
, m_height(move.m_height)
, m_levels(move.m_levels)
, m_layers(move.m_layers)
, m_format(move.m_format)
, m_samples(move.m_samples)
, m_view_type(move.m_view_type)
, m_layout(move.m_layout)
, m_image(move.m_image)
, m_allocation(move.m_allocation)
, m_view(move.m_view)
{
move.m_width = 0;
move.m_height = 0;
move.m_levels = 0;
move.m_layers = 0;
move.m_format = VK_FORMAT_UNDEFINED;
move.m_samples = VK_SAMPLE_COUNT_1_BIT;
move.m_view_type = VK_IMAGE_VIEW_TYPE_2D;
move.m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
move.m_image = VK_NULL_HANDLE;
move.m_allocation = VK_NULL_HANDLE;
move.m_view = VK_NULL_HANDLE;
}
Texture::~Texture()
{
if (IsValid())
Destroy(true);
}
Vulkan::Texture& Texture::operator=(Texture&& move)
{
if (IsValid())
Destroy(true);
std::swap(m_width, move.m_width);
std::swap(m_height, move.m_height);
std::swap(m_levels, move.m_levels);
std::swap(m_layers, move.m_layers);
std::swap(m_format, move.m_format);
std::swap(m_samples, move.m_samples);
std::swap(m_view_type, move.m_view_type);
std::swap(m_layout, move.m_layout);
std::swap(m_image, move.m_image);
std::swap(m_allocation, move.m_allocation);
std::swap(m_view, move.m_view);
return *this;
}
bool Texture::Create(u32 width, u32 height, u32 levels, u32 layers, VkFormat format, VkSampleCountFlagBits samples,
VkImageViewType view_type, VkImageTiling tiling, VkImageUsageFlags usage,
const VkComponentMapping* swizzle /* = nullptr*/)
{
const VkImageCreateInfo image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, nullptr, 0, VK_IMAGE_TYPE_2D, format,
{width, height, 1}, levels, layers, samples, tiling, usage, VK_SHARING_MODE_EXCLUSIVE, 0, nullptr,
VK_IMAGE_LAYOUT_UNDEFINED};
VmaAllocationCreateInfo aci = {};
aci.usage = VMA_MEMORY_USAGE_GPU_ONLY;
aci.flags = VMA_ALLOCATION_CREATE_WITHIN_BUDGET_BIT;
aci.requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
VkImage image = VK_NULL_HANDLE;
VmaAllocation allocation = VK_NULL_HANDLE;
VkResult res =
vmaCreateImage(g_vulkan_context->GetAllocator(), &image_info, &aci, &image, &allocation, nullptr);
if (res == VK_ERROR_OUT_OF_DEVICE_MEMORY)
{
DevCon.WriteLn("Failed to allocate device memory for %ux%u texture", width, height);
return false;
}
else if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vmaCreateImage failed: ");
return false;
}
const VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr, 0, image, view_type,
format, swizzle ? *swizzle : s_identity_swizzle,
{Util::IsDepthFormat(format) ? static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) :
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT),
0, levels, 0, layers}};
VkImageView view = VK_NULL_HANDLE;
res = vkCreateImageView(g_vulkan_context->GetDevice(), &view_info, nullptr, &view);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateImageView failed: ");
vmaDestroyImage(g_vulkan_context->GetAllocator(), image, allocation);
return false;
}
if (IsValid())
Destroy(true);
m_width = width;
m_height = height;
m_levels = levels;
m_layers = layers;
m_format = format;
m_samples = samples;
m_view_type = view_type;
m_image = image;
m_allocation = allocation;
m_view = view;
return true;
}
bool Texture::Adopt(VkImage existing_image, VkImageViewType view_type, u32 width, u32 height, u32 levels,
u32 layers, VkFormat format, VkSampleCountFlagBits samples, const VkComponentMapping* swizzle /* = nullptr*/)
{
// Only need to create the image view, this is mainly for swap chains.
const VkImageViewCreateInfo view_info = {VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, nullptr, 0, existing_image,
view_type, format, swizzle ? *swizzle : s_identity_swizzle,
{Util::IsDepthFormat(format) ? static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_DEPTH_BIT) :
static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_COLOR_BIT),
0, levels, 0, layers}};
// Memory is managed by the owner of the image.
VkImageView view = VK_NULL_HANDLE;
VkResult res = vkCreateImageView(g_vulkan_context->GetDevice(), &view_info, nullptr, &view);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateImageView failed: ");
return false;
}
if (IsValid())
Destroy(true);
m_width = width;
m_height = height;
m_levels = levels;
m_layers = layers;
m_format = format;
m_samples = samples;
m_view_type = view_type;
m_image = existing_image;
m_view = view;
return true;
}
void Texture::Destroy(bool defer /* = true */)
{
if (m_view != VK_NULL_HANDLE)
{
if (defer)
g_vulkan_context->DeferImageViewDestruction(m_view);
else
vkDestroyImageView(g_vulkan_context->GetDevice(), m_view, nullptr);
m_view = VK_NULL_HANDLE;
}
// If we don't have device memory allocated, the image is not owned by us (e.g. swapchain)
if (m_allocation != VK_NULL_HANDLE)
{
pxAssert(m_image != VK_NULL_HANDLE);
if (defer)
g_vulkan_context->DeferImageDestruction(m_image, m_allocation);
else
vmaDestroyImage(g_vulkan_context->GetAllocator(), m_image, m_allocation);
m_image = VK_NULL_HANDLE;
m_allocation = VK_NULL_HANDLE;
}
m_width = 0;
m_height = 0;
m_levels = 0;
m_layers = 0;
m_format = VK_FORMAT_UNDEFINED;
m_samples = VK_SAMPLE_COUNT_1_BIT;
m_view_type = VK_IMAGE_VIEW_TYPE_2D;
m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
}
void Texture::OverrideImageLayout(VkImageLayout new_layout) { m_layout = new_layout; }
void Texture::TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout new_layout)
{
if (m_layout == new_layout)
return;
TransitionSubresourcesToLayout(command_buffer, 0, m_levels, 0, m_layers, m_layout, new_layout);
m_layout = new_layout;
}
void Texture::TransitionSubresourcesToLayout(VkCommandBuffer command_buffer, u32 start_level, u32 num_levels,
u32 start_layer, u32 num_layers, VkImageLayout old_layout, VkImageLayout new_layout)
{
VkImageAspectFlags aspect;
if (Util::IsDepthStencilFormat(m_format))
aspect = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
else if (Util::IsDepthFormat(m_format))
aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
else
aspect = VK_IMAGE_ASPECT_COLOR_BIT;
VkImageMemoryBarrier barrier = {
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType
nullptr, // const void* pNext
0, // VkAccessFlags srcAccessMask
0, // VkAccessFlags dstAccessMask
old_layout, // VkImageLayout oldLayout
new_layout, // VkImageLayout newLayout
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
m_image, // VkImage image
{aspect, start_level, num_levels, start_layer, num_layers} // VkImageSubresourceRange subresourceRange
};
// srcStageMask -> Stages that must complete before the barrier
// dstStageMask -> Stages that must wait for after the barrier before beginning
VkPipelineStageFlags srcStageMask, dstStageMask;
switch (old_layout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
// Layout undefined therefore contents undefined, and we don't care what happens to it.
barrier.srcAccessMask = 0;
srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
break;
case VK_IMAGE_LAYOUT_PREINITIALIZED:
// Image has been pre-initialized by the host, so ensure all writes have completed.
barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
srcStageMask = VK_PIPELINE_STAGE_HOST_BIT;
break;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
// Image was being used as a color attachment, so ensure all writes have completed.
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
// Image was being used as a depthstencil attachment, so ensure all writes have completed.
barrier.srcAccessMask =
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
srcStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
// Image was being used as a shader resource, make sure all reads have finished.
barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
// Image was being used as a copy source, ensure all reads have finished.
barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
// Image was being used as a copy destination, ensure all writes have finished.
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_GENERAL:
// General is used for feedback loops.
barrier.srcAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) :
(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
srcStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) :
(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
break;
default:
srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
break;
}
switch (new_layout)
{
case VK_IMAGE_LAYOUT_UNDEFINED:
barrier.dstAccessMask = 0;
dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
break;
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
break;
case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
barrier.dstAccessMask =
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
break;
case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
srcStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
break;
case VK_IMAGE_LAYOUT_GENERAL:
// General is used for feedback loops.
barrier.dstAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) :
(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
dstStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) :
(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
break;
default:
dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
break;
}
vkCmdPipelineBarrier(command_buffer, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1, &barrier);
}
VkFramebuffer Texture::CreateFramebuffer(VkRenderPass render_pass)
{
const VkFramebufferCreateInfo ci = {VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, 0u, render_pass, 1,
&m_view, m_width, m_height, m_layers};
VkFramebuffer fb = VK_NULL_HANDLE;
VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &ci, nullptr, &fb);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateFramebuffer() failed: ");
return VK_NULL_HANDLE;
}
return fb;
}
void Texture::UpdateFromBuffer(VkCommandBuffer cmdbuf, u32 level, u32 layer, u32 x, u32 y, u32 width, u32 height,
u32 buffer_height, u32 row_length, VkBuffer buffer, u32 buffer_offset)
{
const VkImageLayout old_layout = m_layout;
if (old_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
TransitionSubresourcesToLayout(
cmdbuf, level, 1, layer, 1, old_layout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
const VkBufferImageCopy bic = {static_cast<VkDeviceSize>(buffer_offset), row_length, buffer_height,
{VK_IMAGE_ASPECT_COLOR_BIT, level, layer, 1u}, {static_cast<int32_t>(x), static_cast<int32_t>(y), 0},
{width, height, 1u}};
vkCmdCopyBufferToImage(cmdbuf, buffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bic);
if (old_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
TransitionSubresourcesToLayout(
cmdbuf, level, 1, layer, 1, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, old_layout);
}
} // namespace Vulkan
-92
View File
@@ -1,92 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/Pcsx2Defs.h"
#include "common/Vulkan/Loader.h"
#include <algorithm>
#include <memory>
namespace Vulkan
{
class Texture
{
public:
Texture();
Texture(Texture&& move);
Texture(const Texture&) = delete;
~Texture();
Texture& operator=(Texture&& move);
Texture& operator=(const Texture&) = delete;
__fi bool IsValid() const { return (m_image != VK_NULL_HANDLE); }
/// An image is considered owned/managed if we control the memory.
__fi bool IsOwned() const { return (m_allocation != VK_NULL_HANDLE); }
__fi u32 GetWidth() const { return m_width; }
__fi u32 GetHeight() const { return m_height; }
__fi u32 GetLevels() const { return m_levels; }
__fi u32 GetLayers() const { return m_layers; }
__fi u32 GetMipWidth(u32 level) const { return std::max<u32>(m_width >> level, 1u); }
__fi u32 GetMipHeight(u32 level) const { return std::max<u32>(m_height >> level, 1u); }
__fi VkFormat GetFormat() const { return m_format; }
__fi VkSampleCountFlagBits GetSamples() const { return m_samples; }
__fi VkImageLayout GetLayout() const { return m_layout; }
__fi VkImageViewType GetViewType() const { return m_view_type; }
__fi VkImage GetImage() const { return m_image; }
__fi VmaAllocation GetAllocation() const { return m_allocation; }
__fi VkImageView GetView() const { return m_view; }
bool Create(u32 width, u32 height, u32 levels, u32 layers, VkFormat format, VkSampleCountFlagBits samples,
VkImageViewType view_type, VkImageTiling tiling, VkImageUsageFlags usage,
const VkComponentMapping* swizzle = nullptr);
bool Adopt(VkImage existing_image, VkImageViewType view_type, u32 width, u32 height, u32 levels, u32 layers,
VkFormat format, VkSampleCountFlagBits samples, const VkComponentMapping* swizzle = nullptr);
void Destroy(bool defer = true);
// Used when the render pass is changing the image layout, or to force it to
// VK_IMAGE_LAYOUT_UNDEFINED, if the existing contents of the image is
// irrelevant and will not be loaded.
void OverrideImageLayout(VkImageLayout new_layout);
void TransitionToLayout(VkCommandBuffer command_buffer, VkImageLayout new_layout);
void TransitionSubresourcesToLayout(VkCommandBuffer command_buffer, u32 start_level, u32 num_levels,
u32 start_layer, u32 num_layers, VkImageLayout old_layout, VkImageLayout new_layout);
VkFramebuffer CreateFramebuffer(VkRenderPass render_pass);
void UpdateFromBuffer(VkCommandBuffer cmdbuf, u32 level, u32 layer, u32 x, u32 y, u32 width, u32 height,
u32 buffer_height, u32 row_length, VkBuffer buffer, u32 buffer_offset);
private:
u32 m_width = 0;
u32 m_height = 0;
u32 m_levels = 0;
u32 m_layers = 0;
VkFormat m_format = VK_FORMAT_UNDEFINED;
VkSampleCountFlagBits m_samples = VK_SAMPLE_COUNT_1_BIT;
VkImageViewType m_view_type = VK_IMAGE_VIEW_TYPE_2D;
VkImageLayout m_layout = VK_IMAGE_LAYOUT_UNDEFINED;
VkImage m_image = VK_NULL_HANDLE;
VmaAllocation m_allocation = VK_NULL_HANDLE;
VkImageView m_view = VK_NULL_HANDLE;
};
} // namespace Vulkan
-393
View File
@@ -1,393 +0,0 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2021 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common/Vulkan/Util.h"
#include "common/Vulkan/Context.h"
#include "common/Vulkan/ShaderCompiler.h"
#include "common/Assertions.h"
#include "common/Console.h"
#include "common/StringUtil.h"
#include <cmath>
namespace Vulkan
{
namespace Util
{
bool IsDepthFormat(VkFormat format)
{
switch (format)
{
case VK_FORMAT_D16_UNORM:
case VK_FORMAT_D16_UNORM_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
return true;
default:
return false;
}
}
bool IsDepthStencilFormat(VkFormat format)
{
switch (format)
{
case VK_FORMAT_D16_UNORM_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
return true;
default:
return false;
}
}
VkFormat GetLinearFormat(VkFormat format)
{
switch (format)
{
case VK_FORMAT_R8_SRGB:
return VK_FORMAT_R8_UNORM;
case VK_FORMAT_R8G8_SRGB:
return VK_FORMAT_R8G8_UNORM;
case VK_FORMAT_R8G8B8_SRGB:
return VK_FORMAT_R8G8B8_UNORM;
case VK_FORMAT_R8G8B8A8_SRGB:
return VK_FORMAT_R8G8B8A8_UNORM;
case VK_FORMAT_B8G8R8_SRGB:
return VK_FORMAT_B8G8R8_UNORM;
case VK_FORMAT_B8G8R8A8_SRGB:
return VK_FORMAT_B8G8R8A8_UNORM;
default:
return format;
}
}
u32 GetTexelSize(VkFormat format)
{
// Only contains pixel formats we use.
switch (format)
{
case VK_FORMAT_R8_UNORM:
return 1;
case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
case VK_FORMAT_R5G6B5_UNORM_PACK16:
case VK_FORMAT_B5G6R5_UNORM_PACK16:
case VK_FORMAT_R16_UINT:
return 2;
case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_R32_UINT:
case VK_FORMAT_R32_SFLOAT:
case VK_FORMAT_D32_SFLOAT:
return 4;
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
return 8;
case VK_FORMAT_BC2_UNORM_BLOCK:
case VK_FORMAT_BC3_UNORM_BLOCK:
case VK_FORMAT_BC7_UNORM_BLOCK:
return 16;
default:
pxFailRel("Unhandled pixel format");
return 1;
}
}
VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor)
{
switch (factor)
{
case VK_BLEND_FACTOR_SRC_COLOR:
return VK_BLEND_FACTOR_SRC_ALPHA;
case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
case VK_BLEND_FACTOR_DST_COLOR:
return VK_BLEND_FACTOR_DST_ALPHA;
case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA;
default:
return factor;
}
}
void SetViewport(VkCommandBuffer command_buffer, int x, int y, int width, int height,
float min_depth /*= 0.0f*/, float max_depth /*= 1.0f*/)
{
const VkViewport vp{static_cast<float>(x), static_cast<float>(y), static_cast<float>(width),
static_cast<float>(height), min_depth, max_depth};
vkCmdSetViewport(command_buffer, 0, 1, &vp);
}
void SetScissor(VkCommandBuffer command_buffer, int x, int y, int width, int height)
{
const VkRect2D scissor{{x, y}, {static_cast<u32>(width), static_cast<u32>(height)}};
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
}
void SetViewportAndScissor(VkCommandBuffer command_buffer, int x, int y, int width, int height,
float min_depth /* = 0.0f */, float max_depth /* = 1.0f */)
{
}
void SafeDestroyFramebuffer(VkFramebuffer& fb)
{
if (fb != VK_NULL_HANDLE)
{
vkDestroyFramebuffer(g_vulkan_context->GetDevice(), fb, nullptr);
fb = VK_NULL_HANDLE;
}
}
void SafeDestroyShaderModule(VkShaderModule& sm)
{
if (sm != VK_NULL_HANDLE)
{
vkDestroyShaderModule(g_vulkan_context->GetDevice(), sm, nullptr);
sm = VK_NULL_HANDLE;
}
}
void SafeDestroyPipeline(VkPipeline& p)
{
if (p != VK_NULL_HANDLE)
{
vkDestroyPipeline(g_vulkan_context->GetDevice(), p, nullptr);
p = VK_NULL_HANDLE;
}
}
void SafeDestroyPipelineLayout(VkPipelineLayout& pl)
{
if (pl != VK_NULL_HANDLE)
{
vkDestroyPipelineLayout(g_vulkan_context->GetDevice(), pl, nullptr);
pl = VK_NULL_HANDLE;
}
}
void SafeDestroyDescriptorSetLayout(VkDescriptorSetLayout& dsl)
{
if (dsl != VK_NULL_HANDLE)
{
vkDestroyDescriptorSetLayout(g_vulkan_context->GetDevice(), dsl, nullptr);
dsl = VK_NULL_HANDLE;
}
}
void SafeDestroyBufferView(VkBufferView& bv)
{
if (bv != VK_NULL_HANDLE)
{
vkDestroyBufferView(g_vulkan_context->GetDevice(), bv, nullptr);
bv = VK_NULL_HANDLE;
}
}
void SafeDestroyImageView(VkImageView& iv)
{
if (iv != VK_NULL_HANDLE)
{
vkDestroyImageView(g_vulkan_context->GetDevice(), iv, nullptr);
iv = VK_NULL_HANDLE;
}
}
void SafeDestroySampler(VkSampler& samp)
{
if (samp != VK_NULL_HANDLE)
{
vkDestroySampler(g_vulkan_context->GetDevice(), samp, nullptr);
samp = VK_NULL_HANDLE;
}
}
void SafeDestroySemaphore(VkSemaphore& sem)
{
if (sem != VK_NULL_HANDLE)
{
vkDestroySemaphore(g_vulkan_context->GetDevice(), sem, nullptr);
sem = VK_NULL_HANDLE;
}
}
void SafeFreeGlobalDescriptorSet(VkDescriptorSet& ds)
{
if (ds != VK_NULL_HANDLE)
{
g_vulkan_context->FreeGlobalDescriptorSet(ds);
ds = VK_NULL_HANDLE;
}
}
void BufferMemoryBarrier(VkCommandBuffer command_buffer, VkBuffer buffer, VkAccessFlags src_access_mask,
VkAccessFlags dst_access_mask, VkDeviceSize offset, VkDeviceSize size, VkPipelineStageFlags src_stage_mask,
VkPipelineStageFlags dst_stage_mask)
{
VkBufferMemoryBarrier buffer_info = {
VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType
nullptr, // const void* pNext
src_access_mask, // VkAccessFlags srcAccessMask
dst_access_mask, // VkAccessFlags dstAccessMask
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex
buffer, // VkBuffer buffer
offset, // VkDeviceSize offset
size // VkDeviceSize size
};
vkCmdPipelineBarrier(
command_buffer, src_stage_mask, dst_stage_mask, 0, 0, nullptr, 1, &buffer_info, 0, nullptr);
}
void AddPointerToChain(void* head, const void* ptr)
{
VkBaseInStructure* last_st = static_cast<VkBaseInStructure*>(head);
while (last_st->pNext)
{
if (last_st->pNext == ptr)
return;
last_st = const_cast<VkBaseInStructure*>(last_st->pNext);
}
last_st->pNext = static_cast<const VkBaseInStructure*>(ptr);
}
const char* VkResultToString(VkResult res)
{
switch (res)
{
case VK_SUCCESS:
return "VK_SUCCESS";
case VK_NOT_READY:
return "VK_NOT_READY";
case VK_TIMEOUT:
return "VK_TIMEOUT";
case VK_EVENT_SET:
return "VK_EVENT_SET";
case VK_EVENT_RESET:
return "VK_EVENT_RESET";
case VK_INCOMPLETE:
return "VK_INCOMPLETE";
case VK_ERROR_OUT_OF_HOST_MEMORY:
return "VK_ERROR_OUT_OF_HOST_MEMORY";
case VK_ERROR_OUT_OF_DEVICE_MEMORY:
return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
case VK_ERROR_INITIALIZATION_FAILED:
return "VK_ERROR_INITIALIZATION_FAILED";
case VK_ERROR_DEVICE_LOST:
return "VK_ERROR_DEVICE_LOST";
case VK_ERROR_MEMORY_MAP_FAILED:
return "VK_ERROR_MEMORY_MAP_FAILED";
case VK_ERROR_LAYER_NOT_PRESENT:
return "VK_ERROR_LAYER_NOT_PRESENT";
case VK_ERROR_EXTENSION_NOT_PRESENT:
return "VK_ERROR_EXTENSION_NOT_PRESENT";
case VK_ERROR_FEATURE_NOT_PRESENT:
return "VK_ERROR_FEATURE_NOT_PRESENT";
case VK_ERROR_INCOMPATIBLE_DRIVER:
return "VK_ERROR_INCOMPATIBLE_DRIVER";
case VK_ERROR_TOO_MANY_OBJECTS:
return "VK_ERROR_TOO_MANY_OBJECTS";
case VK_ERROR_FORMAT_NOT_SUPPORTED:
return "VK_ERROR_FORMAT_NOT_SUPPORTED";
case VK_ERROR_SURFACE_LOST_KHR:
return "VK_ERROR_SURFACE_LOST_KHR";
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
case VK_SUBOPTIMAL_KHR:
return "VK_SUBOPTIMAL_KHR";
case VK_ERROR_OUT_OF_DATE_KHR:
return "VK_ERROR_OUT_OF_DATE_KHR";
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
case VK_ERROR_VALIDATION_FAILED_EXT:
return "VK_ERROR_VALIDATION_FAILED_EXT";
case VK_ERROR_INVALID_SHADER_NV:
return "VK_ERROR_INVALID_SHADER_NV";
default:
return "UNKNOWN_VK_RESULT";
}
}
const char* PresentModeToString(VkPresentModeKHR mode)
{
switch (mode)
{
case VK_PRESENT_MODE_IMMEDIATE_KHR:
return "VK_PRESENT_MODE_IMMEDIATE_KHR";
case VK_PRESENT_MODE_MAILBOX_KHR:
return "VK_PRESENT_MODE_MAILBOX_KHR";
case VK_PRESENT_MODE_FIFO_KHR:
return "VK_PRESENT_MODE_FIFO_KHR";
case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
return "VK_PRESENT_MODE_FIFO_RELAXED_KHR";
case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR:
return "VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR";
case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR:
return "VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR";
default:
return "UNKNOWN_VK_PRESENT_MODE";
}
}
void LogVulkanResult(const char* func_name, VkResult res, const char* msg, ...)
{
std::va_list ap;
va_start(ap, msg);
std::string real_msg = StringUtil::StdStringFromFormatV(msg, ap);
va_end(ap);
Console.Error(
"(%s) %s (%d: %s)", func_name, real_msg.c_str(), static_cast<int>(res), VkResultToString(res));
}
} // namespace Util
} // namespace Vulkan
+5 -70
View File
@@ -22,7 +22,7 @@
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="vsprops\CommonLibrary.props" />
<Import Project="vsprops\3rdpartyDeps.props" />
<Import Project="vsprops\common.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="vsprops\CodeGen_Release.props" />
@@ -34,21 +34,13 @@
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\d3d12memalloc\include;$(SolutionDir)3rdparty\glad\include;$(SolutionDir)3rdparty\glslang\glslang;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src\c4\ext\fast_float\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\libpng</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\jpgd</AdditionalIncludeDirectories>
<ExceptionHandling>Async</ExceptionHandling>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\fmt\include</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<ForcedIncludeFiles>PrecompiledHeader.h</ForcedIncludeFiles>
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="!$(Configuration.Contains(AVX2))">_M_SSE=0x401;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(AVX2))">_M_SSE=0x501;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnableEnhancedInstructionSet Condition="!$(Configuration.Contains(AVX2)) Or $(Configuration.Contains(Clang))">NotSet</EnableEnhancedInstructionSet>
<EnableEnhancedInstructionSet Condition="$(Configuration.Contains(AVX2)) And !$(Configuration.Contains(Clang))">AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<AdditionalOptions Condition="$(Configuration.Contains(Clang)) And !$(Configuration.Contains(AVX2))"> -march=nehalem %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(AVX2))"> -march=haswell %(AdditionalOptions)</AdditionalOptions>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
</ClCompile>
</ItemDefinitionGroup>
@@ -56,27 +48,13 @@
<ClCompile Include="AlignedMalloc.cpp" />
<ClCompile Include="Console.cpp" />
<ClCompile Include="CrashHandler.cpp" />
<ClCompile Include="D3D11\ShaderCache.cpp" />
<ClCompile Include="D3D11\ShaderCompiler.cpp" />
<ClCompile Include="D3D12\Builders.cpp" />
<ClCompile Include="D3D12\Context.cpp" />
<ClCompile Include="D3D12\DescriptorHeapManager.cpp" />
<ClCompile Include="D3D12\ShaderCache.cpp" />
<ClCompile Include="D3D12\StreamBuffer.cpp" />
<ClCompile Include="D3D12\Texture.cpp" />
<ClCompile Include="D3D12\Util.cpp" />
<ClCompile Include="DynamicLibrary.cpp" />
<ClCompile Include="Exceptions.cpp" />
<ClCompile Include="FastJmp.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="General.cpp" />
<ClCompile Include="GL\Context.cpp" />
<ClCompile Include="GL\ContextWGL.cpp" />
<ClCompile Include="GL\Program.cpp" />
<ClCompile Include="GL\ShaderCache.cpp" />
<ClCompile Include="GL\StreamBuffer.cpp" />
<ClCompile Include="FileSystem.cpp" />
<ClCompile Include="General.cpp" />
<ClCompile Include="Image.cpp" />
<ClCompile Include="HTTPDownloader.cpp" />
<ClCompile Include="HTTPDownloaderCurl.cpp">
@@ -91,16 +69,6 @@
<ClCompile Include="StringUtil.cpp" />
<ClCompile Include="SettingsWrapper.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="Vulkan\vk_mem_alloc.cpp" />
<ClCompile Include="Vulkan\Builders.cpp" />
<ClCompile Include="Vulkan\Context.cpp" />
<ClCompile Include="Vulkan\Loader.cpp" />
<ClCompile Include="Vulkan\ShaderCache.cpp" />
<ClCompile Include="Vulkan\ShaderCompiler.cpp" />
<ClCompile Include="Vulkan\StreamBuffer.cpp" />
<ClCompile Include="Vulkan\SwapChain.cpp" />
<ClCompile Include="Vulkan\Texture.cpp" />
<ClCompile Include="Vulkan\Util.cpp" />
<ClCompile Include="WAVWriter.cpp" />
<ClCompile Include="WindowInfo.cpp" />
<ClCompile Include="Perf.cpp" />
@@ -131,31 +99,17 @@
</ItemGroup>
<ItemGroup>
<MASM Include="FastJmp.asm" />
<None Include="Vulkan\EntryPoints.inl" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Align.h" />
<ClInclude Include="AlignedMalloc.h" />
<ClInclude Include="BitCast.h" />
<ClInclude Include="ByteSwap.h" />
<ClInclude Include="CrashHandler.h" />
<ClInclude Include="D3D11\ShaderCache.h" />
<ClInclude Include="D3D11\ShaderCompiler.h" />
<ClInclude Include="D3D12\Builders.h" />
<ClInclude Include="D3D12\Context.h" />
<ClInclude Include="D3D12\DescriptorHeapManager.h" />
<ClInclude Include="D3D12\ShaderCache.h" />
<ClInclude Include="D3D12\StreamBuffer.h" />
<ClInclude Include="D3D12\Texture.h" />
<ClInclude Include="D3D12\Util.h" />
<ClInclude Include="DynamicLibrary.h" />
<ClInclude Include="Easing.h" />
<ClInclude Include="boost_spsc_queue.hpp" />
<ClInclude Include="FastJmp.h" />
<ClInclude Include="GL\Context.h" />
<ClInclude Include="GL\ContextWGL.h" />
<ClInclude Include="GL\Program.h" />
<ClInclude Include="GL\ShaderCache.h" />
<ClInclude Include="GL\StreamBuffer.h" />
<ClInclude Include="FileSystem.h" />
<ClInclude Include="HashCombine.h" />
<ClInclude Include="HeapArray.h" />
@@ -188,16 +142,6 @@
<ClInclude Include="SafeArray.h" />
<ClInclude Include="ThreadPool.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="Vulkan\Builders.h" />
<ClInclude Include="Vulkan\Context.h" />
<ClInclude Include="Vulkan\EntryPoints.h" />
<ClInclude Include="Vulkan\Loader.h" />
<ClInclude Include="Vulkan\ShaderCache.h" />
<ClInclude Include="Vulkan\ShaderCompiler.h" />
<ClInclude Include="Vulkan\StreamBuffer.h" />
<ClInclude Include="Vulkan\SwapChain.h" />
<ClInclude Include="Vulkan\Texture.h" />
<ClInclude Include="Vulkan\Util.h" />
<ClInclude Include="WAVWriter.h" />
<ClInclude Include="WindowInfo.h" />
<ClInclude Include="Threading.h" />
@@ -230,15 +174,6 @@
<ClInclude Include="ZipHelpers.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\3rdparty\d3d12memalloc\d3d12memalloc.vcxproj">
<Project>{d45cec7a-3171-40dd-975d-e1544cf16139}</Project>
</ProjectReference>
<ProjectReference Include="..\3rdparty\glad\glad.vcxproj">
<Project>{c0293b32-5acf-40f0-aa6c-e6da6f3bf33a}</Project>
</ProjectReference>
<ProjectReference Include="..\3rdparty\glslang\glslang.vcxproj">
<Project>{ef6834a9-11f3-4331-bc34-21b325abb180}</Project>
</ProjectReference>
<ProjectReference Include="..\3rdparty\jpgd\jpgd.vcxproj">
<Project>{ed2f21fd-0a36-4a8f-9b90-e7d92a2acb63}</Project>
</ProjectReference>
@@ -247,4 +182,4 @@
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
</Project>
+12 -180
View File
@@ -94,18 +94,6 @@
<ClCompile Include="WindowInfo.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GL\ContextWGL.cpp">
<Filter>Source Files\GL</Filter>
</ClCompile>
<ClCompile Include="GL\Context.cpp">
<Filter>Source Files\GL</Filter>
</ClCompile>
<ClCompile Include="GL\StreamBuffer.cpp">
<Filter>Source Files\GL</Filter>
</ClCompile>
<ClCompile Include="FileSystem.cpp">
<Filter>Source Files\GL</Filter>
</ClCompile>
<ClCompile Include="StringUtil.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -115,72 +103,9 @@
<ClCompile Include="ProgressCallback.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Vulkan\Builders.cpp">
<Filter>Source Files\Vulkan</Filter>
</ClCompile>
<ClCompile Include="Vulkan\Context.cpp">
<Filter>Source Files\Vulkan</Filter>
</ClCompile>
<ClCompile Include="Vulkan\Loader.cpp">
<Filter>Source Files\Vulkan</Filter>
</ClCompile>
<ClCompile Include="Vulkan\ShaderCache.cpp">
<Filter>Source Files\Vulkan</Filter>
</ClCompile>
<ClCompile Include="Vulkan\ShaderCompiler.cpp">
<Filter>Source Files\Vulkan</Filter>
</ClCompile>
<ClCompile Include="Vulkan\StreamBuffer.cpp">
<Filter>Source Files\Vulkan</Filter>
</ClCompile>
<ClCompile Include="Vulkan\SwapChain.cpp">
<Filter>Source Files\Vulkan</Filter>
</ClCompile>
<ClCompile Include="Vulkan\Texture.cpp">
<Filter>Source Files\Vulkan</Filter>
</ClCompile>
<ClCompile Include="Vulkan\Util.cpp">
<Filter>Source Files\Vulkan</Filter>
</ClCompile>
<ClCompile Include="MD5Digest.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GL\Program.cpp">
<Filter>Source Files\GL</Filter>
</ClCompile>
<ClCompile Include="GL\ShaderCache.cpp">
<Filter>Source Files\GL</Filter>
</ClCompile>
<ClCompile Include="Vulkan\vk_mem_alloc.cpp">
<Filter>Source Files\Vulkan</Filter>
</ClCompile>
<ClCompile Include="D3D11\ShaderCache.cpp">
<Filter>Source Files\D3D11</Filter>
</ClCompile>
<ClCompile Include="D3D11\ShaderCompiler.cpp">
<Filter>Source Files\D3D11</Filter>
</ClCompile>
<ClCompile Include="D3D12\Context.cpp">
<Filter>Source Files\D3D12</Filter>
</ClCompile>
<ClCompile Include="D3D12\DescriptorHeapManager.cpp">
<Filter>Source Files\D3D12</Filter>
</ClCompile>
<ClCompile Include="D3D12\ShaderCache.cpp">
<Filter>Source Files\D3D12</Filter>
</ClCompile>
<ClCompile Include="D3D12\StreamBuffer.cpp">
<Filter>Source Files\D3D12</Filter>
</ClCompile>
<ClCompile Include="D3D12\Texture.cpp">
<Filter>Source Files\D3D12</Filter>
</ClCompile>
<ClCompile Include="D3D12\Util.cpp">
<Filter>Source Files\D3D12</Filter>
</ClCompile>
<ClCompile Include="D3D12\Builders.cpp">
<Filter>Source Files\D3D12</Filter>
</ClCompile>
<ClCompile Include="StackWalker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -208,7 +133,12 @@
<ClCompile Include="WAVWriter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="General.cpp" />
<ClCompile Include="FileSystem.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="General.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="AlignedMalloc.h">
@@ -352,18 +282,6 @@
<ClInclude Include="BitCast.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GL\Context.h">
<Filter>Header Files\GL</Filter>
</ClInclude>
<ClInclude Include="GL\ContextWGL.h">
<Filter>Header Files\GL</Filter>
</ClInclude>
<ClInclude Include="GL\StreamBuffer.h">
<Filter>Header Files\GL</Filter>
</ClInclude>
<ClInclude Include="FileSystem.h">
<Filter>Header Files\GL</Filter>
</ClInclude>
<ClInclude Include="StringUtil.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -382,75 +300,12 @@
<ClInclude Include="HashCombine.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Vulkan\ShaderCompiler.h">
<Filter>Header Files\Vulkan</Filter>
</ClInclude>
<ClInclude Include="Vulkan\StreamBuffer.h">
<Filter>Header Files\Vulkan</Filter>
</ClInclude>
<ClInclude Include="Vulkan\SwapChain.h">
<Filter>Header Files\Vulkan</Filter>
</ClInclude>
<ClInclude Include="Vulkan\Texture.h">
<Filter>Header Files\Vulkan</Filter>
</ClInclude>
<ClInclude Include="Vulkan\Util.h">
<Filter>Header Files\Vulkan</Filter>
</ClInclude>
<ClInclude Include="Vulkan\Builders.h">
<Filter>Header Files\Vulkan</Filter>
</ClInclude>
<ClInclude Include="Vulkan\Context.h">
<Filter>Header Files\Vulkan</Filter>
</ClInclude>
<ClInclude Include="Vulkan\EntryPoints.h">
<Filter>Header Files\Vulkan</Filter>
</ClInclude>
<ClInclude Include="Vulkan\Loader.h">
<Filter>Header Files\Vulkan</Filter>
</ClInclude>
<ClInclude Include="Vulkan\ShaderCache.h">
<Filter>Header Files\Vulkan</Filter>
</ClInclude>
<ClInclude Include="MD5Digest.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GL\Program.h">
<Filter>Header Files\GL</Filter>
</ClInclude>
<ClInclude Include="GL\ShaderCache.h">
<Filter>Header Files\GL</Filter>
</ClInclude>
<ClInclude Include="D3D11\ShaderCache.h">
<Filter>Header Files\D3D11</Filter>
</ClInclude>
<ClInclude Include="D3D11\ShaderCompiler.h">
<Filter>Header Files\D3D11</Filter>
</ClInclude>
<ClInclude Include="ZipHelpers.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="D3D12\Context.h">
<Filter>Header Files\D3D12</Filter>
</ClInclude>
<ClInclude Include="D3D12\DescriptorHeapManager.h">
<Filter>Header Files\D3D12</Filter>
</ClInclude>
<ClInclude Include="D3D12\ShaderCache.h">
<Filter>Header Files\D3D12</Filter>
</ClInclude>
<ClInclude Include="D3D12\StreamBuffer.h">
<Filter>Header Files\D3D12</Filter>
</ClInclude>
<ClInclude Include="D3D12\Texture.h">
<Filter>Header Files\D3D12</Filter>
</ClInclude>
<ClInclude Include="D3D12\Util.h">
<Filter>Header Files\D3D12</Filter>
</ClInclude>
<ClInclude Include="D3D12\Builders.h">
<Filter>Header Files\D3D12</Filter>
</ClInclude>
<ClInclude Include="CrashHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -493,6 +348,12 @@
<ClInclude Include="WAVWriter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="FileSystem.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ByteSwap.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Source Files">
@@ -501,35 +362,6 @@
<Filter Include="Header Files">
<UniqueIdentifier>{eef579af-e6a8-4d3b-a88e-c0e4cad9e5d8}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\GL">
<UniqueIdentifier>{92d1bb2d-d172-4356-b9f4-a8fcc8e7fcce}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\GL">
<UniqueIdentifier>{5e76b340-cb0e-4946-83ec-7d72e397cac8}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Vulkan">
<UniqueIdentifier>{94154238-8b02-44f8-a7b8-3612e7bfa33c}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Vulkan">
<UniqueIdentifier>{46f36c68-0e0e-4acd-a621-3365e3167c4f}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\D3D11">
<UniqueIdentifier>{f428aac0-c9c5-4b66-b218-9829dce45d13}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\D3D11">
<UniqueIdentifier>{764ddf71-77a6-41b8-bc65-1eef94b6997b}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\D3D12">
<UniqueIdentifier>{96f78eb9-089b-4166-a23e-78c4e7d90b64}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\D3D12">
<UniqueIdentifier>{cf37623d-bb05-4c54-8c72-1c20b5331c69}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="Vulkan\EntryPoints.inl">
<Filter>Source Files\Vulkan</Filter>
</None>
</ItemGroup>
<ItemGroup>
<MASM Include="FastJmp.asm">
-16
View File
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
<_PropertySheetDisplayName>Pcsx3rdpartyDependencies</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\;$(SolutionDir)3rdparty\soundtouch\soundtouch\;$(SolutionDir)3rdparty\rapidyaml\rapidyaml\src;$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src;$(SolutionDir)3rdparty\fmt\fmt\include\;$(SolutionDir)3rdparty\libchdr\libchdr\include;$(SolutionDir)3rdparty\wil\include;$(SolutionDir)3rdparty\Vulkan-Headers\include\;$(SolutionDir)3rdparty\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>WIL_SUPPRESS_EXCEPTIONS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(SolutionDir)deps\$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
</Project>
+1 -32
View File
@@ -1,38 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
<_PropertySheetDisplayName>PcsxBaseProperties</_PropertySheetDisplayName>
<OutDir>$(SolutionDir)bin\$(PcsxSubsection)\</OutDir>
<OutDir>$(SolutionDir)bin\</OutDir>
<IntDir>$(PlatformName)\$(Configuration)\</IntDir>
<ExtensionsToDeleteOnClean>*.bsc;*.idb;*.sbr;*.res;*.pch;*.pdb;*.obj;*.tlb;*.tli;*.tlh;*.tmp;*.rsp;*.pgc;*.pgd;*.meta;$(TargetPath);$(ExtensionsToDeleteOnClean)</ExtensionsToDeleteOnClean>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__WIN32__;WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;WINVER=0x0A00;_WIN32_WINNT=0x0A00;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4063;4100;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
<!-- Force ThinLTO for Release builds, MSVC doesn't seem to do it otherwise. -->
<!-- Also due to include order, needs to be set here, rather than in CodeGen_Release.props -->
<AdditionalOptions Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(Release))"> -flto=thin %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
</Link>
<PreBuildEvent>
<Command>"$(SolutionDir)common\vsprops\preBuild.cmd"</Command>
</PreBuildEvent>
<ResourceCompile>
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
</ItemDefinitionGroup>
</Project>
-15
View File
@@ -1,22 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
<OutDir>$(SolutionDir)deps\$(PlatformName)\$(Configuration)\</OutDir>
<IntDir>$(PlatformName)\$(Configuration)\</IntDir>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)\3rdparty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__WIN32__;WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Platform)'=='x64'">_ARCH_64=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4063;4100;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
</ClCompile>
</ItemDefinitionGroup>
</Project>
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemDefinitionGroup>
<!-- This sucks. Need a better solution. -->
<PreBuildEvent>
<Command>"$(SolutionDir)common\vsprops\preBuild.cmd"</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
</Project>
+3 -3
View File
@@ -2,11 +2,11 @@
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="UserMacros">
<BinaryOutputDir>$(SolutionDir)bin\</BinaryOutputDir>
<PCSX2QTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)3rdparty\qt\6.4.0\msvc2022_64\</PCSX2QTDIRDefault>
<PCSX2QTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)3rdparty\qt\6.4.0\msvc2022_arm64\</PCSX2QTDIRDefault>
<PCSX2QTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)3rdparty\qt\6.5.0\msvc2022_64\</PCSX2QTDIRDefault>
<PCSX2QTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)3rdparty\qt\6.5.0\msvc2022_arm64\</PCSX2QTDIRDefault>
<PCSX2QTDIR Condition="Exists('$(PCSX2QTDIRDefault)') And ('$(PCSX2QTDIR)'=='' Or !Exists('$(PCSX2QTDIR)'))">$(PCSX2QTDIRDefault)</PCSX2QTDIR>
<PCSX2QTDIR Condition="Exists('$(PCSX2QTDIR)') And !HasTrailingSlash('$(PCSX2QTDIR)')">$(PCSX2QTDIR)\</PCSX2QTDIR>
<PCSX2QTDIRHost>$(SolutionDir)3rdparty\qt\6.4.0\msvc2022_64\</PCSX2QTDIRHost>
<PCSX2QTDIRHost>$(SolutionDir)3rdparty\qt\6.5.0\msvc2022_64\</PCSX2QTDIRHost>
<QtDirValid>false</QtDirValid>
<QtDirValid Condition="Exists('$(PCSX2QTDIR)')">true</QtDirValid>
<QtIncludeDir>$(PCSX2QTDIR)include\</QtIncludeDir>
+33 -29
View File
@@ -1,10 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="UserMacros">
<ProjectRootDir>$(ProjectDir)\..\..</ProjectRootDir>
<SvnRootDir>$(ProjectRootDir)\..</SvnRootDir>
<SvnCommonDir>$(SvnRootDir)\common</SvnCommonDir>
<PcsxSubsection />
<SSEString />
<SSEString Condition="$(Configuration.Contains(AVX2))">-avx2</SSEString>
<ArchString />
@@ -17,42 +13,50 @@
<EXEString>$(ProjectName)$(ArchString)$(SSEString)$(ToolkitString)$(BuildString)</EXEString>
</PropertyGroup>
<PropertyGroup>
<_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>./;$(ProjectDir);$(ProjectDir)x86;$(ProjectDir)x86\ix86-32;$(ProjectDir)IPU;$(ProjectDir)System;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>_M_X86;TIXML_USE_STL;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>$(SolutionDir);$(ProjectDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>__WIN32__;WIN32;_WINDOWS;WIN32_LEAN_AND_MEAN;NOMINMAX;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;_SCL_SECURE_NO_WARNINGS;WINVER=0x0A00;_WIN32_WINNT=0x0A00;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Debug))">PCSX2_DEBUG;PCSX2_DEVBUILD;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Devel))">PCSX2_DEVEL;PCSX2_DEVBUILD;NDEBUG;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Release))">NDEBUG;_SECURE_SCL_=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeaderOutputFile>$(IntDir)pcsx2.pch</PrecompiledHeaderOutputFile>
<WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CompileAs>Default</CompileAs>
<DisableSpecificWarnings>4063;4100;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<LanguageStandard>stdcpp17</LanguageStandard>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions Condition="'$(Platform)'=='x64'">_ARCH_64=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ExceptionHandling>Async</ExceptionHandling>
<MinimalRebuild>false</MinimalRebuild>
<ConformanceMode>true</ConformanceMode>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
<!-- SH 2/3 flashlight, explicitly set here don't change -->
<!-- https://github.com/PCSX2/pcsx2/commit/16431653e4d92fda4069031897e24fbe4688d36a -->
<FloatingPointModel>Precise</FloatingPointModel>
<!-- MSVC automatically adds __AVX__ and __AVX2__ appropriately -->
<PreprocessorDefinitions>_M_X86;__SSE4_1__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnableEnhancedInstructionSet Condition="!$(Configuration.Contains(AVX2)) Or $(Configuration.Contains(Clang))">NotSet</EnableEnhancedInstructionSet>
<EnableEnhancedInstructionSet Condition="$(Configuration.Contains(AVX2)) And !$(Configuration.Contains(Clang))">AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<AdditionalOptions Condition="$(Configuration.Contains(Clang)) And !$(Configuration.Contains(AVX2))"> -march=nehalem %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(AVX2))"> -march=haswell %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="!$(Configuration.Contains(Clang))">%(AdditionalOptions) /Zc:externConstexpr /Zc:__cplusplus /Zo /utf-8</AdditionalOptions>
<!-- Force ThinLTO for Release builds, MSVC doesn't seem to do it otherwise. -->
<!-- Also due to include order, needs to be set here, rather than in CodeGen_Release.props -->
<AdditionalOptions Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(Release))"> -flto=thin %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<AdditionalDependencies>setupapi.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\;..\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;rpcrt4.lib;iphlpapi.lib;dsound.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dxguid.lib;dinput8.lib;hid.lib;PowrProf.lib;d3dcompiler.lib;d3d11.lib;d3d12.lib;dxgi.lib;strmiids.lib;opengl32.lib;comsuppw.lib;OneCore.lib;%(AdditionalDependencies)</AdditionalDependencies>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Windows</SubSystem>
</Link>
<PreBuildEvent>
<Command>
</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<BuildMacro Include="ProjectRootDir">
<Value>$(ProjectRootDir)</Value>
</BuildMacro>
<BuildMacro Include="SvnRootDir">
<Value>$(SvnRootDir)</Value>
</BuildMacro>
<BuildMacro Include="SvnCommonDir">
<Value>$(SvnCommonDir)</Value>
</BuildMacro>
<BuildMacro Include="PcsxSubsection">
<Value>$(PcsxSubsection)</Value>
</BuildMacro>
</ItemGroup>
</Project>
-32
View File
@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="UserMacros">
<PcsxSubsection>plugins</PcsxSubsection>
<ProjectRootDir>$(ProjectDir)..</ProjectRootDir>
<SvnRootDir>$(ProjectRootDir)\..\..\..</SvnRootDir>
<SvnCommonDir>$(SvnRootDir)\common</SvnCommonDir>
</PropertyGroup>
<PropertyGroup>
<_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
<_PropertySheetDisplayName>PluginSvnRoot</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(ProjectDir);$(ProjectDir)\..\3rdparty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<BuildMacro Include="PcsxSubsection">
<Value>$(PcsxSubsection)</Value>
</BuildMacro>
<BuildMacro Include="ProjectRootDir">
<Value>$(ProjectRootDir)</Value>
</BuildMacro>
<BuildMacro Include="SvnRootDir">
<Value>$(SvnRootDir)</Value>
</BuildMacro>
<BuildMacro Include="SvnCommonDir">
<Value>$(SvnCommonDir)</Value>
</BuildMacro>
</ItemGroup>
</Project>
+18 -79
View File
@@ -37,25 +37,20 @@
#include "pcsx2/PrecompiledHeader.h"
#include "pcsx2/Achievements.h"
#include "pcsx2/CDVD/CDVD.h"
#include "pcsx2/Frontend/CommonHost.h"
#include "pcsx2/Frontend/InputManager.h"
#include "pcsx2/Frontend/ImGuiManager.h"
#include "pcsx2/Frontend/LogSink.h"
#include "pcsx2/GS.h"
#include "pcsx2/GS/GS.h"
#include "pcsx2/GSDumpReplayer.h"
#include "pcsx2/HostDisplay.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/Host.h"
#include "pcsx2/INISettingsInterface.h"
#include "pcsx2/ImGui/ImGuiManager.h"
#include "pcsx2/Input/InputManager.h"
#include "pcsx2/LogSink.h"
#include "pcsx2/PAD/Host/PAD.h"
#include "pcsx2/PerformanceMetrics.h"
#include "pcsx2/VMManager.h"
#ifdef ENABLE_ACHIEVEMENTS
#include "pcsx2/Frontend/Achievements.h"
#endif
#include "svnrev.h"
namespace GSRunner
@@ -87,14 +82,14 @@ static u32 s_loop_number = s_loop_count;
bool GSRunner::InitializeConfig()
{
if (!CommonHost::InitializeCriticalFolders())
if (!EmuFolders::InitializeCriticalFolders())
return false;
// don't provide an ini path, or bother loading. we'll store everything in memory.
MemorySettingsInterface& si = s_settings_interface;
Host::Internal::SetBaseSettingsLayer(&si);
CommonHost::SetDefaultSettings(si, true, true, true, true, true);
VMManager::SetDefaultSettings(si, true, true, true, true, true);
// complete as quickly as possible
si.SetBoolValue("EmuCore/GS", "FrameLimitEnable", false);
@@ -131,7 +126,7 @@ bool GSRunner::InitializeConfig()
si.SetStringValue("MemoryCards", fmt::format("Slot{}_Filename", i + 1).c_str(), "");
}
CommonHost::LoadStartupSettings();
VMManager::Internal::LoadStartupSettings();
return true;
}
@@ -142,12 +137,10 @@ void Host::CommitBaseSettingChanges()
void Host::LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
{
CommonHost::LoadSettings(si, lock);
}
void Host::CheckForSettingsChanges(const Pcsx2Config& old_config)
{
CommonHost::CheckForSettingsChanges(old_config);
}
bool Host::RequestResetSettings(bool folders, bool core, bool controllers, bool hotkeys, bool ui)
@@ -254,36 +247,16 @@ void Host::SetRelativeMouseMode(bool enabled)
{
}
bool Host::AcquireHostDisplay(RenderAPI api, bool clear_state_on_fail)
std::optional<WindowInfo> Host::AcquireRenderWindow(bool recreate_window)
{
const std::optional<WindowInfo> wi(GSRunner::GetPlatformWindowInfo());
if (!wi.has_value())
return false;
g_host_display = HostDisplay::CreateForAPI(api);
if (!g_host_display)
return false;
if (!g_host_display->CreateDevice(wi.value(), Host::GetEffectiveVSyncMode()) ||
!g_host_display->MakeCurrent() || !g_host_display->SetupDevice() || !ImGuiManager::Initialize())
{
ReleaseHostDisplay(clear_state_on_fail);
return false;
}
Console.WriteLn(Color_StrongGreen, "%s Graphics Driver Info:", HostDisplay::RenderAPIToString(g_host_display->GetRenderAPI()));
Console.Indent().WriteLn(g_host_display->GetDriverInfo());
return g_host_display.get();
return GSRunner::GetPlatformWindowInfo();
}
void Host::ReleaseHostDisplay(bool clear_state)
void Host::ReleaseRenderWindow()
{
ImGuiManager::Shutdown(clear_state);
g_host_display.reset();
}
HostDisplay::PresentResult Host::BeginPresentFrame(bool frame_skip)
void Host::BeginPresentFrame()
{
if (s_loop_number == 0 && !s_output_prefix.empty())
{
@@ -294,33 +267,6 @@ HostDisplay::PresentResult Host::BeginPresentFrame(bool frame_skip)
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
GSQueueSnapshot(dump_path);
}
const HostDisplay::PresentResult result = g_host_display->BeginPresent(frame_skip);
if (result != HostDisplay::PresentResult::OK)
{
// don't render imgui
ImGuiManager::SkipFrame();
}
return result;
}
void Host::EndPresentFrame()
{
if (GSDumpReplayer::IsReplayingDump())
GSDumpReplayer::RenderUI();
ImGuiManager::RenderOSD();
g_host_display->EndPresent();
ImGuiManager::NewFrame();
}
void Host::ResizeHostDisplay(u32 new_window_width, u32 new_window_height, float new_window_scale)
{
}
void Host::UpdateHostDisplay()
{
}
void Host::RequestResizeHostDisplay(s32 width, s32 height)
@@ -425,7 +371,6 @@ SysMtgsThread& GetMTGS()
// Interface Stuff
//////////////////////////////////////////////////////////////////////////
const IConsoleWriter* PatchesCon = &Console;
BEGIN_HOTKEY_LIST(g_host_hotkeys)
END_HOTKEY_LIST()
@@ -461,7 +406,7 @@ void GSRunner::InitializeConsole()
const char* var = std::getenv("PCSX2_NOCONSOLE");
s_no_console = (var && StringUtil::FromChars<bool>(var).value_or(false));
if (!s_no_console)
CommonHost::InitializeEarlyConsole();
LogSink::InitializeEarlyConsole();
}
bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params)
@@ -587,7 +532,7 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
{
// disable timestamps, since we want to be able to diff the logs
Console.WriteLn("Logging to %s...", logfile);
CommonHost::SetFileLogPath(logfile);
LogSink::SetFileLogPath(logfile);
s_settings_interface.SetBoolValue("Logging", "EnableFileLogging", true);
s_settings_interface.SetBoolValue("Logging", "EnableTimestamps", false);
}
@@ -673,12 +618,8 @@ int main(int argc, char* argv[])
if (!GSRunner::ParseCommandLineArgs(argc, argv, params))
return EXIT_FAILURE;
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle::GetForCallingThread());
if (!VMManager::Internal::InitializeGlobals() || !VMManager::Internal::InitializeMemory())
{
Console.Error("Failed to allocate globals/memory.");
if (!VMManager::Internal::CPUThreadInitialize())
return EXIT_FAILURE;
}
if (s_use_window.value_or(true) && !GSRunner::CreatePlatformWindow())
{
@@ -700,16 +641,14 @@ int main(int argc, char* argv[])
VMManager::Shutdown(false);
}
InputManager::CloseSources();
VMManager::Internal::ReleaseMemory();
VMManager::Internal::ReleaseGlobals();
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
VMManager::Internal::CPUThreadShutdown();
GSRunner::DestroyPlatformWindow();
LogSink::CloseFileLog();
return EXIT_SUCCESS;
}
void Host::CPUThreadVSync()
void Host::VSyncOnCPUThread()
{
// update GS thread copy of frame number
GetMTGS().RunOnGSThread([frame_number = GSDumpReplayer::GetFrameNumber()]() { s_dump_frame_number = frame_number; });
+8 -64
View File
@@ -21,7 +21,7 @@
<ImportGroup Label="PropertySheets">
<Import Project="$(SolutionDir)common\vsprops\common.props" />
<Import Project="$(SolutionDir)common\vsprops\BaseProperties.props" />
<Import Project="$(SolutionDir)common\vsprops\3rdpartyDeps.props" />
<Import Project="$(SolutionDir)common\vsprops\GenerateSCMVersion.props" />
<Import Condition="$(Configuration.Contains(Debug))" Project="$(SolutionDir)common\vsprops\CodeGen_Debug.props" />
<Import Condition="$(Configuration.Contains(Devel))" Project="$(SolutionDir)common\vsprops\CodeGen_Devel.props" />
<Import Condition="$(Configuration.Contains(Release))" Project="$(SolutionDir)common\vsprops\CodeGen_Release.props" />
@@ -34,84 +34,28 @@
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\xbyak;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\freetype\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\xz\xz\src\liblzma\api;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\zlib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\libpng;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\glad\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\simpleini\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src\c4\ext\fast_float\include;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)pcsx2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<!-- Needed for moc pch -->
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(ProjectDir)\Settings;$(ProjectDir)\GameList</AdditionalIncludeDirectories>
<ExceptionHandling>Async</ExceptionHandling>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\fmt\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src\c4\ext\fast_float\include;</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\simpleini\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)pcsx2</AdditionalIncludeDirectories>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;LZMA_API_STATIC;BUILD_DX=1;ENABLE_RAINTEGRATION;ENABLE_ACHIEVEMENTS;ENABLE_DISCORD_PRESENCE;ENABLE_OPENGL;ENABLE_VULKAN;DIRECTINPUT_VERSION=0x0800;PCSX2_CORE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Debug))">PCSX2_DEBUG;PCSX2_DEVBUILD;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Devel))">PCSX2_DEVEL;PCSX2_DEVBUILD;NDEBUG;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(Release))">NDEBUG;_SECURE_SCL_=0;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="!$(Configuration.Contains(AVX2))">_M_SSE=0x401;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="$(Configuration.Contains(AVX2))">_M_SSE=0x501;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnableEnhancedInstructionSet Condition="!$(Configuration.Contains(AVX2)) Or $(Configuration.Contains(Clang))">NotSet</EnableEnhancedInstructionSet>
<EnableEnhancedInstructionSet Condition="$(Configuration.Contains(AVX2)) And !$(Configuration.Contains(Clang))">AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<AdditionalOptions Condition="$(Configuration.Contains(Clang)) And !$(Configuration.Contains(AVX2))"> -march=nehalem %(AdditionalOptions)</AdditionalOptions>
<AdditionalOptions Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(AVX2))"> -march=haswell %(AdditionalOptions)</AdditionalOptions>
<MinimalRebuild>false</MinimalRebuild>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
<!-- SH 2/3 flashlight, explicitly set here don't change -->
<!-- https://github.com/PCSX2/pcsx2/commit/16431653e4d92fda4069031897e24fbe4688d36a -->
<FloatingPointModel>Precise</FloatingPointModel>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zc:__cplusplus /Zo /utf-8%(AdditionalOptions)</AdditionalOptions>
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;LZMA_API_STATIC;ENABLE_RAINTEGRATION;ENABLE_ACHIEVEMENTS;ENABLE_DISCORD_PRESENCE;ENABLE_OPENGL;ENABLE_VULKAN;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<LargeAddressAware>Yes</LargeAddressAware>
<AdditionalDependencies>comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;rpcrt4.lib;iphlpapi.lib;dsound.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>dxguid.lib;dinput8.lib;hid.lib;PowrProf.lib;d3dcompiler.lib;d3d11.lib;dxgi.lib;strmiids.lib;opengl32.lib;comsuppw.lib;OneCore.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)3rdparty\fmt\fmt.vcxproj">
<Project>{449ad25e-424a-4714-babc-68706cdcc33b}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\libjpeg\libjpeg.vcxproj">
<Project>{bc236261-77e8-4567-8d09-45cd02965eb6}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\libpng\projects\vstudio\libpng\libpng.vcxproj">
<Project>{d6973076-9317-4ef2-a0b8-b7a18ac0713e}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\soundtouch\SoundTouch.vcxproj">
<Project>{e9b51944-7e6d-4bcd-83f2-7bbd5a46182d}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\xz\liblzma.vcxproj">
<Project>{12728250-16ec-4dc6-94d7-e21dd88947f8}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\libchdr\libchdr.vcxproj">
<Project>{a0d2b3ad-1f72-4ee3-8b5c-f2c358da35f0}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\zlib\zlib.vcxproj">
<Project>{2f6c0388-20cb-4242-9f6c-a6ebb6a83f47}</Project>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\jpgd\jpgd.vcxproj">
<Project>{ed2f21fd-0a36-4a8f-9b90-e7d92a2acb63}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\imgui\imgui.vcxproj">
<Project>{88fb34ec-845e-4f21-a552-f1573b9ed167}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)common\common.vcxproj">
<Project>{4639972e-424e-4e13-8b07-ca403c481346}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)pcsx2\pcsx2core.vcxproj">
<ProjectReference Include="$(SolutionDir)pcsx2\pcsx2.vcxproj">
<Project>{6c7986c4-3e4d-4dcc-b3c6-6bb12b238995}</Project>
</ProjectReference>
<ProjectReference Include="$(SolutionDir)3rdparty\glad\glad.vcxproj">
<Project>{c0293b32-5acf-40f0-aa6c-e6da6f3bf33a}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Main.cpp" />
+9 -10
View File
@@ -7,20 +7,19 @@ import multiprocessing
from pathlib import Path
from functools import partial
def is_gs_path(path):
ppath = Path(path)
for extension in [[".gs"], [".gs", ".xz"], [".gs", ".zst"]]:
if ppath.suffixes == extension:
return True
def get_gs_name(path):
lpath = path.lower()
return False
for extension in [".gs", ".gs.xz", ".gs.zst"]:
if lpath.endswith(extension):
return os.path.basename(path)[:-len(extension)]
return None
def run_regression_test(runner, dumpdir, renderer, upscale, renderhacks, parallel, gspath):
args = [runner]
gsname = Path(gspath).name
while gsname.rfind('.') >= 0:
gsname = gsname[:gsname.rfind('.')]
gsname = get_gs_name(gspath)
real_dumpdir = os.path.join(dumpdir, gsname).strip()
if not os.path.exists(real_dumpdir):
@@ -62,7 +61,7 @@ def run_regression_test(runner, dumpdir, renderer, upscale, renderhacks, paralle
def run_regression_tests(runner, gsdir, dumpdir, renderer, upscale, renderhacks, parallel=1):
paths = glob.glob(gsdir + "/*.*", recursive=True)
gamepaths = list(filter(is_gs_path, paths))
gamepaths = list(filter(lambda x: get_gs_name(x) is not None, paths))
if not os.path.isdir(dumpdir):
os.mkdir(dumpdir)
+2 -2
View File
@@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2022 PCSX2 Dev Team
* Copyright (C) 2002-2023 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
@@ -20,7 +20,7 @@
#include "QtHost.h"
#include "QtUtils.h"
#include "pcsx2/HostSettings.h"
#include "pcsx2/Host.h"
#include "pcsx2/SysForwardDefs.h"
#include "svnrev.h"
+10 -1
View File
@@ -24,6 +24,8 @@ target_sources(pcsx2-qt PRIVATE
MainWindow.ui
PrecompiledHeader.cpp
PrecompiledHeader.h
SettingWidgetBinder.h
Themes.cpp
QtHost.cpp
QtHost.h
QtKeyCodes.cpp
@@ -31,7 +33,6 @@ target_sources(pcsx2-qt PRIVATE
QtProgressCallback.h
QtUtils.cpp
QtUtils.h
SettingWidgetBinder.h
GameList/EmptyGameListWidget.ui
GameList/GameListModel.cpp
GameList/GameListModel.h
@@ -75,12 +76,19 @@ target_sources(pcsx2-qt PRIVATE
Settings/FolderSettingsWidget.cpp
Settings/FolderSettingsWidget.h
Settings/FolderSettingsWidget.ui
Settings/GameCheatSettingsWidget.cpp
Settings/GameCheatSettingsWidget.h
Settings/GameCheatSettingsWidget.ui
Settings/GameFixSettingsWidget.cpp
Settings/GameFixSettingsWidget.h
Settings/GameFixSettingsWidget.ui
Settings/GameListSettingsWidget.cpp
Settings/GameListSettingsWidget.h
Settings/GameListSettingsWidget.ui
Settings/GamePatchDetailsWidget.ui
Settings/GamePatchSettingsWidget.cpp
Settings/GamePatchSettingsWidget.h
Settings/GamePatchSettingsWidget.ui
Settings/GameSummaryWidget.cpp
Settings/GameSummaryWidget.h
Settings/GameSummaryWidget.ui
@@ -115,6 +123,7 @@ target_sources(pcsx2-qt PRIVATE
Settings/DEV9UiCommon.h
Settings/HddCreateQt.cpp
Settings/HddCreateQt.h
Settings/PatchDetailsWidget.ui
Settings/SettingsDialog.cpp
Settings/SettingsDialog.h
Settings/SettingsDialog.ui

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