Compare commits

...

22 Commits

Author SHA1 Message Date
Fabian Thomys
e971a9ebf5 Qt: Implement option for organizing screenshots in folders by game name 2025-07-24 18:10:11 +02:00
TheTechnician27
19f85713ce Settings: Transfer regional frame rate to advanced Graphics settings 2025-07-24 18:09:12 +02:00
Slayer0fRA
4c41de6013 Debugger: Disable filter search button while filter search is active 2025-07-23 22:53:16 -04:00
Slayer0fRA
96f9cde1bc Debugger: Disable filter search button while filter search is active 2025-07-23 22:53:16 -04:00
PCSX2 Bot
3feef0824c [ci skip] PAD: Update to latest controller database. 2025-07-23 03:07:03 +02:00
lightningterror
5f2ab55c93 GS/GL/MTL: Misc fixes.
MTL: Add missing shader case for RGB5A1_TO_8I.
GL: Comment out vendor Nvidia.

Fixes warnings.
2025-07-20 22:41:41 +02:00
GovanifY
0f75bfe17d Revert "GitHub: Add types to issue templates"
This reverts commit 7faa132622.
2025-07-20 12:46:38 +02:00
Berylskid
7faa132622 GitHub: Add types to issue templates 2025-07-19 15:28:51 -04:00
Ziemas
b69e6da105 Debugger: add 3 operand mult to assembler 2025-07-19 15:28:31 -04:00
JordanTheToaster
11edb128e9 GameDB: Kamen Rider Kabuto fixes 2025-07-19 20:25:57 +02:00
TJnotJT
fc4407aaef GS: Add secondary vertex buffer for copy/modifying vertices.
Currently only used in HW renderer to fix vertices for provoking-first-vertex APIs.
2025-07-19 02:39:01 +02:00
TJnotJT
2a418e3282 GS/HW: Handle first vertex provoking APIs in GSRendererHW.cpp. 2025-07-19 02:39:01 +02:00
TJnotJT
59415542ff GS: Remove all usage of provoking first/flat swapped in early pipeline.
Removes said usage from GSState and GSVertexTrace (and helper classes). The end goal is to support first-vertex-provoking APIs in GSRendererHW instead of early in the pipeline.
2025-07-19 02:39:01 +02:00
Jordan
00416e26bb GameDB: Various fixes (#13041)
Various fixes for incorrect names and missing fixes ect in Minority Report Gran Turismo 2000 Trial and fixing the name of Shaun White Snowboarding which was incorrectly labelled Rock Band 2 for some reason.
2025-07-19 00:26:29 +02:00
JordanTheToaster
e936398e17 Deps: Update SDL3 to v3.2.18 2025-07-17 12:24:12 +02:00
PCSX2 Bot
e3b45c3efd [ci skip] Qt: Update Base Translation. 2025-07-17 02:02:52 +02:00
JordanTheToaster
7ad759007a ImGuiOverlays: Internal FPS stat regression fix 2025-07-17 02:00:37 +02:00
refractionpcsx2
2fab554360 GS: Check tex rect of draw on overlap check if draw is single page wide. 2025-07-16 14:08:30 +02:00
refractionpcsx2
e98b6e6cb3 GameDB: Add Sand Grain Games CRC to known affected games 2025-07-16 14:08:30 +02:00
refractionpcsx2
aa5147a52b GS/HW: Add CRC for Sand Grain Games palette shuffle effect. 2025-07-16 14:08:30 +02:00
lightningterror
83ebbe95c5 GS/TC: Don't split/resize buffer when texture buffer width is 0.
Textures wrap within a single page.
2025-07-16 09:49:04 +02:00
Ziemas
2ad71d046b Debugger: Fix copying out of sorted thread view 2025-07-16 09:47:09 +02:00
42 changed files with 914 additions and 554 deletions

View File

@@ -18,7 +18,7 @@ LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
LIBJPEGTURBO=3.1.1
LIBPNG=1.6.50
LIBWEBP=1.5.0
SDL=SDL3-3.2.16
SDL=SDL3-3.2.18
QT=6.9.1
LZ4=1.10.0
ZSTD=1.5.7
@@ -39,7 +39,7 @@ fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.
aadc97ea91f6ef078b0ae3a62bba69e008d9a7db19b34e4ac973b19b71b4217c libjpeg-turbo-$LIBJPEGTURBO.tar.gz
4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 libpng-$LIBPNG.tar.xz
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
6340e58879b2d15830c8460d2f589a385c444d1faa2a4828a9626c7322562be8 $SDL.tar.gz
1a775bde924397a8e0c08bfda198926c17be859d0288ad0dec1dea1b2ee04f8f $SDL.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
40caedbf83cc9a1959610830563565889878bc95f115868bbf545d1914acf28e qtbase-everywhere-src-$QT.tar.xz

View File

@@ -14,8 +14,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL3-3.2.16.tar.gz",
"sha256": "6340e58879b2d15830c8460d2f589a385c444d1faa2a4828a9626c7322562be8"
"url": "https://libsdl.org/release/SDL3-3.2.18.tar.gz",
"sha256": "1a775bde924397a8e0c08bfda198926c17be859d0288ad0dec1dea1b2ee04f8f"
}
],
"cleanup": [

View File

@@ -40,7 +40,7 @@ fi
FREETYPE=2.13.3
HARFBUZZ=11.2.0
SDL=SDL3-3.2.16
SDL=SDL3-3.2.18
ZSTD=1.5.7
LZ4=1.10.0
LIBPNG=1.6.50
@@ -79,7 +79,7 @@ CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
16c0204704f3ebeed057aba100fe7db18d71035505cb10e595ea33d346457fc8 harfbuzz-$HARFBUZZ.tar.gz
6340e58879b2d15830c8460d2f589a385c444d1faa2a4828a9626c7322562be8 $SDL.tar.gz
1a775bde924397a8e0c08bfda198926c17be859d0288ad0dec1dea1b2ee04f8f $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 libpng-$LIBPNG.tar.xz

View File

@@ -22,7 +22,7 @@ fi
FREETYPE=2.13.3
HARFBUZZ=11.2.0
SDL=SDL3-3.2.16
SDL=SDL3-3.2.18
ZSTD=1.5.7
LZ4=1.10.0
LIBPNG=1.6.50
@@ -59,7 +59,7 @@ CMAKE_COMMON=(
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
16c0204704f3ebeed057aba100fe7db18d71035505cb10e595ea33d346457fc8 harfbuzz-$HARFBUZZ.tar.gz
6340e58879b2d15830c8460d2f589a385c444d1faa2a4828a9626c7322562be8 $SDL.tar.gz
1a775bde924397a8e0c08bfda198926c17be859d0288ad0dec1dea1b2ee04f8f $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 libpng-$LIBPNG.tar.xz

View File

@@ -46,7 +46,7 @@ set FREETYPE=2.13.3
set HARFBUZZ=11.2.0
set LIBJPEGTURBO=3.1.1
set LIBPNG=1650
set SDL=SDL3-3.2.16
set SDL=SDL3-3.2.18
set QT=6.9.1
set QTMINOR=6.9
set LZ4=1.10.0
@@ -68,7 +68,7 @@ call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuz
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1650.zip 4be6938313b08d5921f9dede13f2789b653c96f4f8595d92ff3f09c9320e51c7 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" aadc97ea91f6ef078b0ae3a62bba69e008d9a7db19b34e4ac973b19b71b4217c || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 0cc7430fb827c1f843e31b8b26ba7f083b1eeb8f6315a65d3744fd4d25b6c373 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 208028b3b6225b3c9eae3942e50ed243d8798b4b3a56b98a59b3f7e37baa55fd || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" efa6d8ef9f7ae0fd9f7d280fbff574d71882b60a357ae639e516dc173cf26986 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 8439d3394bc380fd17a920ee96df1d2272bf8d3490871d948ef750f95e0ded06 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" a8f90c768b54e28d61e02c1229b74a2b834e9852af523e5c70bcd2ae4c34a772 || goto error

View File

@@ -44,7 +44,7 @@ set FREETYPE=2.13.3
set HARFBUZZ=11.2.0
set LIBJPEGTURBO=3.1.1
set LIBPNG=1650
set SDL=SDL3-3.2.16
set SDL=SDL3-3.2.18
set QT=6.9.1
set QTMINOR=6.9
set LZ4=1.10.0
@@ -66,7 +66,7 @@ call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuz
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1650.zip 4be6938313b08d5921f9dede13f2789b653c96f4f8595d92ff3f09c9320e51c7 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" aadc97ea91f6ef078b0ae3a62bba69e008d9a7db19b34e4ac973b19b71b4217c || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 0cc7430fb827c1f843e31b8b26ba7f083b1eeb8f6315a65d3744fd4d25b6c373 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 208028b3b6225b3c9eae3942e50ed243d8798b4b3a56b98a59b3f7e37baa55fd || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" efa6d8ef9f7ae0fd9f7d280fbff574d71882b60a357ae639e516dc173cf26986 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 8439d3394bc380fd17a920ee96df1d2272bf8d3490871d948ef750f95e0ded06 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" a8f90c768b54e28d61e02c1229b74a2b834e9852af523e5c70bcd2ae4c34a772 || goto error

View File

@@ -193,6 +193,8 @@ PAPX-90203:
region: "NTSC-J"
gsHWFixes:
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
halfPixelOffset: 5 # Fixes edge bleed and lines.
autoFlush: 1 # Fixes missing lens flare and intensity.
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
PAPX-90204:
name: "TVDJ ~ティービィーディージェー~ [体験版]"
@@ -17028,9 +17030,10 @@ SLES-51230:
name: "Minority Report - Everybody Runs"
region: "PAL-E"
gsHWFixes:
gpuTargetCLUT: 1 # Fixes light bleed through objects.
gpuTargetCLUT: 2 # Fixes light bleed through objects.
halfPixelOffset: 1 # Fixes light bleed through objects.
autoFlush: 1 # Fixes light bloom intensity.
bilinearUpscale: 2 # Fixes jagged light bloom.
SLES-51232:
name: "Virtua Tennis 2"
region: "PAL-M4"
@@ -17298,16 +17301,18 @@ SLES-51317:
name: "Minority Report - Le Futur vous Rattrape"
region: "PAL-F"
gsHWFixes:
gpuTargetCLUT: 1 # Fixes light bleed through objects.
gpuTargetCLUT: 2 # Fixes light bleed through objects.
halfPixelOffset: 1 # Fixes light bleed through objects.
autoFlush: 1 # Fixes light bloom intensity.
bilinearUpscale: 2 # Fixes jagged light bloom.
SLES-51318:
name: "Minority Report - Everybody Runs"
region: "PAL-G"
gsHWFixes:
gpuTargetCLUT: 1 # Fixes light bleed through objects.
gpuTargetCLUT: 2 # Fixes light bleed through objects.
halfPixelOffset: 1 # Fixes light bleed through objects.
autoFlush: 1 # Fixes light bloom intensity.
bilinearUpscale: 2 # Fixes jagged light bloom.
SLES-51322:
name: "Robotech - Battlecry"
region: "PAL-M5"
@@ -22200,18 +22205,28 @@ SLES-53142:
SLES-53143:
name: "Fantastic 4"
region: "PAL-E"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53144:
name: "4 Fantastiques, Les"
region: "PAL-F"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53145:
name: "Fantastic 4"
region: "PAL-G"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53146:
name: "I Fantastici Quattro"
region: "PAL-I"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53147:
name: "4 Fantásticos, Los"
region: "PAL-S"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53148:
name: "Fruitfall"
region: "PAL-E"
@@ -22456,6 +22471,8 @@ SLES-53280:
SLES-53281:
name: "Fantastic 4"
region: "PAL-NL"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53282:
name: "Harvest Fishing"
region: "PAL-E"
@@ -24330,6 +24347,7 @@ SLES-53804:
nativeScaling: 1 # Fixes depth intensity.
textureInsideRT: 1 # Fixes depth blur.
estimateTextureRegion: 1 # Massively improves performance in certain situations.
getSkipCount: "GSC_SandGrainGames"
SLES-53805:
name: "Cocoto Funfair"
region: "PAL-M5"
@@ -26906,6 +26924,8 @@ SLES-54653:
SLES-54655:
name: "Cabela's African Safari"
region: "PAL-A"
gsHWFixes:
getSkipCount: "GSC_SandGrainGames"
SLES-54656:
name: "EyeToy - Bob the Builder"
region: "PAL-E"
@@ -28470,9 +28490,12 @@ SLES-55102:
halfPixelOffset: 5 # Fixes depth alignment.
nativeScaling: 1 # Fixes depth intensity.
textureInsideRT: 1 # Fixes depth blur.
getSkipCount: "GSC_SandGrainGames"
SLES-55103:
name: "Cabela's Big Game Hunter [2007]"
region: "PAL-E"
gsHWFixes:
getSkipCount: "GSC_SandGrainGames"
SLES-55104:
name: "UEFA Euro 2008 - Austria-Switzerland"
region: "PAL-E"
@@ -29492,7 +29515,7 @@ SLES-55451:
name: "Rock Band 2"
region: "PAL-M5"
SLES-55452:
name: "Rock Band 2"
name: "Shaun White Snowboarding"
region: "PAL-M5"
SLES-55453:
name: "SingStar - Queen"
@@ -35018,6 +35041,9 @@ SLPM-60279:
name-en: "Kamen Rider Kabuto [Trial]"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 5 # Fixes post-processing alignment.
nativeScaling: 1 # Fixes post-processing alignment.
textureInsideRT: 1 # Fixes garbage and missing effects.
autoFlush: 1 # Fixes garbage corruptions on the bottom of the screen.
SLPM-60280:
name: "電撃PS2 PlayStation 2 SAVE DATA COLLECTION 2007"
@@ -37280,6 +37306,8 @@ SLPM-62286:
name-sort: "もんすたーばす"
name-en: "Monster Bass"
region: "NTSC-J"
gsHWFixes:
getSkipCount: "GSC_SandGrainGames"
SLPM-62287:
name: "ファイヤープロレスリングZ 闘辞苑 同梱BOX"
name-sort: "ふぁいやーぷろれすりんぐZ とうじえん どうこんBOX"
@@ -55659,6 +55687,9 @@ SLPS-20483:
name-en: "Kamen Rider Kabuto"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 5 # Fixes post-processing alignment.
nativeScaling: 1 # Fixes post-processing alignment.
textureInsideRT: 1 # Fixes garbage and missing effects.
autoFlush: 1 # Fixes garbage corruptions on the bottom of the screen.
SLPS-20484:
name: "SIMPLE2000シリーズ Ultimate Vol.34 魁!!男塾"
@@ -64130,9 +64161,10 @@ SLUS-20331:
region: "NTSC-U"
compat: 5
gsHWFixes:
gpuTargetCLUT: 1 # Fixes light bleed through objects.
gpuTargetCLUT: 2 # Fixes light bleed through objects.
halfPixelOffset: 1 # Fixes light bleed through objects.
autoFlush: 1 # Fixes light bloom intensity.
bilinearUpscale: 2 # Fixes jagged light bloom.
SLUS-20332:
name: "NCAA March Madness 2002"
region: "NTSC-U"
@@ -65645,6 +65677,8 @@ SLUS-20615:
name: "Fantastic 4"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLUS-20616:
name: "Virtua Fighter 4 - Evolution"
region: "NTSC-U"
@@ -69749,6 +69783,7 @@ SLUS-21289:
nativeScaling: 1 # Fixes depth intensity.
textureInsideRT: 1 # Fixes depth blur.
estimateTextureRegion: 1 # Massively improves performance in certain situations.
getSkipCount: "GSC_SandGrainGames"
SLUS-21290:
name: "Ford Street Racing"
region: "NTSC-U"
@@ -70376,6 +70411,8 @@ SLUS-21379:
name: "Cabela's African Safari"
region: "NTSC-U"
compat: 5
gsHWFixes:
getSkipCount: "GSC_SandGrainGames"
SLUS-21380:
name: "Snoopy vs. the Red Baron"
region: "NTSC-U"
@@ -71734,10 +71771,14 @@ SLUS-21624:
name: "Cabela's Trophy Bucks"
region: "NTSC-U"
compat: 5
gsHWFixes:
getSkipCount: "GSC_SandGrainGames"
SLUS-21625:
name: "Cabela's Big Game Hunter [2007]"
region: "NTSC-U"
compat: 5
gsHWFixes:
getSkipCount: "GSC_SandGrainGames"
SLUS-21626:
name: "Stuntman - Ignition"
region: "NTSC-U"
@@ -72217,6 +72258,7 @@ SLUS-21712:
halfPixelOffset: 5 # Fixes depth alignment.
nativeScaling: 1 # Fixes depth intensity.
textureInsideRT: 1 # Fixes depth blur.
getSkipCount: "GSC_SandGrainGames"
SLUS-21713:
name: "Winter Sports 2008 - The Ultimate Challenge"
region: "NTSC-U"
@@ -72234,6 +72276,8 @@ SLUS-21715:
name: "Cabela's Monster Bass"
region: "NTSC-U"
compat: 5
gsHWFixes:
getSkipCount: "GSC_SandGrainGames"
SLUS-21716:
name: "The Spiderwick Chronicles"
name-sort: "Spiderwick Chronicles, The"
@@ -72677,6 +72721,8 @@ SLUS-21789:
name: "Cabela's Legendary Adventures"
region: "NTSC-U"
compat: 5
gsHWFixes:
getSkipCount: "GSC_SandGrainGames"
SLUS-21790:
name: "DreamWorks Shrek's Carnival Craze - Party Games"
region: "NTSC-U"

View File

@@ -262,6 +262,8 @@
030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
03000000ac0500006b05000000000000,GT2a,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000008a2e0000dd10000000000000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Windows,
030000008a2e0000df10000000000000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Windows,
030000000d0f00004900000000000000,Hatsune Miku Sho PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,
030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -1130,6 +1132,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,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:Mac OS X,
030000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -1329,6 +1332,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,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,
03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000008a2e0000dd10000011010000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Linux,
030000008a2e0000df10000011010000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Linux,
06000000adde0000efbe000002010000,Hidromancer 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,
03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,
03000000c9110000f055000011010000,HJC 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,
@@ -1793,10 +1798,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000ea02000015050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000ea02000017050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000ea02000016050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000ea02000017050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000007050000,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,
@@ -1822,8 +1827,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000130b000022050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
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,
050000005e040000200b000017050000,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,
050000005e040000220b000017050000,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,
050000005e040000200b000023050000,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,
050000005e040000220b000017050000,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,
03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,

View File

@@ -1301,9 +1301,7 @@ VS_OUTPUT vs_main_expand(uint vid : SV_VertexID)
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;
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));

