Compare commits

...
61 Commits
Author SHA1 Message Date
TheLastRarandlightningterror 38ee1e1e22 GS/DX: Specify shader model directly instead of via feature level 2026-05-11 22:29:45 +02:00
PCSX2 BotandTy 2b02a5dc78 [ci skip] PAD: Update to latest controller database. 2026-05-11 13:30:19 -04:00
descawedandlightningterror dead00eb62 GameDB: Enable Instant DMA Hack for SLPM-74405 to fix hang 2026-05-10 19:07:21 +02:00
TJnotJTandlightningterror 4fa2b8e45d GS/HW: Fixes/improvements to early scissor/bbox test. 2026-05-09 13:48:42 +02:00
refractionpcsx2andlightningterror fc90973509 GS/HW/COLCLIP: Check tex mapping is enabled when checking for recursion 2026-05-09 13:47:58 +02:00
Immersion95andlightningterror ff9176f83e GameDB: fixes wrong title for SLPM-65496 - Hyper Street Fighter II - The Anniversary Edition 2026-05-09 13:46:48 +02:00
refractionpcsx2andlightningterror 63d3dd9978 GS/TC: Update dirty target linked to source when dirty overlaps the read 2026-05-09 13:46:25 +02:00
JordanTheToasterandlightningterror b704c6caaa GameDB: Pump It Up Exceed Fixes 2026-05-08 18:56:51 +02:00
lightningterror a64465681c GS/HW: Disable texture shuffle if there's no tex. 2026-05-08 18:29:05 +02:00
refractionpcsx2andlightningterror 539357436c Build: Clean up a few warnings 2026-05-08 18:17:31 +02:00
refractionpcsx2andlightningterror 22cb6b0c9c GS/HW: Remove zero clear from GSUploadQueue, use transfer_type instead 2026-05-08 18:15:18 +02:00
PCSX2 Botandlightningterror 81df4e5def [ci skip] Qt: Update Base Translation. 2026-05-07 02:15:53 +02:00
ZiemasandTy a3f3e8733d GS: fix build with libstdc++ 16 2026-05-06 18:05:51 -04:00
SternXDandlightningterror 6fc84f76bb FullscreenUI: Fix RA login state, and add dismiss dialog 2026-05-06 20:55:44 +02:00
TJnotJTandlightningterror 0949f193b8 GS/SW: Adjust bounds in assertion to present false positive.
Account for the fact that bottom/right coordinates are exclusive.
2026-05-06 20:46:51 +02:00
TJnotJTandlightningterror 5f3dc1a76e GS/SW: Early exit optimization for multithreaded horizontal lines. 2026-05-06 20:46:51 +02:00
TJnotJTandlightningterror 9afea55bb6 GS/SW: Adjust bbox to account for AA1 and points/line rounding. 2026-05-06 20:46:51 +02:00
TJnotJTandlightningterror 433614ae85 GS: Adjust primitive bbox in vertex kick to account for AA1. 2026-05-06 20:46:51 +02:00
TJnotJTandlightningterror 00c85c4a8f GS/TC: Use temporary source on invalid TEX0. 2026-05-06 19:18:04 +02:00
PCSX2 Botandlightningterror f9885315bd [ci skip] Qt: Update Base Translation. 2026-05-06 11:59:56 +02:00
TheLastRarandlightningterror 26563dbae2 GS/HW: Clamp large UVs in shader anisotropic filtering 2026-05-06 11:59:32 +02:00
Ty 53e3838c1d Qt: Add MainWindowMaximized to ini for human readable maximized override 2026-05-05 16:01:35 -04:00
Ty 4509d11daf Qt: Add MainWindowFullscreen to ini for human readable fullscreen override 2026-05-05 16:01:35 -04:00
JordanTheToasterandlightningterror 37d5bf33e8 Deps: Update SDL3 to v3.4.8 2026-05-05 20:01:47 +02:00
PCSX2 Botandlightningterror 76842401ee [ci skip] PAD: Update to latest controller database. 2026-05-04 23:33:20 +02:00
PCSX2 BotandTy bf9d38e86a [ci skip] Qt: Update Base Translation. 2026-05-03 21:08:21 -04:00
Vishrut SachanandTy 7de2aad05a Qt: Fix Big Picture Mode mnemonic shortcut lost after state change 2026-05-03 19:41:23 -04:00
Florin9doiandTy 7d11e1f963 USB: Support for Olympus storage devices
Also the commands were incorrectly handled as file R/W
operations when the host did not provide unique tags,
causing f.buf to be overwritten with file content
2026-05-03 19:38:07 -04:00
TellowKrinkleandlightningterror 452e239eb4 GS:MTL: Fix AA1 depth clears 2026-05-03 23:51:30 +02:00
TJnotJTandlightningterror 8b82fbb449 GS/HW: Add constant buffer dumping. 2026-05-03 18:05:35 +02:00
lightningterror de84c41757 GS: Check if current tex is valid before resizing. 2026-05-03 15:25:58 +02:00
PCSX2 Botandlightningterror 3000e113e2 [ci skip] Qt: Update Base Translation. 2026-05-02 05:39:03 +02:00
refractionpcsx2andlightningterror c5d6b28be4 GS/HW: Correct buffered rect size of corrected EE->GS transfers 2026-05-02 05:38:48 +02:00
chaoticgdandlightningterror c0dfb8cfa0 Debugger: Call QWidget::update instead of QWidget::repaint 2026-05-01 20:47:40 +02:00
lightningterror f9feca4f4d GS/DX11/GL: Further cleanup to the copy behavior and some features checks. 2026-05-01 20:35:30 +02:00
lightningterror 4fa9c4e382 GS/HW: Check if alpha second pass copies are feedback loops. 2026-05-01 20:35:30 +02:00
lightningterror 93f1fcbe88 GS/HW: Sync rt copy behaviour across renderers. 2026-05-01 20:35:30 +02:00
TJnotJTandlightningterror 3d71e310c0 GSRunner: Add -debugdevice command line parameter. 2026-04-30 02:21:35 +02:00
TJnotJTandlightningterror 02d0f613ba GS/HW: Fix brackets in texture shuffle detection. 2026-04-30 02:03:44 +02:00
PCSX2 Botandlightningterror 3091407e9e [ci skip] Qt: Update Base Translation. 2026-04-29 22:53:37 +02:00
ZiemasandTy 70f6169eff StackWalker: Fix bugs.
Fixes incorrect stack tracing in cases where we are stoppen on certain instructions.
2026-04-28 19:58:38 -04:00
ZiemasandTy a1a3cd9d1b DebugData: Remove stack getters
They're not used and the naming is confused, we can readd these if we
actually want to use them.
2026-04-28 19:57:48 -04:00
ZiemasandTy 86c5d2ae2a DebugInterface: Allow stack tracing any IOP thread 2026-04-28 19:57:48 -04:00
ZiemasandTy d759055231 DebugInterface: Enable stack tracing any EE thread 2026-04-28 19:57:48 -04:00
ZiemasandTy c6474852d5 DebugData: Add function for getting register state 2026-04-28 19:57:48 -04:00
ZiemasandTy a2ac576711 DebugData: Add struct for the saved thread context 2026-04-28 19:57:48 -04:00
ZiemasandTy 1b6924a033 DebugData: Rename EE sleep state to match IOP 2026-04-28 19:57:48 -04:00
ZiemasandTy 8e5e053b81 DebugData: Fix EE thread struct 2026-04-28 19:57:48 -04:00
TheLastRarandlightningterror 6891511a1d GS/HW: Reject malformed UVs in shader anisotropic filtering 2026-04-29 00:14:51 +02:00
chaoticgdandTy c186f8d366 Qt: Fix crash when closing OSD font picker dialog 2026-04-28 12:09:23 -04:00
KamFretoZandlightningterror eed53d19a0 Qt: Move Cheevos Account Box to the top 2026-04-28 03:33:16 +02:00
PCSX2 Botandlightningterror abb218c5cf [ci skip] PAD: Update to latest controller database. 2026-04-27 18:30:02 +02:00
PCSX2 Botandlightningterror 249ac51827 [ci skip] Qt: Update Base Translation. 2026-04-27 02:33:55 +02:00
jasaavedandTy 3da22f126e Qt: Fix Fullscreen not on the correct display
Replace setPosition with setGeometry. This makes sure when rendering to main window, it stays on the current display the main window is currently positioned at.
2026-04-26 16:17:09 -04:00
Ty a509350646 FullscreenUI: Use Host::TranslateTo(C)String directly for non-string literals 2026-04-26 16:13:13 -04:00
KamFretoZandTy bd486f1729 Qt: Add -datapath launch argument 2026-04-26 16:13:04 -04:00
lightningterror f7ef43b155 GS/HW: Match TEXA behavior on shuffles between renderers. 2026-04-26 21:07:44 +02:00
lightningterror 282129030f GS/HW: Exclude shuffles for dst no rgb blend and no rt check. 2026-04-26 21:07:44 +02:00
lightningterror 5734403ffc GS/HW: Several barrier fixes to sw blend and barrier date.
- Accumulation blend: Require 32 bit RT is only when texture barriers/multidraw fb copies are on/supported.