View File

@@ -174,11 +174,7 @@ void main()
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
uint vid_other = is_bottom ? vid_base + 1 : vid_base - 1;
#endif
vtx = load_vertex(vid_base);
ProcessedVertex other = load_vertex(vid_other);

View File

@@ -599,6 +599,7 @@ void MemorySearchView::onSearchButtonClicked()
connect(workerWatcher, &QFutureWatcher<std::vector<u32>>::finished, onSearchFinished);
m_ui.btnSearch->setDisabled(true);
m_ui.btnFilterSearch->setDisabled(true);
if (!isFilterSearch)
{
m_searchResults.clear();

View File

@@ -58,7 +58,8 @@ void ThreadView::openContextMenu(QPoint pos)
if (!selection_model->hasSelection())
return;
QGuiApplication::clipboard()->setText(m_model->data(selection_model->currentIndex()).toString());
auto real_index = m_proxy_model->mapToSource(selection_model->currentIndex());
QGuiApplication::clipboard()->setText(m_model->data(real_index).toString());
});
menu->addSeparator();

View File

@@ -34,10 +34,12 @@
#include "pcsx2/Recording/InputRecording.h"
#include "pcsx2/Recording/InputRecordingControls.h"
#include "pcsx2/SIO/Sio.h"
#include "pcsx2/GS/GSExtra.h"
#include "common/Assertions.h"
#include "common/CocoaTools.h"
#include "common/FileSystem.h"
#include "common/Path.h"
#include <QtCore/QDateTime>
#include <QtCore/QDir>
@@ -1454,6 +1456,8 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
connect(menu.addAction(tr("Check Wiki Page")), &QAction::triggered, [this, entry]() { goToWikiPage(entry); });
}
action = menu.addAction(tr("Open Screenshots Folder"));
connect(action, &QAction::triggered, [this, entry]() { openScreenshotsFolderForGame(entry); });
menu.addSeparator();
if (!s_vm_valid)
@@ -2905,6 +2909,39 @@ void MainWindow::goToWikiPage(const GameList::Entry* entry)
QtUtils::OpenURL(this, fmt::format("https://wiki.pcsx2.net/{}", entry->serial).c_str());
}
void MainWindow::openScreenshotsFolderForGame(const GameList::Entry* entry)
{
if (!entry || entry->title.empty())
return;
// if disabled open the snapshots folder
if (!EmuConfig.GS.OrganizeScreenshotsByGame)
{
QtUtils::OpenURL(this, QUrl::fromLocalFile(QString::fromStdString(EmuFolders::Snapshots)));
return;
}
std::string game_name = entry->title;
Path::SanitizeFileName(&game_name);
if (game_name.length() > 219)
{
game_name.resize(219);
}
const std::string game_dir = Path::Combine(EmuFolders::Snapshots, game_name);
if (!FileSystem::DirectoryExists(game_dir.c_str()))
{
if (!FileSystem::CreateDirectoryPath(game_dir.c_str(), false))
{
QMessageBox::critical(this, tr("Error"), tr("Failed to create screenshots directory '%1'.").arg(QString::fromStdString(game_dir)));
return;
}
}
const QFileInfo fi(QString::fromStdString(game_dir));
QtUtils::OpenURL(this, QUrl::fromLocalFile(fi.absoluteFilePath()));
}
std::optional<bool> MainWindow::promptForResumeState(const QString& save_state_path)
{
if (save_state_path.isEmpty())

View File

@@ -274,6 +274,7 @@ private:
void setGameListEntryCoverImage(const GameList::Entry* entry);
void clearGameListEntryPlayTime(const GameList::Entry* entry);
void goToWikiPage(const GameList::Entry* entry);
void openScreenshotsFolderForGame(const GameList::Entry* entry);
std::optional<bool> promptForResumeState(const QString& save_state_path);
void loadSaveStateSlot(s32 slot, bool load_backup = false);

View File

@@ -1054,8 +1054,14 @@ void EmuThread::updatePerformanceMetrics(bool force)
if (gfps != m_last_game_fps || force)
{
QString text;
if (gfps == 0)
text = tr("FPS: N/A");
else
text = tr("FPS: %1").arg(gfps, 0, 'f', 0);
QMetaObject::invokeMethod(g_main_window->getStatusFPSWidget(), "setText", Qt::QueuedConnection,
Q_ARG(const QString&, tr("FPS: %1").arg(gfps, 0, 'f', 0)));
Q_ARG(const QString&, text));
m_last_game_fps = gfps;
}

View File

@@ -53,9 +53,6 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gameFixes, "EmuCore", "EnableGameFixes", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.patches, "EmuCore", "EnablePatches", true);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.ntscFrameRate, "EmuCore/GS", "FramerateNTSC", 59.94f);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.palFrameRate, "EmuCore/GS", "FrameratePAL", 50.00f);
dialog->registerWidgetHelp(m_ui.savestateSelector, tr("Use Save State Selector"), tr("Checked"),
tr("Show a save state selector UI when switching slots instead of showing a notification bubble."));

View File

@@ -508,61 +508,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="framerateControlSettings">
<property name="title">
<string>Frame Rate Control</string>
</property>
<layout class="QGridLayout" name="framerateControlLayout">
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="palFrameRate">
<property name="suffix">
<string extracomment="hz=Hertz, as in the measuring unit. Shown after the corresponding number. Those languages who'd need to remove the space or do something in between should do so."> hz</string>
</property>
<property name="minimum">
<double>10.000000000000000</double>
</property>
<property name="maximum">
<double>300.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="ntscFrameRate">
<property name="suffix">
<string> hz</string>
</property>
<property name="minimum">
<double>10.000000000000000</double>
</property>
<property name="maximum">
<double>300.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="palLabel">
<property name="text">
<string>PAL Frame Rate:</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="ntscLabel">
<property name="text">
<string>NTSC Frame Rate:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="pineSettings">
<property name="title">

View File

@@ -2,8 +2,10 @@
// SPDX-License-Identifier: GPL-3.0+
#include <QtWidgets/QMessageBox>
#include <algorithm>
#include "FolderSettingsWidget.h"
#include "pcsx2/GS/GS.h"
#include "SettingWidgetBinder.h"
#include "SettingsWindow.h"
@@ -18,8 +20,14 @@ FolderSettingsWidget::FolderSettingsWidget(SettingsWindow* dialog, QWidget* pare
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.cheats, m_ui.cheatsBrowse, m_ui.cheatsOpen, m_ui.cheatsReset, "Folders", "Cheats", Path::Combine(EmuFolders::DataRoot, "cheats"));
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.covers, m_ui.coversBrowse, m_ui.coversOpen, m_ui.coversReset, "Folders", "Covers", Path::Combine(EmuFolders::DataRoot, "covers"));
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.snapshots, m_ui.snapshotsBrowse, m_ui.snapshotsOpen, m_ui.snapshotsReset, "Folders", "Snapshots", Path::Combine(EmuFolders::DataRoot, "snaps"));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.organizeScreenshotsByGame, "EmuCore/GS", "OrganizeScreenshotsByGame", false);
connect(m_ui.organizeScreenshotsByGame, &QCheckBox::checkStateChanged, this, [](int state) {
GSConfig.OrganizeScreenshotsByGame = (state == Qt::Checked);
});
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.saveStates, m_ui.saveStatesBrowse, m_ui.saveStatesOpen, m_ui.saveStatesReset, "Folders", "SaveStates", Path::Combine(EmuFolders::DataRoot, "sstates"));
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.videoDumpingDirectory, m_ui.videoDumpingDirectoryBrowse, m_ui.videoDumpingDirectoryOpen, m_ui.videoDumpingDirectoryReset, "Folders", "Videos", Path::Combine(EmuFolders::DataRoot, "videos"));
dialog->registerWidgetHelp(m_ui.organizeScreenshotsByGame, tr("Organize Screenshots by Game"), tr("Unchecked"),
tr("When enabled, screenshots will be saved in a folder with the game's name, instead of all being saved in the Snapshots folder"));
}
FolderSettingsWidget::~FolderSettingsWidget() = default;

View File

@@ -175,12 +175,19 @@
</item>
<item row="0" column="0" colspan="4">
<widget class="QLabel" name="snaphotsLabel">
<property name="text">
<string>Used for screenshots and saving GS dumps.</string>
</property>
</widget>
</item>
</layout>
<property name="text">
<string>Used for screenshots and saving GS dumps.</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QCheckBox" name="organizeScreenshotsByGame">
<property name="text">
<string>Save Screenshots in Game-Specific Folders</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">

View File