- Barrier DATE:
Always use barrier date if texture barrier/multidraw fb copies are supported.
Check if texture barriers/multidraw fb copies are supported before enabling barrier date for AA1.
2026-04-26 21:07:44 +02:00
lightningterror 8d4d9ce026 GS/HW: Allow Date barrier when texture barriers/multidraw fb copies are disabled. 2026-04-26 21:07:44 +02:00
lightningterror 390e3994ad GS/HW: Clean up date stencil temp ds texture creation.
Add barrier fallback method.
2026-04-26 21:07:44 +02:00
69 changed files with 4151 additions and 3501 deletions
@@ -27,7 +27,7 @@ LIBJPEGTURBO=3.1.4.1
LIBPNG=1.6.56
LIBWEBP=1.6.0
NVENC=13.0.19.0
SDL=SDL3-3.4.4
SDL=SDL3-3.4.8
LZ4=1.10.0
VULKAN=1.4.328.1
ZSTD=1.5.7
@@ -60,7 +60,7 @@ b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a ffmpeg-$FFMPEG
ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
f7d8bf1601b7804f583a254ab343a6549ca6cf27d255c302c47af2d9d36a6f18 libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
ee712dbe6a89bb140bbfc2ce72358fb5ee5cc2240abeabd54855012db30b3864 $SDL.tar.gz
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
9ce32d4a2763a2ac5f258726ba2f49e9011327c1ee8c30862a32d0f30889fbe8 libpng-$LIBPNG-apng.patch.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
13da39edb3a40ed9713ae390ca89faa2f1202c9dda869ef306a8d4383e242bee nv-codec-headers-$NVENC.tar.gz
@@ -14,8 +14,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL3-3.4.4.tar.gz",
"sha256": "ee712dbe6a89bb140bbfc2ce72358fb5ee5cc2240abeabd54855012db30b3864"
"url": "https://libsdl.org/release/SDL3-3.4.8.tar.gz",
"sha256": "e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba"
}
],
"cleanup": [
@@ -47,7 +47,7 @@ QT=6.11.0
QTAPNG=1.3.0
FREETYPE=2.14.3
SDL=SDL3-3.4.4
SDL=SDL3-3.4.8
HARFBUZZ=14.0.0
ZSTD=1.5.7
LZ4=1.10.0
@@ -93,7 +93,7 @@ cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everyw
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
36bc4f1cc413335368ee656c42afca65c5a3987e8768cc28cf11ba775e785a5f freetype-$FREETYPE.tar.xz
ee712dbe6a89bb140bbfc2ce72358fb5ee5cc2240abeabd54855012db30b3864 $SDL.tar.gz
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
f29db9470e0ca5cef484e04e27baeec233aa428e8fdabe9e51b0f706c0809d24 harfbuzz-$HARFBUZZ.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
@@ -24,7 +24,7 @@ QT=6.11.0
QTAPNG=1.3.0
FREETYPE=2.14.3
SDL=SDL3-3.4.4
SDL=SDL3-3.4.8
HARFBUZZ=14.0.0
ZSTD=1.5.7
LZ4=1.10.0
@@ -69,7 +69,7 @@ cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everyw
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
36bc4f1cc413335368ee656c42afca65c5a3987e8768cc28cf11ba775e785a5f freetype-$FREETYPE.tar.xz
ee712dbe6a89bb140bbfc2ce72358fb5ee5cc2240abeabd54855012db30b3864 $SDL.tar.gz
e9fff7467fb60f037e6708da18b25560649e4c63edc2a69bb871b960d9cbfbba $SDL.tar.gz
f29db9470e0ca5cef484e04e27baeec233aa428e8fdabe9e51b0f706c0809d24 harfbuzz-$HARFBUZZ.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
@@ -60,7 +60,7 @@ set QTAPNG=1.3.0
set FREETYPE=2.14.3
set HARFBUZZ=14.0.0
set SDL=SDL3-3.4.4
set SDL=SDL3-3.4.8
set LIBJPEGTURBO=3.1.4.1
set LIBPNG=1656
set LIBPNGLONG=1.6.56
@@ -94,7 +94,7 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 9ce32d4a2763a2ac5f258726ba2f49e9011327c1ee8c30862a32d0f30889fbe8 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 6bd4fbb665f77899a488b381c5b6e9681fc57c60b669738f985fea714f3456c5 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 506206e02f90c1f37e048eacaf9e8a3a7dc682fd27783eb0ff15a7d2dcc9c2af || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
@@ -77,7 +77,7 @@ set LIBX264=b35605ace3ddf7c1a5d67a2eb553f034aef41d55
set FREETYPE=2.14.3
set HARFBUZZ=14.0.0
set SDL=SDL3-3.4.4
set SDL=SDL3-3.4.8
set LIBJPEGTURBO=3.1.4.1
set LIBPNG=1656
set LIBPNGLONG=1.6.56
@@ -121,7 +121,7 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
call :downloadfile "lpng%LIBPNG%-apng.patch.gz" https://download.sourceforge.net/libpng-apng/libpng-%LIBPNGLONG%-apng.patch.gz 9ce32d4a2763a2ac5f258726ba2f49e9011327c1ee8c30862a32d0f30889fbe8 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" ecae8008e2cc9ade2f2c1bb9d5e6d4fb73e7c433866a056bd82980741571a022 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 6bd4fbb665f77899a488b381c5b6e9681fc57c60b669738f985fea714f3456c5 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 506206e02f90c1f37e048eacaf9e8a3a7dc682fd27783eb0ff15a7d2dcc9c2af || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/refs/tags/v%LZ4%.zip" 3224b4c80f351f194984526ef396f6079bd6332dd9825c72ac0d7a37b3cdc565 || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://github.com/madler/zlib/releases/download/v%ZLIB%/zlib%ZLIBSHORT%.zip" e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
+8 -1
View File
@@ -31969,6 +31969,9 @@ SLKA-25176:
name: "펌프 잇 업 익시드"
name-en: "Pump It Up - Exceed"
region: "NTSC-K"
gsHWFixes:
cpuSpriteRenderBW: 4 # Fixes graphical corruption in musical notes.
cpuSpriteRenderLevel: 2 # Needed for above.
SLKA-25180:
name: "스플린터 셀 - 판도라 투머로우"
name-en: "Tom Clancy's Splinter Cell - Pandora Tomorrow"
@@ -44039,7 +44042,7 @@ SLPM-65495:
SLPM-65496:
name: "ハイパーストリートファイターⅡ アニバーサリーエディション"
name-sort: "はいぱーすとりーとふぁいたー2 あにばーさりーえでぃしょん"
name-en: "Hyper Street Fighter"
name-en: "Hyper Street Fighter II - The Anniversary Edition"
region: "NTSC-J"
SLPM-65497:
name: "ワールドサッカーウイニングイレブン7 インターナショナル プレミアムパッケージ supported by アディダス"
@@ -54506,6 +54509,7 @@ SLPM-74405:
region: "NTSC-J"
gameFixes:
- EETimingHack # Stops crash after intro movie.
- InstantDMAHack # Stops hang when entering Sword Select screen.
SLPM-74406:
name: "WRC WORLD RALLY CHAMPIONSHIP [PlayStation2 the Best]"
name-sort: "WRC ~わーるど らりー ちゃんぴおんしっぷ~ [PlayStation2 the Best]"
@@ -70115,6 +70119,9 @@ SLUS-21131:
name: "Pump It Up - Exceed"
region: "NTSC-U"
compat: 5
gsHWFixes:
cpuSpriteRenderBW: 4 # Fixes graphical corruption in musical notes.
cpuSpriteRenderLevel: 2 # Needed for above.
SLUS-21132:
name: "Stella Deus - The Gate of Eternity"
region: "NTSC-U"
+9 -2
View File
@@ -654,7 +654,7 @@
030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000830500000052000000000000,Rockfire CosmoVoyager,a:b0,b:b1,x:b3,y:b4,back:b8,guide:b10,start:b9,leftshoulder:b6,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,misc1:b11,lefttrigger:b7,righttrigger:b2,platform:Windows,
03000000830500000052000000000000,Rockfire CosmoVoyager,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b10,leftshoulder:b6,lefttrigger:b7,misc1:b11,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
03000000830500007030000000000000,Rockfire Space Ranger,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b9,righttrigger:b8,start:b2,x:b3,y:b4,platform:Windows,
03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows,
@@ -683,6 +683,7 @@
03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000bd12000010d1000000000000,Sanwa 4Button,a:b0,b:b1,x:b2,y:b3,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,platform:Windows,
03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows,
03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows,
@@ -774,6 +775,7 @@
03000000d60600002a00000000000000,Trust 850F,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,x:b3,y:b4,platform:Windows,
030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
030000005f1400002a01000000000000,Trust Predator GM1200,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,x:b3,y:b4,platform:Windows,
030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows,
03000000411200000450000000000000,Twin Shock,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:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,
03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
@@ -1336,7 +1338,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
06000000d73700000124000000000000,Flydigi Vader 5 Pro,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,guide:b8,leftstick:b9,rightstick:b10,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,leftx:a0,lefty:a1,lefttrigger:a2,rightx:a3,righty:a4,righttrigger:a5,misc1:b11,misc2:b12,misc3:b13,misc4:b14,paddle1:b15,paddle2:b17,paddle3:b16,paddle4:b18,misc5:b19,platform:Linux,
06000000d73700000124000000000000,Flydigi Vader 5 Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,misc2:b12,misc3:b13,misc4:b14,misc5:b19,paddle1:b15,paddle2:b17,paddle3:b16,paddle4:b18,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000007e0500003703000000000000,GameCube Adapter,a:b0,b:b1,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,
19000000030000000300000002030000,GameForce Controller,a:b1,b:b0,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
03000000373500000b10000019010000,GameSir Cyclone 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1442,6 +1444,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000242f00002d00000011010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
03000000314100001935000000010000,LeadJoy Xeno Plus,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:a4,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -1535,6 +1538,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000853200000503000000010000,Nacon MGX Pro,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,
0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000085320000180d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
0300000085320000160d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux,
@@ -1792,6 +1797,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux,
030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
06000000f51000000870000003010000,Turtle Beach Recon,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,
03000000f51000001370000000010000,Turtle Beach ReactR,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
03000000f51000001370000000000000,Turtle Beach ReactR,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
03000000100800000100000010010000,Twin PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000c0160000e105000010010000,Ultimate Atari Fight Stick,a:b1,b:b2,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b8,x:b0,y:b3,platform:Linux,
03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+8 -4
View File
@@ -263,6 +263,13 @@ float manual_lod(float uv_w)
#if PS_ANISOTROPIC_FILTERING > 1
float4 sample_c_af(float2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = any(isnan(uv) | isinf(uv)) ? float2(0, 0) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
float2 sz;
@@ -1375,10 +1382,7 @@ PS_OUTPUT ps_main(PS_INPUT input)
uint4 denorm_c = uint4(C);
uint2 denorm_TA = uint2(float2(TA.xy) * 255.0f + 0.5f);
C.rb = (float2)float((denorm_c.r >> 3) | (((denorm_c.g >> 3) & 0x7u) << 5));
if (denorm_c.a & 0x80u)
C.ga = (float2)float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.y & 0x80u));
else
C.ga = (float2)float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u));
C.ga = (float2)float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u));
}
else if (PS_SHUFFLE_ACROSS)
{
+8 -4
View File
@@ -212,6 +212,13 @@ float manual_lod(float uv_w)
#if PS_ANISOTROPIC_FILTERING > 1
vec4 sample_c_af(vec2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = (any(isnan(uv)) || any(isinf(uv))) ? vec2(0, 0) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
vec2 sz = textureSize(TextureSampler, 0);
@@ -1323,10 +1330,7 @@ void ps_main()
uvec2 denorm_TA = uvec2(vec2(TA.xy) * 255.0f + 0.5f);
C.rb = vec2(float((denorm_c.r >> 3) | (((denorm_c.g >> 3) & 0x7u) << 5)));
if (bool(denorm_c.a & 0x80u))
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.y & 0x80u)));
else
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u)));
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u)));
#elif PS_SHUFFLE_ACROSS
#if(PS_PROCESS_BA == SHUFFLE_READWRITE && PS_PROCESS_RG == SHUFFLE_READWRITE)
C.br = C.rb;
+7
View File
@@ -552,6 +552,13 @@ float manual_lod(float uv_w)
#if PS_ANISOTROPIC_FILTERING > 1
vec4 sample_c_af(vec2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = (any(isnan(uv)) || any(isinf(uv))) ? vec2(0, 0) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
vec2 sz = textureSize(Texture, 0);
+6
View File
@@ -799,6 +799,12 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
s_perf_enable = true;
continue;
}
else if (CHECK_ARG("-debugdevice"))
{
Console.WriteLn("Enable debug device");
s_settings_interface.SetBoolValue("EmuCore/GS", "UseDebugDevice", true);
continue;
}
else if (CHECK_ARG("--"))
{
no_more_args = true;
+4 -5
View File
@@ -450,7 +450,7 @@ void DebuggerWindow::onStepInto()
cpu->resumeCpu();
});
repaint();
update();
}
void DebuggerWindow::onStepOver()
@@ -500,7 +500,7 @@ void DebuggerWindow::onStepOver()
cpu->resumeCpu();
});
this->repaint();
update();
}
void DebuggerWindow::onStepOut()
@@ -525,8 +525,7 @@ void DebuggerWindow::onStepOut()
cpu->getPC(),
cpu->getRegister(0, 31),
cpu->getRegister(0, 29),
thread->EntryPoint(),
thread->StackTop());
thread->EntryPoint());
break;
}
}
@@ -541,7 +540,7 @@ void DebuggerWindow::onStepOut()
cpu->resumeCpu();
});
this->repaint();
update();
}
void DebuggerWindow::changeEvent(QEvent* event)
+9 -9
View File
@@ -86,7 +86,7 @@ bool DisassemblyView::fromJson(const JsonValueWrapper& json)
if (show_instruction_bytes != json.value().MemberEnd() && show_instruction_bytes->value.IsBool())
m_showInstructionBytes = show_instruction_bytes->value.GetBool();
repaint();
update();
return true;
}
@@ -222,7 +222,7 @@ void DisassemblyView::contextRunToCursor()
void DisassemblyView::contextJumpToCursor()
{
cpu().setPc(m_selectedAddressStart);
this->repaint();
update();
}
void DisassemblyView::contextToggleBreakpoint()
@@ -378,7 +378,7 @@ void DisassemblyView::contextRestoreFunction()
void DisassemblyView::contextShowInstructionBytes()
{
m_showInstructionBytes = !m_showInstructionBytes;
this->repaint();
update();
}
QString DisassemblyView::GetLineDisasm(u32 address)
@@ -610,7 +610,7 @@ void DisassemblyView::mousePressEvent(QMouseEvent* event)
m_selectedAddressEnd = selectedAddress;
}
}
this->repaint();
update();
}
}
@@ -637,7 +637,7 @@ void DisassemblyView::wheelEvent(QWheelEvent* event)
{
m_visibleStart -= 4;
}
this->repaint();
update();
}
void DisassemblyView::keyPressEvent(QKeyEvent* event)
@@ -709,7 +709,7 @@ void DisassemblyView::keyPressEvent(QKeyEvent* event)
break;
}
this->repaint();
update();
}
void DisassemblyView::openContextMenu(QPoint pos)
@@ -1014,9 +1014,9 @@ void DisassemblyView::gotoAddress(u32 address, bool should_set_focus)
m_selectedAddressStart = destAddress;
m_selectedAddressEnd = destAddress;
this->repaint();
update();
if (should_set_focus)
this->setFocus();
setFocus();
}
void DisassemblyView::toggleBreakpoint(u32 address)
@@ -1034,7 +1034,7 @@ void DisassemblyView::toggleBreakpoint(u32 address)
QtHost::RunOnUIThread([view, cpu]() {
BreakpointModel::getInstance(*cpu)->refreshData();
if (view)
view->repaint();
view->update();
});
});
}
@@ -27,7 +27,6 @@ MemorySearchView::MemorySearchView(const DebuggerViewParameters& parameters)
: DebuggerView(parameters, MONOSPACE_FONT)
{
m_ui.setupUi(this);
this->repaint();
m_ui.listSearchResults->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_ui.btnSearch, &QPushButton::clicked, this, &MemorySearchView::onSearchButtonClicked);
+7 -7
View File
@@ -741,7 +741,7 @@ bool MemoryView::fromJson(const JsonValueWrapper& json)
if (little_endian != json.value().MemberEnd() && little_endian->value.IsBool())
m_table.SetLittleEndian(little_endian->value.GetBool());
repaint();
update();
return true;
}
@@ -764,7 +764,7 @@ void MemoryView::mousePressEvent(QMouseEvent* event)
return;
m_table.SelectAt(event->pos());
repaint();
update();
}
void MemoryView::openContextMenu(QPoint pos)
@@ -859,7 +859,7 @@ void MemoryView::openContextMenu(QPoint pos)
menu->popup(this->mapToGlobal(pos));
this->repaint();
update();
return;
}
@@ -934,7 +934,7 @@ void MemoryView::wheelEvent(QWheelEvent* event)
{
m_table.UpdateStartAddress(m_table.startAddress - 0x10);
}
this->repaint();
update();
}
void MemoryView::keyPressEvent(QKeyEvent* event)
@@ -954,7 +954,7 @@ void MemoryView::keyPressEvent(QKeyEvent* event)
break;
}
}
this->repaint();
update();
DebuggerView::broadcastEvent(DebuggerEvents::VMUpdate());
}
@@ -962,8 +962,8 @@ void MemoryView::gotoAddress(u32 address)
{
m_table.UpdateStartAddress(address & ~0xF);
m_table.selectedAddress = address;
this->repaint();
this->setFocus();
update();
setFocus();
}
#include "moc_MemoryView.cpp"
+7 -6
View File
@@ -36,7 +36,7 @@ RegisterView::RegisterView(const DebuggerViewParameters& parameters)
ui.registerTabs->addTab(cpu().getRegisterCategoryName(i));
}
connect(ui.registerTabs, &QTabBar::currentChanged, [this]() { this->repaint(); });
connect(ui.registerTabs, &QTabBar::currentChanged, [this]() { update(); });
receiveEvent<DebuggerEvents::Refresh>([this](const DebuggerEvents::Refresh& event) -> bool {
update();
@@ -69,7 +69,7 @@ bool RegisterView::fromJson(const JsonValueWrapper& json)
if (show_fpr_float != json.value().MemberEnd() && show_fpr_float->value.IsBool())
m_showFPRFloat = show_fpr_float->value.GetBool();
repaint();
update();
return true;
}
@@ -209,7 +209,8 @@ void RegisterView::mousePressEvent(QMouseEvent* event)
}
}
}
this->repaint();
update();
}
void RegisterView::wheelEvent(QWheelEvent* event)
@@ -223,7 +224,7 @@ void RegisterView::wheelEvent(QWheelEvent* event)
m_rowStart -= 1;
}
this->repaint();
update();
}
void RegisterView::mouseDoubleClickEvent(QMouseEvent* event)
@@ -259,7 +260,7 @@ void RegisterView::customMenuRequested(QPoint pos)
action->setChecked(m_showFPRFloat);
connect(action, &QAction::triggered, this, [this]() {
m_showFPRFloat = !m_showFPRFloat;
repaint();
update();
});
menu->addSeparator();
@@ -272,7 +273,7 @@ void RegisterView::customMenuRequested(QPoint pos)
action->setChecked(m_showVU0FFloat);
connect(action, &QAction::triggered, this, [this]() {
m_showVU0FFloat = !m_showVU0FFloat;
repaint();
update();
});
menu->addSeparator();
+1 -2
View File
@@ -111,8 +111,7 @@ void StackModel::refreshData()
{
if (thread->Status() == ThreadStatus::THS_RUN)
{
m_stackFrames = MipsStackWalk::Walk(&m_cpu, m_cpu.getPC(), m_cpu.getRegister(0, 31), m_cpu.getRegister(0, 29),
thread->EntryPoint(), thread->StackTop());
m_stackFrames = m_cpu.StackTrace(*thread);
break;
}
}
-2
View File
@@ -71,8 +71,6 @@ private:
//: Refers to a Thread Wait State in the Debugger.
{WaitState::NONE, tr("NONE")},
//: Refers to a Thread Wait State in the Debugger.
{WaitState::WAKEUP_REQ, tr("WAKEUP REQUEST")},
//: Refers to a Thread Wait State in the Debugger.
{WaitState::SEMA, tr("SEMAPHORE")},
//: Refers to a Thread Wait State in the Debugger.
{WaitState::SLEEP, tr("SLEEP")},
+40 -2
View File
@@ -873,6 +873,26 @@ void MainWindow::saveStateToConfig()
changed = true;
}
if (Host::ContainsBaseSettingValue("UI", "MainWindowMaximized"))
{
const bool maximized = Host::GetBaseBoolSettingValue("UI", "MainWindowMaximized");
if (maximized != isMaximized())
{
Host::SetBaseBoolSettingValue("UI", "MainWindowMaximized", isMaximized());
changed = true;
}
}
if (Host::ContainsBaseSettingValue("UI", "MainWindowFullscreen"))
{
const bool fullscreen = Host::GetBaseBoolSettingValue("UI", "MainWindowFullscreen");
if (fullscreen != isFullScreen())
{
Host::SetBaseBoolSettingValue("UI", "MainWindowFullscreen", isFullScreen());
changed = true;
}
}
if (changed)
Host::CommitBaseSettingChanges();
}
@@ -901,6 +921,24 @@ void MainWindow::restoreStateFromConfig()
m_ui.actionViewStatusBar->setChecked(!m_ui.statusBar->isHidden());
}
}
{
if (Host::ContainsBaseSettingValue("UI", "MainWindowMaximized"))
{
const bool maximized = Host::GetBaseBoolSettingValue("UI", "MainWindowMaximized");
if (maximized)
showMaximized();
}
}
{
if (Host::ContainsBaseSettingValue("UI", "MainWindowFullscreen"))
{
const bool fullscreen = Host::GetBaseBoolSettingValue("UI", "MainWindowFullscreen");
if (fullscreen)
showFullScreen();
}
}
}
void MainWindow::updateEmulationActions(bool starting, bool running, bool stopping)
@@ -1714,7 +1752,7 @@ void MainWindow::onStartFullscreenUITriggered()
void MainWindow::onFullscreenUIStateChange(bool running)
{
m_ui.actionStartFullscreenUI->setText(running ? tr("Stop Big Picture Mode") : tr("Start Big Picture Mode"));
m_ui.actionStartFullscreenUI->setText(running ? tr("Stop Big Picture Mode") : tr("Start Big Picture &Mode"));
m_ui.actionToolbarStartFullscreenUI->setText(running ? tr("Exit Big Picture", "In Toolbar") : tr("Big Picture", "In Toolbar"));
}
@@ -2583,7 +2621,7 @@ void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main)
#ifdef DISPLAY_SURFACE_WINDOW
if (isVisible() && g_emu_thread->shouldRenderToMain())
m_display_surface->setPosition(screen()->availableGeometry().topLeft());
m_display_surface->setGeometry(screen()->geometry());
else
restoreDisplayWindowGeometryFromConfig();
+9 -2
View File
@@ -2086,7 +2086,8 @@ void QtHost::PrintCommandLineHelp(const std::string_view progname)
std::fprintf(stderr, " -version: Displays version information and exits.\n");
std::fprintf(stderr, " -batch: Enables batch mode (exits after shutting down).\n");
std::fprintf(stderr, " -nogui: Hides main window while running (implies batch mode).\n");
std::fprintf(stderr, " -portable: Force enable portable mode to store data in local PCSX2 path instead of the default configuration path.\n");
std::fprintf(stderr, " -portable: Force enable portable mode to store data in local PCSX2 path instead of the default configuration path. Overrides '-datapath'.\n");
std::fprintf(stderr, " -datapath <path>: Specify the directory to be used for all application data.\n");
std::fprintf(stderr, " -elf <file>: Overrides the boot ELF with the specified filename.\n");
std::fprintf(stderr, " -gameargs <string>: passes the specified quoted space-delimited string of launch arguments.\n");
std::fprintf(stderr, " -disc <path>: Uses the specified host DVD drive as a source.\n");
@@ -2165,6 +2166,12 @@ bool QtHost::ParseCommandLineOptions(const QStringList& args, std::shared_ptr<VM
EmuConfig.IsPortableMode = true;
continue;
}
else if (CHECK_ARG_PARAM(QStringLiteral("-datapath")))
{
std::string path = (++it)->toStdString();
EmuConfig.CustomDataPath = path;
continue;
}
else if (CHECK_ARG(QStringLiteral("-fastboot")))
{
AutoBoot(autoboot)->fast_boot = true;
@@ -2297,7 +2304,7 @@ bool QtHost::ParseCommandLineOptions(const QStringList& args, std::shared_ptr<VM
Console.Warning("Skipping autoboot due to no boot parameters.");
autoboot.reset();
}
if(autoboot && autoboot->start_turbo.value_or(false) && autoboot->start_unlimited.value_or(false))
{
Console.Warning("Both turbo and unlimited frame limit modes requested. Using unlimited.");
@@ -120,6 +120,10 @@ void AchievementSettingsWidget::updateEnableState()
const bool info = enabled && sound && dialog()->getEffectiveBoolValue("Achievements", "InfoSound", true);
const bool unlock = enabled && sound && dialog()->getEffectiveBoolValue("Achievements", "UnlockSound", true);
const bool lbsound = enabled && sound && dialog()->getEffectiveBoolValue("Achievements", "LBSubmitSound", true);
m_ui.viewProfile->setEnabled(enabled);
m_ui.loginButton->setEnabled(enabled);
m_ui.hardcoreMode->setEnabled(enabled);
m_ui.achievementNotifications->setEnabled(enabled);
m_ui.leaderboardNotifications->setEnabled(enabled);
+113 -103
View File
@@ -11,13 +11,118 @@
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="loginBox">
<property name="title">
<string>Account</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
<item>
<layout class="QGridLayout" name="acccountLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="enable">
<property name="text">
<string>Enable Achievements</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="loginStatus">
<property name="text">
<string>Username:
Login token generated at:</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
<property name="buddy">
<cstring>viewProfile</cstring>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="achievementButtons">
<item>
<widget class="QPushButton" name="viewProfile">
<property name="text">
<string>View Profile...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="loginButton">
<property name="text">
<string>Login...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gameInfoBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>75</height>
</size>
</property>
<property name="title">
<string>Game Info</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="gameInfo">
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
<property name="buddy">
<cstring>viewProfile</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="rcheevosDisclaimer">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;justify&quot;&gt;PCSX2 uses RetroAchievements as an achievement database and for tracking progress. To use achievements, please sign up for an account at &lt;a href=&quot;https://retroachievements.org/&quot;&gt;retroachievements.org&lt;/a&gt;.&lt;/p&gt;&lt;p align=&quot;justify&quot;&gt;To view the achievement list in-game, press the hotkey for &lt;span style=&quot; font-weight:600;&quot;&gt;Open Pause Menu&lt;/span&gt; and select &lt;span style=&quot; font-weight:600;&quot;&gt;Achievements&lt;/span&gt; from the menu.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::TextFormat::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>8</number>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="buddy">
<cstring>enable</cstring>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="settingsBox">
<property name="title">
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout_5">
<item row="2" column="0">
<item row="1" column="1">
<widget class="QCheckBox" name="unofficialAchievements">
<property name="text">
<string>Test Unofficial Achievements</string>
@@ -25,23 +130,16 @@
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="hardcoreMode">
<widget class="QCheckBox" name="spectatorMode">
<property name="text">
<string>Enable Hardcore Mode</string>
<string>Enable Spectator Mode</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="enable">
<widget class="QCheckBox" name="hardcoreMode">
<property name="text">
<string>Enable Achievements</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="spectatorMode">
<property name="text">
<string>Enable Spectator Mode</string>
<string>Enable Hardcore Mode</string>
</property>
</widget>
</item>
@@ -423,94 +521,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="loginBox">
<property name="title">
<string>Account</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
<item>
<widget class="QLabel" name="loginStatus">
<property name="text">
<string>Username:
Login token generated at:</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
<property name="buddy">
<cstring>viewProfile</cstring>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="achievementButtons">
<item>
<widget class="QPushButton" name="viewProfile">
<property name="text">
<string>View Profile...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="loginButton">
<property name="text">
<string>Login...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gameInfoBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>75</height>
</size>
</property>
<property name="title">
<string>Game Info</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="gameInfo">
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="rcheevosDisclaimer">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;justify&quot;&gt;PCSX2 uses RetroAchievements as an achievement database and for tracking progress. To use achievements, please sign up for an account at &lt;a href=&quot;https://retroachievements.org/&quot;&gt;retroachievements.org&lt;/a&gt;.&lt;/p&gt;&lt;p align=&quot;justify&quot;&gt;To view the achievement list in-game, press the hotkey for &lt;span style=&quot; font-weight:600;&quot;&gt;Open Pause Menu&lt;/span&gt; and select &lt;span style=&quot; font-weight:600;&quot;&gt;Achievements&lt;/span&gt; from the menu.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::TextFormat::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="margin">
<number>8</number>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@@ -528,9 +538,11 @@ Login token generated at:</string>
</widget>
<tabstops>
<tabstop>enable</tabstop>
<tabstop>viewProfile</tabstop>
<tabstop>loginButton</tabstop>
<tabstop>hardcoreMode</tabstop>
<tabstop>encoreMode</tabstop>
<tabstop>spectatorMode</tabstop>
<tabstop>encoreMode</tabstop>
<tabstop>unofficialAchievements</tabstop>
<tabstop>achievementNotifications</tabstop>
<tabstop>achievementNotificationsDuration</tabstop>
@@ -556,8 +568,6 @@ Login token generated at:</string>
<tabstop>lbSoundBrowse</tabstop>
<tabstop>lbSoundOpen</tabstop>
<tabstop>lbSoundReset</tabstop>
<tabstop>viewProfile</tabstop>
<tabstop>loginButton</tabstop>
</tabstops>
<resources>
<include location="../resources/resources.qrc"/>
+1 -5
View File
@@ -184,10 +184,6 @@ void OSDSettingsWidget::onBrowseOsdFontPathClicked()
saveOsdFontPathSetting(QDir::toNativeSeparators(selected));
});
connect(m_font_picker, &QObject::destroyed, this, [this]() {
m_font_picker = nullptr;
});
m_font_picker->show();
}
@@ -313,4 +309,4 @@ void OSDSettingsWidget::onDeselectAllClicked()
m_ui.warnAboutUnsafeSettings->setChecked(true);
}
#include "moc_OSDSettingsWidget.cpp"
#include "moc_OSDSettingsWidget.cpp"
File diff suppressed because it is too large Load Diff
+1
View File
@@ -1403,6 +1403,7 @@ struct Pcsx2Config
std::string CurrentBlockdump;
std::string CurrentIRX;
std::string CurrentGameArgs;
std::string CustomDataPath;
AspectRatioType CurrentAspectRatio = AspectRatioType::RAuto4_3_3_2;
// Fall back aspect ratio for games that have patches (when AspectRatioType::RAuto4_3_3_2) is active.
float CurrentCustomAspectRatio = 0.f;
+1 -1
View File
@@ -876,7 +876,7 @@ static __fi void rcntEndGate(bool isVblank, u64 sCycle)
isVblank ? "vblank" : "hblank", counters[i].mode.GateMode, counters[i].count);
counters[i].count = 0;
counters[i].target &= 0xffff;
counters[i].startCycle = sCycle & ~(counters[i].rate - 1);
counters[i].startCycle = sCycle & ~(static_cast<u64>(counters[i].rate - 1));
break;
}
}
+4 -3
View File
@@ -49,7 +49,8 @@ std::vector<std::unique_ptr<BiosThread>> getIOPThreads()
return {};
}
data.stackTop = iopMemRead32(item + 0x3c);
data.stacMem = iopMemRead32(item + 0x3c);
data.stackSize = iopMemRead32(item + 0x40);
data.status = iopMemRead8(item + 0xc);
data.tid = iopMemRead16(item + 0xa);
data.entrypoint = iopMemRead32(item + 0x38);
@@ -57,9 +58,9 @@ std::vector<std::unique_ptr<BiosThread>> getIOPThreads()
data.waitId = iopMemRead32(item + 0x20);
data.initPriority = iopMemRead16(item + 0xe);
data.SavedSP = iopMemRead32(item + 0x10);
data.regCtx = iopMemRead32(item + 0x10);
data.PC = iopMemRead32(data.SavedSP + 0x8c);
data.PC = iopMemRead32(data.regCtx + 0x8c);
threads.emplace_back(std::make_unique<IOPThread>(data));
+29 -16
View File
@@ -18,26 +18,37 @@ enum class ThreadStatus
THS_DORMANT = 0x10,
};
struct EEInternalCtx
{
u32 sa;
u32 fcsr;
u32 float_thing;
u32 unk;
// gpr excluding $zero
// k0/k1 contains hi, hi1, lo, lo1
u128 gpr[31];
float fpr[32];
};
struct EEInternalThread
{ // internal struct
u32 prev;
u32 next;
int status;
u32 entry;
u32 stack;
u32 resumeAddr; // address to return to when switching
u32 regCtx; // points to the saved regs on stack
u32 gpReg;
short currentPriority;
short initPriority;
short currentPriority;
int waitType;
int semaId;
int wakeupCount;
int attr;
int option;
u32 entry_init;
u32 entry;
int argc;
u32 argstring;
u32 stack_bottom; //FIXME
u32 stackMem;
int stackSize;
u32 root;
u32 heap_base;
@@ -48,8 +59,9 @@ struct IOPInternalThread
{
u32 tid;
u32 PC;
u32 stackTop;
u32 SavedSP;
u32 stacMem;
u32 stackSize;
u32 regCtx;
u32 status;
u32 entrypoint;
u32 waitstate;
@@ -71,14 +83,13 @@ enum class IOPWaitStatus
enum class EEWaitStatus
{
WAIT_NONE = 0,
WAIT_WAKEUP_REQ = 1,
WAIT_SLEEP = 1,
WAIT_SEMA = 2,
};
enum class WaitState
{
NONE,
WAKEUP_REQ,
SEMA,
SLEEP,
DELAY,
@@ -98,8 +109,10 @@ public:
[[nodiscard]] virtual WaitState Wait() const = 0;
[[nodiscard]] virtual u32 WaitId() const = 0;
[[nodiscard]] virtual u32 EntryPoint() const = 0;
[[nodiscard]] virtual u32 StackTop() const = 0;
[[nodiscard]] virtual u32 Priority() const = 0;
// Only call RegCtx on threads that aren't running
[[nodiscard]] virtual u32 RegCtx() const = 0;
};
class EEThread : public BiosThread
@@ -113,7 +126,7 @@ public:
~EEThread() override = default;
[[nodiscard]] u32 TID() const override { return tid; };
[[nodiscard]] u32 PC() const override { return data.entry; };
[[nodiscard]] u32 PC() const override { return data.resumeAddr; };
[[nodiscard]] ThreadStatus Status() const override { return static_cast<ThreadStatus>(data.status); };
[[nodiscard]] WaitState Wait() const override
{
@@ -122,17 +135,17 @@ public:
{
case EEWaitStatus::WAIT_NONE:
return WaitState::NONE;
case EEWaitStatus::WAIT_WAKEUP_REQ:
return WaitState::WAKEUP_REQ;
case EEWaitStatus::WAIT_SLEEP:
return WaitState::SLEEP;
case EEWaitStatus::WAIT_SEMA:
return WaitState::SEMA;
}
return WaitState::NONE;
};
[[nodiscard]] u32 WaitId() const override { return data.semaId; };
[[nodiscard]] u32 EntryPoint() const override { return data.entry_init; };
[[nodiscard]] u32 StackTop() const override { return data.stack; };
[[nodiscard]] u32 EntryPoint() const override { return data.entry; };
[[nodiscard]] u32 Priority() const override { return data.currentPriority; };
[[nodiscard]] u32 RegCtx() const override { return data.regCtx; };
private:
u32 tid;
@@ -175,8 +188,8 @@ public:
};
[[nodiscard]] u32 WaitId() const override { return data.waitId; };
[[nodiscard]] u32 EntryPoint() const override { return data.entrypoint; };
[[nodiscard]] u32 StackTop() const override { return data.stackTop; };
[[nodiscard]] u32 Priority() const override { return data.initPriority; };
[[nodiscard]] u32 RegCtx() const override { return data.regCtx; };
private:
IOPInternalThread data;
+33
View File
@@ -708,6 +708,23 @@ std::vector<std::unique_ptr<BiosThread>> R5900DebugInterface::GetThreadList() co
return getEEThreads();
}
std::vector<MipsStackWalk::StackFrame> R5900DebugInterface::StackTrace(const BiosThread& thread)
{
if (thread.Status() == ThreadStatus::THS_RUN)
{
return MipsStackWalk::Walk(this, getPC(), getRegister(0, 31), getRegister(0, 29),
thread.EntryPoint());
}
EEInternalCtx* ctx = static_cast<EEInternalCtx*>(PSM(thread.RegCtx()));
u32 pc = thread.PC();
// $zero is not in the array so subtract 1
u32 ra = ctx->gpr[31 - 1]._u32[0];
u32 sp = ctx->gpr[29 - 1]._u32[0];
return MipsStackWalk::Walk(this, pc, ra, sp, thread.EntryPoint());
}
std::vector<IopMod> R5900DebugInterface::GetModuleList() const
{
return {};
@@ -1049,6 +1066,22 @@ std::vector<std::unique_ptr<BiosThread>> R3000DebugInterface::GetThreadList() co
return getIOPThreads();
}
std::vector<MipsStackWalk::StackFrame> R3000DebugInterface::StackTrace(const BiosThread& thread)
{
if (thread.Status() == ThreadStatus::THS_RUN)
{
return MipsStackWalk::Walk(this, getPC(), getRegister(0, 31), getRegister(0, 29),
thread.EntryPoint());
}
u32 p = thread.RegCtx();
u32 pc = Read32(p + 0x8c);
u32 ra = Read32(p + 0x7c);
u32 sp = Read32(p + 0x74);
return MipsStackWalk::Walk(this, pc, ra, sp, thread.EntryPoint());
}
std::vector<IopMod> R3000DebugInterface::GetModuleList() const
{
return getIOPModules();
+4
View File
@@ -7,6 +7,7 @@
#include "ExpressionParser.h"
#include "SymbolGuardian.h"
#include "SymbolImporter.h"
#include "MipsStackWalk.h"
#include "common/MemoryInterface.h"
@@ -72,6 +73,7 @@ public:
virtual SymbolGuardian& GetSymbolGuardian() const = 0;
virtual SymbolImporter* GetSymbolImporter() const = 0;
virtual std::vector<std::unique_ptr<BiosThread>> GetThreadList() const = 0;
virtual std::vector<MipsStackWalk::StackFrame> StackTrace(const BiosThread& thread) = 0;
virtual std::vector<IopMod> GetModuleList() const = 0;
bool isAlive();
@@ -135,6 +137,7 @@ public:
SymbolGuardian& GetSymbolGuardian() const override;
SymbolImporter* GetSymbolImporter() const override;
std::vector<std::unique_ptr<BiosThread>> GetThreadList() const override;
std::vector<MipsStackWalk::StackFrame> StackTrace(const BiosThread& thread) override;
std::vector<IopMod> GetModuleList() const override;
std::string disasm(u32 address, bool simplify) override;
@@ -180,6 +183,7 @@ public:
SymbolGuardian& GetSymbolGuardian() const override;
SymbolImporter* GetSymbolImporter() const override;
std::vector<std::unique_ptr<BiosThread>> GetThreadList() const override;
std::vector<MipsStackWalk::StackFrame> StackTrace(const BiosThread& thread) override;
std::vector<IopMod> GetModuleList() const override;
std::string disasm(u32 address, bool simplify) override;
+5 -2
View File
@@ -103,7 +103,10 @@ namespace MipsStackWalk
// TODO: Check if found entry is in the same symbol? Might be wrong sometimes...
int ra_offset = -1;
const u32 start = frame.pc;
// The instruction pointed to by pc hasn't been executed yet,
// so we don't want to consider it here
const u32 start = frame.pc - 4;
u32 stop = entry;
if (entry == INVALIDTARGET)
@@ -183,7 +186,7 @@ namespace MipsStackWalk
return ScanForEntry(cpu, frame, newPossibleEntry, ra);
}
std::vector<StackFrame> Walk(DebugInterface* cpu, u32 pc, u32 ra, u32 sp, u32 threadEntry, u32 threadStackTop)
std::vector<StackFrame> Walk(DebugInterface* cpu, u32 pc, u32 ra, u32 sp, u32 threadEntry)
{
std::vector<StackFrame> frames;
StackFrame current;
+1 -1
View File
@@ -20,5 +20,5 @@ namespace MipsStackWalk {
int stackSize;
};
std::vector<StackFrame> Walk(DebugInterface* cpu, u32 pc, u32 ra, u32 sp, u32 threadEntry, u32 threadStackTop);
std::vector<StackFrame> Walk(DebugInterface* cpu, u32 pc, u32 ra, u32 sp, u32 threadEntry);
};
+4 -4
View File
@@ -91,11 +91,11 @@ void GSDrawingContext::UpdateScissor()
scissor.in = rscissor + GSVector4i::cxpr(0, 0, 1, 1);
// Fixed-point scissor min/max, used for rejecting primitives which are entirely outside.
scissor.cull = rscissor.sll32<4>();
// Add half a pixel around the edges for upscaling and lines/points.
scissor.cull = rscissor.sll32<4>() + GSVector4i(-8, -8, 8, 8);
// Offset applied to vertices for culling, zw is for native resolution culling
// We want to round subpixels down, because at least one pixel gets filled per scanline.
scissor.xyof = GSVector4i::loadl(&XYOFFSET.U64).xyxy().sub32(GSVector4i::cxpr(0, 0, 15, 15));
// Offset applied to vertices for culling.
scissor.xyof = GSVector4i::loadl(&XYOFFSET.U64).xyxy();
}
GIFRegTEX0 GSDrawingContext::GetSizeFixedTEX0(const GSVector4& st, bool linear, bool mipmap) const
+58 -74
View File
@@ -1279,12 +1279,12 @@ void GSState::DumpTransferList(const std::string& filename)
(*file) << std::endl;
// clear, EE->GS, or GS->GS
(*file) << LIST_ITEM << "type: " << (transfer.zero_clear ? "clear" : ((transfer.transfer_type == EEGS_TransferType::EE_to_GS) ? "EE_to_GS" : "GS_to_GS")) << std::endl;
(*file) << LIST_ITEM << "type: " << ((transfer.transfer_type == EEGS_TransferType::Clear) ? "clear" : ((transfer.transfer_type == EEGS_TransferType::EE_to_GS) ? "EE_to_GS" : "GS_to_GS")) << std::endl;
// Dump BITBLTBUF
(*file) << INDENT << "BITBLTBUF: " << OPEN_MAP;
const bool gs_to_gs = (transfer.transfer_type == EEGS_TransferType::GS_to_GS) && !transfer.zero_clear;
const bool gs_to_gs = (transfer.transfer_type == EEGS_TransferType::GS_to_GS) && transfer.transfer_type != EEGS_TransferType::Clear;
if (gs_to_gs)
{
@@ -1330,11 +1330,11 @@ void GSState::DumpTransferImages()
const GSUploadQueue& transfer = m_draw_transfers[i];
std::string filename;
if ((transfer.transfer_type == EEGS_TransferType::EE_to_GS) || transfer.zero_clear)
if ((transfer.transfer_type == EEGS_TransferType::EE_to_GS) || transfer.transfer_type == EEGS_TransferType::Clear)
{
// clear or EE->GS: only the destination info is relevant.
filename = GetDrawDumpPath("%05lld_transfer%02d_%s_%04x_%d_%s_%d_%d_%d_%d.png",
s_n, transfer_n++, (transfer.zero_clear ? "clear" : "EE_to_GS"), transfer.blit.DBP, transfer.blit.DBW,
s_n, transfer_n++, ((transfer.transfer_type == EEGS_TransferType::Clear) ? "clear" : "EE_to_GS"), transfer.blit.DBP, transfer.blit.DBW,
GSUtil::GetPSMName(transfer.blit.DPSM), transfer.rect.x, transfer.rect.y, transfer.rect.z, transfer.rect.w);
}
else
@@ -2403,7 +2403,7 @@ void GSState::FlushWrite()
if (m_draw_transfers.size() > 0 && m_tr.m_blit.DBP == m_draw_transfers.back().blit.DBP)
{
m_draw_transfers.back().rect = r;
m_draw_transfers.back().rect = m_draw_transfers.back().rect.runion(r);
}
}
}
@@ -2666,7 +2666,6 @@ void GSState::FlushPrim()
GSVector4i* RESTRICT vert_ptr = (GSVector4i*)&m_vertex->buff[i];
GSVector4i v = vert_ptr[1];
v = v.xxxx().u16to32().sub32(m_xyof);
v = v.blend32<12>(v.sra32<4>());
m_vertex->xy[i & 3] = v;
m_vertex->xy_tail = unused;
}
@@ -2912,12 +2911,11 @@ void GSState::Write(const u8* mem, int len)
m_draw_transfers.pop_back();
transfer.rect = transfer.rect.runion(r);
transfer.draw = s_n;
transfer.zero_clear = false;
m_draw_transfers.push_back(transfer);
}
else
{
const GSUploadQueue new_transfer = {blit, r, s_n, false, EEGS_TransferType::EE_to_GS};
const GSUploadQueue new_transfer = {blit, s_n, r, EEGS_TransferType::EE_to_GS};
m_draw_transfers.push_back(new_transfer);
}
@@ -3112,12 +3110,11 @@ void GSState::Move()
m_draw_transfers.pop_back();
transfer.rect = transfer.rect.runion(r);
transfer.draw = s_n;
transfer.zero_clear = false;
m_draw_transfers.push_back(transfer);
}
else
{
const GSUploadQueue new_transfer = {m_env.BITBLTBUF, r, s_n, false, EEGS_TransferType::GS_to_GS};
const GSUploadQueue new_transfer = {m_env.BITBLTBUF, s_n, r, EEGS_TransferType::GS_to_GS};
m_draw_transfers.push_back(new_transfer);
}
@@ -3790,10 +3787,8 @@ void GSState::UpdateContext()
void GSState::UpdateScissor()
{
m_scissor_cull_min = m_context->scissor.cull.xyxy();
m_scissor_cull_max = m_context->scissor.cull.zwzw();
m_xyof = m_context->scissor.xyof;
m_scissor_invalid = !m_context->scissor.in.gt32(m_context->scissor.in.zwzw()).allfalse();
m_scissor_invalid = m_context->scissor.in.rempty();
}
void GSState::UpdateVertexKick()
@@ -5841,6 +5836,7 @@ template <u32 prim, bool auto_flush>
__forceinline void GSState::VertexKick(u32 skip)
{
constexpr u32 n = NumIndicesForPrim(prim);
constexpr int primclass = GSUtil::GetPrimClass(prim);
static_assert(n > 0);
pxAssert(m_vertex->tail < m_vertex->maxcount + 3);
@@ -5884,11 +5880,7 @@ __forceinline void GSState::VertexKick(u32 skip)
// We maintain the X/Y coordinates for the last 4 vertices, as well as the head for triangle fans, so we can compute
// the min/max, and cull degenerate triangles, which saves draws in some cases. Why 4? Mod 4 is cheaper than Mod 3.
// These vertices are a full vector containing <X_Fixed_Point, Y_Fixed_Point, X_Integer, Y_Integer>. We use the
// integer coordinates for culling at native resolution, and the fixed point for all others. The XY offset has to be
// applied, then we split it into the fixed/integer portions.
const GSVector4i xy_ofs = new_v1.xxxx().u16to32().sub32(m_xyof);
const GSVector4i xy = xy_ofs.blend32<12>(xy_ofs.sra32<4>());
const GSVector4i xy = new_v1.xxxx().u16to32().sub32(m_xyof);
m_vertex->xy[xy_tail & 3] = xy;
// Backup head for triangle fans so we can read it later, otherwise it'll get lost after the 4th vertex.
@@ -5918,73 +5910,66 @@ __forceinline void GSState::VertexKick(u32 skip)
// Skip draws when scissor is out of range (i.e. bottom-right is less than top-left), since everything will get clipped.
skip |= static_cast<u32>(m_scissor_invalid);
GSVector4i pmin, pmax;
GSVector4i bbox;
if (skip == 0)
{
const GSVector4i v0 = m_vertex->xy[(xy_tail - 1) & 3];
const GSVector4i v1 = m_vertex->xy[(xy_tail - 2) & 3];
const GSVector4i v2 = (prim == GS_TRIANGLEFAN) ? m_vertex->xyhead : m_vertex->xy[(xy_tail - 3) & 3];
switch (prim)
if constexpr (n == 1)
{
case GS_POINTLIST:
pmin = v0;
pmax = v0;
break;
case GS_LINELIST:
case GS_LINESTRIP:
case GS_SPRITE:
pmin = v0.min_i32(v1);
pmax = v0.max_i32(v1);
break;
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
pmin = v0.min_i32(v1.min_i32(v2));
pmax = v0.max_i32(v1.max_i32(v2));
break;
default:
break;
bbox = v0;
}
else if constexpr (n == 2)
{
bbox = v0.runion(v1);
}
else if constexpr (n == 3)
{
bbox = v0.runion(v1).runion(v2);
}
GSVector4i test = pmax.lt32(m_scissor_cull_min) | pmin.gt32(m_scissor_cull_max);
switch (prim)
if constexpr (primclass == GS_TRIANGLE_CLASS || primclass == GS_SPRITE_CLASS)
{
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
case GS_SPRITE:
if (m_nativeres)
{
// Discard degenerate triangles which don't cover at least one pixel. Since the vertices are in native
// resolution space, we can use the integer locations. When upscaling, we can't, because a primitive which
// does not span a single pixel at 1x may span multiple pixels at higher resolutions.
const GSVector4i degen_test = pmin.eq32(pmax);
test |= m_nativeres ? degen_test.zwzw() : degen_test;
// For triangles and sprites at native res take the interior pixel centers.
const GSVector4i interior = (bbox + GSVector4i(0xF, 0xF, -1, -1)) & GSVector4i(~0xF);
bbox = interior + GSVector4i(0, 0, 1, 1); // +1 to bottom/right so empty test works correctly.
}
else
{
// For upscaling, remove bottom/right subtexels.
bbox -= ((bbox & GSVector4i(0xF)) == GSVector4i(0)) & GSVector4i(0, 0, 1, 1);
}
// For AA1 triangles and lines, expand the bounds by 1 pixel on all sides.
// Note: redundant check for the AA1 flag to avoid calling a function if not needed.
if (PRIM->AA1 && IsCoverageAlphaSupported())
{
bbox += GSVector4i(-0x10, -0x10, 0x10, 0x10);
}
break;
default:
break;
}
switch (prim)
// Do scissor test.
const GSVector4i bbox_ex = bbox + GSVector4i(0, 0, 1, 1); // Exclusive coords for the scissor test.
const GSVector4i& scissor = m_context->scissor.cull;
u32 test = static_cast<u32>(!bbox_ex.rintersects(scissor));
// Test for empty bbox.
if constexpr (primclass == GS_TRIANGLE_CLASS || primclass == GS_SPRITE_CLASS)
{
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
test = (test | v0.eq64(v1)) | (v1.eq64(v2) | v0.eq64(v2));
break;
default:
break;
test |= static_cast<u32>(bbox.rempty());
}
#ifndef ARCH_ARM64
// We only care about the xy passing the skip test. zw is the offset coordinates for native culling.
skip |= test.mask() & 0xff;
#else
// mask() is slow on ARM, so just pull the bits out instead, thankfully we only care about the first 4 bytes.
skip |= (static_cast<u64>(test.extract64<0>()) & UINT64_C(0x8080808080808080)) != 0;
#endif
// Test for degenerate triangle.
if constexpr (primclass == GS_TRIANGLE_CLASS)
{
test |= static_cast<u32>(v0.eq(v1)) | static_cast<u32>(v1.eq(v2)) | static_cast<u32>(v0.eq(v2));
}
skip |= test;
}
if (skip != 0)
@@ -6094,13 +6079,12 @@ __forceinline void GSState::VertexKick(u32 skip)
ASSUME(0);
}
// Update rectangle for the current draw. We can use the re-integer coordinates from min/max here.
const GSVector4i draw_min = pmin.zwzw();
const GSVector4i draw_max = pmax;
if (m_index->tail != n)
temp_draw_rect = temp_draw_rect.min_i32(draw_min).blend32<12>(temp_draw_rect.max_i32(draw_max));
// Update rectangle for the current draw. Needs exclusive endpoints.
const GSVector4i draw_rect = bbox.sra32<4>() + GSVector4i(0, 0, 1, 1);
if (m_vertex->tail != n)
temp_draw_rect = temp_draw_rect.runion(draw_rect);
else
temp_draw_rect = draw_min.blend32<12>(draw_max);
temp_draw_rect = draw_rect;
temp_draw_rect = temp_draw_rect.rintersect(m_context->scissor.in);
constexpr u32 max_vertices = MaxVerticesForPrim(prim);
+3 -5
View File
@@ -131,8 +131,6 @@ protected:
GSVertex m_v = {};
float m_q = 1.0f;
GSVector4i m_scissor_cull_min = {};
GSVector4i m_scissor_cull_max = {};
GSVector4i m_xyof = {};
int m_used_buffers_idx = 0;
int m_current_buffer_idx = 0;
@@ -260,15 +258,15 @@ public:
{
EE_to_GS,
GS_to_GS,
GS_to_EE
GS_to_EE,
Clear
};
struct GSUploadQueue
{
GIFRegBITBLTBUF blit;
GSVector4i rect;
u64 draw;
bool zero_clear;
GSVector4i rect;
EEGS_TransferType transfer_type;
};
+24
View File
@@ -339,3 +339,27 @@ const char* GSUtil::GetPSMName(int psm)
}
return "BAD_PSM";
}
bool GSUtil::IsValidPSM(int psm)
{
switch (psm)
{
case PSMCT32:
case PSMCT24:
case PSMCT16:
case PSMCT16S:
case PSMT8:
case PSMT4:
case PSMT8H:
case PSMT4HL:
case PSMT4HH:
case PSMZ32:
case PSMZ24:
case PSMZ16:
case PSMZ16S:
case PSGPU24:
return true;
default:
return false;
}
}
+3
View File
@@ -6,6 +6,7 @@
#include "GS.h"
#include "GSRegs.h"
#include "GSPerfMon.h"
#include <climits>
class GSUtil
{
@@ -28,6 +29,8 @@ public:
static const char* GetACName(u32 ac);
static const char* GetPerfMonCounterName(GSPerfMon::counter_t counter, bool hw = true);
static bool IsValidPSM(int psm);
static const u32* HasSharedBitsPtr(u32 dpsm);
static bool HasSharedBits(u32 spsm, const u32* ptr);
static bool HasSharedBits(u32 spsm, u32 dpsm);
+58 -3
View File
@@ -1559,8 +1559,51 @@ static void DumpBlendMultipass(DrawConfigWriter& out, const GSHWDrawConfig::Blen
DumpBlendState(out.WithIndent(), bmp.blend);
}
template<typename T, typename U = int>
static void DumpVector4(DrawConfigWriter& out, const char* name, const T& val)
{
out.WriteLn("{}: [{}, {}, {}, {}]", name, val.x, val.y, val.z, val.w);
};
template<typename T>
static void DumpVector2(DrawConfigWriter& out, const char* name, const T& val)
{
out.WriteLn("{}: [{}, {}]", name, val.x, val.y);
};
static void DumpPSConstantBuffer(DrawConfigWriter& out, const GSHWDrawConfig::PSConstantBuffer& cb)
{
DumpVector4(out, "FogColor_AREF", cb.FogColor_AREF);
DumpVector4(out, "WH", cb.WH);
DumpVector4(out, "TA_MaxDepth_Af", cb.TA_MaxDepth_Af);
DumpVector4(out, "FbMask", cb.FbMask);
DumpVector4(out, "HalfTexel", cb.HalfTexel);
DumpVector4(out, "MinMax", cb.MinMax);
DumpVector4(out, "LODParams", cb.LODParams);
DumpVector4(out, "STRange", cb.STRange);
DumpVector4(out, "ChannelShuffle", cb.ChannelShuffle);
DumpVector2(out, "ChannelShuffleOffset", cb.ChannelShuffleOffset);
DumpVector2(out, "TCOffsetHack", cb.TCOffsetHack);
DumpVector2(out, "STScale", cb.STScale);
DumpVector4(out, "DitherMatrix_0", cb.DitherMatrix[0]);
DumpVector4(out, "DitherMatrix_1", cb.DitherMatrix[1]);
DumpVector4(out, "DitherMatrix_2", cb.DitherMatrix[2]);
DumpVector4(out, "DitherMatrix_3", cb.DitherMatrix[3]);
DumpVector4(out, "ScaleFactor", cb.ScaleFactor);
}
static void DumpVSConstantBuffer(DrawConfigWriter& out, const GSHWDrawConfig::VSConstantBuffer& cb)
{
DumpVector2(out, "vertex_scale", cb.vertex_scale);
DumpVector2(out, "vertex_offset", cb.vertex_offset);
DumpVector2(out, "texture_scale", cb.texture_scale);
DumpVector2(out, "texture_offset", cb.texture_offset);
DumpVector2(out, "point_size", cb.point_size);
DumpVector2(out, "max_depth", cb.max_depth);
}
static void DumpConfig(DrawConfigWriter& out, const GSHWDrawConfig& conf,
bool ps, bool vs, bool bs, bool dss, bool ss, bool asp, bool bmp)
bool ps, bool vs, bool bs, bool dss, bool ss, bool asp, bool bmp, bool cbvs, bool cbps)
{
out.WriteLn("topology: {} ({})", GetTopologyName(conf.topology), static_cast<u32>(conf.topology));
out.WriteLn("require_one_barrier: {}", conf.require_one_barrier);
@@ -1612,15 +1655,27 @@ static void DumpConfig(DrawConfigWriter& out, const GSHWDrawConfig& conf,
out.WriteLn("blend_multi_pass:");
DumpBlendMultipass(out.WithIndent(), conf.blend_multi_pass);
}
if (cbvs)
{
out.WriteLn("cb_vs:");
DumpVSConstantBuffer(out.WithIndent(), conf.cb_vs);
}
if (cbps)
{
out.WriteLn("cb_ps:");
DumpPSConstantBuffer(out.WithIndent(), conf.cb_ps);
}
}
void GSHWDrawConfig::DumpConfig(const std::string& path, const GSHWDrawConfig& conf,
bool ps, bool vs, bool bs, bool dss, bool ss, bool asp, bool bmp)
bool ps, bool vs, bool bs, bool dss, bool ss, bool asp, bool bmp, bool cbvs, bool cbps)
{
if (FileSystem::ManagedCFilePtr file = FileSystem::OpenManagedCFile(path.c_str(), "w"))
{
DrawConfigWriter writer;
::DumpConfig(writer, conf, ps, vs, bs, dss, ss, asp, bmp);
::DumpConfig(writer, conf, ps, vs, bs, dss, ss, asp, bmp, cbvs, cbps);
fwrite(writer.buffer.data(), 1, writer.buffer.size(), file.get());
}
}
+2 -1
View File
@@ -879,7 +879,8 @@ struct alignas(16) GSHWDrawConfig
// Dumping
static void DumpConfig(const std::string& path, const GSHWDrawConfig& conf,
bool ps = true, bool vs = true, bool bs = true, bool dss = true, bool ss = true, bool asp = true, bool bmp = true);
bool ps = true, bool vs = true, bool bs = true, bool dss = true, bool ss = true, bool asp = true, bool bmp = true,
bool cbvs = true, bool cbps = true);
};
static inline u32 GetExpansionFactor(GSHWDrawConfig::VSExpand expand)
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#include "GSDirtyRect.h"
#include <climits>
#include <vector>
GSDirtyRect::GSDirtyRect() :
+1
View File
@@ -4,6 +4,7 @@
#pragma once
#include "common/AlignedMalloc.h"
#include <climits>
template <class T>
struct Element
+1 -1
View File
@@ -718,7 +718,7 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
const GSTexture* current = g_gs_device->GetCurrent();
const GSVector2i internal_res = GetInternalResolution();
if (current->GetWidth() > internal_res.x || current->GetHeight() > internal_res.y)
if (current && (current->GetWidth() > internal_res.x || current->GetHeight() > internal_res.y))
g_gs_device->Resize(internal_res.x, internal_res.y);
}
+29 -5
View File
@@ -466,28 +466,52 @@ GSRendererType D3D::GetPreferredRenderer()
}
}
wil::com_ptr_nothrow<ID3DBlob> D3D::CompileShader(D3D::ShaderType type, D3D_FEATURE_LEVEL feature_level, bool debug,
const char* D3D::ShaderModelToCacheString(D3D::ShaderModel shader_model)
{
switch (shader_model)
{
case ShaderModel::SM40:
return "sm40";
case ShaderModel::SM41:
return "sm41";
case ShaderModel::SM50:
return "sm50";
case ShaderModel::SM51:
return "sm51";
default:
return "unk";
}
}
wil::com_ptr_nothrow<ID3DBlob> D3D::CompileShader(D3D::ShaderType type, D3D::ShaderModel shader_model, bool debug,
const std::string_view code, const D3D_SHADER_MACRO* macros /* = nullptr */,
const char* entry_point /* = "main" */)
{
const char* target;
switch (feature_level)
switch (shader_model)
{
case D3D_FEATURE_LEVEL_10_0:
case ShaderModel::SM40:
{
static constexpr std::array<const char*, 4> targets = {{"vs_4_0", "ps_4_0", "cs_4_0"}};
target = targets[static_cast<int>(type)];
}
break;
case D3D_FEATURE_LEVEL_11_0:
case ShaderModel::SM41:
{
static constexpr std::array<const char*, 4> targets = {{"vs_4_1", "ps_4_1", "cs_4_1"}};
target = targets[static_cast<int>(type)];
}
break;
case ShaderModel::SM50:
{
static constexpr std::array<const char*, 4> targets = {{"vs_5_0", "ps_5_0", "cs_5_0"}};
target = targets[static_cast<int>(type)];
}
break;
case D3D_FEATURE_LEVEL_11_1:
case ShaderModel::SM51:
default:
{
static constexpr std::array<const char*, 4> targets = {{"vs_5_1", "ps_5_1", "cs_5_1"}};
+11 -1
View File
@@ -63,6 +63,16 @@ namespace D3D
Compute
};
wil::com_ptr_nothrow<ID3DBlob> CompileShader(ShaderType type, D3D_FEATURE_LEVEL feature_level, bool debug,
enum class ShaderModel
{
SM40 = 0x40, // DX11 FL 10_0
SM41 = 0x41, // DX11 FL 10_1
SM50 = 0x50, // DX11 FL 11_0
SM51 = 0x51, // DX12
};
const char* ShaderModelToCacheString(ShaderModel shader_model);
wil::com_ptr_nothrow<ID3DBlob> CompileShader(ShaderType type, ShaderModel shader_model, bool debug,
const std::string_view code, const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
}; // namespace D3D
+20 -14
View File
@@ -56,12 +56,27 @@ bool D3D11ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const
bool D3D11ShaderCache::Open(D3D_FEATURE_LEVEL feature_level, bool debug)
{
m_feature_level = feature_level;
switch (feature_level)
{
case D3D_FEATURE_LEVEL_10_0:
m_shader_model = D3D::ShaderModel::SM40;
break;
case D3D_FEATURE_LEVEL_10_1:
m_shader_model = D3D::ShaderModel::SM41;
break;
case D3D_FEATURE_LEVEL_11_0:
m_shader_model = D3D::ShaderModel::SM50;
break;
default:
pxAssert(false);
return false;
}
m_debug = debug;
if (!GSConfig.DisableShaderCache)
{
const std::string base_filename = GetCacheBaseFileName(feature_level, debug);
const std::string base_filename = GetCacheBaseFileName(m_shader_model, debug);
const std::string index_filename = base_filename + ".idx";
const std::string blob_filename = base_filename + ".bin";
@@ -198,19 +213,10 @@ bool D3D11ShaderCache::ReadExisting(const std::string& index_filename, const std
return true;
}
std::string D3D11ShaderCache::GetCacheBaseFileName(D3D_FEATURE_LEVEL feature_level, bool debug)
std::string D3D11ShaderCache::GetCacheBaseFileName(D3D::ShaderModel shader_model, bool debug)
{
std::string base_filename = "d3d_shaders_";
switch (feature_level)
{
case D3D_FEATURE_LEVEL_11_0:
base_filename += "sm50";
break;
default:
base_filename += "unk";
break;
}
base_filename += D3D::ShaderModelToCacheString(shader_model);
if (debug)
base_filename += "_debug";
@@ -400,7 +406,7 @@ wil::com_ptr_nothrow<ID3DBlob> D3D11ShaderCache::CompileAndAddShaderBlob(const C
const std::string_view shader_code, const D3D_SHADER_MACRO* macros, const char* entry_point)
{
wil::com_ptr_nothrow<ID3DBlob> blob =
D3D::CompileShader(key.shader_type, m_feature_level, m_debug, shader_code, macros, entry_point);
D3D::CompileShader(key.shader_type, m_shader_model, m_debug, shader_code, macros, entry_point);
if (!blob)
return {};
+2 -3
View File
@@ -16,7 +16,6 @@ public:
D3D11ShaderCache();
~D3D11ShaderCache();
D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; }
bool UsingDebugShaders() const { return m_debug; }
bool Open(D3D_FEATURE_LEVEL feature_level, bool debug);
@@ -74,7 +73,7 @@ private:
using CacheIndex = std::unordered_map<CacheIndexKey, CacheIndexData, CacheIndexEntryHasher>;
static std::string GetCacheBaseFileName(D3D_FEATURE_LEVEL feature_level, bool debug);
static std::string GetCacheBaseFileName(D3D::ShaderModel shader_mode, bool debug);
static CacheIndexKey GetCacheKey(D3D::ShaderType type, const std::string_view shader_code,
const D3D_SHADER_MACRO* macros, const char* entry_point);
@@ -89,6 +88,6 @@ private:
CacheIndex m_index;
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0;
D3D::ShaderModel m_shader_model = D3D::ShaderModel::SM50;
bool m_debug = false;
};
+65 -52
View File
@@ -57,7 +57,7 @@ GSDevice11::GSDevice11()
m_features.primitive_id = true;
m_features.texture_barrier = false;
m_features.multidraw_fb_copy = GSConfig.OverrideTextureBarriers != 0;
m_features.multidraw_fb_copy = false;
m_features.provoking_vertex_last = false;
m_features.point_expand = false;
m_features.line_expand = false;
@@ -68,7 +68,8 @@ GSDevice11::GSDevice11()
m_features.stencil_buffer = true;
m_features.cas_sharpening = true;
m_features.test_and_sample_depth = false;
m_features.depth_feedback = true;
m_features.depth_feedback = false;
m_features.aa1 = false;
}
GSDevice11::~GSDevice11() = default;
@@ -636,16 +637,19 @@ void GSDevice11::Destroy()
void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
{
// Check these first as others depend on them.
m_features.multidraw_fb_copy = GSConfig.OverrideTextureBarriers != 0;
m_features.vs_expand = (!GSConfig.DisableVertexShaderExpand && m_feature_level >= D3D_FEATURE_LEVEL_11_0);
// Check all three formats, since the feature means any can be used.
m_features.dxt_textures = SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC1_UNORM) &&
SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC2_UNORM) &&
SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC3_UNORM);
m_features.bptc_textures = SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC7_UNORM);
m_features.vs_expand = (!GSConfig.DisableVertexShaderExpand && m_feature_level >= D3D_FEATURE_LEVEL_11_0);
m_features.cas_sharpening = (m_feature_level >= D3D_FEATURE_LEVEL_11_0);
m_features.test_and_sample_depth = (m_feature_level >= D3D_FEATURE_LEVEL_11_0);
m_features.depth_feedback = m_features.feedback_loops();
m_features.aa1 = GSConfig.HWAA1 && m_features.vs_expand && m_features.feedback_loops();
m_max_texture_size = (m_feature_level >= D3D_FEATURE_LEVEL_11_0) ?
@@ -2835,7 +2839,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
}
// Destination Alpha Setup
const bool multidraw_fb_copy = m_features.multidraw_fb_copy && (config.require_one_barrier || config.require_full_barrier);
const bool need_barrier = config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy);
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking)
{
primid_texture = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::PrimID, false);
@@ -2849,7 +2853,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
primid_texture, GSVector4(config.drawarea), m_date.primid_init_ps[static_cast<u8>(config.datm)].get(), nullptr, false);
}
else if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::Stencil ||
(config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && !multidraw_fb_copy))
(config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && !need_barrier))
SetupDATE(colclip_rt ? colclip_rt : config.rt, config.ds, config.datm, config.drawarea);
if (config.vs.expand != GSHWDrawConfig::VSExpand::None)
@@ -2944,19 +2948,30 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
draw_ds = m_state.current_ds;
}
if (draw_rt && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy) || (config.tex && config.tex == config.rt)))
const bool tex_is_fb = config.tex && config.tex == draw_rt;
const bool rt_feedbackloop_pass1 = config.ps.IsFeedbackLoopRT() || tex_is_fb;
const bool rt_feedbackloop_pass2 = config.alpha_second_pass.ps.IsFeedbackLoopRT() || tex_is_fb;
if (draw_rt && (((config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
(rt_feedbackloop_pass1 || rt_feedbackloop_pass2))))
{
config.require_one_barrier |= (tex_is_fb && !config.require_full_barrier);
config.alpha_second_pass.require_one_barrier |= (tex_is_fb && !config.require_full_barrier);
// Requires a copy of the RT.
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true);
if (!draw_rt_clone)
Console.Warning("D3D11: Failed to allocate temp texture for RT copy.");
}
if (draw_ds && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
m_features.depth_feedback && config.ps.IsFeedbackLoopDepth())
const bool ds_feedbackloop_pass1 = config.ps.IsFeedbackLoopDepth();
const bool ds_feedbackloop_pass2 = config.alpha_second_pass.ps.IsFeedbackLoopDepth();
if (draw_ds && m_features.depth_feedback && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
(ds_feedbackloop_pass1 || ds_feedbackloop_pass2))
{
// Requires a copy of the DS.
draw_ds_clone = CreateTexture(rtsize.x, rtsize.y, 1, draw_ds->GetFormat(), true);
if (!draw_ds_clone)
Console.Warning("D3D11: Failed to allocate temp texture for DS copy.");
}
@@ -2966,10 +2981,10 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
SetupOM(config.depth, OMBlendSelector(config.colormask, config.blend), config.blend.constant);
// Clear stencil as close as possible to the RT bind, to avoid framebuffer swaps.
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && multidraw_fb_copy)
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && need_barrier)
m_ctx->ClearDepthStencilView(*static_cast<GSTexture11*>(draw_ds), D3D11_CLEAR_STENCIL, 0.0f, 1);
SendHWDraw(config, draw_rt_clone, draw_rt, draw_ds_clone, draw_ds,
SendHWDraw(config, rt_feedbackloop_pass1 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass1 ? draw_ds_clone : nullptr, draw_ds,
config.require_one_barrier, config.require_full_barrier);
if (config.blend_multi_pass.enable)
@@ -2995,9 +3010,10 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
SetupPS(config.alpha_second_pass.ps, nullptr, config.sampler);
}
const bool one_barrier = config.alpha_second_pass.require_one_barrier && m_features.multidraw_fb_copy;
SetupOM(config.alpha_second_pass.depth, OMBlendSelector(config.alpha_second_pass.colormask, config.blend), config.blend.constant);
SendHWDraw(config, draw_rt_clone, draw_rt, draw_ds_clone, draw_ds,
false, config.alpha_second_pass.require_full_barrier);
SendHWDraw(config, rt_feedbackloop_pass2 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass2 ? draw_ds_clone : nullptr, draw_ds,
one_barrier, config.alpha_second_pass.require_full_barrier);
}
if (colclip_rt)
@@ -3021,58 +3037,55 @@ void GSDevice11::SendHWDraw(const GSHWDrawConfig& config,
GSTexture* draw_rt_clone, GSTexture* draw_rt, GSTexture* draw_ds_clone, GSTexture* draw_ds,
const bool one_barrier, const bool full_barrier)
{
if (draw_rt_clone || draw_ds_clone)
{
#ifdef PCSX2_DEVBUILD
if ((one_barrier || full_barrier) && !(config.ps.IsFeedbackLoopRT() || config.ps.IsFeedbackLoopDepth())) [[unlikely]]
Console.Warning("D3D11: Possible unnecessary copy detected.");
if ((one_barrier || full_barrier) && !(config.ps.IsFeedbackLoopRT() || config.ps.IsFeedbackLoopDepth())) [[unlikely]]
Console.Warning("D3D11: Possible unnecessary copy detected.");
#endif
auto CopyAndBind = [&](GSVector4i drawarea) {
if (draw_rt_clone)
{
CopyRect(draw_rt, draw_rt_clone, drawarea, drawarea.left, drawarea.top);
if ((one_barrier || full_barrier))
PSSetShaderResource(2, draw_rt_clone);
if (config.tex && config.tex == draw_rt)
PSSetShaderResource(0, draw_rt_clone);
}
if (draw_ds_clone)
{
CopyRect(draw_ds, draw_ds_clone, drawarea, drawarea.left, drawarea.top);
PSSetShaderResource(4, draw_ds_clone);
}
};
const GSVector4i rtsize(0, 0, (draw_rt ? draw_rt : draw_ds)->GetWidth(), (draw_rt ? draw_rt : draw_ds)->GetHeight());
if (full_barrier)
auto CopyAndBind = [&](GSVector4i drawarea) {
if (draw_rt_clone)
{
const u32 draw_list_size = static_cast<u32>(config.drawlist->size());
const u32 indices_per_prim = config.indices_per_prim;
CopyRect(draw_rt, draw_rt_clone, drawarea, drawarea.left, drawarea.top);
if ((one_barrier || full_barrier))
PSSetShaderResource(2, draw_rt_clone);
if (config.tex && config.tex == draw_rt)
PSSetShaderResource(0, draw_rt_clone);
}
if (draw_ds_clone)
{
CopyRect(draw_ds, draw_ds_clone, drawarea, drawarea.left, drawarea.top);
PSSetShaderResource(4, draw_ds_clone);
}
};
pxAssert(config.drawlist && !config.drawlist->empty());
pxAssert(config.drawlist_bbox && static_cast<u32>(config.drawlist_bbox->size()) == draw_list_size);
const GSVector4i rtsize(0, 0, (draw_rt ? draw_rt : draw_ds)->GetWidth(), (draw_rt ? draw_rt : draw_ds)->GetHeight());
for (u32 n = 0, p = 0; n < draw_list_size; n++)
{
const u32 count = (*config.drawlist)[n] * indices_per_prim;
if (full_barrier)
{
const u32 draw_list_size = static_cast<u32>(config.drawlist->size());
const u32 indices_per_prim = config.indices_per_prim;
const GSVector4i original_bbox = (*config.drawlist_bbox)[n].rintersect(config.drawarea);
CopyAndBind(ProcessCopyArea(rtsize, original_bbox));
pxAssert(config.drawlist && !config.drawlist->empty());
pxAssert(config.drawlist_bbox && static_cast<u32>(config.drawlist_bbox->size()) == draw_list_size);
Draw(config, p, count);
p += count;
}
for (u32 n = 0, p = 0; n < draw_list_size; n++)
{
const u32 count = (*config.drawlist)[n] * indices_per_prim;
return;
const GSVector4i original_bbox = (*config.drawlist_bbox)[n].rintersect(config.drawarea);
CopyAndBind(ProcessCopyArea(rtsize, original_bbox));
Draw(config, p, count);
p += count;
}
// Optimization: For alpha second pass we can reuse the copy snapshot from the first pass.
CopyAndBind(ProcessCopyArea(rtsize, config.drawarea));
return;
}
if (one_barrier)
CopyAndBind(ProcessCopyArea(rtsize, config.drawarea));
Draw(config);
}
+13 -21
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-3.0+
#include "GS/Renderers/DX12/D3D12ShaderCache.h"
#include "GS/Renderers/DX11/D3D.h"
#include "GS/GS.h"
#include "Config.h"
@@ -54,16 +53,18 @@ bool D3D12ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const
source_length != key.source_length);
}
bool D3D12ShaderCache::Open(D3D_FEATURE_LEVEL feature_level, bool debug)
bool D3D12ShaderCache::Open(D3D::ShaderModel shader_model, bool debug)
{
m_feature_level = feature_level;
// Only support SM5.1 for now, which is the minimum for D3D12.
pxAssert(shader_model >= D3D::ShaderModel::SM51);
m_shader_model = shader_model;
m_debug = debug;
bool result = true;
if (!GSConfig.DisableShaderCache)
{
const std::string base_shader_filename = GetCacheBaseFileName("shaders", feature_level, debug);
const std::string base_shader_filename = GetCacheBaseFileName("shaders", m_shader_model, debug);
const std::string shader_index_filename = base_shader_filename + ".idx";
const std::string shader_blob_filename = base_shader_filename + ".bin";
@@ -75,7 +76,7 @@ bool D3D12ShaderCache::Open(D3D_FEATURE_LEVEL feature_level, bool debug)
if (result)
{
const std::string base_pipelines_filename = GetCacheBaseFileName("pipelines", feature_level, debug);
const std::string base_pipelines_filename = GetCacheBaseFileName("pipelines", m_shader_model, debug);
const std::string pipelines_index_filename = base_pipelines_filename + ".idx";
const std::string pipelines_blob_filename = base_pipelines_filename + ".bin";
@@ -133,7 +134,7 @@ void D3D12ShaderCache::InvalidatePipelineCache()
if (GSConfig.DisableShaderCache)
return;
const std::string base_pipelines_filename = GetCacheBaseFileName("pipelines", m_feature_level, m_debug);
const std::string base_pipelines_filename = GetCacheBaseFileName("pipelines", m_shader_model, m_debug);
const std::string pipelines_index_filename = base_pipelines_filename + ".idx";
const std::string pipelines_blob_filename = base_pipelines_filename + ".bin";
CreateNew(pipelines_index_filename, pipelines_blob_filename, m_pipeline_index_file, m_pipeline_blob_file);
@@ -253,21 +254,12 @@ bool D3D12ShaderCache::ReadExisting(const std::string& index_filename, const std
return true;
}
std::string D3D12ShaderCache::GetCacheBaseFileName(const std::string_view type, D3D_FEATURE_LEVEL feature_level, bool debug)
std::string D3D12ShaderCache::GetCacheBaseFileName(const std::string_view type, D3D::ShaderModel shader_model, bool debug)
{
std::string base_filename = "d3d12_";
base_filename += type;
base_filename += "_";
switch (feature_level)
{
case D3D_FEATURE_LEVEL_11_0:
base_filename += "sm50";
break;
default:
base_filename += "unk";
break;
}
base_filename += D3D::ShaderModelToCacheString(shader_model);
if (debug)
base_filename += "_debug";
@@ -497,15 +489,15 @@ D3D12ShaderCache::ComPtr<ID3DBlob> D3D12ShaderCache::CompileAndAddShaderBlob(
{
case EntryType::VertexShader:
blob =
D3D::CompileShader(D3D::ShaderType::Vertex, m_feature_level, m_debug, shader_code, macros, entry_point);
D3D::CompileShader(D3D::ShaderType::Vertex, m_shader_model, m_debug, shader_code, macros, entry_point);
break;
case EntryType::PixelShader:
blob =
D3D::CompileShader(D3D::ShaderType::Pixel, m_feature_level, m_debug, shader_code, macros, entry_point);
D3D::CompileShader(D3D::ShaderType::Pixel, m_shader_model, m_debug, shader_code, macros, entry_point);
break;
case EntryType::ComputeShader:
blob = D3D::CompileShader(
D3D::ShaderType::Compute, m_feature_level, m_debug, shader_code, macros, entry_point);
blob =
D3D::CompileShader(D3D::ShaderType::Compute, m_shader_model, m_debug, shader_code, macros, entry_point);
break;
default:
break;
+4 -4
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#pragma once
#include "GS/Renderers/DX11/D3D.h"
#include "common/Pcsx2Defs.h"
#include "common/HashCombine.h"
@@ -32,10 +33,9 @@ public:
D3D12ShaderCache();
~D3D12ShaderCache();
__fi D3D_FEATURE_LEVEL GetFeatureLevel() const { return m_feature_level; }
__fi bool UsingDebugShaders() const { return m_debug; }
bool Open(D3D_FEATURE_LEVEL feature_level, bool debug);
bool Open(D3D::ShaderModel shader_model, bool debug);
void Close();
__fi ComPtr<ID3DBlob> GetVertexShader(
@@ -95,7 +95,7 @@ private:
using CacheIndex = std::unordered_map<CacheIndexKey, CacheIndexData, CacheIndexEntryHasher>;
static std::string GetCacheBaseFileName(const std::string_view type, D3D_FEATURE_LEVEL feature_level, bool debug);
static std::string GetCacheBaseFileName(const std::string_view type, D3D::ShaderModel shader_model, bool debug);
static CacheIndexKey GetShaderCacheKey(
EntryType type, const std::string_view shader_code, const D3D_SHADER_MACRO* macros, const char* entry_point);
static CacheIndexKey GetPipelineCacheKey(const D3D12_GRAPHICS_PIPELINE_STATE_DESC& gpdesc);
@@ -123,6 +123,6 @@ private:
std::FILE* m_pipeline_blob_file = nullptr;
CacheIndex m_pipeline_index;
D3D_FEATURE_LEVEL m_feature_level = D3D_FEATURE_LEVEL_11_0;
D3D::ShaderModel m_shader_model = D3D::ShaderModel::SM51;
bool m_debug = false;
};
+4 -3
View File
@@ -892,7 +892,7 @@ bool GSDevice12::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
m_tfx_source = std::move(*shader);
}
if (!m_shader_cache.Open(m_feature_level, GSConfig.UseDebugDevice))
if (!m_shader_cache.Open(D3D::ShaderModel::SM51, GSConfig.UseDebugDevice))
Console.Warning("D3D12: Shader cache failed to open.");
if (!CreateRootSignatures())
@@ -4250,7 +4250,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
}
// Destination Alpha Setup
const bool need_barrier = m_features.texture_barrier && (config.require_one_barrier || config.require_full_barrier);
const bool need_barrier = config.require_one_barrier || (config.require_full_barrier && m_features.texture_barrier);
switch (config.destination_alpha)
{
case GSHWDrawConfig::DestinationAlphaMode::Off: // No setup
@@ -4371,7 +4371,8 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
GSTexture12* draw_ds_as_rt = static_cast<GSTexture12*>(m_ds_as_rt);
const bool feedback_rt = draw_rt && (config.require_one_barrier || (config.require_full_barrier && m_features.texture_barrier) || (config.tex && config.tex == config.rt));
const bool feedback_rt = draw_rt && (((config.require_one_barrier || (config.require_full_barrier && m_features.texture_barrier)) && (config.ps.IsFeedbackLoopRT() ||
config.alpha_second_pass.ps.IsFeedbackLoopRT())) || (config.tex && config.tex == config.rt));
const bool feedback_depth = draw_ds_as_rt != nullptr;
if (feedback_rt && !m_features.texture_barrier)
+55 -38
View File
@@ -790,11 +790,14 @@ void GSRendererHW::DetectTextureShuffle()
void GSRendererHW::DetectTextureShuffleSecondPass(GSTextureCache::Target* rt, GSTextureCache::Source* tex)
{
const auto HasLowerOnes = [&](u32 x) { return x != 0 && (x & (x + 1)) == 0; };
if (!m_process_texture || !rt)
{
GL_INS("HW: Texture shuffle detection (2): Not detected.");
m_texture_shuffle.Disable();
return;
}
const GSLocalMemory::psm_t& tex_psm = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM];
const GSLocalMemory::psm_t& frame_psm = GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM];
if (frame_psm.bpp != 16)
{
GL_INS("HW: Texture shuffle detection (2): Failed (not 16 bit RT).");
@@ -804,7 +807,7 @@ void GSRendererHW::DetectTextureShuffleSecondPass(GSTextureCache::Target* rt, GS
if (m_texture_shuffle)
{
if (tex->m_32_bits_fmt)
if (tex && tex->m_32_bits_fmt)
{
GL_INS("HW: Texture shuffle detection (2): Passed.");
}
@@ -812,9 +815,9 @@ void GSRendererHW::DetectTextureShuffleSecondPass(GSTextureCache::Target* rt, GS
{
// Detects when the source texture is really a 16 bit texture instead of 32 bit being reinterpreted as 16 bit.
// Make sure it's opaque and not bilinear to reduce false positives.
const auto HasLowerOnes = [&](u32 x) { return x != 0 && (x & (x + 1)) == 0; };
if (m_cached_ctx.TEX0.TBP0 != m_cached_ctx.FRAME.Block() &&
rt->m_32_bits_fmt == true && IsOpaque() && !m_vt.IsRealLinear() &&
rt && rt->m_32_bits_fmt == true && IsOpaque() && !m_vt.IsRealLinear() &&
HasLowerOnes(m_cached_ctx.FRAME.FBMSK))
{
GL_INS("HW: Texture shuffle detection (2): Passed (real 16 bit source).");
@@ -832,10 +835,10 @@ void GSRendererHW::DetectTextureShuffleSecondPass(GSTextureCache::Target* rt, GS
// Last ditch check for reinterpreting a 32 bit source and RT as 16 bits.
// These "shuffles" appear to not do anything useful for games, but using the texture shuffle
// path helps to maintain correct sizes in the texture cache. Occurs in NFS Most Wanted.
const GSLocalMemory::psm_t& tex_psm = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM];
if (PRIM->TME &&
(m_vt.m_primclass == GS_SPRITE_CLASS || m_vt.m_primclass == GS_TRIANGLE_CLASS && TrianglesAreQuads(true)) &&
(tex_psm.bpp == 16) && (frame_psm.bpp == 16) && rt->m_32_bits_fmt && tex->m_32_bits_fmt)
((m_vt.m_primclass == GS_SPRITE_CLASS || m_vt.m_primclass == GS_TRIANGLE_CLASS) && TrianglesAreQuads(true)) &&
(tex_psm.bpp == 16) && (frame_psm.bpp == 16) && rt && rt->m_32_bits_fmt && tex && tex->m_32_bits_fmt)
{
GL_INS("HW: Texture shuffle detection (2): Passed (HACK: reinterpreting both source/RT as 16 bit).");
m_texture_shuffle.type = TextureShuffleType::HackShuffle;
@@ -2918,7 +2921,7 @@ void GSRendererHW::Draw()
}
// Test if we can optimize Alpha Test as a NOP
m_cached_ctx.TEST.ATE = m_cached_ctx.TEST.ATE && !GSRenderer::TryAlphaTest(fm, zm);
m_cached_ctx.TEST.ATE = !!m_cached_ctx.TEST.ATE && !GSRenderer::TryAlphaTest(fm, zm);
// Need to fix the alpha test, since the alpha will be fixed to 1.0 if ABE is disabled and AA1 is enabled
// So if it doesn't meet the condition, always fail, if it does, always pass (turn off the test).
@@ -2992,7 +2995,7 @@ void GSRendererHW::Draw()
// I hate that I have to do this, but some games (like Pac-Man World Rally) troll us by causing a flush with degenerate triangles, so we don't have all available information about the next draw.
// So we have to check when the next draw happens if our frame has changed or if it's become recursive.
const bool has_colclip_texture = g_gs_device->GetColorClipTexture() != nullptr;
if (!no_rt && has_colclip_texture && (m_conf.colclip_frame.FBP != m_cached_ctx.FRAME.FBP || m_conf.colclip_frame.Block() == m_cached_ctx.TEX0.TBP0))
if (!no_rt && has_colclip_texture && (m_conf.colclip_frame.FBP != m_cached_ctx.FRAME.FBP || (PRIM->TME && m_conf.colclip_frame.Block() == m_cached_ctx.TEX0.TBP0)))
{
GIFRegTEX0 FRAME;
FRAME.TBP0 = m_conf.colclip_frame.Block();
@@ -4388,15 +4391,15 @@ void GSRendererHW::Draw()
}
}
// Second pass texture shuffle detection using RT and source.
DetectTextureShuffleSecondPass(rt, src);
if (m_process_texture)
{
GIFRegCLAMP MIP_CLAMP = m_cached_ctx.CLAMP;
if (rt)
{
// Second pass texture shuffle detection using RT and source.
DetectTextureShuffleSecondPass(rt, src);
if (m_texture_shuffle)
{
if (IsSplitTextureShuffle(rt->m_TEX0, rt->m_valid))
@@ -5888,24 +5891,31 @@ void GSRendererHW::EmulateDATESelectMethod(DATEOptions& date_options, GSTextureC
if (features.framebuffer_fetch)
{
// Full DATE is "free" with framebuffer fetch. The barrier gets cleared below.
GL_PERF("DATE: Accurate with framebuffer fetch");
date_options.barrier = true;
m_conf.require_full_barrier = true;
}
else if (IsCoverageAlphaSupported())
else if (features.feedback_loops() && IsCoverageAlphaSupported())
{
// We're using AA1 for this draw so use only full barrier DATE, to avoid the complications
// with stencil/primid setup with AA1 vertex shaders. AA1 triangles usually require full barriers anyway.
GL_PERF("DATE: Accurate with IsCoverageAlphaSupported");
date_options.barrier = true;
m_conf.require_full_barrier = true;
}
else if ((features.texture_barrier && m_prim_overlap == PRIM_OVERLAP_NO) || m_texture_shuffle)
else if ((features.texture_barrier && m_prim_overlap == PRIM_OVERLAP_NO))
{
GL_PERF("DATE: Accurate with %s", (features.texture_barrier && m_prim_overlap == PRIM_OVERLAP_NO) ? "no overlap" : "texture shuffle");
if (features.texture_barrier)
{
m_conf.require_full_barrier = true;
date_options.barrier = true;
}
// We only enable this for texture barriers as it's fast, multidraw fb copy might be slower.
GL_PERF("DATE: Accurate with no overlap");
m_conf.require_full_barrier = true;
date_options.barrier = true;
}
else if (features.feedback_loops() && m_texture_shuffle)
{
// Ensure texture shuffles run with full barrier DATE.
GL_PERF("DATE: Accurate with texture shuffle");
m_conf.require_full_barrier = true;
date_options.barrier = true;
}
// When Blending is disabled and Edge Anti Aliasing is enabled,
// the output alpha is Coverage (which we force to 128) so DATE will fail/pass guaranteed on second pass.
@@ -5989,7 +5999,7 @@ void GSRendererHW::EmulateDATEGetConfig(DATEOptions& date_options, bool scale_rt
// Always swap DATE with DATE_BARRIER if we have barriers on when alpha write is masked.
// This is always enabled on VK/GL/DX12 but not on DX11 as copies are slow so we can selectively enable it like now.
if (!m_conf.colormask.wa && (m_conf.require_one_barrier || m_conf.require_full_barrier))
if (!m_conf.colormask.wa && (m_conf.require_one_barrier || (m_conf.require_full_barrier && features.feedback_loops())))
date_options.barrier = true;
if (m_conf.ps.scanmsk & 2)
@@ -6009,17 +6019,25 @@ void GSRendererHW::EmulateDATEGetConfig(DATEOptions& date_options, bool scale_rt
else
m_conf.datm = static_cast<SetDATM>(m_cached_ctx.TEST.DATM);
if (m_conf.destination_alpha >= GSHWDrawConfig::DestinationAlphaMode::Stencil &&
m_conf.destination_alpha <= GSHWDrawConfig::DestinationAlphaMode::StencilOne && !m_conf.ds)
// DATE Stencil always needs a depth stencil texture.
const bool date_stencil_needs_ds = !m_conf.ds &&
(m_conf.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::Stencil || m_conf.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne);
if (date_stencil_needs_ds)
{
const bool is_one_barrier = (features.texture_barrier && m_conf.require_full_barrier &&
(m_prim_overlap == PRIM_OVERLAP_NO || m_conf.ps.shuffle || m_channel_shuffle));
const bool need_barrier = m_conf.require_one_barrier || (m_conf.require_full_barrier && features.feedback_loops());
if ((temp_ds.reset(g_gs_device->CreateDepthStencil(m_conf.rt->GetWidth(), m_conf.rt->GetHeight(),
GSTexture::Format::DepthStencil, false)), temp_ds))
{
m_conf.ds = temp_ds.get();
}
else if (features.primitive_id && !(m_conf.ps.scanmsk & 2) && (!m_conf.require_full_barrier || is_one_barrier))
else if (need_barrier)
{
date_options.stencil_one = false;
date_options.barrier = true;
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Full;
DevCon.Warning("HW: Depth buffer creation failed for Stencil Date. Fallback to Full.");
}
else if (features.primitive_id && !(m_conf.ps.scanmsk & 2))
{
date_options.stencil_one = false;
date_options.primid = true;
@@ -6041,7 +6059,7 @@ void GSRendererHW::EmulateDATEGetConfig(DATEOptions& date_options, bool scale_rt
}
else if (date_options.stencil_one)
{
const bool multidraw_fb_copy = features.multidraw_fb_copy && (m_conf.require_one_barrier || m_conf.require_full_barrier);
const bool multidraw_fb_copy = m_conf.require_one_barrier || (m_conf.require_full_barrier && features.multidraw_fb_copy);
if (features.texture_barrier || multidraw_fb_copy)
{
m_conf.require_one_barrier = true;
@@ -6150,7 +6168,7 @@ void GSRendererHW::DetermineBarriers(GSTextureCache::Target* rt)
// If we use depth feedback directly, we must use barriers for the depth texture.
// If we use depth-as-color feedback, then FB fetch can be used for depth also.
bool need_barriers_for_depth = m_conf.ps.IsFeedbackLoopDepth() && features.depth_feedback;
const bool need_barriers_for_depth = m_conf.ps.IsFeedbackLoopDepth() && features.depth_feedback;
if (!need_barriers_for_depth)
{
@@ -6171,7 +6189,6 @@ void GSRendererHW::DetermineBarriers(GSTextureCache::Target* rt)
else if (!features.feedback_loops())
{
// These shouldn't be enabled if texture barriers aren't supported, make sure they are off.
m_conf.ps.write_rg = 0;
m_conf.require_full_barrier = false;
}
@@ -6247,7 +6264,7 @@ void GSRendererHW::EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GS
// If date is enabled you need to test the green channel instead of the alpha channel.
// Only enable this code in DATE mode to reduce the number of shaders.
m_conf.ps.write_rg = (process_rg & SHUFFLE_WRITE) && features.feedback_loops() && m_cached_ctx.TEST.DATE;
m_conf.ps.write_rg = !!(process_rg & SHUFFLE_WRITE) && !!m_cached_ctx.TEST.DATE;
m_conf.ps.real16src = m_texture_shuffle.real_16_bit_source;
@@ -6901,7 +6918,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, DATEOptio
{
case AccBlendLevel::Maximum:
sw_blending |= true;
accumulation_blend &= (GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 32);
accumulation_blend &= !barriers_supported || (GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 32);
[[fallthrough]];
case AccBlendLevel::Full:
sw_blending |= m_conf.ps.blend_a != m_conf.ps.blend_b && alpha_c0_high_max_one;
@@ -6920,7 +6937,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, DATEOptio
case AccBlendLevel::Basic:
default:
// Prefer sw blend if possible.
color_dest_blend &= !(m_channel_shuffle || m_conf.ps.dither);
color_dest_blend &= !m_conf.ps.dither;
color_dest_blend2 &= !(prefer_sw_blend || m_conf.ps.dither);
blend_zero_to_one_range &= !(prefer_sw_blend || m_conf.ps.dither);
accumulation_blend &= !prefer_sw_blend;
@@ -8790,7 +8807,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
EmulateDATESelectMethod(date_options, rt, blend_alpha_min, blend_alpha_max);
// Before emulateblending, dither will be used
m_conf.ps.dither = GSConfig.Dithering > 0 && m_conf.ps.dst_fmt == GSLocalMemory::PSM_FMT_16 && env.DTHE.DTHE;
m_conf.ps.dither = GSConfig.Dithering > 0 && m_conf.ps.dst_fmt == GSLocalMemory::PSM_FMT_16 && !!env.DTHE.DTHE;
if (m_conf.ps.dst_fmt == GSLocalMemory::PSM_FMT_24)
{
@@ -8851,7 +8868,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
}
// Similar to IsRTWritten(), check if the rt will change.
const bool no_rt = !rt || !(m_conf.colormask.wrgba || m_channel_shuffle);
const bool no_rt = !rt || m_conf.colormask.wrgba == 0;
const bool no_ds = !ds ||
// Depth will be written through the RT.
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && m_cached_ctx.ZBUF.ZMSK == 0 &&
@@ -9747,12 +9764,12 @@ bool GSRendererHW::TryGSMemClear(bool no_rt, bool preserve_rt, bool invalidate_r
rt_end_bp, m_cached_ctx.FRAME.PSM, m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.FBMSK);
GSUploadQueue clear_queue;
clear_queue.transfer_type = EEGS_TransferType::Clear;
clear_queue.draw = s_n;
clear_queue.rect = m_r;
clear_queue.blit.DBP = m_cached_ctx.FRAME.Block();
clear_queue.blit.DBW = m_cached_ctx.FRAME.FBW;
clear_queue.blit.DPSM = m_cached_ctx.FRAME.PSM;
clear_queue.zero_clear = true;
m_draw_transfers.push_back(clear_queue);
}
else
@@ -9777,12 +9794,12 @@ bool GSRendererHW::TryGSMemClear(bool no_rt, bool preserve_rt, bool invalidate_r
ds_end_bp, m_cached_ctx.ZBUF.PSM, m_cached_ctx.FRAME.FBW);
GSUploadQueue clear_queue;
clear_queue.transfer_type = EEGS_TransferType::Clear;
clear_queue.draw = s_n;
clear_queue.rect = m_r;
clear_queue.blit.DBP = m_cached_ctx.ZBUF.Block();
clear_queue.blit.DBW = m_cached_ctx.FRAME.FBW;
clear_queue.blit.DPSM = m_cached_ctx.ZBUF.PSM;
clear_queue.zero_clear = true;
m_draw_transfers.push_back(clear_queue);
}
}
@@ -551,13 +551,13 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc, b
if (add_ee_transfer)
{
GSRendererHW::GSUploadQueue uq;
uq.transfer_type = GSRendererHW::GetInstance()->EEGS_TransferType::EE_to_GS;
uq.blit.U64 = 0;
uq.blit.DBP = hw.m_cached_ctx.FRAME.Block();
uq.blit.DBW = hw.m_cached_ctx.FRAME.FBW;
uq.blit.DPSM = hw.m_cached_ctx.FRAME.PSM;
uq.draw = GSState::s_n;
uq.rect = bbox;
uq.zero_clear = false;
hw.m_draw_transfers.push_back(uq);
}
+40 -18
View File
@@ -1340,6 +1340,14 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
return nullptr;
}
// Invalid values show up in dumps but it's unclear if it's a core issue or a bug in the games.
// Return a temporary source to prevent the lookup from corrupting the TC.
if (TEX0.TBW > 32 && !GSUtil::IsValidPSM(static_cast<int>(TEX0.PSM)))
{
GL_CACHE("TC: Invalid TEX0 (TBW=%d, PSM=%x), using temporary source.", TEX0.TBW, TEX0.PSM);
return CreateSource(TEX0, TEXA, CLAMP, nullptr, 0, 0, nullptr, nullptr, nullptr, SourceRegion(), true);
}
const GSVector2i compare_lod(lod ? *lod : GSVector2i(0, 0));
Source* src = nullptr;
@@ -2253,20 +2261,34 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
}
}
if (src->m_from_target && src->m_target_direct && src->m_region.HasEither())
if (src->m_from_target && src->m_target_direct)
{
if (src->m_from_target->m_TEX0.TBP0 == src->m_TEX0.TBP0)
GSVector4i req_rect = r;
// The read area might be offset but the start of the texture is at the beginning of the space.
req_rect.x = region.HasX() ? region.GetMinX() : 0;
req_rect.y = region.HasY() ? region.GetMinY() : 0;
const bool dirty_overlap = !src->m_from_target->m_dirty.GetTotalRect(src->m_from_target->m_TEX0, src->m_from_target->m_unscaled_size).rintersect(req_rect).rempty();
if (dirty_overlap)
src->m_from_target->Update();
if (src->m_region.HasEither())
{
src->m_region.bits = 0;
src->m_region.SetX(0, region.HasX() ? region.GetMaxX() : (1 << TEX0.TW));
src->m_region.SetY(0, region.HasY() ? region.GetMaxY() : (1 << TEX0.TH));
}
else if (src->m_TEX0.TBP0 > src->m_from_target->m_TEX0.TBP0)
{
GSVector4i dst_offset = TranslateAlignedRectByPage(src->m_from_target, src->m_TEX0.TBP0, src->m_TEX0.PSM, src->m_TEX0.TBW, GSVector4i(0, 0, 1, 1), false);
src->m_region.bits = 0;
src->m_region.SetX(dst_offset.x, dst_offset.x + (region.HasX() ? std::min(region.GetMaxX(), (1 << TEX0.TW)) : (1 << TEX0.TW)));
src->m_region.SetY(dst_offset.y, dst_offset.y + (region.HasY() ? std::min(region.GetMaxY(), (1 << TEX0.TH)) : (1 << TEX0.TH)));
if (src->m_from_target->m_TEX0.TBP0 == src->m_TEX0.TBP0)
{
src->m_region.bits = 0;
src->m_region.SetX(0, region.HasX() ? region.GetMaxX() : (1 << TEX0.TW));
src->m_region.SetY(0, region.HasY() ? region.GetMaxY() : (1 << TEX0.TH));
}
else if (src->m_TEX0.TBP0 > src->m_from_target->m_TEX0.TBP0)
{
GSVector4i dst_offset = TranslateAlignedRectByPage(src->m_from_target, src->m_TEX0.TBP0, src->m_TEX0.PSM, src->m_TEX0.TBW, GSVector4i(0, 0, 1, 1), false);
src->m_region.bits = 0;
src->m_region.SetX(dst_offset.x, dst_offset.x + (region.HasX() ? std::min(region.GetMaxX(), (1 << TEX0.TW)) : (1 << TEX0.TW)));
src->m_region.SetY(dst_offset.y, dst_offset.y + (region.HasY() ? std::min(region.GetMaxY(), (1 << TEX0.TH)) : (1 << TEX0.TH)));
}
}
}
@@ -2341,7 +2363,7 @@ void GSTextureCache::CombineAlignedInsideTargets(Target* target, GSTextureCache:
const GSVector4 target_drect = GSVector4(target_drect_unscaled) * target->m_scale;
const bool valid_color = t->m_valid_rgb;
const bool valid_alpha = (t->m_valid_alpha_high | t->m_valid_alpha_low) && (GSUtil::GetChannelMask(t->m_TEX0.PSM) & 0x8);
const bool valid_alpha = (t->m_valid_alpha_high || t->m_valid_alpha_low) && (GSUtil::GetChannelMask(t->m_TEX0.PSM) & 0x8);
target->m_valid_alpha_high |= t->m_valid_alpha_high;
target->m_valid_alpha_low |= t->m_valid_alpha_low;
@@ -3474,14 +3496,15 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
else
eerect = eerect.runion(targetr);
const bool transfer_is_clear = iter->transfer_type == GSRendererHW::GetInstance()->EEGS_TransferType::Clear;
// Later writes might be partial over a previously cleared area. We want to upload in these cases.
hw_clear = hw_clear.has_value() ? (hw_clear.value() && iter->zero_clear) : iter->zero_clear;
hw_clear = hw_clear.has_value() ? (hw_clear.value() && transfer_is_clear) : transfer_is_clear;
// When the write covers the entire target, don't bother checking any earlier writes.
if (iter->blit.DBP <= TEX0.TBP0 && transfer_end >= rect_end)
{
// If it was a clear draw then we can use that as our target size.
if (iter->zero_clear && iter->blit.DBP == TEX0.TBP0 && iter->blit.DPSM == TEX0.PSM)
if (iter->transfer_type == GSRendererHW::GetInstance()->EEGS_TransferType::Clear && iter->blit.DBP == TEX0.TBP0 && iter->blit.DPSM == TEX0.PSM)
dst->UpdateValidity(iter->rect);
// Some games clear RT and Z at the same time, only erase if it's specifically this target.
@@ -3520,7 +3543,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
if (iter->draw < (GSState::s_n - 1))
break;
if (iter->zero_clear && iter->blit.DBP == TEX0.TBP0 && iter->blit.DBW == TEX0.TBW)
if (iter->transfer_type == GSRendererHW::GetInstance()->EEGS_TransferType::Clear && iter->blit.DBP == TEX0.TBP0 && iter->blit.DBW == TEX0.TBW)
{
hw_clear = true;
transfers.erase(std::next(iter).base());
@@ -3855,7 +3878,6 @@ GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(GIFRegTEX0 TEX0, con
const u32 bp = TEX0.TBP0;
Target* dst = nullptr;
Target* dst_match = nullptr;
auto* list = &m_dst[RenderTarget];
// Let's try to find a perfect frame that contains valid data
@@ -4011,7 +4033,7 @@ GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(GIFRegTEX0 TEX0, con
else
eerect = eerect.runion(targetr);
if (iter->zero_clear && iter->draw == last_draw)
if (iter->transfer_type == GSRendererHW::GetInstance()->EEGS_TransferType::Clear && iter->draw == last_draw)
{
can_create = false;
break;
+1 -1
View File
@@ -263,7 +263,7 @@ public:
bool OverlapsValid(u32 bp, u32 bw, u32 psm, const GSVector4i& rect) const;
__fi bool HasValidAlpha() const { return (m_valid_alpha_low | m_valid_alpha_high); }
__fi bool HasValidAlpha() const { return (m_valid_alpha_low || m_valid_alpha_high); }
bool HasValidBitsForFormat(u32 psm, bool req_color, bool req_alpha, bool width_match);
void ResizeDrawn(const GSVector4i& rect);
+5 -10
View File
@@ -492,7 +492,10 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
if (rt1)
{
pxAssert(md);
desc.colorAttachments[1].texture = GetRT1DepthTexture(md);
MTLRenderPassColorAttachmentDescriptor* color1 = desc.colorAttachments[1];
color1.texture = GetRT1DepthTexture(md);
if (m_features.framebuffer_fetch)
color1.clearColor = MTLClearColorMake(depth_load == MTLLoadActionClear ? depth_clear : -1, 0, 0, 0);
}
EndRenderPass();
@@ -1031,15 +1034,7 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
{
MTLRenderPassColorAttachmentDescriptor* color1 = [[desc colorAttachments] objectAtIndexedSubscript:1];
[color1 setStoreAction:MTLStoreActionDontCare];
if (m_features.framebuffer_fetch)
{
[color1 setLoadAction:MTLLoadActionClear];
[color1 setClearColor:MTLClearColorMake(-1, 0, 0, 0)];
}
else
{
[color1 setLoadAction:MTLLoadActionLoad];
}
[color1 setLoadAction:m_features.framebuffer_fetch ? MTLLoadActionClear : MTLLoadActionLoad];
}
m_render_pass_desc[i] = desc;
}
+8 -4
View File
@@ -461,6 +461,13 @@ struct PSMain
float4 sample_c_af(float2 uv, float uv_w)
{
// HW sampler will reject bad UVs, match that here.
uv = any(isnan(uv) | isinf(uv)) ? float2(0, 0) : uv;
// Large floating point values risk NaN/Inf values.
// Above this value floats lose decimal precision, so seems a resonable limit for UVs.
uv = clamp(uv, -8388608.0f, 8388608.0f);
// Below taken from https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#7.18.11%20LOD%20Calculations
// With guidance from https://pema.dev/2025/05/09/mipmaps-too-much-detail/
float2 sz = float2(get_tex_dims());
@@ -1431,10 +1438,7 @@ struct PSMain
uint2 denorm_TA = uint2(cb.ta * 255.5f);
C.rb = (denorm_c.r >> 3) | (((denorm_c.g >> 3) & 0x7) << 5);
if (denorm_c.a & 0x80)
C.ga = (denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.y & 0x80);
else
C.ga = (denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80);
C.ga = (denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80);
}
else if (PS_SHUFFLE_ACROSS)
{
+21 -10
View File
@@ -2743,7 +2743,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
}
// Destination Alpha Setup
const bool multidraw_fb_copy = m_features.multidraw_fb_copy && (config.require_one_barrier || config.require_full_barrier);
const bool need_barrier = config.require_one_barrier || (config.require_full_barrier && m_features.feedback_loops());
switch (config.destination_alpha)
{
case GSHWDrawConfig::DestinationAlphaMode::Off:
@@ -2758,7 +2758,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
}
break;
case GSHWDrawConfig::DestinationAlphaMode::StencilOne:
if (m_features.texture_barrier || multidraw_fb_copy)
if (need_barrier)
{
// Cleared after RT bind.
break;
@@ -2931,20 +2931,30 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
glTextureBarrier();
}
if (draw_rt && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy) || (config.tex && config.tex == config.rt)) &&
!m_features.texture_barrier)
const bool tex_is_fb = config.tex && config.tex == draw_rt;
const bool rt_feedbackloop_pass1 = config.ps.IsFeedbackLoopRT() || tex_is_fb;
const bool rt_feedbackloop_pass2 = config.alpha_second_pass.ps.IsFeedbackLoopRT() || tex_is_fb;
if (draw_rt && !m_features.texture_barrier && (((config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
(rt_feedbackloop_pass1 || rt_feedbackloop_pass2))))
{
config.require_one_barrier |= (tex_is_fb && !config.require_full_barrier);
config.alpha_second_pass.require_one_barrier |= (tex_is_fb && !config.require_full_barrier);
// Requires a copy of the RT.
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true);
if (!draw_rt_clone)
Console.Warning("GL: Failed to allocate temp texture for RT copy.");
}
if (draw_ds && (config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) &&
!m_features.texture_barrier && m_features.depth_feedback && config.ps.IsFeedbackLoopDepth())
const bool ds_feedbackloop_pass1 = config.ps.IsFeedbackLoopDepth();
const bool ds_feedbackloop_pass2 = config.alpha_second_pass.ps.IsFeedbackLoopDepth();
if (draw_ds && !m_features.texture_barrier && m_features.depth_feedback &&
(config.require_one_barrier || (config.require_full_barrier && m_features.multidraw_fb_copy)) && (ds_feedbackloop_pass1 || ds_feedbackloop_pass2))
{
// Requires a copy of the DS.
draw_ds_clone = CreateTexture(rtsize.x, rtsize.y, 1, draw_ds->GetFormat(), true);
if (!draw_ds_clone)
Console.Warning("GL: Failed to allocate temp texture for DS copy.");
}
@@ -2954,13 +2964,13 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
SetupOM(config.depth);
// Clear stencil as close as possible to the RT bind, to avoid framebuffer swaps.
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && (m_features.texture_barrier || multidraw_fb_copy))
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && need_barrier)
{
constexpr GLint clear_color = 1;
glClearBufferiv(GL_STENCIL, 0, &clear_color);
}
SendHWDraw(config, draw_rt_clone, draw_rt, draw_ds_clone, draw_ds,
SendHWDraw(config, rt_feedbackloop_pass1 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass1 ? draw_ds_clone : nullptr, draw_ds,
config.require_one_barrier, config.require_full_barrier);
if (config.blend_multi_pass.enable)
@@ -3006,9 +3016,10 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
{
OMSetBlendState();
}
const bool one_barrier = config.alpha_second_pass.require_one_barrier && m_features.feedback_loops();
SetupOM(config.alpha_second_pass.depth);
SendHWDraw(config, draw_rt_clone, draw_rt, draw_ds_clone, draw_ds,
m_features.texture_barrier ? config.alpha_second_pass.require_one_barrier : false, config.alpha_second_pass.require_full_barrier);
SendHWDraw(config, rt_feedbackloop_pass2 ? draw_rt_clone : nullptr, draw_rt, ds_feedbackloop_pass2 ? draw_ds_clone : nullptr, draw_ds,
one_barrier, config.alpha_second_pass.require_full_barrier);
}
if (colclip_rt)
+5 -1
View File
@@ -527,6 +527,10 @@ void GSRasterizer::DrawEdgeLine(const GSVertexSW& v0, const GSVertexSW& v1, cons
const int rxi1 = static_cast<int>(rx1);
const int ryi1 = static_cast<int>(ry1);
// Early exit for horizontal lines.
if (delta_y == 0.0f && !IsOneOfMyScanlines(ryi0) && !aa)
return;
const GSVertexSW dedge = dv / GSVector4(std::abs(step_x ? delta_x : delta_y));
GSVertexSW edge(v0);
@@ -1546,7 +1550,7 @@ void GSRasterizerList::Queue(const GSRingHeap::SharedPtr<GSRasterizerData>& data
m_ds.SetupDraw(*data.get());
}
pxAssert(r.top >= 0 && r.top < 2048 && r.bottom >= 0 && r.bottom < 2048);
pxAssert(r.top >= 0 && r.top <= 2048 && r.bottom >= 0 && r.bottom <= 2048);
int top = r.top >> m_thread_height;
int bottom = std::min<int>((r.bottom + (1 << m_thread_height) - 1) >> m_thread_height, top + (int)m_workers.size());
+19 -1
View File
@@ -468,7 +468,25 @@ void GSRendererSW::Draw()
std::memcpy(sd->index, m_index->buff, sizeof(u16) * m_index->tail);
GSVector4i scissor = context->scissor.in;
GSVector4i bbox = GSVector4i(m_vt.m_min.p.floor().upld(m_vt.m_max.p.floor())) + GSVector4i(0, 0, 1, 1); // right/bottom should be exclusive so +1
GSVector4i bbox;
if (m_vt.m_primclass == GS_LINE_CLASS || m_vt.m_primclass == GS_POINT_CLASS)
{
// min: round, max: round
bbox = GSVector4i((m_vt.m_min.p + GSVector4(0.5f)).floor().upld((m_vt.m_max.p + GSVector4(0.5f)).floor()));
}
else
{
// min: ceil, max: floor
bbox = GSVector4i(m_vt.m_min.p.ceil().upld(m_vt.m_max.p.floor()));
}
if (PRIM->AA1 && (m_vt.m_primclass == GS_LINE_CLASS || m_vt.m_primclass == GS_TRIANGLE_CLASS))
{
bbox += GSVector4i(-1, -1, 1, 1); // Expand bbox by 1 on all sides when using antialiasing.
}
bbox += GSVector4i(0, 0, 1, 1); // right/bottom should be exclusive so +1
GSVector4i r = bbox.rintersect(scissor);
+4 -2
View File
@@ -5892,6 +5892,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
}
// Destination Alpha Setup
const bool need_barrier = config.require_one_barrier || (config.require_full_barrier && m_features.texture_barrier);
switch (config.destination_alpha)
{
case GSHWDrawConfig::DestinationAlphaMode::Off: // No setup
@@ -5901,7 +5902,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
case GSHWDrawConfig::DestinationAlphaMode::StencilOne: // setup is done below
{
// we only need to do the setup here if we don't have barriers, in which case do full DATE.
if (!m_features.texture_barrier)
if (!need_barrier)
{
SetupDATE(draw_rt, config.ds, config.datm, config.drawarea);
config.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Stencil;
@@ -5991,7 +5992,8 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
pipe.feedback_loop_flags |= m_current_framebuffer_feedback_loop;
}
if (draw_rt && (config.require_one_barrier || (config.tex && config.tex == config.rt)) && !m_features.texture_barrier)
if (draw_rt && ((config.require_one_barrier && (config.ps.IsFeedbackLoopRT() || config.alpha_second_pass.ps.IsFeedbackLoopRT())) ||
(config.tex && config.tex == config.rt)) && !m_features.texture_barrier)
{
// Requires a copy of the RT.
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, 1, draw_rt->GetFormat(), true));
+85 -31
View File
@@ -649,7 +649,7 @@ void FullscreenUI::Render()
if (s_about_window_open)
DrawAboutWindow();
if (s_achievements_login_open)
if (s_achievements_login_open || ImGui::IsPopupOpen("RetroAchievements"))
DrawAchievementsLoginWindow();
if (s_input_binding_type != InputBindingInfo::Type::Unknown)
@@ -3499,14 +3499,18 @@ bool FullscreenUI::OpenAchievementsWindow()
void FullscreenUI::DrawAchievementsLoginWindow()
{
ImGui::SetNextWindowSize(LayoutScale(400.0f, 330.0f));
if (s_achievements_login_open && !ImGui::IsPopupOpen("RetroAchievements"))
ImGui::OpenPopup("RetroAchievements");
const float dialog_width = std::clamp(LayoutScale(420.0f), 300.0f, ImGui::GetIO().DisplaySize.x);
ImGui::SetNextWindowSizeConstraints(ImVec2(dialog_width, 0.0f), ImVec2(dialog_width, ImGui::GetIO().DisplaySize.y));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(ImGuiFullscreen::LAYOUT_WINDOW_ROUNDING));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(24.0f, 24.0f));
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0.13f, 0.13f, 0.13f, 0.95f));
if (ImGui::BeginPopupModal("RetroAchievements", &s_achievements_login_open, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar))
if (ImGui::BeginPopupModal("RetroAchievements", &s_achievements_login_open, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize))
{
const float content_width = ImGui::GetContentRegionAvail().x;
@@ -3553,7 +3557,7 @@ void FullscreenUI::DrawAchievementsLoginWindow()
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.4f, 0.4f, 0.4f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
if (s_achievements_login_logging_in)
if (s_achievements_login_logging_in || s_achievements_login_show_dismiss)
ImGui::BeginDisabled();
ImGui::SetNextItemWidth(content_width);
@@ -3567,7 +3571,7 @@ void FullscreenUI::DrawAchievementsLoginWindow()
ImGui::PopStyleColor(5);
ImGui::PopStyleVar(3);
if (s_achievements_login_logging_in)
if (s_achievements_login_logging_in || s_achievements_login_show_dismiss)
ImGui::EndDisabled();
ImGui::Spacing();
@@ -3582,20 +3586,67 @@ void FullscreenUI::DrawAchievementsLoginWindow()
ImGui::PopStyleColor();
ImGui::Spacing();
}
else if (s_achievements_login_show_dismiss)
{
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.35f, 0.9f, 0.35f, 1.0f));
const TinyString username = Host::GetBaseTinyStringSettingValue("Achievements", "Username", "");
const SmallString success_text = SmallString::from_format(
FSUI_FSTR("Successfully logged in as {}."), username.empty() ? "Unknown" : username.view());
const float status_width = ImGui::CalcTextSize(success_text.c_str()).x;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (content_width - status_width) * 0.5f);
ImGui::TextUnformatted(success_text.c_str());
ImGui::PopStyleColor();
ImGui::Spacing();
}
const float button_height = LayoutScale(36.0f);
const float button_width = LayoutScale(100.0f);
const float button_height = std::max(LayoutScale(36.0f), 28.0f);
const float button_spacing = LayoutScale(12.0f);
const float total_width = (button_width * 2) + button_spacing;
const float start_x = (content_width - total_width) * 0.5f;
const float button_width = (content_width - button_spacing) * 0.5f;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + start_x);
auto CloseLoginPopup = []() {
ImGui::CloseCurrentPopup();
s_achievements_login_open = false;
s_achievements_login_logging_in = false;
s_achievements_login_show_dismiss = false;
s_achievements_login_username[0] = '\0';
s_achievements_login_password[0] = '\0';
};
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(ImGuiFullscreen::LAYOUT_FRAME_ROUNDING));
const bool can_login = !s_achievements_login_logging_in &&
strlen(s_achievements_login_username) > 0 &&
strlen(s_achievements_login_password) > 0;
const bool can_login = !s_achievements_login_show_dismiss && !s_achievements_login_logging_in &&
strlen(s_achievements_login_username) > 0 &&
strlen(s_achievements_login_password) > 0;
if (s_achievements_login_show_dismiss)
{
// keep dialog open and let user explicitly dismiss.
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.5f, 0.9f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.6f, 1.0f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.1f, 0.4f, 0.8f, 1.0f));
if (ImGui::Button(FSUI_CSTR("Dismiss"), ImVec2(button_width, button_height)) && !s_achievements_login_logging_in)
CloseLoginPopup();
ImGui::PopStyleColor(3);
ImGui::SameLine(0, button_spacing);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
ImGui::BeginDisabled();
ImGui::Button(FSUI_CSTR("Login"), ImVec2(button_width, button_height));
ImGui::EndDisabled();
ImGui::PopStyleColor(3);
ImGui::PopStyleVar();
ImGui::EndPopup();
ImGui::PopStyleColor();
ImGui::PopStyleVar(2);
return;
}
if (can_login)
{
@@ -3613,6 +3664,7 @@ void FullscreenUI::DrawAchievementsLoginWindow()
if (ImGui::Button(FSUI_CSTR("Login"), ImVec2(button_width, button_height)) && can_login)
{
s_achievements_login_logging_in = true;
s_achievements_login_show_dismiss = false;
Host::RunOnCPUThread([username = std::string(s_achievements_login_username),
password = std::string(s_achievements_login_password)]() {
@@ -3624,14 +3676,10 @@ void FullscreenUI::DrawAchievementsLoginWindow()
if (!result)
{
ShowToast(std::string(), fmt::format(FSUI_FSTR("Login failed.\nError: {}\n\nPlease check your username and password, and try again."),
error.GetDescription()));
error.GetDescription()));
return;
}
ImGui::CloseCurrentPopup();
s_achievements_login_open = false;
s_achievements_login_username[0] = '\0';
s_achievements_login_password[0] = '\0';
if (s_achievements_login_reason == Achievements::LoginRequestReason::UserInitiated)
@@ -3683,11 +3731,12 @@ void FullscreenUI::DrawAchievementsLoginWindow()
});
}
}
s_achievements_login_show_dismiss = true;
});
}
ImGui::PopStyleColor(3);
ImGui::SameLine(0, button_spacing);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.4f, 0.4f, 0.4f, 1.0f));
@@ -3702,12 +3751,7 @@ void FullscreenUI::DrawAchievementsLoginWindow()
Achievements::DisableHardcoreMode();
}
ImGui::CloseCurrentPopup();
s_achievements_login_open = false;
s_achievements_login_logging_in = false;
s_achievements_login_username[0] = '\0';
s_achievements_login_password[0] = '\0';
CloseLoginPopup();
}
ImGui::PopStyleColor(3);
@@ -3718,9 +3762,6 @@ void FullscreenUI::DrawAchievementsLoginWindow()
ImGui::PopStyleColor();
ImGui::PopStyleVar(2);
if (!ImGui::IsPopupOpen("RetroAchievements"))
ImGui::OpenPopup("RetroAchievements");
}
bool FullscreenUI::IsAchievementsWindowOpen()
@@ -3960,11 +4001,14 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
"sounds/achievements/lbsubmit.wav", FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Select Leaderboard Submit Sound"));
MenuHeading(FSUI_CSTR("Account"));
if (bsi->ContainsValue("Achievements", "Token"))
SettingsInterface* secrets_si = Host::Internal::GetSecretsSettingsLayer();
const TinyString username = bsi->GetTinyStringValue("Achievements", "Username", "");
const bool has_token = (secrets_si && secrets_si->ContainsValue("Achievements", "Token"));
if (has_token)
{
ImGui::PushStyleColor(ImGuiCol_TextDisabled, ImGui::GetStyle().Colors[ImGuiCol_Text]);
ActiveButton(SmallString::from_format(
fmt::runtime(FSUI_ICONSTR(ICON_FA_USER, "Username: {}")), bsi->GetTinyStringValue("Achievements", "Username")),
fmt::runtime(FSUI_ICONSTR(ICON_FA_USER, "Username: {}")), username.empty() ? "Unknown" : username.view()),
false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY);
ActiveButton(SmallString::from_format(fmt::runtime(FSUI_ICONSTR(ICON_FA_CLOCK, "Login token generated on {}")),
TimeToPrintableString(static_cast<time_t>(
@@ -3984,6 +4028,7 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
if (MenuButton(FSUI_ICONSTR(ICON_FA_KEY, "Login"), FSUI_CSTR("Logs in to RetroAchievements.")))
{
s_achievements_login_reason = Achievements::LoginRequestReason::UserInitiated;
s_achievements_login_show_dismiss = false;
s_achievements_login_open = true;
}
}
@@ -4117,6 +4162,9 @@ TRANSLATE_NOOP("FullscreenUI", "Reset System");
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?");
TRANSLATE_NOOP("FullscreenUI", "This game has no achievements.");
TRANSLATE_NOOP("FullscreenUI", "This game has no leaderboards.");
TRANSLATE_NOOP("FullscreenUI", "No file selected.");
TRANSLATE_NOOP("FullscreenUI", "Sound reset to default.");
TRANSLATE_NOOP("FullscreenUI", "Sound is already using default.");
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State");
TRANSLATE_NOOP("FullscreenUI", "Failed to Save State");
TRANSLATE_NOOP("FullscreenUI", "Game List");
@@ -4164,12 +4212,12 @@ TRANSLATE_NOOP("FullscreenUI", "Forces a full rescan of all games previously ide
TRANSLATE_NOOP("FullscreenUI", "About PCSX2");
TRANSLATE_NOOP("FullscreenUI", "PCSX2 is a free and open-source PlayStation 2 (PS2) emulator. Its purpose is to emulate the PS2's hardware, using a combination of MIPS CPU Interpreters, Recompilers and a Virtual Machine which manages hardware states and PS2 system memory. This allows you to play PS2 games on your PC, with many additional features and benefits.");
TRANSLATE_NOOP("FullscreenUI", "PlayStation 2 and PS2 are registered trademarks of Sony Interactive Entertainment. This application is not affiliated in any way with Sony Interactive Entertainment.");
TRANSLATE_NOOP("FullscreenUI", "Version: %s");
TRANSLATE_NOOP("FullscreenUI", "RetroAchievements");
TRANSLATE_NOOP("FullscreenUI", "Please enter your user name and password for retroachievements.org below.\n\nYour password will not be saved in PCSX2, an access token will be generated and used instead.");
TRANSLATE_NOOP("FullscreenUI", "Username");
TRANSLATE_NOOP("FullscreenUI", "Password");
TRANSLATE_NOOP("FullscreenUI", "Logging in...");
TRANSLATE_NOOP("FullscreenUI", "Dismiss");
TRANSLATE_NOOP("FullscreenUI", "Login");
TRANSLATE_NOOP("FullscreenUI", "Cancel");
TRANSLATE_NOOP("FullscreenUI", "When enabled and logged in, PCSX2 will scan for achievements on startup.");
@@ -4207,7 +4255,10 @@ TRANSLATE_NOOP("FullscreenUI", "Time Played: {}");
TRANSLATE_NOOP("FullscreenUI", "Last Played: {}");
TRANSLATE_NOOP("FullscreenUI", "Size: {:.2f} MB");
TRANSLATE_NOOP("FullscreenUI", "Are you sure you want to reset the play time for '{}' ({})?\n\nYour current play time is {}.\n\nThis action cannot be undone.");
TRANSLATE_NOOP("FullscreenUI", "Version: {}");
TRANSLATE_NOOP("FullscreenUI", "Successfully logged in as {}.");
TRANSLATE_NOOP("FullscreenUI", "Login failed.\nError: {}\n\nPlease check your username and password, and try again.");
TRANSLATE_NOOP("FullscreenUI", "Failed to preview sound:\n{}");
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State From Backup Slot {}");
TRANSLATE_NOOP("FullscreenUI", "Failed to Load State From Slot {}");
TRANSLATE_NOOP("FullscreenUI", "Failed to Save State To Slot {}");
@@ -4289,6 +4340,9 @@ TRANSLATE_NOOP("FullscreenUI", "Notification Position");
TRANSLATE_NOOP("FullscreenUI", "Encore Mode");
TRANSLATE_NOOP("FullscreenUI", "Spectator Mode");
TRANSLATE_NOOP("FullscreenUI", "Test Unofficial Achievements");
TRANSLATE_NOOP("FullscreenUI", "Select File");
TRANSLATE_NOOP("FullscreenUI", "Preview");
TRANSLATE_NOOP("FullscreenUI", "Reset to Default");
TRANSLATE_NOOP("FullscreenUI", "Notification Sound");
TRANSLATE_NOOP("FullscreenUI", "Select Notification Sound");
TRANSLATE_NOOP("FullscreenUI", "Unlock Sound");
+1
View File
@@ -234,6 +234,7 @@ namespace FullscreenUI
// achievements login dialog state
inline bool s_achievements_login_open = false;
inline bool s_achievements_login_logging_in = false;
inline bool s_achievements_login_show_dismiss = false;
inline char s_achievements_login_username[256] = {};
inline char s_achievements_login_password[256] = {};
inline Achievements::LoginRequestReason s_achievements_login_reason = Achievements::LoginRequestReason::UserInitiated;
+69 -64
View File
@@ -2308,12 +2308,12 @@ void FullscreenUI::DrawInterfaceSettingsPage()
}
if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Controller Glyph Style"),
FSUI_CSTR("Changes which gamepad button glyph set is used in Big Picture UI and input binding displays."),
(glyph_index < std::size(glyph_values)) ? FSUI_CSTR(glyph_names[glyph_index]) : FSUI_CSTR("Unknown")))
(glyph_index < std::size(glyph_values)) ? Host::TranslateToCString(TR_CONTEXT, glyph_names[glyph_index]) : FSUI_CSTR("Unknown")))
{
ImGuiFullscreen::ChoiceDialogOptions cd_options;
cd_options.reserve(std::size(glyph_values));
for (size_t i = 0; i < std::size(glyph_values); i++)
cd_options.emplace_back(FSUI_STR(glyph_names[i]), i == static_cast<size_t>(glyph_index));
cd_options.emplace_back(Host::TranslateToString(TR_CONTEXT, glyph_names[i]), i == static_cast<size_t>(glyph_index));
OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Controller Glyph Style"), false, std::move(cd_options), [](s32 index, const std::string& title, bool checked) {
if (index >= 0 && static_cast<size_t>(index) < std::size(glyph_values))
@@ -2356,7 +2356,7 @@ void FullscreenUI::DrawInterfaceSettingsPage()
swap_summery.format(FSUI_FSTR("Uses {} as confirm when using a controller."),
glyphs.confirm(ImGui::GetIO().ConfigNavSwapGamepadButtons));
if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Swap OK/Cancel in Big Picture Mode"), swap_summery.c_str(),
(swap_index < std::size(swap_values)) ? FSUI_CSTR(swap_names[swap_index]) : FSUI_CSTR("Unknown")))
(swap_index < std::size(swap_values)) ? Host::TranslateToCString(TR_CONTEXT, swap_names[swap_index]) : FSUI_CSTR("Unknown")))
{
ImGuiFullscreen::ChoiceDialogOptions cd_options;
cd_options.reserve(std::size(swap_values));
@@ -2390,7 +2390,7 @@ void FullscreenUI::DrawInterfaceSettingsPage()
swap_summery.format(FSUI_FSTR("Swaps both {}/{} (When Swap OK/Cancel is set to automatic) and {}/{} buttons"),
glyphs.south, glyphs.east, glyphs.west, glyphs.north);
if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Use Legacy Nintendo Layout in Big Picture Mode"), swap_summery.c_str(),
(nintendo_index < std::size(swap_values)) ? FSUI_CSTR(swap_names[nintendo_index]) : FSUI_CSTR("Unknown")))
(nintendo_index < std::size(swap_values)) ? Host::TranslateToCString(TR_CONTEXT, swap_names[nintendo_index]) : FSUI_CSTR("Unknown")))
{
ImGuiFullscreen::ChoiceDialogOptions cd_options;
cd_options.reserve(std::size(swap_values));
@@ -5206,6 +5206,7 @@ TRANSLATE_NOOP("FullscreenUI", "Display a modal dialog when a save state load/sa
TRANSLATE_NOOP("FullscreenUI", "Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed.");
TRANSLATE_NOOP("FullscreenUI", "Automatically saves the emulator state when powering down or exiting. You can then resume directly from where you left off next time.");
TRANSLATE_NOOP("FullscreenUI", "Creates a backup copy of a save state if it already exists when the save is created. The backup copy has a .backup suffix");
TRANSLATE_NOOP("FullscreenUI", "Changes which gamepad button glyph set is used in Big Picture UI and input binding displays.");
TRANSLATE_NOOP("FullscreenUI", "Integration");
TRANSLATE_NOOP("FullscreenUI", "Shows the game you are currently playing as part of your profile on Discord.");
TRANSLATE_NOOP("FullscreenUI", "Game Display");
@@ -5272,57 +5273,30 @@ TRANSLATE_NOOP("FullscreenUI", "Force a primitive flush when a framebuffer is al
TRANSLATE_NOOP("FullscreenUI", "Enables emulation of the GS's edge anti-aliasing (AA1).");
TRANSLATE_NOOP("FullscreenUI", "Hardware Fixes");
TRANSLATE_NOOP("FullscreenUI", "Disables automatic hardware fixes, allowing you to set fixes manually.");
TRANSLATE_NOOP("FullscreenUI", "CPU Sprite Render Size");
TRANSLATE_NOOP("FullscreenUI", "Uses software renderer to draw texture decompression-like sprites.");
TRANSLATE_NOOP("FullscreenUI", "CPU Sprite Render Level");
TRANSLATE_NOOP("FullscreenUI", "Determines filter level for CPU sprite render.");
TRANSLATE_NOOP("FullscreenUI", "Software CLUT Render");
TRANSLATE_NOOP("FullscreenUI", "Uses software renderer to draw texture CLUT points/sprites.");
TRANSLATE_NOOP("FullscreenUI", "GPU Target CLUT");
TRANSLATE_NOOP("FullscreenUI", "Try to detect when a game is drawing its own color palette and then renders it on the GPU with special handling.");
TRANSLATE_NOOP("FullscreenUI", "Skip Draw Start");
TRANSLATE_NOOP("FullscreenUI", "Object range to skip drawing.");
TRANSLATE_NOOP("FullscreenUI", "Skip Draw End");
TRANSLATE_NOOP("FullscreenUI", "Auto Flush (Hardware)");
TRANSLATE_NOOP("FullscreenUI", "CPU Framebuffer Conversion");
TRANSLATE_NOOP("FullscreenUI", "Convert 4-bit and 8-bit framebuffer on the CPU instead of the GPU.");
TRANSLATE_NOOP("FullscreenUI", "Disable Depth Conversion");
TRANSLATE_NOOP("FullscreenUI", "Disable the support of depth buffers in the texture cache.");
TRANSLATE_NOOP("FullscreenUI", "Disable Safe Features");
TRANSLATE_NOOP("FullscreenUI", "This option disables multiple safe features.");
TRANSLATE_NOOP("FullscreenUI", "Disable Render Fixes");
TRANSLATE_NOOP("FullscreenUI", "This option disables game-specific render fixes.");
TRANSLATE_NOOP("FullscreenUI", "Preload Frame Data");
TRANSLATE_NOOP("FullscreenUI", "Uploads GS data when rendering a new frame to reproduce some effects accurately.");
TRANSLATE_NOOP("FullscreenUI", "Disable Partial Invalidation");
TRANSLATE_NOOP("FullscreenUI", "Removes texture cache entries when there is any intersection, rather than only the intersected areas.");
TRANSLATE_NOOP("FullscreenUI", "Texture Inside RT");
TRANSLATE_NOOP("FullscreenUI", "Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer.");
TRANSLATE_NOOP("FullscreenUI", "Read Targets When Closing");
TRANSLATE_NOOP("FullscreenUI", "Flushes all targets in the texture cache back to local memory when shutting down.");
TRANSLATE_NOOP("FullscreenUI", "Estimate Texture Region");
TRANSLATE_NOOP("FullscreenUI", "Attempts to reduce the texture size when games do not set it themselves (e.g. Snowblind games).");
TRANSLATE_NOOP("FullscreenUI", "GPU Palette Conversion");
TRANSLATE_NOOP("FullscreenUI", "When enabled GPU converts colormap-textures, otherwise the CPU will. It is a trade-off between GPU and CPU.");
TRANSLATE_NOOP("FullscreenUI", "Upscaling Fixes");
TRANSLATE_NOOP("FullscreenUI", "Half Pixel Offset");
TRANSLATE_NOOP("FullscreenUI", "Adjusts vertices relative to upscaling.");
TRANSLATE_NOOP("FullscreenUI", "Native Scaling");
TRANSLATE_NOOP("FullscreenUI", "Attempt to do rescaling at native resolution.");
TRANSLATE_NOOP("FullscreenUI", "Round Sprite");
TRANSLATE_NOOP("FullscreenUI", "Adjusts sprite coordinates.");
TRANSLATE_NOOP("FullscreenUI", "Bilinear Dirty Upscale");
TRANSLATE_NOOP("FullscreenUI", "Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare.");
TRANSLATE_NOOP("FullscreenUI", "Texture Offset X");
TRANSLATE_NOOP("FullscreenUI", "Adjusts target texture offsets.");
TRANSLATE_NOOP("FullscreenUI", "Texture Offset Y");
TRANSLATE_NOOP("FullscreenUI", "Align Sprite");
TRANSLATE_NOOP("FullscreenUI", "Fixes issues with upscaling (vertical lines) in some games.");
TRANSLATE_NOOP("FullscreenUI", "Merge Sprite");
TRANSLATE_NOOP("FullscreenUI", "Replaces multiple post-processing sprites with a larger single sprite.");
TRANSLATE_NOOP("FullscreenUI", "Force Even Sprite Position");
TRANSLATE_NOOP("FullscreenUI", "Lowers the GS precision to avoid gaps between pixels when upscaling. Fixes the text on Wild Arms games.");
TRANSLATE_NOOP("FullscreenUI", "Unscaled Palette Texture Draws");
TRANSLATE_NOOP("FullscreenUI", "Can fix some broken effects which rely on pixel perfect precision.");
TRANSLATE_NOOP("FullscreenUI", "Texture Replacement");
TRANSLATE_NOOP("FullscreenUI", "Loads replacement textures where available and user-provided.");
@@ -5341,35 +5315,22 @@ TRANSLATE_NOOP("FullscreenUI", "Filters");
TRANSLATE_NOOP("FullscreenUI", "Enables brightness/contrast/gamma/saturation adjustment.");
TRANSLATE_NOOP("FullscreenUI", "Adjusts brightness. 50 is normal.");
TRANSLATE_NOOP("FullscreenUI", "Adjusts contrast. 50 is normal.");
TRANSLATE_NOOP("FullscreenUI", "Shade Boost Gamma");
TRANSLATE_NOOP("FullscreenUI", "Adjusts gamma. 50 is normal.");
TRANSLATE_NOOP("FullscreenUI", "Adjusts saturation. 50 is normal.");
TRANSLATE_NOOP("FullscreenUI", "Applies a shader which replicates the visual effects of different styles of television set.");
TRANSLATE_NOOP("FullscreenUI", "Advanced");
TRANSLATE_NOOP("FullscreenUI", "Skip Presenting Duplicate Frames");
TRANSLATE_NOOP("FullscreenUI", "Skips displaying frames that don't change in 25/30fps games. Can improve speed, but increase input lag/make frame pacing worse.");
TRANSLATE_NOOP("FullscreenUI", "Disable Mailbox Presentation");
TRANSLATE_NOOP("FullscreenUI", "Forces the use of FIFO over Mailbox presentation, i.e. double buffering instead of triple buffering. Usually results in worse frame pacing.");
TRANSLATE_NOOP("FullscreenUI", "Displays additional, very high upscaling multipliers dependent on GPU and driver capability.");
TRANSLATE_NOOP("FullscreenUI", "Hardware Download Mode");
TRANSLATE_NOOP("FullscreenUI", "Changes synchronization behavior for GS downloads.");
TRANSLATE_NOOP("FullscreenUI", "Allow Exclusive Fullscreen");
TRANSLATE_NOOP("FullscreenUI", "Overrides the driver's heuristics for enabling exclusive fullscreen, or direct flip/scanout.");
TRANSLATE_NOOP("FullscreenUI", "Override Texture Barriers");
TRANSLATE_NOOP("FullscreenUI", "Forces texture barrier functionality to the specified value.");
TRANSLATE_NOOP("FullscreenUI", "GS Dump Compression");
TRANSLATE_NOOP("FullscreenUI", "Sets the compression algorithm for GS dumps.");
TRANSLATE_NOOP("FullscreenUI", "Disable Framebuffer Fetch");
TRANSLATE_NOOP("FullscreenUI", "Prevents the usage of framebuffer fetch when supported by host GPU.");
TRANSLATE_NOOP("FullscreenUI", "Disable Shader Cache");
TRANSLATE_NOOP("FullscreenUI", "Prevents the loading and saving of shaders/pipelines to disk.");
TRANSLATE_NOOP("FullscreenUI", "Disable Vertex Shader Expand");
TRANSLATE_NOOP("FullscreenUI", "Falls back to the CPU for expanding sprites/lines.");
TRANSLATE_NOOP("FullscreenUI", "Texture Preloading");
TRANSLATE_NOOP("FullscreenUI", "Uploads full textures to the GPU on use, rather than only the utilized regions. Can improve performance in some games.");
TRANSLATE_NOOP("FullscreenUI", "NTSC Frame Rate");
TRANSLATE_NOOP("FullscreenUI", "Determines what frame rate NTSC games run at.");
TRANSLATE_NOOP("FullscreenUI", "PAL Frame Rate");
TRANSLATE_NOOP("FullscreenUI", "Determines what frame rate PAL games run at.");
TRANSLATE_NOOP("FullscreenUI", "On-Screen Display");
TRANSLATE_NOOP("FullscreenUI", "Determines how large the on-screen messages and monitors are.");
@@ -5377,7 +5338,6 @@ TRANSLATE_NOOP("FullscreenUI", "Determines the distance in pixels from the edges
TRANSLATE_NOOP("FullscreenUI", "Determines where on-screen display messages are positioned.");
TRANSLATE_NOOP("FullscreenUI", "Determines where performance statistics are positioned.");
TRANSLATE_NOOP("FullscreenUI", "Select OSD Font");
TRANSLATE_NOOP("FullscreenUI", "Clear OSD Font Override");
TRANSLATE_NOOP("FullscreenUI", "Use default bundled font");
TRANSLATE_NOOP("FullscreenUI", "Draws OSD text with heavier weight for improved readability.");
TRANSLATE_NOOP("FullscreenUI", "Shows the current PCSX2 version.");
@@ -5487,7 +5447,6 @@ TRANSLATE_NOOP("FullscreenUI", "Sets the compression level for savestate.");
TRANSLATE_NOOP("FullscreenUI", "Graphics");
TRANSLATE_NOOP("FullscreenUI", "Enables API-level validation of graphics commands.");
TRANSLATE_NOOP("FullscreenUI", "Settings");
TRANSLATE_NOOP("FullscreenUI", "Enable Cheats");
TRANSLATE_NOOP("FullscreenUI", "No cheats are available for this game.");
TRANSLATE_NOOP("FullscreenUI", "Cheat Codes");
TRANSLATE_NOOP("FullscreenUI", "No patches are available for this game.");
@@ -5497,41 +5456,23 @@ TRANSLATE_NOOP("FullscreenUI", "Activating game patches can cause unpredictable
TRANSLATE_NOOP("FullscreenUI", "Use patches at your own risk, the PCSX2 team will provide no support for users who have enabled game patches.");
TRANSLATE_NOOP("FullscreenUI", "Game Fixes");
TRANSLATE_NOOP("FullscreenUI", "Game fixes should not be modified unless you are aware of what each option does and the implications of doing so.");
TRANSLATE_NOOP("FullscreenUI", "FPU Multiply Hack");
TRANSLATE_NOOP("FullscreenUI", "For Tales of Destiny.");
TRANSLATE_NOOP("FullscreenUI", "Use Software Renderer For FMVs");
TRANSLATE_NOOP("FullscreenUI", "Needed for some games with complex FMV rendering.");
TRANSLATE_NOOP("FullscreenUI", "Skip MPEG Hack");
TRANSLATE_NOOP("FullscreenUI", "Skips videos/FMVs in games to avoid game hanging/freezes.");
TRANSLATE_NOOP("FullscreenUI", "Preload TLB Hack");
TRANSLATE_NOOP("FullscreenUI", "To avoid TLB miss on Goemon.");
TRANSLATE_NOOP("FullscreenUI", "EE Timing Hack");
TRANSLATE_NOOP("FullscreenUI", "General-purpose timing hack. Known to affect following games: Digital Devil Saga, SSX.");
TRANSLATE_NOOP("FullscreenUI", "Instant DMA Hack");
TRANSLATE_NOOP("FullscreenUI", "Good for cache emulation problems. Known to affect following games: Fire Pro Wrestling Z.");
TRANSLATE_NOOP("FullscreenUI", "OPH Flag Hack");
TRANSLATE_NOOP("FullscreenUI", "Known to affect following games: Bleach Blade Battlers, Growlanser II and III, Wizardry.");
TRANSLATE_NOOP("FullscreenUI", "Emulate GIF FIFO");
TRANSLATE_NOOP("FullscreenUI", "Correct but slower. Known to affect the following games: FIFA Street 2.");
TRANSLATE_NOOP("FullscreenUI", "DMA Busy Hack");
TRANSLATE_NOOP("FullscreenUI", "Known to affect following games: Mana Khemia 1, Metal Saga, Pilot Down Behind Enemy Lines.");
TRANSLATE_NOOP("FullscreenUI", "Delay VIF1 Stalls");
TRANSLATE_NOOP("FullscreenUI", "For SOCOM 2 HUD and Spy Hunter loading hang.");
TRANSLATE_NOOP("FullscreenUI", "Emulate VIF FIFO");
TRANSLATE_NOOP("FullscreenUI", "Simulate VIF1 FIFO read ahead. Known to affect following games: Test Drive Unlimited, Transformers.");
TRANSLATE_NOOP("FullscreenUI", "Full VU0 Synchronization");
TRANSLATE_NOOP("FullscreenUI", "Forces tight VU0 sync on every COP2 instruction.");
TRANSLATE_NOOP("FullscreenUI", "VU I Bit Hack");
TRANSLATE_NOOP("FullscreenUI", "Avoids constant recompilation in some games. Known to affect the following games: Scarface The World is Yours, Crash Tag Team Racing.");
TRANSLATE_NOOP("FullscreenUI", "VU Add Hack");
TRANSLATE_NOOP("FullscreenUI", "For Tri-Ace Games: Star Ocean 3, Radiata Stories, Valkyrie Profile 2.");
TRANSLATE_NOOP("FullscreenUI", "VU Overflow Hack");
TRANSLATE_NOOP("FullscreenUI", "To check for possible float overflows (Superman Returns).");
TRANSLATE_NOOP("FullscreenUI", "VU Sync");
TRANSLATE_NOOP("FullscreenUI", "Run behind. To avoid sync problems when reading or writing VU registers.");
TRANSLATE_NOOP("FullscreenUI", "VU XGKick Sync");
TRANSLATE_NOOP("FullscreenUI", "Use accurate timing for VU XGKicks (slower).");
TRANSLATE_NOOP("FullscreenUI", "Force Blit Internal FPS Detection");
TRANSLATE_NOOP("FullscreenUI", "Use alternative method to calculate internal FPS to avoid false readings in some games.");
TRANSLATE_NOOP("FullscreenUI", "{0}/{1}/{2}/{3}");
TRANSLATE_NOOP("FullscreenUI", "Automatic mapping completed for {}.");
@@ -5595,6 +5536,9 @@ TRANSLATE_NOOP("FullscreenUI", "Fill");
TRANSLATE_NOOP("FullscreenUI", "Stretch");
TRANSLATE_NOOP("FullscreenUI", "Center");
TRANSLATE_NOOP("FullscreenUI", "Tile");
TRANSLATE_NOOP("FullscreenUI", "Xbox");
TRANSLATE_NOOP("FullscreenUI", "PlayStation");
TRANSLATE_NOOP("FullscreenUI", "Nintendo");
TRANSLATE_NOOP("FullscreenUI", "Enabled");
TRANSLATE_NOOP("FullscreenUI", "Disabled");
TRANSLATE_NOOP("FullscreenUI", "2% [1 FPS (NTSC) / 1 FPS (PAL)]");
@@ -5818,6 +5762,7 @@ TRANSLATE_NOOP("FullscreenUI", "Prompt On State Load/Save Failure");
TRANSLATE_NOOP("FullscreenUI", "Confirm Shutdown");
TRANSLATE_NOOP("FullscreenUI", "Save State On Shutdown");
TRANSLATE_NOOP("FullscreenUI", "Create Save State Backups");
TRANSLATE_NOOP("FullscreenUI", "Controller Glyph Style");
TRANSLATE_NOOP("FullscreenUI", "Swap OK/Cancel in Big Picture Mode");
TRANSLATE_NOOP("FullscreenUI", "Use Legacy Nintendo Layout in Big Picture Mode");
TRANSLATE_NOOP("FullscreenUI", "Enable Discord Presence");
@@ -5835,6 +5780,7 @@ TRANSLATE_NOOP("FullscreenUI", "EE Cycle Rate");
TRANSLATE_NOOP("FullscreenUI", "EE Cycle Skipping");
TRANSLATE_NOOP("FullscreenUI", "Enable MTVU (Multi-Threaded VU1)");
TRANSLATE_NOOP("FullscreenUI", "Thread Pinning");
TRANSLATE_NOOP("FullscreenUI", "Enable Cheats");
TRANSLATE_NOOP("FullscreenUI", "Enable Host Filesystem");
TRANSLATE_NOOP("FullscreenUI", "Enable Fast CDVD");
TRANSLATE_NOOP("FullscreenUI", "Enable CDVD Precaching");
@@ -5869,6 +5815,33 @@ TRANSLATE_NOOP("FullscreenUI", "Software Rendering Threads");
TRANSLATE_NOOP("FullscreenUI", "Auto Flush (Software)");
TRANSLATE_NOOP("FullscreenUI", "Edge AA (AA1)");
TRANSLATE_NOOP("FullscreenUI", "Manual Hardware Fixes");
TRANSLATE_NOOP("FullscreenUI", "CPU Sprite Render Size");
TRANSLATE_NOOP("FullscreenUI", "CPU Sprite Render Level");
TRANSLATE_NOOP("FullscreenUI", "Software CLUT Render");
TRANSLATE_NOOP("FullscreenUI", "GPU Target CLUT");
TRANSLATE_NOOP("FullscreenUI", "Skip Draw Start");
TRANSLATE_NOOP("FullscreenUI", "Skip Draw End");
TRANSLATE_NOOP("FullscreenUI", "Auto Flush (Hardware)");
TRANSLATE_NOOP("FullscreenUI", "CPU Framebuffer Conversion");
TRANSLATE_NOOP("FullscreenUI", "Disable Depth Conversion");
TRANSLATE_NOOP("FullscreenUI", "Disable Safe Features");
TRANSLATE_NOOP("FullscreenUI", "Disable Render Fixes");
TRANSLATE_NOOP("FullscreenUI", "Preload Frame Data");
TRANSLATE_NOOP("FullscreenUI", "Disable Partial Invalidation");
TRANSLATE_NOOP("FullscreenUI", "Texture Inside RT");
TRANSLATE_NOOP("FullscreenUI", "Read Targets When Closing");
TRANSLATE_NOOP("FullscreenUI", "Estimate Texture Region");
TRANSLATE_NOOP("FullscreenUI", "GPU Palette Conversion");
TRANSLATE_NOOP("FullscreenUI", "Half Pixel Offset");
TRANSLATE_NOOP("FullscreenUI", "Native Scaling");
TRANSLATE_NOOP("FullscreenUI", "Round Sprite");
TRANSLATE_NOOP("FullscreenUI", "Bilinear Dirty Upscale");
TRANSLATE_NOOP("FullscreenUI", "Texture Offset X");
TRANSLATE_NOOP("FullscreenUI", "Texture Offset Y");
TRANSLATE_NOOP("FullscreenUI", "Align Sprite");
TRANSLATE_NOOP("FullscreenUI", "Merge Sprite");
TRANSLATE_NOOP("FullscreenUI", "Force Even Sprite Position");
TRANSLATE_NOOP("FullscreenUI", "Unscaled Palette Texture Draws");
TRANSLATE_NOOP("FullscreenUI", "Load Textures");
TRANSLATE_NOOP("FullscreenUI", "Asynchronous Texture Loading");
TRANSLATE_NOOP("FullscreenUI", "Precache Replacements");
@@ -5882,14 +5855,28 @@ TRANSLATE_NOOP("FullscreenUI", "CAS Sharpness");
TRANSLATE_NOOP("FullscreenUI", "Shade Boost");
TRANSLATE_NOOP("FullscreenUI", "Shade Boost Brightness");
TRANSLATE_NOOP("FullscreenUI", "Shade Boost Contrast");
TRANSLATE_NOOP("FullscreenUI", "Shade Boost Gamma");
TRANSLATE_NOOP("FullscreenUI", "Shade Boost Saturation");
TRANSLATE_NOOP("FullscreenUI", "TV Shaders");
TRANSLATE_NOOP("FullscreenUI", "Skip Presenting Duplicate Frames");
TRANSLATE_NOOP("FullscreenUI", "Disable Mailbox Presentation");
TRANSLATE_NOOP("FullscreenUI", "Extended Upscaling Multipliers");
TRANSLATE_NOOP("FullscreenUI", "Hardware Download Mode");
TRANSLATE_NOOP("FullscreenUI", "Allow Exclusive Fullscreen");
TRANSLATE_NOOP("FullscreenUI", "Override Texture Barriers");
TRANSLATE_NOOP("FullscreenUI", "GS Dump Compression");
TRANSLATE_NOOP("FullscreenUI", "Disable Framebuffer Fetch");
TRANSLATE_NOOP("FullscreenUI", "Disable Shader Cache");
TRANSLATE_NOOP("FullscreenUI", "Disable Vertex Shader Expand");
TRANSLATE_NOOP("FullscreenUI", "Texture Preloading");
TRANSLATE_NOOP("FullscreenUI", "NTSC Frame Rate");
TRANSLATE_NOOP("FullscreenUI", "PAL Frame Rate");
TRANSLATE_NOOP("FullscreenUI", "OSD Scale");
TRANSLATE_NOOP("FullscreenUI", "OSD Margin");
TRANSLATE_NOOP("FullscreenUI", "OSD Messages Position");
TRANSLATE_NOOP("FullscreenUI", "OSD Performance Position");
TRANSLATE_NOOP("FullscreenUI", "OSD Font File");
TRANSLATE_NOOP("FullscreenUI", "Clear OSD Font Override");
TRANSLATE_NOOP("FullscreenUI", "Bold OSD Text");
TRANSLATE_NOOP("FullscreenUI", "Show PCSX2 Version");
TRANSLATE_NOOP("FullscreenUI", "Show Speed");
@@ -6010,6 +5997,24 @@ TRANSLATE_NOOP("FullscreenUI", "Enable IOP Recompiler");
TRANSLATE_NOOP("FullscreenUI", "Compression Method");
TRANSLATE_NOOP("FullscreenUI", "Compression Level");
TRANSLATE_NOOP("FullscreenUI", "Use Debug Device");
TRANSLATE_NOOP("FullscreenUI", "FPU Multiply Hack");
TRANSLATE_NOOP("FullscreenUI", "Use Software Renderer For FMVs");
TRANSLATE_NOOP("FullscreenUI", "Skip MPEG Hack");
TRANSLATE_NOOP("FullscreenUI", "Preload TLB Hack");
TRANSLATE_NOOP("FullscreenUI", "EE Timing Hack");
TRANSLATE_NOOP("FullscreenUI", "Instant DMA Hack");
TRANSLATE_NOOP("FullscreenUI", "OPH Flag Hack");
TRANSLATE_NOOP("FullscreenUI", "Emulate GIF FIFO");
TRANSLATE_NOOP("FullscreenUI", "DMA Busy Hack");
TRANSLATE_NOOP("FullscreenUI", "Delay VIF1 Stalls");
TRANSLATE_NOOP("FullscreenUI", "Emulate VIF FIFO");
TRANSLATE_NOOP("FullscreenUI", "Full VU0 Synchronization");
TRANSLATE_NOOP("FullscreenUI", "VU I Bit Hack");
TRANSLATE_NOOP("FullscreenUI", "VU Add Hack");
TRANSLATE_NOOP("FullscreenUI", "VU Overflow Hack");
TRANSLATE_NOOP("FullscreenUI", "VU Sync");
TRANSLATE_NOOP("FullscreenUI", "VU XGKick Sync");
TRANSLATE_NOOP("FullscreenUI", "Force Blit Internal FPS Detection");
TRANSLATE_NOOP("FullscreenUI", "Memory Card Enabled");
TRANSLATE_NOOP("FullscreenUI", "Card Name");
TRANSLATE_NOOP("FullscreenUI", "Eject Card");
+1 -1
View File
@@ -709,7 +709,7 @@ __fi void psxRcntWmode32(int index, u32 value)
// Current counter *always* resets on mode write.
counter.count = 0;
counter.startCycle = psxRegs.cycle & ~(counter.rate - 1);
counter.startCycle = psxRegs.cycle & ~(static_cast<u64>(counter.rate - 1));
counter.target &= 0xffffffff;
_rcntSet(index);
}
+43 -36
View File
@@ -2195,51 +2195,58 @@ std::string EmuFolders::GetPortableModePath()
bool EmuFolders::SetDataDirectory(Error* error)
{
// Portable mode has the absolute priority.
if (!ShouldUsePortableMode())
{
// Also check if the user has overriden the DataRoot path.
if (EmuConfig.CustomDataPath.empty())
{
#if defined(_WIN32)
// On Windows, use My Documents\PCSX2 to match old installs.
PWSTR documents_directory;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory)))
{
if (std::wcslen(documents_directory) > 0)
DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "PCSX2");
CoTaskMemFree(documents_directory);
}
// On Windows, use My Documents\PCSX2 to match old installs.
PWSTR documents_directory;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory)))
{
if (std::wcslen(documents_directory) > 0)
DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "PCSX2");
CoTaskMemFree(documents_directory);
}
#elif defined(__linux__) || defined(__FreeBSD__)
// Use $XDG_CONFIG_HOME/PCSX2 if it exists.
const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
{
DataRoot = Path::RealPath(Path::Combine(xdg_config_home, "PCSX2"));
}
else
{
// Use ~/PCSX2 for non-XDG, and ~/.config/PCSX2 for XDG.
// Use $XDG_CONFIG_HOME/PCSX2 if it exists.
const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
{
DataRoot = Path::RealPath(Path::Combine(xdg_config_home, "PCSX2"));
}
else
{
// Use ~/PCSX2 for non-XDG, and ~/.config/PCSX2 for XDG.
const char* home_dir = getenv("HOME");
if (home_dir)
{
// ~/.config should exist, but just in case it doesn't and this is a fresh profile..
const std::string config_dir(Path::Combine(home_dir, ".config"));
if (!FileSystem::DirectoryExists(config_dir.c_str()))
FileSystem::CreateDirectoryPath(config_dir.c_str(), false);
DataRoot = Path::RealPath(Path::Combine(config_dir, "PCSX2"));
}
}
#elif defined(__APPLE__)
static constexpr char MAC_DATA_DIR[] = "Library/Application Support/PCSX2";
const char* home_dir = getenv("HOME");
if (home_dir)
{
// ~/.config should exist, but just in case it doesn't and this is a fresh profile..
const std::string config_dir(Path::Combine(home_dir, ".config"));
if (!FileSystem::DirectoryExists(config_dir.c_str()))
FileSystem::CreateDirectoryPath(config_dir.c_str(), false);
DataRoot = Path::RealPath(Path::Combine(config_dir, "PCSX2"));
}
}
#elif defined(__APPLE__)
static constexpr char MAC_DATA_DIR[] = "Library/Application Support/PCSX2";
const char* home_dir = getenv("HOME");
if (home_dir)
DataRoot = Path::RealPath(Path::Combine(home_dir, MAC_DATA_DIR));
DataRoot = Path::RealPath(Path::Combine(home_dir, MAC_DATA_DIR));
#endif
}
}
else // Otherwise use the custom path provided by the user
DataRoot = Path::RealPath(Path::Combine(EmuConfig.CustomDataPath, "PCSX2"));
}
// couldn't determine the data directory, or using portable mode? fallback to portable.
// Couldn't determine the data directory, or using portable mode? fallback to portable.
if (DataRoot.empty())
{
#if defined(__linux__)
// special check if we're on appimage
// Special check if we're on appimage
// always make sure that DataRoot
// is adjacent next to the appimage
if (getenv("APPIMAGE"))
@@ -2254,10 +2261,10 @@ bool EmuFolders::SetDataDirectory(Error* error)
#endif
}
// inis is always below the data root
// Inis is always below the data root
Settings = Path::Combine(DataRoot, "inis");
// make sure it exists
// Make sure it exists
Console.WriteLnFmt("DataRoot Directory: {}", DataRoot);
return (FileSystem::EnsureDirectoryExists(DataRoot.c_str(), false, error) &&
FileSystem::EnsureDirectoryExists(Settings.c_str(), false, error));
+1 -1
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 = 89; // Last changed in PR 14188
static constexpr u32 SHADER_CACHE_VERSION = 92; // Last changed in PR 14399
+91 -13
View File
@@ -29,6 +29,20 @@ namespace usb_msd
"00000000000PCSX2",
};
static const USBDescStrings olympus_camera_desc_strings = {
"",
"OLYMPUS",
"USB Mass Storage",
"00000000000PCSX2",
};
static const USBDescStrings olympus_mo_desc_strings = {
"",
"OLYMPUS",
"MOS3412",
"00000000000PCSX2",
};
static const USBDescStrings sony_msac_desc_strings = {
"",
"Sony",
@@ -38,14 +52,14 @@ namespace usb_msd
static const uint8_t zip100_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x10, 0x01, // bcdUSB 0.10
0x10, 0x01, // bcdUSB 1.10
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 8
0x9B, 0x05, // idVendor 0x059B
0x34, 0x00, // idProduct 0x0034
0x00, 0x01, // bcdDevice 0.00
0x00, 0x01, // bcdDevice 1.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x03, // iSerialNumber (String Index)
@@ -94,6 +108,23 @@ namespace usb_msd
0x20, // bInterval 32 (unit depends on device speed)
};
static const uint8_t olympus_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x10, 0x01, // bcdUSB 1.10
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 8
0xb4, 0x07, // idVendor 0x07b4
0x02, 0x01, // idProduct 0x0102
0x00, 0x01, // bcdDevice 1.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x03, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t sony_msac_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
@@ -535,7 +566,7 @@ namespace usb_msd
len = std::min<size_t>(len, s->f.data_len);
//TODO No async reader/writer so do it right here
if (s->f.tag == s->f.file_op_tag)
if (s->f.file_op_tag)
{
switch (s->f.mode)
{
@@ -586,6 +617,7 @@ namespace usb_msd
s->f.result = COMMAND_PASSED;
s->f.off = 0;
s->f.file_op_tag = false;
if (cbw->cmd[0] != REQUEST_SENSE)
set_sense(s, SENSE_CODE(NO_SENSE));
@@ -698,7 +730,7 @@ namespace usb_msd
xfer_len = bswap32(*(uint32_t*)&cbw->cmd[6]);
s->f.data_len = xfer_len * LBA_BLOCK_SIZE;
s->f.file_op_tag = s->f.tag;
s->f.file_op_tag = true;
if (xfer_len == 0) // nothing to do
@@ -733,7 +765,7 @@ namespace usb_msd
xfer_len = bswap32(*(uint32_t*)&cbw->cmd[6]);
s->f.data_len = xfer_len * LBA_BLOCK_SIZE;
s->f.file_op_tag = s->f.tag;
s->f.file_op_tag = true;
if (xfer_len == 0) //nothing to do
break;
@@ -1125,6 +1157,26 @@ namespace usb_msd
s->dev.klass.handle_control = usb_msd_handle_control;
s->dev.klass.handle_data = usb_msd_handle_data;
break;
case OLYMPUS_CAMERA:
path = USB::GetConfigString(si, port, TypeName(), "ImagePathOlympusCamera");
s->desc.str = olympus_camera_desc_strings;
if (usb_desc_parse_dev(olympus_dev_descriptor, sizeof(olympus_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(zip100_config_descriptor, sizeof(zip100_config_descriptor), s->desc_dev) < 0)
goto fail;
s->dev.klass.handle_control = usb_msd_handle_control;
s->dev.klass.handle_data = usb_msd_handle_data;
break;
case OLYMPUS_MO:
path = USB::GetConfigString(si, port, TypeName(), "ImagePathOlympusMD");
s->desc.str = olympus_mo_desc_strings;
if (usb_desc_parse_dev(olympus_dev_descriptor, sizeof(olympus_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(zip100_config_descriptor, sizeof(zip100_config_descriptor), s->desc_dev) < 0)
goto fail;
s->dev.klass.handle_control = usb_msd_handle_control;
s->dev.klass.handle_data = usb_msd_handle_data;
break;
case SONY_MSAC_US1:
path = USB::GetConfigString(si, port, TypeName(), "ImagePathMsac");
s->desc.str = sony_msac_desc_strings;
@@ -1230,6 +1282,8 @@ namespace usb_msd
{
static const char* subtypes[] = {
TRANSLATE_NOOP("USB", "Iomega Zip-100 (Generic)"),
TRANSLATE_NOOP("USB", "Olympus Camera"),
TRANSLATE_NOOP("USB", "Olympus Turbo MO"),
TRANSLATE_NOOP("USB", "Sony MSAC-US1 (PictureParadise)")
};
return subtypes;
@@ -1241,18 +1295,42 @@ namespace usb_msd
{
case IOMEGA_ZIP_100:
{
static constexpr const SettingInfo settings[] = {
{SettingInfo::Type::Path, "ImagePathMsd", TRANSLATE_NOOP("USB", "Image Path"),
TRANSLATE_NOOP("USB", "Sets the path to the disk image which will back the virtual mass storage device.")},
};
static constexpr const SettingInfo settings[] = {{
.type = SettingInfo::Type::Path,
.name = "ImagePathMsd",
.display_name = TRANSLATE_NOOP("USB", "Image Path"),
.description = TRANSLATE_NOOP("USB", "Sets the path to the disk image which will back the virtual mass storage device.")
}};
return settings;
}
case OLYMPUS_CAMERA:
{
static constexpr const SettingInfo settings[] = {{
.type = SettingInfo::Type::Path,
.name = "ImagePathOlympusCamera",
.display_name = TRANSLATE_NOOP("USB", "Image Path"),
.description = TRANSLATE_NOOP("USB", "Sets the path to the disk image which will back the virtual mass storage device.")
}};
return settings;
}
case OLYMPUS_MO:
{
static constexpr const SettingInfo settings[] = {{
.type = SettingInfo::Type::Path,
.name = "ImagePathOlympusMD",
.display_name = TRANSLATE_NOOP("USB", "Image Path"),
.description = TRANSLATE_NOOP("USB", "Sets the path to the disk image which will back the virtual mass storage device.")
}};
return settings;
}
case SONY_MSAC_US1:
{
static constexpr const SettingInfo settings[] = {
{SettingInfo::Type::Path, "ImagePathMsac", TRANSLATE_NOOP("USB", "Image Path"),
TRANSLATE_NOOP("USB", "Sets the path to the disk image which will back the virtual mass storage device.")},
};
static constexpr const SettingInfo settings[] = {{
.type = SettingInfo::Type::Path,
.name = "ImagePathMsac",
.display_name = TRANSLATE_NOOP("USB", "Image Path"),
.description = TRANSLATE_NOOP("USB", "Sets the path to the disk image which will back the virtual mass storage device.")
}};
return settings;
}
default:
+2
View File
@@ -10,6 +10,8 @@ namespace usb_msd
enum MSDType
{
IOMEGA_ZIP_100,
OLYMPUS_CAMERA,
OLYMPUS_MO,
SONY_MSAC_US1,
};