@@ -130,7 +130,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowHardwareInfo, "EmuCore/GS", "OsdShowHardwareInfo", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowVideoCapture, "EmuCore/GS", "OsdShowVideoCapture", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowInputRec, "EmuCore/GS", "OsdShowInputRec", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdWarnAboutUnsafeSettings, "EmuCore", "osdWarnAboutUnsafeSettings", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdWarnAboutUnsafeSettings, "EmuCore", "OsdWarnAboutUnsafeSettings", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fxaa, "EmuCore/GS", "fxaa", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.shadeBoost, "EmuCore/GS", "ShadeBoost", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.shadeBoostBrightness, "EmuCore/GS", "ShadeBoost_Brightness", false);
@@ -254,6 +254,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableVertexShaderExpand, "EmuCore/GS", "DisableVertexShaderExpand", false);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.gsDownloadMode, "EmuCore/GS", "HWDownloadMode", static_cast<int>(GSHardwareDownloadMode::Enabled));
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.ntscFrameRate, "EmuCore/GS", "FrameRateNTSC", 59.94f);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.palFrameRate, "EmuCore/GS", "FrameRatePAL", 50.00f);
//////////////////////////////////////////////////////////////////////////
// SW Settings
@@ -392,6 +394,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
m_ui.useBlitSwapChain = nullptr;
m_ui.disableMailboxPresentation = nullptr;
m_ui.extendedUpscales = nullptr;
m_ui.ntscFrameRate = nullptr;
m_ui.palFrameRate = nullptr;
m_ui.spinCPUDuringReadbacks = nullptr;
m_ui.spinGPUDuringReadbacks = nullptr;
m_ui.overrideTextureBarriers = nullptr;
@@ -857,6 +861,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
tr("Skips synchronizing with the GS thread and host GPU for GS downloads. "
"Can result in a large speed boost on slower systems, at the cost of many broken graphical effects. "
"If games are broken and you have this option enabled, please disable it first."));
dialog->registerWidgetHelp(m_ui.ntscFrameRate, tr("NTSC Frame Rate"), tr("59.94 Hz"),
tr("Determines what frame rate NTSC games run at."));
dialog->registerWidgetHelp(m_ui.palFrameRate, tr("PAL Frame Rate"), tr("50.00 Hz"),
tr("Determines what frame rate PAL games run at."));
}
}

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>720</width>
<height>588</height>
<width>722</width>
<height>626</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@@ -55,12 +55,12 @@
<item>
<widget class="QTabWidget" name="tabs">
<property name="currentIndex">
<number>0</number>
<number>9</number>
</property>
<property name="documentMode">
<bool>true</bool>
</property>
<widget class="QGroupBox" name="gameDisplayTab">
<widget class="QWidget" name="gameDisplayTab">
<attribute name="title">
<string>Display</string>
</attribute>
@@ -391,7 +391,7 @@
</item>
</layout>
</widget>
<widget class="QGroupBox" name="hardwareRenderingTab">
<widget class="QWidget" name="hardwareRenderingTab">
<attribute name="title">
<string>Rendering</string>
</attribute>
@@ -652,7 +652,7 @@
</item>
</layout>
</widget>
<widget class="QGroupBox" name="hardwareFixesTab">
<widget class="QWidget" name="hardwareFixesTab">
<attribute name="title">
<string>Hardware Fixes</string>
</attribute>
@@ -950,7 +950,7 @@
</item>
</layout>
</widget>
<widget class="QGroupBox" name="upscalingFixesTab">
<widget class="QWidget" name="upscalingFixesTab">
<attribute name="title">
<string>Upscaling Fixes</string>
</attribute>
@@ -1470,7 +1470,7 @@
</item>
</layout>
</widget>
<widget class="QGroupBox" name="osdTab">
<widget class="QWidget" name="osdTab">
<attribute name="title">
<string>OSD</string>
</attribute>
@@ -1837,7 +1837,7 @@
</item>
</layout>
</widget>
<widget class="QGroupBox" name="recordingTab">
<widget class="QWidget" name="recordingTab">
<attribute name="title">
<string>Media Capture</string>
</attribute>
@@ -2158,7 +2158,7 @@
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@@ -2170,248 +2170,394 @@
</item>
</layout>
</widget>
<widget class="QGroupBox" name="advancedTab">
<widget class="QWidget" name="advancedTab">
<attribute name="title">
<string extracomment="Advanced here refers to the advanced graphics options.">Advanced</string>
</attribute>
<layout class="QVBoxLayout" name="advancedTabLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="advancedOptions">
<property name="title">
<string>Advanced Options</string>
<widget class="QScrollArea" name="advancedScrollArea">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<layout class="QFormLayout" name="advancedOptionsFormLayout">
<item row="0" column="0">
<widget class="QLabel" name="hwDownloadModeLabel">
<property name="text">
<string>Hardware Download Mode:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="gsDownloadMode">
<item>
<property name="text">
<string>Accurate (Recommended)</string>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="advancedScrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>722</width>
<height>499</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>499</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="advancedOptions">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</item>
<item>
<property name="text">
<string>Disable Readbacks (Synchronize GS Thread)</string>
<property name="title">
<string>Advanced Options</string>
</property>
</item>
<item>
<property name="text">
<string>Unsynchronized (Non-Deterministic)</string>
<layout class="QFormLayout" name="advancedOptionsFormLayout">
<item row="0" column="0">
<widget class="QLabel" name="hwDownloadModeLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Hardware Download Mode:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="gsDownloadMode">
<item>
<property name="text">
<string>Accurate (Recommended)</string>
</property>
</item>
<item>
<property name="text">
<string>Disable Readbacks (Synchronize GS Thread)</string>
</property>
</item>
<item>
<property name="text">
<string>Unsynchronized (Non-Deterministic)</string>
</property>
</item>
<item>
<property name="text">
<string>Disabled (Ignore Transfers)</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="gsDumpCompressionLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>GS Dump Compression:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="gsDumpCompression">
<item>
<property name="text">
<string>Uncompressed</string>
</property>
</item>
<item>
<property name="text">
<string>LZMA (xz)</string>
</property>
</item>
<item>
<property name="text">
<string>Zstandard (zst)</string>
</property>
</item>
</widget>
</item>
<item row="10" column="0" colspan="2">
<layout class="QGridLayout" name="advancedLayout">
<item row="1" column="1">
<widget class="QCheckBox" name="extendedUpscales">
<property name="text">
<string>Extended Upscaling Multipliers</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="disableMailboxPresentation">
<property name="text">
<string extracomment="Mailbox Presentation: a type of graphics-rendering technique that has not been exposed to the public that often, so chances are you will need to keep the word mailbox in English. It does not have anything to do with postal mailboxes or email inboxes/outboxes.">Disable Mailbox Presentation</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="useBlitSwapChain">
<property name="text">
<string extracomment="Blit = a data operation. You might want to write it as-is, but fully uppercased. More information: https://en.wikipedia.org/wiki/Bit_blit \nSwap chain: see Microsoft's Terminology Portal.">Use Blit Swap Chain</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="spinCPUDuringReadbacks">
<property name="text">
<string>Spin CPU During Readbacks</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="spinGPUDuringReadbacks">
<property name="text">
<string>Spin GPU During Readbacks</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="QLabel" name="exclussiveFSLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Allow Exclusive Fullscreen:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="exclusiveFullscreenControl">
<item>
<property name="text">
<string>Automatic (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Disallowed</string>
</property>
</item>
<item>
<property name="text">
<string>Allowed</string>
</property>
</item>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="texturePreloading">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Partial</string>
</property>
</item>
<item>
<property name="text">
<string>Full (Hash Cache)</string>
</property>
</item>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Texture Preloading:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="frameRateOptions">
<property name="title">
<string>Frame Rate Options</string>
</property>
</item>
<item>
<property name="text">
<string>Disabled (Ignore Transfers)</string>
<layout class="QGridLayout" name="frameRateOptionsFormLayout">
<item row="0" column="0">
<widget class="QLabel" name="ntscLabel">
<property name="text">
<string>NTSC Frame Rate:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="ntscFrameRate">
<property name="suffix">
<string extracomment="Hz=Hertz, as in the measuring unit. Shown after the corresponding number. Those languages who'd need to remove the space or do something in between should do so."> Hz</string>
</property>
<property name="minimum">
<double>10.000000000000000</double>
</property>
<property name="maximum">
<double>300.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="palLabel">
<property name="text">
<string>PAL Frame Rate:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="palFrameRate">
<property name="suffix">
<string> Hz</string>
</property>
<property name="minimum">
<double>10.000000000000000</double>
</property>
<property name="maximum">
<double>300.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="debuggingOptions">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="gsDumpCompressionLabel">
<property name="text">
<string>GS Dump Compression:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="gsDumpCompression">
<item>
<property name="text">
<string>Uncompressed</string>
<property name="title">
<string>Debugging Options</string>
</property>
</item>
<item>
<property name="text">
<string>LZMA (xz)</string>
<layout class="QFormLayout" name="debuggingOptionsFormLayout">
<item row="0" column="0">
<widget class="QLabel" name="barriersLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Override Texture Barriers:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="overrideTextureBarriers">
<item>
<property name="text">
<string>Automatic (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Force Disabled</string>
</property>
</item>
<item>
<property name="text">
<string>Force Enabled</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QGridLayout" name="debuggingOptionsLayout">
<item row="0" column="1">
<widget class="QCheckBox" name="disableFramebufferFetch">
<property name="text">
<string>Disable Framebuffer Fetch</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="disableShaderCache">
<property name="text">
<string>Disable Shader Cache</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="disableVertexShaderExpand">
<property name="text">
<string>Disable Vertex Shader Expand</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="useDebugDevice">
<property name="text">
<string>Use Debug Device</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</item>
<item>
<property name="text">
<string>Zstandard (zst)</string>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</item>
</widget>
</item>
<item row="10" column="0" colspan="2">
<layout class="QGridLayout" name="advancedLayout">
<item row="1" column="1">
<widget class="QCheckBox" name="extendedUpscales">
<property name="text">
<string>Extended Upscaling Multipliers</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="disableMailboxPresentation">
<property name="text">
<string extracomment="Mailbox Presentation: a type of graphics-rendering technique that has not been exposed to the public that often, so chances are you will need to keep the word mailbox in English. It does not have anything to do with postal mailboxes or email inboxes/outboxes.">Disable Mailbox Presentation</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="useBlitSwapChain">
<property name="text">
<string extracomment="Blit = a data operation. You might want to write it as-is, but fully uppercased. More information: https://en.wikipedia.org/wiki/Bit_blit \nSwap chain: see Microsoft's Terminology Portal.">Use Blit Swap Chain</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="spinCPUDuringReadbacks">
<property name="text">
<string>Spin CPU During Readbacks</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="spinGPUDuringReadbacks">
<property name="text">
<string>Spin GPU During Readbacks</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<widget class="QLabel" name="exclussiveFSLabel">
<property name="text">
<string>Allow Exclusive Fullscreen:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="exclusiveFullscreenControl">
<item>
<property name="text">
<string>Automatic (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Disallowed</string>
</property>
</item>
<item>
<property name="text">
<string>Allowed</string>
</property>
</item>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="texturePreloading">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Partial</string>
</property>
</item>
<item>
<property name="text">
<string>Full (Hash Cache)</string>
</property>
</item>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Texture Preloading:</string>
</property>
</widget>
</item>
</layout>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="debuggingOptions">
<property name="title">
<string>Debugging Options</string>
</property>
<layout class="QFormLayout" name="debuggingOptionsFormLayout">
<item row="0" column="0">
<widget class="QLabel" name="barriersLabel">
<property name="text">
<string>Override Texture Barriers:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="overrideTextureBarriers">
<item>
<property name="text">
<string>Automatic (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Force Disabled</string>
</property>
</item>
<item>
<property name="text">
<string>Force Enabled</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QGridLayout" name="debuggingOptionsLayout">
<item row="0" column="1">
<widget class="QCheckBox" name="disableFramebufferFetch">
<property name="text">
<string>Disable Framebuffer Fetch</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="disableShaderCache">
<property name="text">
<string>Disable Shader Cache</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="disableVertexShaderExpand">
<property name="text">
<string>Disable Vertex Shader Expand</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="useDebugDevice">
<property name="text">
<string>Use Debug Device</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>

View File

@@ -5672,66 +5672,71 @@ Do you want to overwrite?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1058"/>
<location filename="../QtHost.cpp" line="1059"/>
<source>FPS: N/A</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1061"/>
<source>FPS: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1065"/>
<location filename="../QtHost.cpp" line="1071"/>
<source>VPS: %1 </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1071"/>
<location filename="../QtHost.cpp" line="1077"/>
<source>Speed: %1% </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1126"/>
<location filename="../QtHost.cpp" line="1132"/>
<source>Game: %1 (%2)
</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1134"/>
<location filename="../QtHost.cpp" line="1140"/>
<source>Rich presence inactive or unsupported.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1138"/>
<location filename="../QtHost.cpp" line="1144"/>
<source>Game not loaded or no RetroAchievements available.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1557"/>
<location filename="../QtHost.cpp" line="1577"/>
<location filename="../QtHost.cpp" line="1585"/>
<location filename="../QtHost.cpp" line="1619"/>
<location filename="../QtHost.cpp" line="1563"/>
<location filename="../QtHost.cpp" line="1583"/>
<location filename="../QtHost.cpp" line="1591"/>
<location filename="../QtHost.cpp" line="1625"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1557"/>
<location filename="../QtHost.cpp" line="1563"/>
<source>Failed to create HTTPDownloader.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1565"/>
<location filename="../QtHost.cpp" line="1571"/>
<source>Downloading %1...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1578"/>
<location filename="../QtHost.cpp" line="1584"/>
<source>Download failed with HTTP status code %1.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1586"/>
<location filename="../QtHost.cpp" line="1592"/>
<source>Download failed: Data is empty.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1620"/>
<location filename="../QtHost.cpp" line="1626"/>
<source>Failed to write &apos;%1&apos;.</source>
<translation type="unfinished"></translation>
</message>
@@ -15846,7 +15851,7 @@ Swap chain: see Microsoft&apos;s Terminology Portal.</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1279"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1277"/>
<source>Save slot {0} selected ({1}).</source>
<translation type="unfinished"></translation>
</message>
@@ -15854,63 +15859,63 @@ Swap chain: see Microsoft&apos;s Terminology Portal.</extracomment>
<context>
<name>ImGuiOverlays</name>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="825"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="823"/>
<source>{} Recording Input</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="829"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="827"/>
<source>{} Replaying</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="898"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="896"/>
<source>Saved at {0:%H:%M} on {0:%a} {0:%Y/%m/%d}.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="925"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="923"/>
<source>Save state selector is unavailable without a valid game serial.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1012"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1010"/>
<source>Load</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1014"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1012"/>
<source>Save</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1016"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1014"/>
<source>Select Previous</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1018"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1016"/>
<source>Select Next</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1020"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1018"/>
<source>Close Menu</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1073"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1095"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1071"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1093"/>
<source>Save Slot {0}</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1096"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1094"/>
<source>No save present in this slot.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1276"/>
<location filename="../../pcsx2/ImGui/ImGuiOverlays.cpp" line="1274"/>
<source>no save yet</source>
<translation type="unfinished"></translation>
</message>
@@ -19833,45 +19838,45 @@ Ejecting {3} and replacing it with {2}.</source>
<context>
<name>QtHost</name>
<message>
<location filename="../QtHost.cpp" line="1106"/>
<location filename="../QtHost.cpp" line="1112"/>
<source>RA: Logged in as %1 (%2 pts, softcore: %3 pts). %4 unread messages.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1527"/>
<location filename="../QtHost.cpp" line="1542"/>
<location filename="../QtHost.cpp" line="1533"/>
<location filename="../QtHost.cpp" line="1548"/>
<source>Error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1528"/>
<location filename="../QtHost.cpp" line="1534"/>
<source>An error occurred while deleting empty game settings:
{}</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1543"/>
<location filename="../QtHost.cpp" line="1549"/>
<source>An error occurred while saving game settings:
{}</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1703"/>
<location filename="../QtHost.cpp" line="1709"/>
<source>Controller {} connected.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1716"/>
<location filename="../QtHost.cpp" line="1722"/>
<source>System paused because controller {} was disconnected.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1729"/>
<location filename="../QtHost.cpp" line="1735"/>
<source>Controller {} disconnected.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../QtHost.cpp" line="1957"/>
<location filename="../QtHost.cpp" line="1963"/>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
@@ -21087,7 +21092,7 @@ Rename it to {} to remove this warning.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../Debugger/ThreadView.cpp" line="66"/>
<location filename="../Debugger/ThreadView.cpp" line="67"/>
<source>Copy all as CSV</source>
<translation type="unfinished"></translation>
</message>

View File

@@ -781,7 +781,8 @@ struct Pcsx2Config
EnableVideoCaptureParameters : 1,
VideoCaptureAutoResolution : 1,
EnableAudioCapture : 1,
EnableAudioCaptureParameters : 1;
EnableAudioCaptureParameters : 1,
OrganizeScreenshotsByGame : 1;
};
};

View File

@@ -205,8 +205,10 @@ const tMipsOpcode MipsOpcodes[] = {
{ "dsrav", "d,s", MIPS_SPECIAL(0x17), MA_MIPS3, MO_64BIT|MO_RDT },
{ "clo", "d,s", MIPS_SPECIAL(0x17), MA_PSP, 0 },
{ "mult", "s,t", MIPS_SPECIAL(0x18), MA_MIPS1, 0 },
{ "mult", "d,s,t", MIPS_SPECIAL(0x18), MA_PS2, 0 },
{ "mult", "r\x0,s,t", MIPS_SPECIAL(0x18), MA_MIPS1, 0 },
{ "multu", "s,t", MIPS_SPECIAL(0x19), MA_MIPS1, 0 },
{ "multu", "d,s,t", MIPS_SPECIAL(0x19), MA_PS2, 0 },
{ "multu", "r\x0,s,t", MIPS_SPECIAL(0x19), MA_MIPS1, 0 },
{ "div", "s,t", MIPS_SPECIAL(0x1A), MA_MIPS1, 0 },
{ "div", "r\x0,s,t", MIPS_SPECIAL(0x1A), MA_MIPS1, 0 },

View File

@@ -27,11 +27,6 @@ static __fi bool IsAutoFlushEnabled()
return GSIsHardwareRenderer() ? (GSConfig.UserHacks_AutoFlush != GSHWAutoFlushLevel::Disabled) : GSConfig.AutoFlushSW;
}
static __fi bool IsFirstProvokingVertex()
{
return (GSIsHardwareRenderer() && !g_gs_device->Features().provoking_vertex_last);
}
constexpr int GSState::GetSaveStateSize(int version)
{
int size = 0;
@@ -99,7 +94,7 @@ constexpr int GSState::GetSaveStateSize(int version)
}
GSState::GSState()
: m_vt(this, IsFirstProvokingVertex())
: m_vt(this)
{
// m_nativeres seems to be a hack. Unfortunately it impacts draw call number which make debug painful in the replayer.
// Let's keep it disabled to ease debug.
@@ -130,6 +125,8 @@ GSState::~GSState()
{
if (m_vertex.buff)
_aligned_free(m_vertex.buff);
if (m_vertex.buff_copy)
_aligned_free(m_vertex.buff_copy);
if (m_index.buff)
_aligned_free(m_index.buff);
if (m_draw_vertex.buff)
@@ -206,29 +203,29 @@ void GSState::Reset(bool hardware_reset)
memcpy(&m_prev_env, &m_env, sizeof(m_prev_env));
}
template<bool auto_flush, bool index_swap>
template<bool auto_flush>
void GSState::SetPrimHandlers()
{
#define SetHandlerXYZ(P, auto_flush, index_swap) \
m_fpGIFPackedRegHandlerXYZ[P][0] = &GSState::GIFPackedRegHandlerXYZF2<P, 0, auto_flush, index_swap>; \
m_fpGIFPackedRegHandlerXYZ[P][1] = &GSState::GIFPackedRegHandlerXYZF2<P, 1, auto_flush, index_swap>; \
m_fpGIFPackedRegHandlerXYZ[P][2] = &GSState::GIFPackedRegHandlerXYZ2<P, 0, auto_flush, index_swap>; \
m_fpGIFPackedRegHandlerXYZ[P][3] = &GSState::GIFPackedRegHandlerXYZ2<P, 1, auto_flush, index_swap>; \
m_fpGIFRegHandlerXYZ[P][0] = &GSState::GIFRegHandlerXYZF2<P, 0, auto_flush, index_swap>; \
m_fpGIFRegHandlerXYZ[P][1] = &GSState::GIFRegHandlerXYZF2<P, 1, auto_flush, index_swap>; \
m_fpGIFRegHandlerXYZ[P][2] = &GSState::GIFRegHandlerXYZ2<P, 0, auto_flush, index_swap>; \
m_fpGIFRegHandlerXYZ[P][3] = &GSState::GIFRegHandlerXYZ2<P, 1, auto_flush, index_swap>; \
m_fpGIFPackedRegHandlerSTQRGBAXYZF2[P] = &GSState::GIFPackedRegHandlerSTQRGBAXYZF2<P, auto_flush, index_swap>; \
m_fpGIFPackedRegHandlerSTQRGBAXYZ2[P] = &GSState::GIFPackedRegHandlerSTQRGBAXYZ2<P, auto_flush, index_swap>;
#define SetHandlerXYZ(P, auto_flush) \
m_fpGIFPackedRegHandlerXYZ[P][0] = &GSState::GIFPackedRegHandlerXYZF2<P, 0, auto_flush>; \
m_fpGIFPackedRegHandlerXYZ[P][1] = &GSState::GIFPackedRegHandlerXYZF2<P, 1, auto_flush>; \
m_fpGIFPackedRegHandlerXYZ[P][2] = &GSState::GIFPackedRegHandlerXYZ2<P, 0, auto_flush>; \
m_fpGIFPackedRegHandlerXYZ[P][3] = &GSState::GIFPackedRegHandlerXYZ2<P, 1, auto_flush>; \
m_fpGIFRegHandlerXYZ[P][0] = &GSState::GIFRegHandlerXYZF2<P, 0, auto_flush>; \
m_fpGIFRegHandlerXYZ[P][1] = &GSState::GIFRegHandlerXYZF2<P, 1, auto_flush>; \
m_fpGIFRegHandlerXYZ[P][2] = &GSState::GIFRegHandlerXYZ2<P, 0, auto_flush>; \
m_fpGIFRegHandlerXYZ[P][3] = &GSState::GIFRegHandlerXYZ2<P, 1, auto_flush>; \
m_fpGIFPackedRegHandlerSTQRGBAXYZF2[P] = &GSState::GIFPackedRegHandlerSTQRGBAXYZF2<P, auto_flush>; \
m_fpGIFPackedRegHandlerSTQRGBAXYZ2[P] = &GSState::GIFPackedRegHandlerSTQRGBAXYZ2<P, auto_flush>;
SetHandlerXYZ(GS_POINTLIST, true, false);
SetHandlerXYZ(GS_LINELIST, auto_flush, index_swap);
SetHandlerXYZ(GS_LINESTRIP, auto_flush, index_swap);
SetHandlerXYZ(GS_TRIANGLELIST, auto_flush, index_swap);
SetHandlerXYZ(GS_TRIANGLESTRIP, auto_flush, index_swap);
SetHandlerXYZ(GS_TRIANGLEFAN, auto_flush, index_swap);
SetHandlerXYZ(GS_SPRITE, auto_flush, false);
SetHandlerXYZ(GS_INVALID, auto_flush, false);
SetHandlerXYZ(GS_POINTLIST, true);
SetHandlerXYZ(GS_LINELIST, auto_flush);
SetHandlerXYZ(GS_LINESTRIP, auto_flush);
SetHandlerXYZ(GS_TRIANGLELIST, auto_flush);
SetHandlerXYZ(GS_TRIANGLESTRIP, auto_flush);
SetHandlerXYZ(GS_TRIANGLEFAN, auto_flush);
SetHandlerXYZ(GS_SPRITE, auto_flush);
SetHandlerXYZ(GS_INVALID, auto_flush);
#undef SetHandlerXYZ
}
@@ -249,11 +246,10 @@ void GSState::ResetHandlers()
m_fpGIFPackedRegHandlers[GIF_REG_A_D] = &GSState::GIFPackedRegHandlerA_D;
m_fpGIFPackedRegHandlers[GIF_REG_NOP] = &GSState::GIFPackedRegHandlerNOP;
// swap first/last indices when the provoking vertex is the first (D3D/Vulkan)
if (IsAutoFlushEnabled())
IsFirstProvokingVertex() ? SetPrimHandlers<true, true>() : SetPrimHandlers<true, false>();
SetPrimHandlers<true>();
else
IsFirstProvokingVertex() ? SetPrimHandlers<false, true>() : SetPrimHandlers<false, false>();
SetPrimHandlers<false>();
std::fill(std::begin(m_fpGIFRegHandlers), std::end(m_fpGIFRegHandlers), &GSState::GIFRegHandlerNull);
@@ -606,7 +602,7 @@ void GSState::GIFPackedRegHandlerUV_Hack(const GIFPackedReg* RESTRICT r)
m_isPackedUV_HackFlag = true;
}
template <u32 prim, u32 adc, bool auto_flush, bool index_swap>
template <u32 prim, u32 adc, bool auto_flush>
void GSState::GIFPackedRegHandlerXYZF2(const GIFPackedReg* RESTRICT r)
{
const bool skip = adc || r->XYZF2.Skip();
@@ -622,10 +618,10 @@ void GSState::GIFPackedRegHandlerXYZF2(const GIFPackedReg* RESTRICT r)
m_v.m[1] = xy.upl32(zf);
VertexKick<prim, auto_flush, index_swap>(skip);
VertexKick<prim, auto_flush>(skip);
}
template <u32 prim, u32 adc, bool auto_flush, bool index_swap>
template <u32 prim, u32 adc, bool auto_flush>
void GSState::GIFPackedRegHandlerXYZ2(const GIFPackedReg* RESTRICT r)
{
const bool skip = adc || r->XYZ2.Skip();
@@ -639,7 +635,7 @@ void GSState::GIFPackedRegHandlerXYZ2(const GIFPackedReg* RESTRICT r)
m_v.m[1] = xyz.upl64(GSVector4i::loadl(&m_v.UV));
VertexKick<prim, auto_flush, index_swap>(skip);
VertexKick<prim, auto_flush>(skip);
}
void GSState::GIFPackedRegHandlerFOG(const GIFPackedReg* RESTRICT r)
@@ -656,7 +652,7 @@ void GSState::GIFPackedRegHandlerNOP(const GIFPackedReg* RESTRICT r)
{
}
template <u32 prim, bool auto_flush, bool index_swap>
template <u32 prim, bool auto_flush>
void GSState::GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u32 size)
{
pxAssert(size > 0 && size % 3 == 0);
@@ -682,7 +678,7 @@ void GSState::GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u3
m_v.m[1] = xy.upl32(zf); // TODO: only store the last one
VertexKick<prim, auto_flush, index_swap>(r[2].XYZF2.Skip());
VertexKick<prim, auto_flush>(r[2].XYZF2.Skip());
r += 3;
}
@@ -690,7 +686,7 @@ void GSState::GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u3
m_q = r[-3].STQ.Q; // remember the last one, STQ outputs this to the temp Q each time
}
template <u32 prim, bool auto_flush, bool index_swap>
template <u32 prim, bool auto_flush>
void GSState::GIFPackedRegHandlerSTQRGBAXYZ2(const GIFPackedReg* RESTRICT r, u32 size)
{
pxAssert(size > 0 && size % 3 == 0);
@@ -715,7 +711,7 @@ void GSState::GIFPackedRegHandlerSTQRGBAXYZ2(const GIFPackedReg* RESTRICT r, u32
m_v.m[1] = xyz.upl64(GSVector4i::loadl(&m_v.UV)); // TODO: only store the last one
VertexKick<prim, auto_flush, index_swap>(r[2].XYZ2.Skip());
VertexKick<prim, auto_flush>(r[2].XYZ2.Skip());
r += 3;
}
@@ -749,7 +745,7 @@ __forceinline void GSState::ApplyPRIM(u32 prim)
UpdateVertexKick();
pxAssert(m_index.tail == 0 || !g_gs_device->Features().provoking_vertex_last || m_index.buff[m_index.tail - 1] + 1 == m_vertex.next);
pxAssert(m_index.tail == 0 || m_index.buff[m_index.tail - 1] + 1 == m_vertex.next);
if (m_index.tail == 0)
m_vertex.next = 0;
@@ -800,7 +796,7 @@ void GSState::GIFRegHandlerUV_Hack(const GIFReg* RESTRICT r)
m_isPackedUV_HackFlag = false;
}
template <u32 prim, u32 adc, bool auto_flush, bool index_swap>
template <u32 prim, u32 adc, bool auto_flush>
void GSState::GIFRegHandlerXYZF2(const GIFReg* RESTRICT r)
{
if (!adc || GSUtil::GetPrimClass(m_prev_env.PRIM.PRIM) != GSUtil::GetPrimClass(m_env.PRIM.PRIM) || (m_dirty_gs_regs & (1 << DIRTY_REG_XYOFFSET)))
@@ -812,10 +808,10 @@ void GSState::GIFRegHandlerXYZF2(const GIFReg* RESTRICT r)
m_v.m[1] = xyz.upl64(uvf);
VertexKick<prim, auto_flush, index_swap>(adc);
VertexKick<prim, auto_flush>(adc);
}
template <u32 prim, u32 adc, bool auto_flush, bool index_swap>
template <u32 prim, u32 adc, bool auto_flush>
void GSState::GIFRegHandlerXYZ2(const GIFReg* RESTRICT r)
{
if (!adc || GSUtil::GetPrimClass(m_prev_env.PRIM.PRIM) != GSUtil::GetPrimClass(m_env.PRIM.PRIM) || (m_dirty_gs_regs & (1 << DIRTY_REG_XYOFFSET)))
@@ -823,7 +819,7 @@ void GSState::GIFRegHandlerXYZ2(const GIFReg* RESTRICT r)
m_v.m[1] = GSVector4i::load(&r->XYZ, &m_v.UV);
VertexKick<prim, auto_flush, index_swap>(adc);
VertexKick<prim, auto_flush>(adc);
}
template <int i>
@@ -1858,7 +1854,7 @@ void GSState::CheckWriteOverlap(bool req_write, bool req_read)
const GSVector4i write_rect = GSVector4i(m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, m_env.TRXPOS.DSAX + w, m_env.TRXPOS.DSAY + h);
const u32 write_start_bp = GSLocalMemory::GetStartBlockAddress(blit.DBP, blit.DBW, blit.DPSM, write_rect);
const u32 write_end_bp = ((GSLocalMemory::GetEndBlockAddress(blit.DBP, blit.DBW, blit.DPSM, write_rect) + 1) + (GS_BLOCKS_PER_PAGE - 1)) & ~(GS_BLOCKS_PER_PAGE - 1);
const GSVector4i tex_rect = m_prev_env.PRIM.TME ? GetTEX0Rect() : GSVector4i::zero();
GSVector4i tex_rect = m_prev_env.PRIM.TME ? GetTEX0Rect() : GSVector4i::zero();
if (m_index.tail > 0)
{
@@ -1870,6 +1866,49 @@ void GSState::CheckWriteOverlap(bool req_write, bool req_read)
if (req_write && m_prev_env.PRIM.TME)
{
// Tex rect could be invalid showing 1024x1024 when it isn't. If the frame is only 1 page wide, it's either a big strip or a single page draw.
// This large texture causes misdetection of overlapping writes, causing our heuristics in the hardware renderer for future draws to be missing.
// Either way if we check the queued up coordinates, it should give us a fair idea. (Cabela's Trophy Bucks)
if (prev_ctx.FRAME.FBW == 1 && tex_rect.width() > (prev_ctx.TEX0.TBW * 64))
{
GSVector4i tex_draw_rect = GSVector4i::zero();
for (u32 i = 0; i < m_index.tail; i++)
{
const GSVertex* v = &m_vertex.buff[m_index.buff[i]];
GSVector2i tex_coord;
if (PRIM->FST)
{
tex_coord.x = v->U >> 4;
tex_coord.y = v->V >> 4;
}
else
{
const float s = std::min((v->ST.S / v->RGBAQ.Q), 1.0f);
const float t = std::min((v->ST.T / v->RGBAQ.Q), 1.0f);
tex_coord.x = static_cast<int>(std::round((1 << m_context->TEX0.TW) * s));
tex_coord.y = static_cast<int>(std::round((1 << m_context->TEX0.TH) * t));
}
if (i == 0)
{
tex_draw_rect.x = tex_coord.x;
tex_draw_rect.y = tex_coord.y;
tex_draw_rect.z = tex_coord.x;
tex_draw_rect.w = tex_coord.y;
continue;
}
tex_draw_rect.x = std::min(tex_draw_rect.x, tex_coord.x);
tex_draw_rect.z = std::max(tex_draw_rect.z, tex_coord.x);
tex_draw_rect.y = std::min(tex_draw_rect.y, tex_coord.y);
tex_draw_rect.w = std::max(tex_draw_rect.w, tex_coord.y);
}
tex_rect = tex_rect.rintersect(tex_draw_rect);
}
if (GSLocalMemory::HasOverlap(blit.DBP, blit.DBW, blit.DPSM, write_rect, prev_ctx.TEX0.TBP0, prev_ctx.TEX0.TBW, prev_ctx.TEX0.PSM, tex_rect))
{
@@ -2865,56 +2904,53 @@ void GSState::UpdateVertexKick()
void GSState::GrowVertexBuffer()
{
const u32 maxcount = std::max<u32>(m_vertex.maxcount * 3 / 2, 10000);
const u32 old_vertex_size = sizeof(GSVertex) * m_vertex.tail;
const u32 new_vertex_size = sizeof(GSVertex) * maxcount;
const u32 old_index_size = sizeof(u16) * m_index.tail;
const u32 new_index_size = sizeof(u16) * maxcount * 6; // Worst case index list is a list of points with vs expansion, 6 indices per point
GSVertex* vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
GSVertex* draw_vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
// Worst case index list is a list of points with vs expansion, 6 indices per point
u16* index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));
u16* draw_index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));
if (!vertex || !index)
// Structure describing buffers to reallocate
struct AllocDesc
{
const u32 vert_byte_count = sizeof(GSVertex) * maxcount;
const u32 idx_byte_count = sizeof(u16) * maxcount * 3;
void** pbuff;
u32 old_size;
u32 new_size;
};
std::vector<AllocDesc> alloc_desc = {
{reinterpret_cast<void**>(&m_vertex.buff), old_vertex_size, new_vertex_size},
// discard contents of buff_copy by setting old_size = 0
{reinterpret_cast<void**>(&m_vertex.buff_copy), 0, new_vertex_size},
{reinterpret_cast<void**>(&m_draw_vertex.buff), old_vertex_size, new_vertex_size},
{reinterpret_cast<void**>(&m_index.buff), old_index_size, new_index_size},
{reinterpret_cast<void**>(&m_draw_index.buff), old_index_size, new_index_size}
};
Console.Error("GS: failed to allocate %zu bytes for vertices and %zu for indices.",
vert_byte_count, idx_byte_count);
pxFailRel("Memory allocation failed");
// For logging
u32 total_size = 0;
for (const auto& desc : alloc_desc)
total_size += desc.new_size;
// Reallocate each of the needed buffers
for (const auto [pbuff, old_size, new_size] : alloc_desc)
{
void* new_buff = _aligned_malloc(new_size, 32);
if (!new_buff)
{
Console.Error("GS: failed to allocate %zu bytes for vertices and indices.", total_size);
pxFailRel("Memory allocation failed");
}
if (*pbuff)
{
if (old_size)
{
std::memcpy(new_buff, *pbuff, old_size);
}
_aligned_free(*pbuff);
}
*pbuff = new_buff;
}
if (m_vertex.buff)
{
std::memcpy(vertex, m_vertex.buff, sizeof(GSVertex) * m_vertex.tail);
_aligned_free(m_vertex.buff);
}
if (m_index.buff)
{
std::memcpy(index, m_index.buff, sizeof(u16) * m_index.tail);
_aligned_free(m_index.buff);
}
if (m_draw_vertex.buff)
{
std::memcpy(draw_vertex, m_draw_vertex.buff, sizeof(GSVertex) * m_vertex.tail);
_aligned_free(m_draw_vertex.buff);
}
if (m_draw_index.buff)
{
std::memcpy(draw_index, m_draw_index.buff, sizeof(u16) * m_index.tail);
_aligned_free(m_draw_index.buff);
}
m_draw_vertex.buff = draw_vertex;
m_draw_index.buff = draw_index;
m_vertex.buff = vertex;
m_vertex.maxcount = maxcount - 3; // -3 to have some space at the end of the buffer before DrawingKick can grow it
m_index.buff = index;
}
bool GSState::TrianglesAreQuads(bool shuffle_check)
@@ -3381,7 +3417,7 @@ __forceinline void GSState::CheckCLUTValidity(u32 prim)
}
}
template<u32 prim, bool index_swap>
template<u32 prim>
__forceinline void GSState::HandleAutoFlush()
{
// Kind of a cheat, making the assumption that 2 consecutive fan/strip triangles won't overlap each other (*should* be safe)
@@ -3477,9 +3513,8 @@ __forceinline void GSState::HandleAutoFlush()
if (tex_rect.y == tex_rect.w)
tex_rect += GSVector4i::cxpr(0, 0, 0, 1);
const bool swap_index = index_swap && GSUtil::GetPrimClass(m_prev_env.PRIM.PRIM) != GS_SPRITE_CLASS;
// Get the last texture position from the last draw.
const GSVertex* v = &m_vertex.buff[m_index.buff[m_index.tail - (swap_index ? n : 1)]];
const GSVertex* v = &m_vertex.buff[m_index.buff[m_index.tail - 1]];
if (PRIM->FST)
{
@@ -3657,7 +3692,7 @@ __forceinline void GSState::HandleAutoFlush()
}
}
template <u32 prim, bool auto_flush, bool index_swap>
template <u32 prim, bool auto_flush>
__forceinline void GSState::VertexKick(u32 skip)
{
constexpr u32 n = NumIndicesForPrim(prim);
@@ -3673,7 +3708,7 @@ __forceinline void GSState::VertexKick(u32 skip)
if (auto_flush && skip == 0 && m_index.tail > 0 && ((m_vertex.tail + 1) - m_vertex.head) >= n)
{
HandleAutoFlush<prim, index_swap>();
HandleAutoFlush<prim>();
}
u32 head = m_vertex.head;
@@ -3835,8 +3870,8 @@ __forceinline void GSState::VertexKick(u32 skip)
m_index.tail += 1;
break;
case GS_LINELIST:
buff[0] = static_cast<u16>(head + (index_swap ? 1 : 0));
buff[1] = static_cast<u16>(head + (index_swap ? 0 : 1));
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
m_vertex.head = head + 2;
m_vertex.next = head + 2;
m_index.tail += 2;
@@ -3849,16 +3884,16 @@ __forceinline void GSState::VertexKick(u32 skip)
head = next;
m_vertex.tail = next + 2;
}
buff[0] = static_cast<u16>(head + (index_swap ? 1 : 0));
buff[1] = static_cast<u16>(head + (index_swap ? 0 : 1));
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
m_vertex.head = head + 1;
m_vertex.next = head + 2;
m_index.tail += 2;
break;
case GS_TRIANGLELIST:
buff[0] = static_cast<u16>(head + (index_swap ? 2 : 0));
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
buff[2] = static_cast<u16>(head + (index_swap ? 0 : 2));
buff[2] = static_cast<u16>(head + 2);
m_vertex.head = head + 3;
m_vertex.next = head + 3;
m_index.tail += 3;
@@ -3872,18 +3907,18 @@ __forceinline void GSState::VertexKick(u32 skip)
head = next;
m_vertex.tail = next + 3;
}
buff[0] = static_cast<u16>(head + (index_swap ? 2 : 0));
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
buff[2] = static_cast<u16>(head + (index_swap ? 0 : 2));
buff[2] = static_cast<u16>(head + 2);
m_vertex.head = head + 1;
m_vertex.next = head + 3;
m_index.tail += 3;
break;
case GS_TRIANGLEFAN:
// TODO: remove gaps, next == head && head < tail - 3 || next > head && next < tail - 2 (very rare)
buff[0] = static_cast<u16>(index_swap ? (tail - 1) : (head + 0));
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(tail - 2);
buff[2] = static_cast<u16>(index_swap ? (head + 0) : (tail - 1));
buff[2] = static_cast<u16>(tail - 1);
m_vertex.next = tail;
m_index.tail += 3;
break;

View File

@@ -38,8 +38,8 @@ private:
void GIFPackedRegHandlerSTQ(const GIFPackedReg* RESTRICT r);
void GIFPackedRegHandlerUV(const GIFPackedReg* RESTRICT r);
void GIFPackedRegHandlerUV_Hack(const GIFPackedReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush, bool index_swap> void GIFPackedRegHandlerXYZF2(const GIFPackedReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush, bool index_swap> void GIFPackedRegHandlerXYZ2(const GIFPackedReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush> void GIFPackedRegHandlerXYZF2(const GIFPackedReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush> void GIFPackedRegHandlerXYZ2(const GIFPackedReg* RESTRICT r);
void GIFPackedRegHandlerFOG(const GIFPackedReg* RESTRICT r);
void GIFPackedRegHandlerA_D(const GIFPackedReg* RESTRICT r);
void GIFPackedRegHandlerNOP(const GIFPackedReg* RESTRICT r);
@@ -55,8 +55,8 @@ private:
GIFPackedRegHandlerC m_fpGIFPackedRegHandlerSTQRGBAXYZF2[8] = {};
GIFPackedRegHandlerC m_fpGIFPackedRegHandlerSTQRGBAXYZ2[8] = {};
template<u32 prim, bool auto_flush, bool index_swap> void GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u32 size);
template<u32 prim, bool auto_flush, bool index_swap> void GIFPackedRegHandlerSTQRGBAXYZ2(const GIFPackedReg* RESTRICT r, u32 size);
template<u32 prim, bool auto_flush> void GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u32 size);
template<u32 prim, bool auto_flush> void GIFPackedRegHandlerSTQRGBAXYZ2(const GIFPackedReg* RESTRICT r, u32 size);
void GIFPackedRegHandlerNOP(const GIFPackedReg* RESTRICT r, u32 size);
template<int i> void ApplyTEX0(GIFRegTEX0& TEX0);
@@ -68,8 +68,8 @@ private:
void GIFRegHandlerST(const GIFReg* RESTRICT r);
void GIFRegHandlerUV(const GIFReg* RESTRICT r);
void GIFRegHandlerUV_Hack(const GIFReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush, bool index_swap> void GIFRegHandlerXYZF2(const GIFReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush, bool index_swap> void GIFRegHandlerXYZ2(const GIFReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush> void GIFRegHandlerXYZF2(const GIFReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush> void GIFRegHandlerXYZ2(const GIFReg* RESTRICT r);
template<int i> void GIFRegHandlerTEX0(const GIFReg* RESTRICT r);
template<int i> void GIFRegHandlerCLAMP(const GIFReg* RESTRICT r);
void GIFRegHandlerFOG(const GIFReg* RESTRICT r);
@@ -102,8 +102,7 @@ private:
void GIFRegHandlerTRXDIR(const GIFReg* RESTRICT r);
void GIFRegHandlerHWREG(const GIFReg* RESTRICT r);
template<bool auto_flush, bool index_swap>
void SetPrimHandlers();
template<bool auto_flush> void SetPrimHandlers();
struct GSTransferBuffer
{
@@ -137,6 +136,7 @@ protected:
struct
{
GSVertex* buff;
GSVertex* buff_copy; // same size buffer to copy/modify the original buffer
u32 head, tail, next, maxcount; // head: first vertex, tail: last vertex + 1, next: last indexed + 1
u32 xy_tail;
GSVector4i xy[4];
@@ -171,12 +171,10 @@ protected:
void GrowVertexBuffer();
bool IsAutoFlushDraw(u32 prim);
template<u32 prim, bool index_swap>
void HandleAutoFlush();
template<u32 prim> void HandleAutoFlush();
void CheckCLUTValidity(u32 prim);
template <u32 prim, bool auto_flush, bool index_swap>
void VertexKick(u32 skip);
template <u32 prim, bool auto_flush> void VertexKick(u32 skip);
// following functions need m_vt to be initialized

View File

@@ -876,7 +876,30 @@ static std::string GSGetBaseFilename()
std::string GSGetBaseSnapshotFilename()
{
// prepend snapshots directory
return Path::Combine(EmuFolders::Snapshots, GSGetBaseFilename());
std::string base_path = EmuFolders::Snapshots;
// If organize by game is enabled, create a game-specific folder
if (GSConfig.OrganizeScreenshotsByGame)
{
std::string game_name = VMManager::GetTitle(true);
if (!game_name.empty())
{
Path::SanitizeFileName(&game_name);
if (game_name.length() > 219)
{
game_name.resize(219);
}
const std::string game_dir = Path::Combine(base_path, game_name);
if (!FileSystem::DirectoryExists(game_dir.c_str()))
{
FileSystem::CreateDirectoryPath(game_dir.c_str(), false);
}
base_path = game_dir;
}
}
return Path::Combine(base_path, GSGetBaseFilename());
}
std::string GSGetBaseVideoFilename()

View File

@@ -7,10 +7,10 @@
#include "common/Console.h"
GSVertexTrace::GSVertexTrace(const GSState* state, bool provoking_vertex_first)
GSVertexTrace::GSVertexTrace(const GSState* state)
: m_state(state)
{
MULTI_ISA_SELECT(GSVertexTracePopulateFunctions)(*this, provoking_vertex_first);
MULTI_ISA_SELECT(GSVertexTracePopulateFunctions)(*this);
}
void GSVertexTrace::Update(const void* vertex, const u16* index, int v_count, int i_count, GS_PRIM_CLASS primclass)

View File

@@ -15,7 +15,7 @@ class GSState;
class GSVertexTrace;
MULTI_ISA_DEF(class GSVertexTraceFMM;)
MULTI_ISA_DEF(void GSVertexTracePopulateFunctions(GSVertexTrace& vt, bool provoking_vertex_first);)
MULTI_ISA_DEF(void GSVertexTracePopulateFunctions(GSVertexTrace& vt);)
class alignas(32) GSVertexTrace final : public GSAlignedClass<32>
{
@@ -63,7 +63,7 @@ public:
GSVector2 m_lod = {}; // x = min, y = max
public:
GSVertexTrace(const GSState* state, bool provoking_vertex_first);
GSVertexTrace(const GSState* state);
void Update(const void* vertex, const u16* index, int v_count, int i_count, GS_PRIM_CLASS primclass);

View File

@@ -9,41 +9,36 @@ class CURRENT_ISA::GSVertexTraceFMM
{
static constexpr GSVector4 s_minmax = GSVector4::cxpr(FLT_MAX, -FLT_MAX, 0.f, 0.f);
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color, bool flat_swapped>
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
static void FindMinMax(GSVertexTrace& vt, const void* vertex, const u16* index, int count);
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
static constexpr GSVertexTrace::FindMinMaxPtr GetFMM(bool provoking_vertex_first);
static constexpr GSVertexTrace::FindMinMaxPtr GetFMM();
public:
static void Populate(GSVertexTrace& vt, bool provoking_vertex_first);
static void Populate(GSVertexTrace& vt);
};
MULTI_ISA_UNSHARED_IMPL;
void CURRENT_ISA::GSVertexTracePopulateFunctions(GSVertexTrace& vt, bool provoking_vertex_first)
void CURRENT_ISA::GSVertexTracePopulateFunctions(GSVertexTrace& vt)
{
GSVertexTraceFMM::Populate(vt, provoking_vertex_first);
GSVertexTraceFMM::Populate(vt);
}
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
constexpr GSVertexTrace::FindMinMaxPtr GSVertexTraceFMM::GetFMM(bool provoking_vertex_first)
constexpr GSVertexTrace::FindMinMaxPtr GSVertexTraceFMM::GetFMM()
{
constexpr bool real_iip = primclass == GS_SPRITE_CLASS ? false : iip;
constexpr bool real_fst = tme ? fst : false;
constexpr bool provoking_vertex_first_class = primclass == GS_LINE_CLASS || primclass == GS_TRIANGLE_CLASS;
const bool swap = provoking_vertex_first_class && !iip && provoking_vertex_first;
if (swap)
return FindMinMax<primclass, real_iip, tme, real_fst, color, true>;
else
return FindMinMax<primclass, real_iip, tme, real_fst, color, false>;
return FindMinMax<primclass, real_iip, tme, real_fst, color>;
}
void GSVertexTraceFMM::Populate(GSVertexTrace& vt, bool provoking_vertex_first)
void GSVertexTraceFMM::Populate(GSVertexTrace& vt)
{
#define InitUpdate3(P, IIP, TME, FST, COLOR) \
vt.m_fmm[COLOR][FST][TME][IIP][P] = GetFMM<P, IIP, TME, FST, COLOR>(provoking_vertex_first);
vt.m_fmm[COLOR][FST][TME][IIP][P] = GetFMM<P, IIP, TME, FST, COLOR>();
#define InitUpdate2(P, IIP, TME) \
InitUpdate3(P, IIP, TME, 0, 0) \
@@ -63,7 +58,7 @@ void GSVertexTraceFMM::Populate(GSVertexTrace& vt, bool provoking_vertex_first)
InitUpdate(GS_SPRITE_CLASS);
}
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color, bool flat_swapped>
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
void GSVertexTraceFMM::FindMinMax(GSVertexTrace& vt, const void* vertex, const u16* index, int count)
{
const GSDrawingContext* context = vt.m_state->m_context;
@@ -110,7 +105,7 @@ void GSVertexTraceFMM::FindMinMax(GSVertexTrace& vt, const void* vertex, const u
{
// For even n, we process v1 and v2 of the same prim
// (For odd n, we process one vertex from each of two prims)
GSVector4i c = flat_swapped ? c0 : c1;
GSVector4i c = c1; // second color is provoking in flat-shaded primitives
cmin = cmin.min_u8(c);
cmax = cmax.max_u8(c);
}
@@ -196,26 +191,16 @@ void GSVertexTraceFMM::FindMinMax(GSVertexTrace& vt, const void* vertex, const u
int i = 0;
for (; i < (count - 3); i += 6)
{
processVertices(v[index[i + 0]], v[index[i + 3]], flat_swapped);
processVertices(v[index[i + 0]], v[index[i + 3]], false);
processVertices(v[index[i + 1]], v[index[i + 4]], false);
processVertices(v[index[i + 2]], v[index[i + 5]], !flat_swapped);
processVertices(v[index[i + 2]], v[index[i + 5]], true);
}
if (count & 1)
{
if (flat_swapped)
{
processVertices(v[index[i + 1]], v[index[i + 2]], false);
// Compiler optimizations go!
// (And if they don't, it's only one vertex out of many)
processVertices(v[index[i + 0]], v[index[i + 0]], true);
}
else
{
processVertices(v[index[i + 0]], v[index[i + 1]], false);
// Compiler optimizations go!
// (And if they don't, it's only one vertex out of many)
processVertices(v[index[i + 2]], v[index[i + 2]], true);
}
processVertices(v[index[i + 0]], v[index[i + 1]], false);
// Compiler optimizations go!
// (And if they don't, it's only one vertex out of many)
processVertices(v[index[i + 2]], v[index[i + 2]], true);
}
}
else

View File

@@ -211,6 +211,76 @@ bool GSHwHack::GSC_NamcoGames(GSRendererHW& r, int& skip)
return true;
}
bool GSHwHack::GSC_SandGrainGames(GSRendererHW& r, int& skip)
{
if (skip == 0)
{
// These games do a kind of manual shuffle from a real Z16S to a real C16S, by moving the first 8 pixels in to the second column of 8 pixels.
// In 32bit format this will mean that the whole contents of the 16bit depth buffer will be in the BA part of a 32bit colour.
// This then gets read as PSMT8H using a palette where the bottom two alphas are quite extreme, then a slight gradient, to create a kind of depth plain distance for the blur effect.
// This is kind of akin to a manual G->A shuffle (in this case it's the upper 8bits of the depth buffer), but with use of a palette in between.
// So here we use a channel shuffle to copy Green->Alpha (green being the upper 8 bits of the depth), then read itself in PSMT8H mode with the palette and update it to the correct value.
const int get_next_ctx = r.m_env.PRIM.CTXT;
const GSDrawingContext& next_ctx = r.m_env.CTXT[get_next_ctx];
if (r.PRIM->PRIM == GS_SPRITE && RTME && RFPSM == PSMCT16S && RTPSM == PSMZ16S && next_ctx.TEX0.TBP0 == RFBP && next_ctx.TEX0.PSM == PSMT8H)
{
GSTextureCache::Target* texsrc = g_texture_cache->LookupTarget(GIFRegTEX0::Create(RTBP0, RTBW, RTPSM),
GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil);
if (!texsrc)
return false;
GSTextureCache::Target* rt = g_texture_cache->LookupTarget(GIFRegTEX0::Create(next_ctx.FRAME.Block(), next_ctx.FRAME.FBW, next_ctx.FRAME.PSM),
GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget);
if (!rt)
return false;
r.m_mem.m_clut.Read32(next_ctx.TEX0, r.m_env.TEXA);
std::shared_ptr<GSTextureCache::Palette> palette =
g_texture_cache->LookupPaletteObject(r.m_mem.m_clut, GSLocalMemory::m_psm[next_ctx.TEX0.PSM].pal, true);
if (!palette)
return false;
// Shuffle the green depth channel in to the destination RT alpha.
GSHWDrawConfig& config = r.BeginHLEHardwareDraw(
rt->GetTexture(), nullptr, rt->GetScale(), texsrc->GetTexture(), texsrc->GetScale(), texsrc->GetUnscaledRect());
config.ps.channel = ChannelFetch_GXBY;
config.cb_ps.ChannelShuffle = GSVector4i(0, 0, 0xFF, 0);
config.ps.depth_fmt = 2;
config.colormask.wrgba = 8;
config.ps.tfx = TFX_DECAL;
config.ps.tcc = true;
r.EndHLEHardwareDraw(true);
// Draw over itself using a palette to adjust the alpha value.
GSHWDrawConfig& modulate_config = r.BeginHLEHardwareDraw(
rt->GetTexture(), nullptr, rt->GetScale(), rt->GetTexture(), rt->GetScale(), rt->GetUnscaledRect());
modulate_config.pal = palette->GetPaletteGSTexture();
modulate_config.ps.aem_fmt = 0;
modulate_config.ps.aem = 0;
modulate_config.ps.pal_fmt = 3;
modulate_config.colormask.wrgba = 8;
modulate_config.ps.tfx = TFX_DECAL;
modulate_config.ps.tcc = true;
r.EndHLEHardwareDraw(true);
rt->m_alpha_min = 0;
rt->m_alpha_max = 128;
rt->m_rt_alpha_scale = false;
rt->ScaleRTAlpha();
const int pages = (rt->m_valid.w / 32) * rt->m_TEX0.TBW;
skip = pages;
}
}
return true;
}
bool GSHwHack::GSC_BurnoutGames(GSRendererHW& r, int& skip)
{
// Burnout has a... creative way of achieving its bloom effect, to avoid horizontal page breaks.
@@ -1337,6 +1407,7 @@ const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_function
// Channel Effect
CRC_F(GSC_NamcoGames),
CRC_F(GSC_SandGrainGames),
CRC_F(GSC_SteambotChronicles),
// Depth Issue

View File

@@ -12,6 +12,7 @@ public:
static bool GSC_SFEX3(GSRendererHW& r, int& skip);
static bool GSC_DTGames(GSRendererHW& r, int& skip);
static bool GSC_NamcoGames(GSRendererHW& r, int& skip);
static bool GSC_SandGrainGames(GSRendererHW& r, int& skip);
static bool GSC_BurnoutGames(GSRendererHW& r, int& skip);
static bool GSC_BlackAndBurnoutSky(GSRendererHW& r, int& skip);
static bool GSC_MidnightClub3(GSRendererHW& r, int& skip);

View File

@@ -4791,21 +4791,10 @@ bool GSRendererHW::VerifyIndices()
return false;
// Expect each line to be a pair next to each other
// VS expand relies on this!
if (g_gs_device->Features().provoking_vertex_last)
for (u32 i = 0; i < m_index.tail; i += 2)
{
for (u32 i = 0; i < m_index.tail; i += 2)
{
if (m_index.buff[i] + 1 != m_index.buff[i + 1])
return false;
}
}
else
{
for (u32 i = 0; i < m_index.tail; i += 2)
{
if (m_index.buff[i] != m_index.buff[i + 1] + 1)
return false;
}
if (m_index.buff[i] + 1 != m_index.buff[i + 1])
return false;
}
break;
case GS_TRIANGLE_CLASS:
@@ -4818,6 +4807,52 @@ bool GSRendererHW::VerifyIndices()
return true;
}
// Fix the colors in vertices in case the API only supports "provoking first vertex"
// (i.e., when using flat shading the color comes from the first vertex, unlike PS2
// which is "provoking last vertex").
void GSRendererHW::HandleProvokingVertexFirst()
{
// Early exit conditions:
if (g_gs_device->Features().provoking_vertex_last || // device supports provoking last vertex
m_conf.vs.iip || // we are doing Gouraud shading
m_vt.m_primclass == GS_POINT_CLASS || // drawing points (one vertex per primitive; color is unambiguous)
m_vt.m_primclass == GS_SPRITE_CLASS) // drawing sprites (handled by the sprites -> triangles expand shader)
return;
const int n = GSUtil::GetClassVertexCount(m_vt.m_primclass);
// If all first/last vertices have the same color there is nothing to do.
bool first_eq_last = true;
for (u32 i = 0; i < m_index.tail; i += n)
{
if (m_vertex.buff[m_index.buff[i]].RGBAQ.U32[0] != m_vertex.buff[m_index.buff[i + n - 1]].RGBAQ.U32[0])
{
first_eq_last = false;
break;
}
}
if (first_eq_last)
return;
// De-index the vertices using the copy buffer
while (m_vertex.maxcount < m_index.tail)
GrowVertexBuffer();
for (int i = static_cast<int>(m_index.tail) - 1; i >= 0; i--)
{
m_vertex.buff_copy[i] = m_vertex.buff[m_index.buff[i]];
m_index.buff[i] = static_cast<u16>(i);
}
std::swap(m_vertex.buff, m_vertex.buff_copy);
m_vertex.head = m_vertex.next = m_vertex.tail = m_index.tail;
// Put correct color in the first vertex
for (u32 i = 0; i < m_index.tail; i += n)
{
m_vertex.buff[i].RGBAQ.U32[0] = m_vertex.buff[i + n - 1].RGBAQ.U32[0];
m_vertex.buff[i + n - 1].RGBAQ.U32[0] = 0xff; // Make last vertex red for debugging if used improperly
}
}
void GSRendererHW::SetupIA(float target_scale, float sx, float sy, bool req_vert_backup)
{
GL_PUSH("HW: IA");
@@ -7899,6 +7934,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
m_conf.drawarea = m_channel_shuffle ? scissor : scissor.rintersect(ComputeBoundingBox(rtsize, rtscale));
m_conf.scissor = (DATE && !DATE_BARRIER) ? m_conf.drawarea : scissor;
HandleProvokingVertexFirst();
SetupIA(rtscale, sx, sy, m_channel_shuffle_width != 0);
if (ate_second_pass)

View File

@@ -92,6 +92,7 @@ private:
void DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Target* ds, GSTextureCache::Source* tex, const TextureMinMaxResult& tmm);
void ResetStates();
void HandleProvokingVertexFirst();
void SetupIA(float target_scale, float sx, float sy, bool req_vert_backup);
void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GSTextureCache::Source* tex);
bool EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt = nullptr);

View File

@@ -3452,8 +3452,9 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
continue;
}
// could be overwriting a double buffer, so if it's the second half of it, just reduce the size down to half.
if (((((t->UnwrappedEndBlock() + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) == dst->m_TEX0.TBP0 && dst->m_TEX0.TBW == t->m_TEX0.TBW)
// Could be overwriting a double buffer, so if it's the second half of it, just reduce the size down to half.
// Don't split/resize buffer when TBW is 0, textures wrap within a single page.
if (((((t->UnwrappedEndBlock() + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) == dst->m_TEX0.TBP0 && dst->m_TEX0.TBW == t->m_TEX0.TBW && dst->m_TEX0.TBW != 0)
{
GSVector4i new_valid = t->m_valid;
new_valid.w /= 2;

View File

@@ -1146,6 +1146,7 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
case ShaderConvert::COPY:
case ShaderConvert::DOWNSAMPLE_COPY:
case ShaderConvert::RGBA_TO_8I: // Yes really
case ShaderConvert::RGB5A1_TO_8I:
case ShaderConvert::RTA_CORRECTION:
case ShaderConvert::RTA_DECORRECTION:
case ShaderConvert::TRANSPARENCY_FILTER:

View File

@@ -233,9 +233,7 @@ vertex MainVSOut vs_main_expand(
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 Metal 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;
uint vid_other = is_bottom ? vid_base - 1 : vid_base + 1;
MainVSOut point = vs_main_run(load_vertex(vertices[vid_base]), cb);
MainVSOut other = vs_main_run(load_vertex(vertices[vid_other]), cb);

View File

@@ -605,7 +605,7 @@ bool GSDeviceOGL::CreateTextureFX()
bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
{
//bool vendor_id_amd = false;
bool vendor_id_nvidia = false;
//bool vendor_id_nvidia = false;
//bool vendor_id_intel = false;
const char* vendor = (const char*)glGetString(GL_VENDOR);
@@ -618,7 +618,7 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
else if (std::strstr(vendor, "NVIDIA Corporation"))
{
Console.WriteLn(Color_StrongGreen, "GL: NVIDIA GPU detected.");
vendor_id_nvidia = true;
//vendor_id_nvidia = true;
}
else if (std::strstr(vendor, "Intel"))
{

View File

@@ -367,12 +367,9 @@ namespace FullscreenUI
static void DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key,
int default_value, int min_value, int max_value, int step_value, const char* format = "%d", bool enabled = true,
float height = ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT, std::pair<ImFont*, float> font = g_large_font, std::pair<ImFont*, float> summary_font = g_medium_font);
#if 0
// Unused as of now
static void DrawFloatRangeSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key,
float default_value, float min_value, float max_value, const char* format = "%f", float multiplier = 1.0f, bool enabled = true,
float height = ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT, std::pair<ImFont*, float> font = g_large_font, std::pair<ImFont*, float> summary_font = g_medium_font);
#endif
static void DrawFloatSpinBoxSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section,
const char* key, float default_value, float min_value, float max_value, float step_value, float multiplier,
const char* format = "%f", bool enabled = true, float height = ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT,
@@ -2217,8 +2214,6 @@ void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* tit
ImGui::PopFont();
}
#if 0
// Unused as of now
void FullscreenUI::DrawFloatRangeSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section,
const char* key, float default_value, float min_value, float max_value, const char* format, float multiplier, bool enabled,
float height, std::pair<ImFont*, float> font, std::pair<ImFont*, float> summary_font)
@@ -2275,7 +2270,6 @@ void FullscreenUI::DrawFloatRangeSetting(SettingsInterface* bsi, const char* tit
ImGui::PopStyleVar(4);
ImGui::PopFont();
}
#endif
void FullscreenUI::DrawFloatSpinBoxSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section,
const char* key, float default_value, float min_value, float max_value, float step_value, float multiplier, const char* format,
@@ -4479,6 +4473,10 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
"Uploads full textures to the GPU on use, rather than only the utilized regions. Can improve performance in some games."),
"EmuCore/GS", "texture_preloading", static_cast<int>(TexturePreloadingLevel::Off), s_preloading_options,
std::size(s_preloading_options), true);
DrawFloatRangeSetting(bsi, FSUI_CSTR("NTSC Frame Rate"), FSUI_CSTR("Determines what frame rate NTSC games run at."),
"EmuCore/GS", "FrameRateNTSC", 59.94f, 10.0f, 300.0f, "%.2f Hz");
DrawFloatRangeSetting(bsi, FSUI_CSTR("PAL Frame Rate"), FSUI_CSTR("Determines what frame rate PAL games run at."),
"EmuCore/GS", "FrameRatePAL", 50.0f, 10.0f, 300.0f, "%.2f Hz");
}
EndMenuButtons();

View File

@@ -221,18 +221,16 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
switch (PerformanceMetrics::GetInternalFPSMethod())
{
case PerformanceMetrics::InternalFPSMethod::GSPrivilegedRegister:
text.append_format("FPS: {:.2f} [P]", PerformanceMetrics::GetInternalFPS(),
PerformanceMetrics::GetFPS());
text.append_format("FPS: {:.2f} [P]", PerformanceMetrics::GetInternalFPS());
break;
case PerformanceMetrics::InternalFPSMethod::DISPFBBlit:
text.append_format("FPS: {:.2f} [B]", PerformanceMetrics::GetInternalFPS(),
PerformanceMetrics::GetFPS());
text.append_format("FPS: {:.2f} [B]", PerformanceMetrics::GetInternalFPS());
break;
case PerformanceMetrics::InternalFPSMethod::None:
default:
text.append_format("FPS: {:.2f}", PerformanceMetrics::GetFPS());
text.append("FPS: N/A");
break;
}
first = false;

View File

@@ -920,6 +920,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapIntEnumEx(ScreenshotSize, "ScreenshotSize");
SettingsWrapIntEnumEx(ScreenshotFormat, "ScreenshotFormat");
SettingsWrapEntry(ScreenshotQuality);
SettingsWrapBitBool(OrganizeScreenshotsByGame);
SettingsWrapEntry(StretchY);
SettingsWrapEntryEx(Crop[0], "CropLeft");
SettingsWrapEntryEx(Crop[1], "CropTop");

View File

@@ -3,4 +3,4 @@
/// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 68;
static constexpr u32 SHADER_CACHE_VERSION = 69;