Compare commits

...
Author SHA1 Message Date
lightningterror 427096dc29 GS/HW: Adjust texture copies perfmon info for CopyRect.
If we are optimizing out copies we don't need to increment the perf monitor info.

Also remove duplicate tex copies perf monitor info in tc as we already add it in CopyRect function.
2025-09-20 02:27:50 +02:00
lightningterror a7f948c00f GS: Backport and unify CopyRect optimizations to avoid redundant copies.
Moved the shared code in GSDevice where it can be shared between renderers.

Backported optimizations to DX11/GL/Metal:
Source is cleared, destination is a render target, and it's a full copy
we can clear it instead.

Source is cleared, destination is a render target, destination is cleared,
if it's the same colour and rect, we can just avoid this entirely.
2025-09-20 02:27:50 +02:00
TellowKrinkleandlightningterror 4afa5b8409 GS:SW: Use accurate fog equation 2025-09-19 23:56:03 +02:00
JordanTheToasterandlightningterror 7f285b2164 VMManager: Warn when integer scaling is enabled 2025-09-19 23:52:17 +02:00
JordanTheToasterandlightningterror 9dac7825d7 VMManager: Warn when disabling dithering 2025-09-19 23:52:17 +02:00
JordanTheToasterandlightningterror 305d0e81d6 Qt/FSUI: Adjust renderer nomenclature 2025-09-19 23:52:17 +02:00
JordanTheToasterandlightningterror 56f3d6ea09 VMManager: Warn when using Force 32bit dithering 2025-09-19 23:52:17 +02:00
PCSX2 BotandTy edc04fb8e3 [ci skip] Qt: Update Base Translation. 2025-09-17 20:08:33 -04:00
JordanTheToasterandlightningterror a72f78fd79 Config: Increase space in GS config struct 2025-09-17 14:43:46 +02:00
PCSX2 Botandlightningterror aadd0fd65e [ci skip] Qt: Update Base Translation. 2025-09-17 09:40:02 +02:00
SternXDandTy e2bc80a96f FSUI: Fix regression allowing Save State load in Hardcore Mode via ESC menu 2025-09-16 09:43:39 -04:00
TJnotJTandlightningterror 704e531c1f GS: Make sure transfers are dumped between consecutive vsyncs. 2025-09-16 14:02:10 +02:00
TJnotJTandlightningterror 203981182d GS: Make privileged registers dumping YAML. 2025-09-16 14:02:10 +02:00
TJnotJTandlightningterror 14b67e3ac3 GS: Make context dump YAML. Add comments to output. 2025-09-16 14:02:10 +02:00
TJnotJTandlightningterror f83e11892b GS: Add dumping of transfer bitmaps. 2025-09-16 14:02:10 +02:00
TJnotJTandlightningterror a8c549baee GS: Refactor duplicated debugging code in HW/SW renderer.
Specifically, code for dumping the draw information (vertices, registers, transfers).
2025-09-16 14:02:10 +02:00
TJnotJTandlightningterror 13142dd31d GS: Add memory transfers dumping as a text file.
In addition to vertices and registers, dumps the memory transfers that occurred just before the draw. Helps with debugging.
2025-09-16 14:02:10 +02:00
TJnotJTandlightningterror ed5c364603 GS: YAML dumping of vertices. 2025-09-16 14:02:10 +02:00
PCSX2 Botandlightningterror 0ccf7d2e10 [ci skip] Qt: Update Base Translation. 2025-09-15 18:22:33 +02:00
PCSX2 Botandlightningterror ebb0dc7cc5 [ci skip] PAD: Update to latest controller database. 2025-09-15 18:22:20 +02:00
TheTechnician27andTy 52ebebc739 Toolbar: Add 'Hotkeys' action 2025-09-14 13:28:14 -04:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
c8141261f2 actions: Bump the ci-deps group with 3 updates (#13244)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-14 12:15:08 -04:00
KamFretoZandTy 9c7750b85d OSD: Add Accessories type indicator to USB Input OSD 2025-09-14 12:10:19 -04:00
chaoticgdandTy bf10b55aa1 PINE: Use the correct naming convention for static globals 2025-09-13 14:45:10 -04:00
chaoticgdandTy 43d9ea99b0 PINE: Don't crash with SIGPIPE if the client dies while writing 2025-09-13 14:45:10 -04:00
Ziemasandlightningterror 37f28e95b6 Core: Calculate EE/IOPmemSize based on structs 2025-09-11 12:45:12 +02:00
Ziemasandlightningterror 1870193615 Core: Fix EEmemSize
It's got desynced from the actual size of the EEVM_MemoryAllocMess
struct at some point.
2025-09-11 12:45:12 +02:00
lightningterror 189374d19c GS: Bump shader cache version.
Forgot to re include it when I reset the commit.
2025-09-09 20:32:25 +02:00
lightningterror ac04695edd GS/shaders: Fix false positive warning for pow being negative.
Replaced pow with exp2 log2.
2025-09-09 20:29:02 +02:00
lightningterror 93bf9db0b4 GS/shaders: Fix types mismatch for ps_convert_rgb5a1_8i shader.
Fixes shader compile errors and warnings on mesa, also synch vk and dx shaders for consistency.
2025-09-09 20:29:02 +02:00
PCSX2 Botandlightningterror 9219a1a38b [ci skip] PAD: Update to latest controller database. 2025-09-08 18:15:01 +02:00
PCSX2 Botandlightningterror 1a28d6f0d1 [ci skip] Qt: Update Base Translation. 2025-09-08 18:14:48 +02:00
JordanTheToasterandTy aca1b4478e Deps: Update SDL3 to v3.2.22 2025-09-07 10:30:26 -04:00
TheTechnician27andTy 9a794f7aaa CDVD: Add message for attempting to remove a disc when no disc exists 2025-09-07 10:29:55 -04:00
TheTechnician27andTy 6e65558d42 Hotkeys: Better organize hotkeys page 2025-09-07 10:28:52 -04:00
JordanTheToasterandlightningterror 74936f49e0 GameDB: Deadly Strike fixes 2025-09-02 14:50:37 +02:00
97 changed files with 4502 additions and 2653 deletions
+3 -3
View File
@@ -68,7 +68,7 @@ jobs:
mv ./release-notes.md ${GITHUB_WORKSPACE}/release-notes.md
- name: Create a GitHub Release (Manual)
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
if: steps.tag_version.outputs.new_tag && github.event_name == 'workflow_dispatch'
with:
body_path: ./release-notes.md
@@ -77,7 +77,7 @@ jobs:
tag_name: ${{ steps.tag_version.outputs.new_tag }}
- name: Create a GitHub Release (Push)
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836
if: steps.tag_version.outputs.new_tag && github.event_name != 'workflow_dispatch'
with:
body_path: ./release-notes.md
@@ -203,7 +203,7 @@ jobs:
echo "TAG_VAL=${TAG_VAL}"
gh release edit ${TAG_VAL} --draft=false --repo PCSX2/pcsx2
- uses: actions/setup-node@v4
- uses: actions/setup-node@v5
with:
node-version: 22
@@ -20,7 +20,7 @@ LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
LIBJPEGTURBO=3.1.1
LIBPNG=1.6.50
LIBWEBP=1.6.0
SDL=SDL3-3.2.20
SDL=SDL3-3.2.22
QT=6.9.2
LZ4=1.10.0
ZSTD=1.5.7
@@ -43,7 +43,7 @@ fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.
aadc97ea91f6ef078b0ae3a62bba69e008d9a7db19b34e4ac973b19b71b4217c libjpeg-turbo-$LIBJPEGTURBO.tar.gz
4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
467600ae090dd28616fa37369faf4e3143198ff1da37729b552137e47f751a67 $SDL.tar.gz
f29d00cbcee273c0a54f3f32f86bf5c595e8823a96b1d92a145aac40571ebfcc $SDL.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
44be9c9ecfe04129c4dea0a7e1b36ad476c9cc07c292016ac98e7b41514f2440 qtbase-everywhere-src-$QT.tar.xz
@@ -14,8 +14,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL3-3.2.20.tar.gz",
"sha256": "467600ae090dd28616fa37369faf4e3143198ff1da37729b552137e47f751a67"
"url": "https://libsdl.org/release/SDL3-3.2.22.tar.gz",
"sha256": "f29d00cbcee273c0a54f3f32f86bf5c595e8823a96b1d92a145aac40571ebfcc"
}
],
"cleanup": [
@@ -40,7 +40,7 @@ fi
FREETYPE=2.13.3
HARFBUZZ=11.2.0
SDL=SDL3-3.2.20
SDL=SDL3-3.2.22
ZSTD=1.5.7
LZ4=1.10.0
LIBPNG=1.6.50
@@ -79,7 +79,7 @@ CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
16c0204704f3ebeed057aba100fe7db18d71035505cb10e595ea33d346457fc8 harfbuzz-$HARFBUZZ.tar.gz
467600ae090dd28616fa37369faf4e3143198ff1da37729b552137e47f751a67 $SDL.tar.gz
f29d00cbcee273c0a54f3f32f86bf5c595e8823a96b1d92a145aac40571ebfcc $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 libpng-$LIBPNG.tar.xz
@@ -22,7 +22,7 @@ fi
FREETYPE=2.13.3
HARFBUZZ=11.2.0
SDL=SDL3-3.2.20
SDL=SDL3-3.2.22
ZSTD=1.5.7
LZ4=1.10.0
LIBPNG=1.6.50
@@ -59,7 +59,7 @@ CMAKE_COMMON=(
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
16c0204704f3ebeed057aba100fe7db18d71035505cb10e595ea33d346457fc8 harfbuzz-$HARFBUZZ.tar.gz
467600ae090dd28616fa37369faf4e3143198ff1da37729b552137e47f751a67 $SDL.tar.gz
f29d00cbcee273c0a54f3f32f86bf5c595e8823a96b1d92a145aac40571ebfcc $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
537512904744b35e232912055ccf8ec66d768639ff3abe5788d90d792ec5f48b lz4-$LZ4.tar.gz
4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 libpng-$LIBPNG.tar.xz
@@ -46,7 +46,7 @@ set FREETYPE=2.13.3
set HARFBUZZ=11.2.0
set LIBJPEGTURBO=3.1.1
set LIBPNG=1650
set SDL=SDL3-3.2.20
set SDL=SDL3-3.2.22
set QT=6.9.2
set QTMINOR=6.9
set LZ4=1.10.0
@@ -68,7 +68,7 @@ call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuz
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1650.zip 4be6938313b08d5921f9dede13f2789b653c96f4f8595d92ff3f09c9320e51c7 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" aadc97ea91f6ef078b0ae3a62bba69e008d9a7db19b34e4ac973b19b71b4217c || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" d76454913ea6f5f38856fbf00578d8e39daf842887f3396c95608414680250f7 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 3d60068b1e5c83c66bb14c325dfef46f8fcc380735b4591de6f5e7b9738929d1 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 97d59c78e40b4ddd018738d285a12afc320b57f8265a3f760353739a3619ccdb || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" f2fc6ff382c6f3af79493d0709dbd64847d0356313518f094f9096315f2fdb30 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" af80bb671ea0f66c0036ce7041a56b0e550fc94fb88d2c77b5b6a3e33e42139b || goto error
@@ -44,7 +44,7 @@ set FREETYPE=2.13.3
set HARFBUZZ=11.2.0
set LIBJPEGTURBO=3.1.1
set LIBPNG=1650
set SDL=SDL3-3.2.20
set SDL=SDL3-3.2.22
set QT=6.9.2
set QTMINOR=6.9
set LZ4=1.10.0
@@ -66,7 +66,7 @@ call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuz
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1650.zip 4be6938313b08d5921f9dede13f2789b653c96f4f8595d92ff3f09c9320e51c7 || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" aadc97ea91f6ef078b0ae3a62bba69e008d9a7db19b34e4ac973b19b71b4217c || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" d76454913ea6f5f38856fbf00578d8e39daf842887f3396c95608414680250f7 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 3d60068b1e5c83c66bb14c325dfef46f8fcc380735b4591de6f5e7b9738929d1 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 97d59c78e40b4ddd018738d285a12afc320b57f8265a3f760353739a3619ccdb || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" f2fc6ff382c6f3af79493d0709dbd64847d0356313518f094f9096315f2fdb30 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" af80bb671ea0f66c0036ce7041a56b0e550fc94fb88d2c77b5b6a3e33e42139b || goto error
+1 -1
View File
@@ -8,7 +8,7 @@ jobs:
if: github.repository == 'PCSX2/pcsx2'
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v5
- uses: actions/labeler@v6
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
+18
View File
@@ -185,7 +185,24 @@
#define ICON_PF_KEYBOARD "\xE2\x90\xBD"
#define ICON_PF_MOUSE "\xE2\x90\xBE"
#define ICON_PF_MOUSE_AND_KEYBOARD "\xE2\x90\xBF"
#define ICON_PF_DUALSHOCK2 "\xE2\x91\x81"
#define ICON_PF_DUALSHOCK2_SLASH "\xE2\x91\x82"
#define ICON_PF_GUITAR "\xE2\x91\x83"
#define ICON_PF_STEERING_WHEEL_ALT "\xE2\x91\x84"
#define ICON_PF_SEGA_SEAMIC "\xE2\x91\x85"
#define ICON_PF_JOGCON "\xE2\x91\x86"
#define ICON_PF_BUZZ_CONTROLLER "\xE2\x91\x87"
#define ICON_PF_GAMETRAK_DEVICE "\xE2\x91\x88"
#define ICON_PF_DJ_HERO_TURNTABLE "\xE2\x91\x89"
#define ICON_PF_REALPLAY_BOWLING "\xE2\x91\x8A"
#define ICON_PF_NEGCON "\xE2\x91\x8B"
#define ICON_PF_REZ_VIBRATOR "\xE2\x91\x8C"
#define ICON_PF_EYETOY_WEBCAM "\xE2\x91\x8D"
#define ICON_PF_SINGSTAR_MIC "\xE2\x91\x8E"
#define ICON_PF_GUNCON2 "\xE2\x91\x8F"
#define ICON_PF_HEADSET "\xE2\x91\x90"
#define ICON_PF_KEYBOARDMANIA "\xE2\x91\x91"
#define ICON_PF_PRINTER "\xE2\x91\x92"
#define ICON_PF_F1 "\xE2\x91\xA0"
#define ICON_PF_F2 "\xE2\x91\xA1"
#define ICON_PF_F3 "\xE2\x91\xA2"
@@ -362,6 +379,7 @@
#define ICON_PF_HEARTBEAT_MAG "\xE2\x8D\xBE"
#define ICON_PF_MONITOR_CODE "\xE2\x8D\xBF"
#define ICON_PF_SIXTY_CIRCLE "\xE2\x8E\x80"
#define ICON_PF_VIDEO_CAMERA "\xE2\x8E\x81"
#define ICON_PF_SPEAKER_ALT "\xE2\x8D\xA7"
#define ICON_PF_THUNDERBOLT "\xE2\x8D\x9C"
#define ICON_PF_BACKWARD "\xE2\x8F\x8C"
+1186 -28
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -21758,6 +21758,8 @@ SLES-52954:
SLES-52955:
name: "Deadly Strike"
region: "PAL-E"
roundModes:
eeDivRoundMode: 3 # Fixes grid like pattern.
SLES-52956:
name: "Action Girlz Racing"
region: "PAL-E"
@@ -38928,6 +38930,8 @@ SLPM-62459:
name-en: "Simple 2000 Series Vol. 16 - Sengoku vs. Gendai"
region: "NTSC-J"
compat: 5
roundModes:
eeDivRoundMode: 3 # Fixes grid like pattern.
SLPM-62460:
name: "SuperLite2000 シミュレーション 箱庭鉄道 ~ブルートレイン・特急編~"
name-sort: "すーぱーらいと 2000 しみゅれーしょん はこにわてつどう ぶるーとれいんとっきゅうへん"
Binary file not shown.
+13 -8
View File
@@ -191,6 +191,7 @@
0300004112000000e500000000000000,Elecom JC-U909Z,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows,
03000041120000001050000000000000,Elecom JC-U911,a:b1,b:b2,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b0,x:b4,y:b5,platform:Windows,
030000006e0500000520000000000000,Elecom P301U PlayStation Controller Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
03000000250900000218000000000000,Elecom PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
030000006e0500000e20000000000000,Elecom U3912T,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows,
@@ -252,6 +253,7 @@
03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000f025000021c1000010010000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -478,6 +480,7 @@
030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows,
03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows,
03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000ec110000e1a7000000000000,Nintendo Switch,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000007e0500006920000000000000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Windows,
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows,
@@ -535,7 +538,6 @@
03000000120c00001cf1000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f90e000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000250900000118000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000250900000218000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,
030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows,
030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
@@ -681,6 +683,7 @@
03000000c01100004150000000000000,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:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,platform:Windows,
03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows,
030000009d0d00001130000000000000,Sanwa PlayStation Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows,
03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -841,6 +844,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,platform:Windows,
030000002c3600000100000000000000,Yawman Arrow,+rightx:h0.2,+righty:h0.4,-rightx:h0.8,-righty:h0.1,a:b4,b:b5,back:b6,dpdown:b15,dpleft:b14,dpright:b16,dpup:b13,leftshoulder:b10,leftstick:b0,lefttrigger:-a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b12,rightshoulder:b8,rightstick:b9,righttrigger:+a4,start:b3,x:b1,y:b2,platform:Windows,
03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000073500000400000000000000,Zenaim Arcade 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
03000000120c00000500000000000000,Zeroplus Adapter,a:b2,b:b1,back:b11,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:b0,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows,
03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -1018,6 +1022,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X,
030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000ec110000e1a7000001010000,Nintendo Switch,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
030000007e0500006920000001010000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Mac OS X,
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
@@ -1290,6 +1295,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000af1e00002400000010010000,Clockwork Pi DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,
030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,
03000000632500007a05000001020000,Cosmic Byte Ares Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,
03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
030000005e0400008e02000002010000,Data Frog S80,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux,
@@ -1311,6 +1317,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
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,
03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1503,8 +1510,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux,
060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux,
03000000ec110000e1a7000010010000,Nintendo Switch,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000007e0500006920000011010000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Linux,
060000004e696e74656e646f20537700,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
@@ -1656,7 +1663,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000032150000140a000001010000,Razer Wolverine Ultimate Xbox,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,
030000000d0f0000c100000010010000,Retro Bit Legacy16,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b4,lefttrigger:b6,misc1:b13,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f0000c100000072056800,Retro Bit Legacy16,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:+a4,misc1:b11,rightshoulder:b10,righttrigger:+a5,start:b6,x:b3,y:b2,platform:Linux,
03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,
0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
@@ -1692,11 +1698,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
03000000632500002305000010010000,Shanwan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000632500002605000010010000,Shanwan Gamepad,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,
03000000632500007505000010010000,Shanwan 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,
03000000bc2000000055000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000f025000021c1000010010000,Shanwan Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000632500002605000010010000,ShanWan Gamepad,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,
03000000632500007505000010010000,ShanWan 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,
03000000bc2000000055000010010000,ShanWan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000004b2900000430000011000000,Snakebyte Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
+34 -36
View File
@@ -305,64 +305,64 @@ PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
uint2 pos = uint2(input.p.xy);
// Collapse separate R G B A areas into their base pixel
uint2 column = (pos & ~uint2(0u, 3u)) / uint2(1,2);
uint2 column = (pos & ~uint2(0u, 3u)) / uint2(1u, 2u);
uint2 subcolumn = (pos & uint2(0u, 1u));
column.x -= (column.x / 128) * 64;
column.y += (column.y / 32) * 32;
column.x -= (column.x / 128u) * 64u;
column.y += (column.y / 32u) * 32u;
uint PSM = uint(DOFFSET);
// Deal with swizzling differences
if ((PSM & 0x8) != 0) // PSMCT16S
if ((PSM & 0x8u) != 0u) // PSMCT16S
{
if ((pos.x & 32) != 0)
if ((pos.x & 32u) != 0u)
{
column.y += 32; // 4 columns high times 4 to get bottom 4 blocks
column.x &= ~32;
column.y += 32u; // 4 columns high times 4 to get bottom 4 blocks
column.x &= ~32u;
}
if ((pos.x & 64) != 0)
if ((pos.x & 64u) != 0u)
{
column.x -= 32;
column.x -= 32u;
}
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
if (((pos.x & 16u) != 0u) != ((pos.y & 16u) != 0u))
{
column.x ^= 16;
column.y ^= 8;
column.x ^= 16u;
column.y ^= 8u;
}
if ((PSM & 0x30) != 0) // PSMZ16S - Untested but hopefully ok if anything uses it.
if ((PSM & 0x30u) != 0u) // PSMZ16S - Untested but hopefully ok if anything uses it.
{
column.x ^= 32;
column.y ^= 16;
column.x ^= 32u;
column.y ^= 16u;
}
}
else // PSMCT16
{
if ((pos.y & 32) != 0)
if ((pos.y & 32u) != 0u)
{
column.y -= 16;
column.x += 32;
column.y -= 16u;
column.x += 32u;
}
if ((pos.x & 96) != 0)
if ((pos.x & 96u) != 0u)
{
uint multi = (pos.x & 96) / 32;
column.y += 16 * multi; // 4 columns high times 4 to get bottom 4 blocks
column.x -= (pos.x & 96);
uint multi = (pos.x & 96u) / 32u;
column.y += 16u * multi; // 4 columns high times 4 to get bottom 4 blocks
column.x -= (pos.x & 96u);
}
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
if (((pos.x & 16u) != 0u) != ((pos.y & 16) != 0))
{
column.x ^= 16;
column.y ^= 8;
column.x ^= 16u;
column.y ^= 8u;
}
if ((PSM & 0x30) != 0) // PSMZ16 - Untested but hopefully ok if anything uses it.
if ((PSM & 0x30u) != 0u) // PSMZ16 - Untested but hopefully ok if anything uses it.
{
column.x ^= 32;
column.y ^= 32;
column.x ^= 32u;
column.y ^= 32u;
}
}
@@ -371,10 +371,10 @@ PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
// Compensate for potentially differing page pitch.
uint SBW = uint(EMODA);
uint DBW = uint(EMODC);
uint2 block_xy = coord / uint2(64,64);
uint block_num = (block_xy.y * (DBW / 128)) + block_xy.x;
uint2 block_offset = uint2((block_num % (SBW / 64)) * 64, (block_num / (SBW / 64)) * 64);
coord = (coord % uint2(64, 64)) + block_offset;
uint2 block_xy = coord / uint2(64u, 64u);
uint block_num = (block_xy.y * (DBW / 128u)) + block_xy.x;
uint2 block_offset = uint2((block_num % (SBW / 64u)) * 64u, (block_num / (SBW / 64u)) * 64u);
coord = (coord % uint2(64u, 64u)) + block_offset;
// Apply offset to cols 1 and 2
uint is_col23 = pos.y & 4u;
@@ -394,18 +394,16 @@ PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
{
uint red = (denorm_c.r >> 3) & 0x1Fu;
uint green = (denorm_c.g >> 3) & 0x1Fu;
float sel0 = (float)(((green << 5) | red) & 0xFF) / 255.0f;
output.c = (float4)(sel0);
output.c = (float4)(((float)(((green << 5) | red) & 0xFFu)) / 255.0f);
}
else
{
uint green = (denorm_c.g >> 3) & 0x1Fu;
uint blue = (denorm_c.b >> 3) & 0x1Fu;
uint alpha = denorm_c.a & 0x80u;
float sel0 = (float)((alpha | (blue << 2) | (green >> 3)) & 0xFF) / 255.0f;
output.c = (float4)(sel0);
output.c = (float4)(((float)((alpha | (blue << 2) | (green >> 3)) & 0xFFu)) / 255.0f);
}
return output;
}
+1 -1
View File
@@ -37,7 +37,7 @@ float4 ContrastSaturationBrightness(float4 color) // Ported to HLSL
float3 conColor = lerp(AvgLumin, satColor, con);
float3 csb = conColor;
csb = pow(csb, 1.0 / gam);
csb = exp2(log2(csb) * (1.0 / gam));
color.rgb = csb;
return color;
}
+30 -32
View File
@@ -258,62 +258,62 @@ void ps_convert_rgb5a1_8i()
uvec2 pos = uvec2(gl_FragCoord.xy);
// Collapse separate R G B A areas into their base pixel
uvec2 column = (pos & ~uvec2(0u, 3u)) / uvec2(1,2);
uvec2 column = (pos & ~uvec2(0u, 3u)) / uvec2(1u, 2u);
uvec2 subcolumn = (pos & uvec2(0u, 1u));
column.x -= (column.x / 128) * 64;
column.y += (column.y / 32) * 32;
column.x -= (column.x / 128u) * 64u;
column.y += (column.y / 32u) * 32u;
// Deal with swizzling differences
if ((PSM & 0x8) != 0) // PSMCT16S
if ((PSM & 0x8u) != 0u) // PSMCT16S
{
if ((pos.x & 32) != 0)
if ((pos.x & 32u) != 0u)
{
column.y += 32; // 4 columns high times 4 to get bottom 4 blocks
column.x &= ~32;
column.y += 32u; // 4 columns high times 4 to get bottom 4 blocks
column.x &= ~32u;
}
if ((pos.x & 64) != 0)
if ((pos.x & 64u) != 0u)
{
column.x -= 32;
column.x -= 32u;
}
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
if (((pos.x & 16u) != 0u) != ((pos.y & 16u) != 0u))
{
column.x ^= 16;
column.y ^= 8;
column.x ^= 16u;
column.y ^= 8u;
}
if ((PSM & 0x30) != 0) // PSMZ16S - Untested but hopefully ok if anything uses it.
if ((PSM & 0x30u) != 0u) // PSMZ16S - Untested but hopefully ok if anything uses it.
{
column.x ^= 32;
column.y ^= 16;
column.x ^= 32u;
column.y ^= 16u;
}
}
else // PSMCT16
{
if ((pos.y & 32) != 0)
if ((pos.y & 32u) != 0u)
{
column.y -= 16;
column.x += 32;
column.y -= 16u;
column.x += 32u;
}
if ((pos.x & 96) != 0)
if ((pos.x & 96u) != 0u)
{
uint multi = (pos.x & 96) / 32;
column.y += 16 * multi; // 4 columns high times 4 to get bottom 4 blocks
column.x -= (pos.x & 96);
uint multi = (pos.x & 96u) / 32u;
column.y += 16u * multi; // 4 columns high times 4 to get bottom 4 blocks
column.x -= (pos.x & 96u);
}
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
if (((pos.x & 16u) != 0u) != ((pos.y & 16u) != 0u))
{
column.x ^= 16;
column.y ^= 8;
column.x ^= 16u;
column.y ^= 8u;
}
if ((PSM & 0x30) != 0) // PSMZ16 - Untested but hopefully ok if anything uses it.
if ((PSM & 0x30u) != 0u) // PSMZ16 - Untested but hopefully ok if anything uses it.
{
column.x ^= 32;
column.y ^= 32;
column.x ^= 32u;
column.y ^= 32u;
}
}
uvec2 coord = column | subcolumn;
@@ -342,18 +342,16 @@ void ps_convert_rgb5a1_8i()
{
uint red = (denorm_c.r >> 3) & 0x1Fu;
uint green = (denorm_c.g >> 3) & 0x1Fu;
float sel0 = float(((green << 5) | red) & 0xFF) / 255.0f;
SV_Target0 = vec4(sel0);
SV_Target0 = vec4(float(((green << 5) | red) & 0xFFu) / 255.0f);
}
else
{
uint green = (denorm_c.g >> 3) & 0x1Fu;
uint blue = (denorm_c.b >> 3) & 0x1Fu;
uint alpha = denorm_c.a & 0x80u;
float sel0 = float((alpha | (blue << 2) | (green >> 3)) & 0xFF) / 255.0f;
SV_Target0 = vec4(sel0);
SV_Target0 = vec4(float((alpha | (blue << 2) | (green >> 3)) & 0xFFu) / 255.0f);
}
}
#endif
+31 -32
View File
@@ -332,62 +332,62 @@ void ps_convert_rgb5a1_8i()
uvec2 pos = uvec2(gl_FragCoord.xy);
// Collapse separate R G B A areas into their base pixel
uvec2 column = (pos & ~uvec2(0u, 3u)) / uvec2(1,2);
uvec2 column = (pos & ~uvec2(0u, 3u)) / uvec2(1u, 2u);
uvec2 subcolumn = (pos & uvec2(0u, 1u));
column.x -= (column.x / 128) * 64;
column.y += (column.y / 32) * 32;
column.x -= (column.x / 128u) * 64u;
column.y += (column.y / 32u) * 32u;
// Deal with swizzling differences
if ((PSM & 0x8) != 0) // PSMCT16S
if ((PSM & 0x8u) != 0u) // PSMCT16S
{
if ((pos.x & 32) != 0)
if ((pos.x & 32u) != 0u)
{
column.y += 32; // 4 columns high times 4 to get bottom 4 blocks
column.x &= ~32;
column.y += 32u; // 4 columns high times 4 to get bottom 4 blocks
column.x &= ~32u;
}
if ((pos.x & 64) != 0)
if ((pos.x & 64u) != 0u)
{
column.x -= 32;
column.x -= 32u;
}
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
if (((pos.x & 16u) != 0u) != ((pos.y & 16u) != 0u))
{
column.x ^= 16;
column.y ^= 8;
column.x ^= 16u;
column.y ^= 8u;
}
if ((PSM & 0x30) != 0) // PSMZ16S - Untested but hopefully ok if anything uses it.
if ((PSM & 0x30u) != 0u) // PSMZ16S - Untested but hopefully ok if anything uses it.
{
column.x ^= 32;
column.y ^= 16;
column.x ^= 32u;
column.y ^= 16u;
}
}
else // PSMCT16
{
if ((pos.y & 32) != 0)
if ((pos.y & 32u) != 0u)
{
column.y -= 16;
column.x += 32;
column.y -= 16u;
column.x += 32u;
}
if ((pos.x & 96) != 0)
if ((pos.x & 96u) != 0u)
{
uint multi = (pos.x & 96) / 32;
column.y += 16 * multi; // 4 columns high times 4 to get bottom 4 blocks
column.x -= (pos.x & 96);
uint multi = (pos.x & 96u) / 32u;
column.y += 16u * multi; // 4 columns high times 4 to get bottom 4 blocks
column.x -= (pos.x & 96u);
}
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
if (((pos.x & 16u) != 0u) != ((pos.y & 16u) != 0u))
{
column.x ^= 16;
column.y ^= 8;
column.x ^= 16u;
column.y ^= 8u;
}
if ((PSM & 0x30) != 0) // PSMZ16 - Untested but hopefully ok if anything uses it.
if ((PSM & 0x30u) != 0u) // PSMZ16 - Untested but hopefully ok if anything uses it.
{
column.x ^= 32;
column.y ^= 32;
column.x ^= 32u;
column.y ^= 32u;
}
}
uvec2 coord = column | subcolumn;
@@ -410,23 +410,22 @@ void ps_convert_rgb5a1_8i()
coord *= uvec2(ScaleFactor);
vec4 pixel = texelFetch(samp0, ivec2(coord), 0);
uvec4 denorm_c = uvec4(pixel * 255.5f);
if ((pos.y & 2u) == 0u)
{
uint red = (denorm_c.r >> 3) & 0x1Fu;
uint green = (denorm_c.g >> 3) & 0x1Fu;
float sel0 = float(((green << 5) | red) & 0xFF) / 255.0f;
o_col0 = vec4(sel0);
o_col0 = vec4(float(((green << 5) | red) & 0xFFu) / 255.0f);
}
else
{
uint green = (denorm_c.g >> 3) & 0x1Fu;
uint blue = (denorm_c.b >> 3) & 0x1Fu;
uint alpha = denorm_c.a & 0x80u;
float sel0 = float((alpha | (blue << 2) | (green >> 3)) & 0xFF) / 255.0f;
o_col0 = vec4(sel0);
o_col0 = vec4(float((alpha | (blue << 2) | (green >> 3)) & 0xFFu) / 255.0f);
}
}
#endif
+4 -2
View File
@@ -473,8 +473,8 @@ static void PrintCommandLineHelp(const char* progname)
std::fprintf(stderr, " -help: Displays this information and exits.\n");
std::fprintf(stderr, " -version: Displays version information and exits.\n");
std::fprintf(stderr, " -dumpdir <dir>: Frame dump directory (will be dumped as filename_frameN.png).\n");
std::fprintf(stderr, " -dump [rt|tex|z|f|a|i]: Enabling dumping of render target, texture, z buffer, frame, "
"alphas, and info (context, vertices), respectively, per draw. Generates lots of data.\n");
std::fprintf(stderr, " -dump [rt|tex|z|f|a|i|tr]: Enabling dumping of render target, texture, z buffer, frame, "
"alphas, and info (context, vertices, transfers (list)), transfers (images), respectively, per draw. Generates lots of data.\n");
std::fprintf(stderr, " -dumprange N[,L,B]: Start dumping from draw N (base 0), stops after L draws, and only "
"those draws that are multiples of B (intersection of -dumprange and -dumprangef used)."
"Defaults to 0,-1,1 (all draws). Only used if -dump used.\n");
@@ -558,6 +558,8 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveAlpha", true);
if (str.find("i") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveInfo", true);
if (str.find("tr") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveTransferImages", true);
continue;
}
else if (CHECK_ARG_PARAM("-dumprange"))
+2
View File
@@ -339,6 +339,8 @@ void MainWindow::connectSignals()
connect(m_ui.actionToolbarSettings, &QAction::triggered, this, &MainWindow::onSettingsTriggeredFromToolbar);
connect(m_ui.actionToolbarControllerSettings, &QAction::triggered,
[this]() { doControllerSettings(ControllerSettingsWindow::Category::GlobalSettings); });
connect(m_ui.actionToolbarHotkeySettings, &QAction::triggered,
[this]() { doControllerSettings(ControllerSettingsWindow::Category::HotkeySettings); });
connect(m_ui.actionToolbarScreenshot, &QAction::triggered, this, &MainWindow::onScreenshotActionTriggered);
connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close);
connect(m_ui.actionScreenshot, &QAction::triggered, this, &MainWindow::onScreenshotActionTriggered);
+10 -1
View File
@@ -132,7 +132,7 @@
</property>
<widget class="QMenu" name="menuDebugSwitchRenderer">
<property name="title">
<string>&amp;Switch Renderer</string>
<string>&amp;Switch Graphics API</string>
</property>
<property name="icon">
<iconset theme="brush-line"/>
@@ -266,6 +266,7 @@
<addaction name="separator"/>
<addaction name="actionToolbarSettings"/>
<addaction name="actionToolbarControllerSettings"/>
<addaction name="actionToolbarHotkeySettings"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<action name="actionStartFile">
@@ -458,6 +459,14 @@
<string>&amp;Hotkeys</string>
</property>
</action>
<action name="actionToolbarHotkeySettings">
<property name="icon">
<iconset theme="keyboard-line"/>
</property>
<property name="text">
<string comment="In Toolbar">Hotkeys</string>
</property>
</action>
<action name="actionGraphicsSettings">
<property name="icon">
<iconset theme="image-fill"/>
+7
View File
@@ -71,6 +71,13 @@
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="saveTransferImages">
<property name="text">
<string>Save Transfer Image Data</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
@@ -109,6 +109,7 @@ DebugSettingsWidget::DebugSettingsWidget(SettingsWindow* settings_dialog, QWidge
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveDepth, "EmuCore/GS", "SaveDepth", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveAlpha, "EmuCore/GS", "SaveAlpha", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveInfo, "EmuCore/GS", "SaveInfo", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_gs.saveTransferImages, "EmuCore/GS", "SaveTransferImages", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.saveDrawStart, "EmuCore/GS", "SaveDrawStart", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.saveDrawCount, "EmuCore/GS", "SaveDrawCount", 5000);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_gs.saveFrameStart, "EmuCore/GS", "SaveFrameStart", 0);
@@ -213,6 +214,7 @@ void DebugSettingsWidget::onDrawDumpingChanged()
m_gs.saveDepth->setEnabled(enabled);
m_gs.saveAlpha->setEnabled(enabled);
m_gs.saveInfo->setEnabled(enabled);
m_gs.saveTransferImages->setEnabled(enabled);
m_gs.saveDrawStart->setEnabled(enabled);
m_gs.saveDrawCount->setEnabled(enabled);
m_gs.saveFrameStart->setEnabled(enabled);
+1 -1
View File
@@ -23,7 +23,7 @@
<item row="0" column="0">
<widget class="QLabel" name="rendererText">
<property name="text">
<string>Renderer:</string>
<string>Graphics API:</string>
</property>
</widget>
</item>
+3 -3
View File
@@ -40,7 +40,7 @@ static constexpr RendererInfo s_renderer_info[] = {
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Metal"), GSRendererType::Metal},
#endif
//: Graphics backend/engine type (refers to emulating the GS in software, on the CPU). Translate accordingly.
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Software"), GSRendererType::SW},
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Software Renderer"), GSRendererType::SW},
//: Null here means that this is a graphics backend that will show nothing.
{QT_TRANSLATE_NOOP("GraphicsSettingsWidget", "Null"), GSRendererType::Null},
};
@@ -635,7 +635,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
dialog()->registerWidgetHelp(m_fixes.readTCOnClose, tr("Read Targets When Closing"), tr("Unchecked"),
tr("Flushes all targets in the texture cache back to local memory when shutting down. Can prevent lost visuals when saving "
"state or switching renderers, but can also cause graphical corruption."));
"state or switching graphics APIs, but can also cause graphical corruption."));
dialog()->registerWidgetHelp(m_fixes.estimateTextureRegion, tr("Estimate Texture Region"), tr("Unchecked"),
tr("Attempts to reduce the texture size when games do not set it themselves (e.g. Snowblind games)."));
@@ -828,7 +828,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
dialog()->registerWidgetHelp(m_advanced.useBlitSwapChain, tr("Use Blit Swap Chain"), tr("Unchecked"),
//: Blit = a data operation. You might want to write it as-is, but fully uppercased. More information: https://en.wikipedia.org/wiki/Bit_blit
tr("Uses a blit presentation model instead of flipping when using the Direct3D 11 "
"renderer. This usually results in slower performance, but may be required for some "
"graphics API. This usually results in slower performance, but may be required for some "
"streaming applications, or to uncap framerates on some systems."));
dialog()->registerWidgetHelp(m_advanced.exclusiveFullscreenControl, tr("Allow Exclusive Fullscreen"), tr("Automatic (Default)"),
+12 -4
View File
@@ -53,16 +53,24 @@ void HotkeySettingsWidget::createButtons()
auto iter = m_categories.find(category);
if (iter == m_categories.end())
{
// Top line
QLabel* top_line = new QLabel(m_container);
top_line->setFrameShape(QFrame::HLine);
top_line->setFixedHeight(12);
m_layout->addWidget(top_line);
// Category label
QLabel* label = new QLabel(category, m_container);
QFont label_font(label->font());
label_font.setPointSizeF(14.0f);
label->setFont(label_font);
m_layout->addWidget(label);
QLabel* line = new QLabel(m_container);
line->setFrameShape(QFrame::HLine);
line->setFixedHeight(4);
m_layout->addWidget(line);
// Bottom line
QLabel* bottom_line = new QLabel(m_container);
bottom_line->setFrameShape(QFrame::HLine);
bottom_line->setFixedHeight(12);
m_layout->addWidget(bottom_line);
QGridLayout* layout = new QGridLayout();
layout->setContentsMargins(0, 0, 0, 0);
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -711,7 +711,7 @@ struct Pcsx2Config
union
{
u64 bitset;
u64 bitset[2];
struct
{
@@ -774,6 +774,7 @@ struct Pcsx2Config
SaveDepth : 1,
SaveAlpha : 1,
SaveInfo : 1,
SaveTransferImages : 1,
DumpReplaceableTextures : 1,
DumpReplaceableMipmaps : 1,
DumpTexturesWithFMVActive : 1,
+85 -83
View File
@@ -169,121 +169,123 @@ void GSDrawingContext::Dump(const std::string& filename)
if (!fp)
return;
// Warning: The indentation must be consistent with GSDrawingEnvironment::Dump().
fprintf(fp,
"XYOFFSET\n"
"\tOFX:%.4f\n"
"\tOFY:%.4f\n\n",
"XYOFFSET:\n"
" OFX: %.4f\n"
" OFY: %.4f\n\n",
XYOFFSET.OFX / 16.0f, XYOFFSET.OFY / 16.0f);
fprintf(fp,
"MIPTBP1\n"
"\tTBP1:0x%x\n"
"\tTBW1:%u\n"
"\tTBP2:0x%x\n"
"\tTBW2:%u\n"
"\tTBP3:0x%x\n"
"\tTBW3:%u\n\n",
"MIPTBP1:\n"
" TBP1: 0x%x\n"
" TBW1: %u\n"
" TBP2: 0x%x\n"
" TBW2: %u\n"
" TBP3: 0x%x\n"
" TBW3: %u\n\n",
static_cast<uint32_t>(MIPTBP1.TBP1), static_cast<uint32_t>(MIPTBP1.TBW1), static_cast<uint32_t>(MIPTBP1.TBP2),
static_cast<uint32_t>(MIPTBP1.TBW2), static_cast<uint32_t>(MIPTBP1.TBP3), static_cast<uint32_t>(MIPTBP1.TBW3));
fprintf(fp,
"MIPTBP2\n"
"\tTBP4:0x%x\n"
"\tTBW4:%u\n"
"\tTBP5:0x%x\n"
"\tTBW5:%u\n"
"\tTBP6:0x%x\n"
"\tTBW6:%u\n\n",
"MIPTBP2:\n"
" TBP4: 0x%x\n"
" TBW4: %u\n"
" TBP5: 0x%x\n"
" TBW5: %u\n"
" TBP6: 0x%x\n"
" TBW6: %u\n\n",
static_cast<uint32_t>(MIPTBP2.TBP4), static_cast<uint32_t>(MIPTBP2.TBW4), static_cast<uint32_t>(MIPTBP2.TBP5),
static_cast<uint32_t>(MIPTBP2.TBW5), static_cast<uint32_t>(MIPTBP2.TBP6), static_cast<uint32_t>(MIPTBP2.TBW6));
fprintf(fp,
"TEX0\n"
"\tTBP0:0x%x\n"
"\tTBW:%u\n"
"\tPSM:0x%x (%s)\n"
"\tTW:%u\n"
"\tTH:%u\n"
"\tTCC:%u\n"
"\tTFX:%u\n"
"\tCBP:0x%x\n"
"\tCPSM:0x%x (%s)\n"
"\tCSM:%u\n"
"\tCSA:%u\n"
"\tCLD:%u\n\n",
TEX0.TBP0, TEX0.TBW, TEX0.PSM, GSUtil::GetPSMName(TEX0.PSM), TEX0.TW, static_cast<uint32_t>(TEX0.TH), TEX0.TCC, TEX0.TFX, TEX0.CBP, TEX0.CPSM, GSUtil::GetPSMName(TEX0.CPSM), TEX0.CSM,TEX0.CSA, TEX0.CLD);
"TEX0:\n"
" TBP0: 0x%x\n"
" TBW: %u\n"
" PSM: 0x%x # %s\n"
" TW: %u\n"
" TH: %u\n"
" TCC: %u # %s\n"
" TFX: %u # %s\n"
" CBP: 0x%x\n"
" CPSM: 0x%x # %s\n"
" CSM: %u\n"
" CSA: %u\n"
" CLD: %u\n\n",
TEX0.TBP0, TEX0.TBW, TEX0.PSM, GSUtil::GetPSMName(TEX0.PSM), TEX0.TW, static_cast<uint32_t>(TEX0.TH), TEX0.TCC, GSUtil::GetTCCName(TEX0.TCC), TEX0.TFX, GSUtil::GetTFXName(TEX0.TFX), TEX0.CBP, TEX0.CPSM, GSUtil::GetPSMName(TEX0.CPSM), TEX0.CSM, TEX0.CSA, TEX0.CLD);
fprintf(fp,
"TEX1\n"
"\tLCM:%u\n"
"\tMXL:%u\n"
"\tMMAG:%u\n"
"\tMMIN:%u\n"
"\tMTBA:%u\n"
"\tL:%u\n"
"\tK:%d\n\n",
TEX1.LCM, TEX1.MXL, TEX1.MMAG, TEX1.MMIN, TEX1.MTBA, TEX1.L, TEX1.K);
"TEX1:\n"
" LCM: %u # %s\n"
" MXL: %u\n"
" MMAG: %u # %s\n"
" MMIN: %u # %s\n"
" MTBA: %u\n"
" L: %u\n"
" K: %.4f\n\n",
TEX1.LCM, GSUtil::GetLCMName(TEX1.LCM), TEX1.MXL, TEX1.MMAG, GSUtil::GetMMAGName(TEX1.MMAG), TEX1.MMIN, GSUtil::GetMMINName(TEX1.MMIN), TEX1.MTBA, TEX1.L, static_cast<float>((static_cast<int>(TEX1.K) ^ 0x800) - 0x800) / 16.0f);
fprintf(fp,
"CLAMP\n"
"\tWMS:%u (%s)\n"
"\tWMT:%u (%s)\n"
"\tMINU:%u\n"
"\tMAXU:%u\n"
"\tMAXV:%u\n"
"\tMINV:%u\n\n",
CLAMP.WMS, GSUtil::GetWMName(CLAMP.WMS), CLAMP.WMT,GSUtil::GetWMName(CLAMP.WMT), CLAMP.MINU, CLAMP.MAXU, CLAMP.MAXV, static_cast<uint32_t>(CLAMP.MINV));
"CLAMP:\n"
" WMS: %u # %s\n"
" WMT: %u # %s\n"
" MINU: %u\n"
" MAXU: %u\n"
" MINV: %u\n"
" MAXV: %u\n\n",
CLAMP.WMS, GSUtil::GetWMName(CLAMP.WMS), CLAMP.WMT,GSUtil::GetWMName(CLAMP.WMT), CLAMP.MINU, CLAMP.MAXU, static_cast<uint32_t>(CLAMP.MINV), CLAMP.MAXV);
fprintf(fp,
"SCISSOR\n"
"\tSCAX0:%u\n"
"\tSCAX1:%u\n"
"\tSCAY0:%u\n"
"\tSCAY1:%u\n\n",
"SCISSOR:\n"
" SCAX0: %u\n"
" SCAX1: %u\n"
" SCAY0: %u\n"
" SCAY1: %u\n\n",
SCISSOR.SCAX0, SCISSOR.SCAX1, SCISSOR.SCAY0, SCISSOR.SCAY1);
fprintf(fp,
"ALPHA\n"
"\tA:%u\n"
"\tB:%u\n"
"\tC:%u\n"
"\tD:%u\n"
"\tFIX:%u\n",
"ALPHA:\n"
" A: %u\n"
" B: %u\n"
" C: %u\n"
" D: %u\n"
" FIX: %u\n",
ALPHA.A, ALPHA.B, ALPHA.C, ALPHA.D, ALPHA.FIX);
const char* col[3] = {"Cs", "Cd", "0"};
const char* alpha[3] = {"As", "Ad", "Af"};
fprintf(fp, "\t=> (%s - %s) * %s + %s\n\n", col[ALPHA.A], col[ALPHA.B], alpha[ALPHA.C], col[ALPHA.D]);
constexpr const char* col[3] = {"Cs", "Cd", "0"};
constexpr const char* alpha[3] = {"As", "Ad", "Af"};
fprintf(fp, " # => (%s - %s) * %s + %s\n\n", col[ALPHA.A], col[ALPHA.B], alpha[ALPHA.C], col[ALPHA.D]);
fprintf(fp,
"TEST\n"
"\tATE:%u\n"
"\tATST:%u (%s)\n"
"\tAREF:%u\n"
"\tAFAIL:%u (%s)\n"
"\tDATE:%u\n"
"\tDATM:%u\n"
"\tZTE:%u\n"
"\tZTST:%u (%s)\n\n",
TEST.ATE, TEST.ATST, GSUtil::GetATSTName(TEST.ATST), TEST.AREF, TEST.AFAIL, GSUtil::GetAFAILName(TEST.AFAIL), TEST.DATE, TEST.DATM, TEST.ZTE, TEST.ZTST, GSUtil::GetZTSTName(TEST.ZTST));
"TEST:\n"
" ATE: %u\n"
" ATST: %u # %s\n"
" AREF: %u\n"
" AFAIL: %u # %s\n"
" DATE: %u\n"
" DATM: %u # %s\n"
" ZTE: %u\n"
" ZTST: %u # %s\n\n",
TEST.ATE, TEST.ATST, GSUtil::GetATSTName(TEST.ATST), TEST.AREF, TEST.AFAIL, GSUtil::GetAFAILName(TEST.AFAIL), TEST.DATE, TEST.DATM, GSUtil::GetDATMName(TEST.DATM), TEST.ZTE, TEST.ZTST, GSUtil::GetZTSTName(TEST.ZTST));
fprintf(fp,
"FBA\n"
"\tFBA:%u\n\n",
"FBA:\n"
" FBA: %u\n\n",
FBA.FBA);
fprintf(fp,
"FRAME\n"
"\tFBP (*32):0x%x\n"
"\tFBW:%u\n"
"\tPSM:0x%x (%s)\n"
"\tFBMSK:0x%x\n\n",
"FRAME:\n"
" FBP: 0x%x # (*32)\n"
" FBW: %u\n"
" PSM: 0x%x # %s\n"
" FBMSK: 0x%x\n\n",
FRAME.FBP * 32, FRAME.FBW, FRAME.PSM, GSUtil::GetPSMName(FRAME.PSM), FRAME.FBMSK);
fprintf(fp,
"ZBUF\n"
"\tZBP (*32):0x%x\n"
"\tPSM:0x%x (%s)\n"
"\tZMSK:%u\n\n",
"ZBUF:\n"
" ZBP: 0x%x # (*32)\n"
" PSM: 0x%x # %s\n"
" ZMSK: %u\n\n",
ZBUF.ZBP * 32, ZBUF.PSM, GSUtil::GetPSMName(ZBUF.PSM), ZBUF.ZMSK);
fclose(fp);
+83 -81
View File
@@ -35,112 +35,114 @@ void GSDrawingEnvironment::Dump(const std::string& filename) const
if (!fp)
return;
fprintf(fp, "PRIM\n"
"\tPRIM:%u (%s)\n"
"\tIIP:%u\n"
"\tTME:%u\n"
"\tFGE:%u\n"
"\tABE:%u\n"
"\tAA1:%u\n"
"\tFST:%u\n"
"\tCTXT:%u\n"
"\tFIX:%u\n\n",
// Warning: The indentation must be consistent with GSDrawingContext::Dump().
fprintf(fp, "PRIM:\n"
" PRIM: %u # %s\n"
" IIP: %u\n"
" TME: %u\n"
" FGE: %u\n"
" ABE: %u\n"
" AA1: %u\n"
" FST: %u\n"
" CTXT: %u\n"
" FIX: %u\n\n",
PRIM.PRIM, GSUtil::GetPrimName(PRIM.PRIM), PRIM.IIP, PRIM.TME, PRIM.FGE, PRIM.ABE, PRIM.AA1, PRIM.FST, PRIM.CTXT, PRIM.FIX);
fprintf(fp, "PRMODE (when AC=0)\n"
"\t_PRIM:%u (%s)\n"
"\tIIP:%u\n"
"\tTME:%u\n"
"\tFGE:%u\n"
"\tABE:%u\n"
"\tAA1:%u\n"
"\tFST:%u\n"
"\tCTXT:%u\n"
"\tFIX:%u\n\n",
fprintf(fp, "PRMODE: # when AC=0\n"
" _PRIM: %u # %s\n"
" IIP: %u\n"
" TME: %u\n"
" FGE: %u\n"
" ABE: %u\n"
" AA1: %u\n"
" FST: %u\n"
" CTXT: %u\n"
" FIX: %u\n\n",
PRMODE._PRIM, GSUtil::GetPrimName(PRMODE._PRIM), PRMODE.IIP, PRMODE.TME, PRMODE.FGE, PRMODE.ABE, PRMODE.AA1, PRMODE.FST, PRMODE.CTXT, PRMODE.FIX);
fprintf(fp, "PRMODECONT\n"
"\tAC:%u\n\n",
PRMODECONT.AC);
fprintf(fp, "PRMODECONT:\n"
" AC: %u # %s\n\n",
PRMODECONT.AC, GSUtil::GetACName(PRMODECONT.AC));
fprintf(fp, "TEXCLUT\n"
"\tCOU:%u\n"
"\tCBW:%u\n"
"\tCOV:%u\n\n",
TEXCLUT.COU, TEXCLUT.CBW, TEXCLUT.COV);
fprintf(fp, "TEXCLUT:\n"
" CBW: %u\n"
" COU: %u\n"
" COV: %u\n\n",
TEXCLUT.CBW, TEXCLUT.COU, TEXCLUT.COV);
fprintf(fp, "SCANMSK\n"
"\tMSK:%u\n\n",
SCANMSK.MSK);
fprintf(fp, "SCANMSK:\n"
" MSK: %u # %s\n\n",
SCANMSK.MSK, GSUtil::GetSCANMSKName(SCANMSK.MSK));
fprintf(fp, "TEXA\n"
"\tAEM:%u\n"
"\tTA0:%u\n"
"\tTA1:%u\n\n",
fprintf(fp, "TEXA:\n"
" AEM: %u\n"
" TA0: %u\n"
" TA1: %u\n\n",
TEXA.AEM, TEXA.TA0, TEXA.TA1);
fprintf(fp, "FOGCOL\n"
"\tFCG:%u\n"
"\tFCB:%u\n"
"\tFCR:%u\n\n",
fprintf(fp, "FOGCOL:\n"
" FCG: %u\n"
" FCB: %u\n"
" FCR: %u\n\n",
FOGCOL.FCG, FOGCOL.FCB, FOGCOL.FCR);
fprintf(fp, "DIMX\n"
"\tDM22:%d\n"
"\tDM23:%d\n"
"\tDM31:%d\n"
"\tDM02:%d\n"
"\tDM21:%d\n"
"\tDM12:%d\n"
"\tDM03:%d\n"
"\tDM01:%d\n"
"\tDM33:%d\n"
"\tDM30:%d\n"
"\tDM11:%d\n"
"\tDM10:%d\n"
"\tDM20:%d\n"
"\tDM32:%d\n"
"\tDM00:%d\n"
"\tDM13:%d\n\n",
fprintf(fp, "DIMX:\n"
" DM22: %d\n"
" DM23: %d\n"
" DM31: %d\n"
" DM02: %d\n"
" DM21: %d\n"
" DM12: %d\n"
" DM03: %d\n"
" DM01: %d\n"
" DM33: %d\n"
" DM30: %d\n"
" DM11: %d\n"
" DM10: %d\n"
" DM20: %d\n"
" DM32: %d\n"
" DM00: %d\n"
" DM13: %d\n\n",
DIMX.DM22, DIMX.DM23, DIMX.DM31, DIMX.DM02, DIMX.DM21, DIMX.DM12, DIMX.DM03, DIMX.DM01, DIMX.DM33, DIMX.DM30, DIMX.DM11, DIMX.DM10, DIMX.DM20, DIMX.DM32, DIMX.DM00, DIMX.DM13);
fprintf(fp, "DTHE\n"
"\tDTHE:%u\n\n",
fprintf(fp, "DTHE:\n"
" DTHE: %u\n\n",
DTHE.DTHE);
fprintf(fp, "COLCLAMP\n"
"\tCLAMP:%u\n\n",
fprintf(fp, "COLCLAMP:\n"
" CLAMP: %u\n\n",
COLCLAMP.CLAMP);
fprintf(fp, "PABE\n"
"\tPABE:%u\n\n",
fprintf(fp, "PABE:\n"
" PABE: %u\n\n",
PABE.PABE);
fprintf(fp, "BITBLTBUF\n"
"\tSBW:%u\n"
"\tSBP:0x%x\n"
"\tSPSM:%u (%s)\n"
"\tDBW:%u\n"
"\tDPSM:%u (%s)\n"
"\tDBP:0x%x\n\n",
fprintf(fp, "BITBLTBUF:\n"
" SBW: %u\n"
" SBP: 0x%x\n"
" SPSM: %u # %s\n"
" DBW: %u\n"
" DPSM: %u # %s\n"
" DBP: 0x%x\n\n",
BITBLTBUF.SBW, BITBLTBUF.SBP, BITBLTBUF.SPSM, GSUtil::GetPSMName(BITBLTBUF.SPSM), BITBLTBUF.DBW, BITBLTBUF.DPSM, GSUtil::GetPSMName(BITBLTBUF.DPSM), BITBLTBUF.DBP);
fprintf(fp, "TRXDIR\n"
"\tXDIR:%u\n\n",
fprintf(fp, "TRXDIR:\n"
" XDIR: %u\n\n",
TRXDIR.XDIR);
fprintf(fp, "TRXPOS\n"
"\tDIRY:%u\n"
"\tSSAY:%u\n"
"\tSSAX:%u\n"
"\tDIRX:%u\n"
"\tDSAX:%u\n"
"\tDSAY:%u\n\n",
fprintf(fp, "TRXPOS:\n"
" DIRY: %u\n"
" SSAY: %u\n"
" SSAX: %u\n"
" DIRX: %u\n"
" DSAX: %u\n"
" DSAY: %u\n\n",
TRXPOS.DIRY, TRXPOS.SSAY, TRXPOS.SSAX, TRXPOS.DIRX, TRXPOS.DSAX, TRXPOS.DSAY);
fprintf(fp, "TRXREG\n"
"\tRRH:%u\n"
"\tRRW:%u\n\n",
fprintf(fp, "TRXREG:\n"
" RRH: %u\n"
" RRW: %u\n\n",
TRXREG.RRH, TRXREG.RRW);
fclose(fp);
+2 -2
View File
@@ -651,7 +651,7 @@ void GSLocalMemory::ReadTexture(const GSOffset& off, const GSVector4i& r, u8* ds
//
void GSLocalMemory::SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int w, int h)
void GSLocalMemory::SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int w, int h, int x, int y)
{
int pitch = w * 4;
int size = pitch * h;
@@ -671,7 +671,7 @@ void GSLocalMemory::SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int
{
for (int i = 0; i < w; i++)
{
((u32*)p)[i] = (this->*rp)(i, j, TEX0.TBP0, TEX0.TBW);
((u32*)p)[i] = (this->*rp)(x + i, y + j, TEX0.TBP0, TEX0.TBW);
}
}
+1 -1
View File
@@ -1121,7 +1121,7 @@ public:
//
void SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int w, int h);
void SaveBMP(const std::string& fn, u32 bp, u32 bw, u32 psm, int w, int h, int x = 0, int y = 0);
};
constexpr inline GSOffset GSOffset::fromKnownPSM(u32 bp, u32 bw, GS_PSM psm)
+388 -83
View File
@@ -15,6 +15,7 @@
#include <algorithm>
#include <cfloat>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <bit>
@@ -433,6 +434,34 @@ const char* GSState::GetFlushReasonString(GSFlushReason reason)
}
}
void GSState::DumpDrawInfo(bool dump_regs, bool dump_verts, bool dump_transfers)
{
std::string s;
// Dump Register state
if (dump_regs)
{
s = GetDrawDumpPath("%05d_context.txt", s_n);
m_draw_env->Dump(s);
m_context->Dump(s);
}
// Dump vertices
if (dump_verts)
{
s = GetDrawDumpPath("%05d_vertex.txt", s_n);
DumpVertices(s);
}
// Dump transfers
if (dump_transfers)
{
s = GetDrawDumpPath("%05d_transfers.txt", s_n);
DumpTransferList(s);
}
}
void GSState::DumpVertices(const std::string& filename)
{
std::ofstream file(filename);
@@ -440,108 +469,370 @@ void GSState::DumpVertices(const std::string& filename)
if (!file.is_open())
return;
file << "FLUSH REASON: " << GetFlushReasonString(m_state_flush_reason);
file.imbue(std::locale::classic()); // Disable integer separators.
if (m_state_flush_reason != GSFlushReason::CONTEXTCHANGE && m_dirty_gs_regs)
file << " AND POSSIBLE CONTEXT CHANGE";
constexpr const char* DEL = ", ";
constexpr const char* INDENT = " ";
constexpr const char* LIST_ITEM = "- ";
constexpr const char* OPEN_MAP = "{";
constexpr const char* CLOSE_MAP = "}";
constexpr int TRACE_INDEX_WIDTH = 10;
constexpr int XYUV_WIDTH = 9;
constexpr int Z_WIDTH = 10;
constexpr int RGBA_WIDTH = 3;
constexpr int SCI_FLOAT_WIDTH = 15;
constexpr int STQ_BITS_WIDTH = 10;
file << std::endl << std::endl;
auto WriteVertexIndex = [&file](int index) {
file << std::left << std::dec << " # " << index;
};
const u32 count = m_index.tail;
GSVertex* buffer = &m_vertex.buff[0];
auto WriteTraceIndex = [&file](const char* index) {
file << std::left << std::dec << std::setw(TRACE_INDEX_WIDTH) << std::setfill(' ') << index;
};
const char* DEL = ", ";
auto WriteXYZ_vec = [&file](const GSVector4& v) {
file << std::dec << std::right << std::fixed;
file << "X: " << std::setprecision(4) << std::setw(XYUV_WIDTH) << std::setfill(' ') << v.x << DEL;
file << "Y: " << std::setprecision(4) << std::setw(XYUV_WIDTH) << std::setfill(' ') << v.y << DEL;
file << "Z: " << std::setw(Z_WIDTH) << std::setfill(' ') << static_cast<u32>(v.z);
};
file << "VERTEX COORDS (XYZ)" << std::endl;
file << std::fixed << std::setprecision(4);
for (u32 i = 0; i < count; ++i)
{
file << "\t" << std::dec << "v" << i << ": ";
GSVertex v = buffer[m_index.buff[i]];
// Different handler because we have full precision on Z
auto WriteXYZ_vert = [this, &file](const GSVertex& v) {
const float x = (static_cast<int>(v.XYZ.X) - static_cast<int>(m_context->XYOFFSET.OFX)) / 16.0f;
const float y = (static_cast<int>(v.XYZ.Y) - static_cast<int>(m_context->XYOFFSET.OFY)) / 16.0f;
file << std::dec << std::right << std::fixed;
file << "X: " << std::setprecision(4) << std::setw(XYUV_WIDTH) << std::setfill(' ') << x << DEL;
file << "Y: " << std::setprecision(4) << std::setw(XYUV_WIDTH) << std::setfill(' ') << y << DEL;
file << "Z: " << std::setw(Z_WIDTH) << std::setfill(' ') << v.XYZ.Z;
};
const float x = (v.XYZ.X - (int)m_context->XYOFFSET.OFX) / 16.0f;
const float y = (v.XYZ.Y - (int)m_context->XYOFFSET.OFY) / 16.0f;
file << x << DEL;
file << y << DEL;
file << v.XYZ.Z;
file << std::endl;
}
file << std::endl;
file << "VERTEX COLOR (RGBA)" << std::endl;
file << std::fixed << std::setprecision(6);
for (u32 i = 0; i < count; ++i)
{
file << "\t" << std::dec << "v" << i << ": ";
GSVertex v = buffer[m_index.buff[i]];
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.R) << DEL;
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.G) << DEL;
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.B) << DEL;
file << std::setfill('0') << std::setw(3) << unsigned(v.RGBAQ.A) << DEL;
file << "FOG: " << std::setfill('0') << std::setw(3) << unsigned(v.FOG);
file << std::endl;
}
file << std::endl;
const bool use_uv = PRIM->FST;
const std::string qualifier = use_uv ? "UV" : "STQ";
file << "TEXTURE COORDS (" << qualifier << ")" << std::endl;;
for (u32 i = 0; i < count; ++i)
{
file << "\t" << "v" << std::dec << i << ": ";
const GSVertex v = buffer[m_index.buff[i]];
// note
// Yes, technically as far as the GS is concerned Q belongs
// to RGBAQ. However, the purpose of this dump is to print
// our data in a more human readable format and typically Q
// is associated with STQ.
if (use_uv)
auto WriteUV_vec = [this, &file](const GSVector4& v) {
file << std::right;
if (PRIM->FST)
{
const float uv_U = v.U / 16.0f;
const float uv_V = v.V / 16.0f;
file << uv_U << DEL << uv_V;
file << std::fixed;
file << "U: " << std::setprecision(4) << std::setw(XYUV_WIDTH) << std::setfill(' ') << v.x << DEL;
file << "V: " << std::setprecision(4) << std::setw(XYUV_WIDTH) << std::setfill(' ') << v.y;
}
else
{
float x = (v.ST.S / v.RGBAQ.Q) * (1 << m_context->TEX0.TW);
float y = (v.ST.T / v.RGBAQ.Q) * (1 << m_context->TEX0.TH);
file << v.ST.S << "(" << std::hex << std::bit_cast<u32>(v.ST.S) << ")" << DEL << v.ST.T << "(" << std::hex << std::bit_cast<u32>(v.ST.T) << ")" << DEL << v.RGBAQ.Q << "(" << std::hex << std::bit_cast<u32>(v.RGBAQ.Q) << ") - " << x << "," << y;
file << std::defaultfloat;
file << "U: " << std::setw(SCI_FLOAT_WIDTH) << std::setfill(' ') << v.x << DEL;
file << "V: " << std::setw(SCI_FLOAT_WIDTH) << std::setfill(' ') << v.y;
}
};
auto WriteUV_vert = [this, WriteUV_vec](const GSVertex& v) {
GSVector4 vec;
if (PRIM->FST)
vec = GSVector4(v.U / 16.0f, v.V / 16.0f);
else
vec = GSVector4(
(v.ST.S / v.RGBAQ.Q) * (1 << m_context->TEX0.TW),
(v.ST.T / v.RGBAQ.Q) * (1 << m_context->TEX0.TH)
);
WriteUV_vec(vec);
};
auto WriteRGBA_vec = [&file](const GSVector4i& v) {
file << std::dec << std::right;
file << "R: " << std::setw(RGBA_WIDTH) << std::setfill(' ') << v.r << DEL;
file << "G: " << std::setw(RGBA_WIDTH) << std::setfill(' ') << v.g << DEL;
file << "B: " << std::setw(RGBA_WIDTH) << std::setfill(' ') << v.b << DEL;
file << "A: " << std::setw(RGBA_WIDTH) << std::setfill(' ') << v.a;
};
auto WriteRGBA_vert = [WriteRGBA_vec](const GSVertex& v) {
GSVector4i vec = GSVector4i(v.RGBAQ.R, v.RGBAQ.G, v.RGBAQ.B, v.RGBAQ.A);
WriteRGBA_vec(vec);
};
auto WriteSTQ_vec = [&file](const GSVector4& v) {
file << std::defaultfloat << std::right;
file << "S: " << std::setw(SCI_FLOAT_WIDTH) << std::setfill(' ') << v.x << DEL;
file << "T: " << std::setw(SCI_FLOAT_WIDTH) << std::setfill(' ') << v.y << DEL;
file << "Q: " << std::setw(SCI_FLOAT_WIDTH) << std::setfill(' ') << v.z;
};
auto WriteSTQ_bits = [&file](const GSVector4& v) {
file << std::hex << std::showbase << std::right;
file << "Si: " << std::setw(STQ_BITS_WIDTH) << std::setfill('0') << std::bit_cast<u32>(v.x) << DEL;
file << "Ti: " << std::setw(STQ_BITS_WIDTH) << std::setfill('0') << std::bit_cast<u32>(v.y) << DEL;
file << "Qi: " << std::setw(STQ_BITS_WIDTH) << std::setfill('0') << std::bit_cast<u32>(v.z);
};
auto WriteSTQ_vert = [&file, WriteSTQ_vec, WriteSTQ_bits](const GSVertex& v) {
GSVector4 vec = GSVector4(v.ST.S, v.ST.T, v.RGBAQ.Q, v.RGBAQ.Q);
WriteSTQ_vec(vec);
file << DEL;
WriteSTQ_bits(vec);
};
auto WriteBools = [&file](std::vector<const char*> names, std::vector<u32> values) {
for (int i = 0; i < static_cast<int>(names.size()); i++)
{
if (i > 0)
file << DEL;
file << names[i] << ": " << static_cast<bool>(values[i]);
}
};
// Dump flush reason
file << "flush_reason: \"" << GetFlushReasonString(m_state_flush_reason);
if (m_state_flush_reason != GSFlushReason::CONTEXTCHANGE && m_dirty_gs_regs)
file << " AND POSSIBLE CONTEXT CHANGE";
file << "\"" << std::endl;
file << std::endl;
// Dump vertices
file << "vertex:" << std::endl;
const u32 count = m_index.tail;
GSVertex* buffer = &m_vertex.buff[0];
for (u32 i = 0; i < count; ++i)
{
GSVertex v = buffer[m_index.buff[i]];
file << INDENT << LIST_ITEM << OPEN_MAP;
WriteXYZ_vert(v);
if (PRIM->TME)
{
file << DEL;
WriteUV_vert(v);
}
file << DEL;
WriteRGBA_vert(v);
file << CLOSE_MAP;
WriteVertexIndex(i);
file << std::endl;
}
file << std::endl;
file << "TRACER" << std::dec << std::endl;
// Dump extra info for STQ
if (PRIM->TME && !PRIM->FST)
{
file << "vertex_stq:" << std::endl;
for (u32 i = 0; i < count; ++i)
{
file << INDENT << LIST_ITEM << OPEN_MAP;
WriteSTQ_vert(buffer[m_index.buff[i]]);
file << CLOSE_MAP;
GSVector4i v = m_vt.m_min.c;
file << "\tmin c (r,g,b,a): " << v.x << DEL << v.y << DEL << v.z << DEL << v.w << std::endl;
v = m_vt.m_max.c;
file << "\tmax c (r,g,b,a): " << v.x << DEL << v.y << DEL << v.z << DEL << v.w << std::endl;
WriteVertexIndex(i);
GSVector4 v2 = m_vt.m_min.p;
file << "\tmin p (x,y,z,f): " << v2.x << DEL << v2.y << DEL << v2.z << DEL << (u32)v2.w << std::endl;
v2 = m_vt.m_max.p;
file << "\tmax p (x,y,z,f): " << v2.x << DEL << v2.y << DEL << v2.z << DEL << (u32)v2.w << std::endl;
v2 = m_vt.m_min.t;
file << "\tmin t (u,v,q): " << v2.x << DEL << v2.y << DEL << v2.z << std::endl;
v2 = m_vt.m_max.t;
file << "\tmax t (u,v,q): " << v2.x << DEL << v2.y << DEL << v2.z << std::endl;
file << std::endl;
}
}
file << std::endl;
file << "\teq c (r,g,b,a): " << (m_vt.m_eq.r & 1) << DEL << (m_vt.m_eq.g & 1) << DEL << (m_vt.m_eq.b & 1) << DEL << (m_vt.m_eq.a & 1) << std::endl;
file << "\teq p (x,y,z,f): " << (m_vt.m_eq.x & 1) << DEL << (m_vt.m_eq.y & 1) << DEL << (m_vt.m_eq.z & 1) << DEL << (m_vt.m_eq.f & 1) << std::endl;
file << "\teq t (u,v,q) : " << (m_vt.m_eq.s & 1) << DEL << (m_vt.m_eq.t & 1) << DEL << (m_vt.m_eq.q & 1) << std::endl;
file.close();
// Dump vertex trace
file << "vertex_trace:" << std::endl;
file << INDENT;
WriteTraceIndex("min_xyz: ");
file << OPEN_MAP;
WriteXYZ_vec(m_vt.m_min.p);
file << CLOSE_MAP << std::endl;
file << INDENT;
WriteTraceIndex("max_xyz: ");
file << OPEN_MAP;
WriteXYZ_vec(m_vt.m_max.p);
file << CLOSE_MAP << std::endl;
if (PRIM->TME)
{
if (PRIM->FST)
{
file << INDENT;
WriteTraceIndex("min_uv: ");
file << OPEN_MAP;
WriteUV_vec(m_vt.m_min.t);
file << CLOSE_MAP << std::endl;
file << INDENT;
WriteTraceIndex("max_uv: ");
file << OPEN_MAP;
WriteUV_vec(m_vt.m_max.t);
file << CLOSE_MAP << std::endl;
}
else
{
// Note: The vertex trace does not actually track the min/max of raw ST values
// hence the labels "min_uvq" and "max_uvq" are used instead of "min_stq" and "max_stq".
file << INDENT;
WriteTraceIndex("min_uvq: ");
file << OPEN_MAP;
WriteSTQ_vec(m_vt.m_min.t);
file << CLOSE_MAP << std::endl;
file << INDENT;
WriteTraceIndex("max_uvq: ");
file << OPEN_MAP;
WriteSTQ_vec(m_vt.m_max.t);
file << CLOSE_MAP << std::endl;
}
}
file << INDENT;
WriteTraceIndex("min_rgba: ");
file << OPEN_MAP;
WriteRGBA_vec(m_vt.m_min.c);
file << CLOSE_MAP << std::endl;
file << INDENT;
WriteTraceIndex("max_rgba: ");
file << OPEN_MAP;
WriteRGBA_vec(m_vt.m_max.c);
file << CLOSE_MAP << std::endl;
file << std::endl;
file << INDENT;
WriteTraceIndex("eq_xyz: ");
file << OPEN_MAP;
WriteBools({"X", "Y", "Z"}, {m_vt.m_eq.x, m_vt.m_eq.y, m_vt.m_eq.z});
file << CLOSE_MAP << std::endl;
if (PRIM->TME)
{
if (PRIM->FST)
{
file << INDENT;
WriteTraceIndex("eq_uv: ");
file << OPEN_MAP;
WriteBools({"U", "V"}, {m_vt.m_eq.s, m_vt.m_eq.t});
file << CLOSE_MAP << std::endl;
}
else
{
// Note: The vertex trace does not actually track the min/max of raw ST values
// hence the labels "eq_uvq" is used instead of "eq_stq".
file << INDENT;
WriteTraceIndex("eq_uvq: ");
file << OPEN_MAP;
WriteBools({"U", "V", "Q"}, {m_vt.m_eq.s, m_vt.m_eq.t, m_vt.m_eq.q});
file << CLOSE_MAP << std::endl;
}
}
file << INDENT;
WriteTraceIndex("eq_rgba: ");
file << OPEN_MAP;
WriteBools({"R", "G", "B", "A"}, {m_vt.m_eq.r, m_vt.m_eq.g, m_vt.m_eq.b, m_vt.m_eq.a});
file << CLOSE_MAP << std::endl;
}
void GSState::DumpTransferList(const std::string& filename)
{
// Only create the file if there are transfers to dump
std::optional<std::ofstream> file;
constexpr const char* LIST_ITEM = "- ";
constexpr const char* DEL = ", ";
constexpr const char* INDENT = " ";
constexpr const char* OPEN_MAP = "{";
constexpr const char* CLOSE_MAP = "}";
constexpr const char* COMMENT = " # ";
int n_dumped = 0; // Number of transfers dumped for this draw.
for (int i = 0; i < static_cast<int>(m_draw_transfers.size()); ++i)
{
if (m_draw_transfers[i].draw != s_n - 1)
continue; // skip transfers that did not start in the previous draw
if (!file.has_value())
{
file.emplace(filename);
if (!file->is_open())
return; // failed to open file
file->imbue(std::locale::classic()); // Disable integer separators.
}
const GSUploadQueue& transfer = m_draw_transfers[i];
if (n_dumped > 0)
(*file) << std::endl;
// EE->GS or GS->GS
(*file) << LIST_ITEM << "type: " << (transfer.ee_to_gs ? "EE_to_GS" : "GS_to_GS") << std::endl;
// Dump BITBLTBUF
(*file) << INDENT << "BITBLTBUF: " << OPEN_MAP;
if (!transfer.ee_to_gs)
{
// Transferring GS->GS so the source info is relevant
(*file) << "SBP: " << std::hex << std::showbase << transfer.blit.SBP << DEL <<
"SBW: " << std::dec << transfer.blit.SBW << DEL <<
"SPSM: " << std::hex << std::showbase << transfer.blit.SPSM << DEL;
}
(*file) << "DBP: " << std::hex << std::showbase << transfer.blit.DBP << DEL <<
"DBW: " << std::dec << transfer.blit.DBW << DEL <<
"DPSM: " << std::hex << std::showbase << transfer.blit.DPSM << CLOSE_MAP;
(*file) << COMMENT; // Write the human-readable PSM in comments
if (!transfer.ee_to_gs)
{
// Transferring GS->GS so the source info is relevant
(*file) << GSUtil::GetPSMName(transfer.blit.SPSM) << " -> ";
}
(*file) << GSUtil::GetPSMName(transfer.blit.DPSM) << std::endl;
// Dump rectangle
(*file) << INDENT << "rect: [" << std::dec << transfer.rect.x << DEL << transfer.rect.y << DEL <<
transfer.rect.z << DEL << transfer.rect.w << "]" << std::endl;
// Dump zero_clear
(*file) << INDENT << "zero_clear: " << (transfer.zero_clear ? "true" : "false") << std::endl;
n_dumped++;
}
}
void GSState::DumpTransferImages()
{
// Only create the file if there are transfers to dump
std::optional<std::ofstream> file;
int transfer_n = 0;
for (int i = 0; i < static_cast<int>(m_draw_transfers.size()); ++i)
{
if (m_draw_transfers[i].draw != s_n - 1)
continue; // skip transfers that did not start in the previous draw
const GSUploadQueue& transfer = m_draw_transfers[i];
std::string filename;
if (transfer.ee_to_gs)
{
// Transferring EE->GS then only the destination info is relevant.
filename = GetDrawDumpPath("%05d_transfer%02d_EE_to_GS_%03x_%d_%s_%d_%d_%d_%d.png",
s_n, transfer_n++, transfer.blit.DBP, transfer.blit.DBW, GSUtil::GetPSMName(transfer.blit.DPSM),
transfer.rect.x, transfer.rect.y, transfer.rect.z, transfer.rect.w);
}
else
{
// Transferring GS->GS then the source info is relevant.
filename = GetDrawDumpPath("%05d_transfer%02d_GS_to_GS_%03x_%d_%s_%03x_%d_%s_%d_%d_%d_%d.bmp",
s_n, transfer_n++, transfer.blit.SBP, transfer.blit.SBW, GSUtil::GetPSMName(transfer.blit.SPSM),
transfer.blit.DBP, transfer.blit.DBW, GSUtil::GetPSMName(transfer.blit.DPSM),
transfer.rect.x, transfer.rect.y, transfer.rect.z, transfer.rect.w);
}
m_mem.SaveBMP(filename, transfer.blit.DBP, transfer.blit.DBW, transfer.blit.DPSM,
transfer.rect.width(), transfer.rect.height(), transfer.rect.x, transfer.rect.y);
}
}
__inline void GSState::CheckFlushes()
@@ -1771,6 +2062,20 @@ void GSState::FlushPrim()
const bool skip_draw = (m_context->TEST.ZTE && m_context->TEST.ZTST == ZTST_NEVER);
m_quad_check_valid = false;
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
if (GSConfig.SaveInfo)
{
// Only dump registers/vertices if we are drawing.
// Always dump the transfers since these are relevant for debugging regardless of
// whether the draw is skipped or not.
DumpDrawInfo(!skip_draw, !skip_draw, true);
}
if (GSConfig.SaveTransferImages)
DumpTransferImages();
}
if (!skip_draw)
Draw();
@@ -2016,7 +2321,7 @@ void GSState::Write(const u8* mem, int len)
}
else
{
GSUploadQueue new_transfer = { blit, r, s_n, false };
const GSUploadQueue new_transfer = { blit, r, s_n, false, true };
m_draw_transfers.push_back(new_transfer);
}
@@ -2207,7 +2512,7 @@ void GSState::Move()
}
else
{
GSUploadQueue new_transfer = { m_env.BITBLTBUF, r, s_n, false };
const GSUploadQueue new_transfer = { m_env.BITBLTBUF, r, s_n, false, false };
m_draw_transfers.push_back(new_transfer);
}
+4
View File
@@ -215,6 +215,7 @@ public:
GSVector4i rect;
int draw;
bool zero_clear;
bool ee_to_gs;
};
enum NoGapsType
@@ -441,7 +442,10 @@ public:
u8* GetRegsMem() const { return reinterpret_cast<u8*>(m_regs); }
void SetRegsMem(u8* basemem) { m_regs = reinterpret_cast<GSPrivRegSet*>(basemem); }
void DumpDrawInfo(bool dump_regs, bool dump_verts, bool dump_transfers);
void DumpVertices(const std::string& filename);
void DumpTransferList(const std::string& filename);
void DumpTransferImages();
bool TrianglesAreQuads(bool shuffle_check = false);
PRIM_OVERLAP PrimitiveOverlap();
+55
View File
@@ -114,6 +114,61 @@ const char* GSUtil::GetPrimName(u32 prim)
return (prim < std::size(names)) ? names[prim] : "";
}
const char* GSUtil::GetMMAGName(u32 mmag)
{
static constexpr const char* names[] = {"NEAREST", "LINEAR"};
return (mmag < std::size(names)) ? names[mmag] : "";
}
const char* GSUtil::GetMMINName(u32 mmin)
{
static constexpr const char* names[8] = {"NEAREST", "LINEAR", "NEAREST_MIPMAP_NEAREST", "NEAREST_MIPMAP_LINEAR",
"LINEAR_MIPMAP_NEAREST", "LINEAR_MIPMAP_LINEAR"};
return (mmin < std::size(names)) ? names[mmin] : "";
}
const char* GSUtil::GetMTBAName(u32 mtba)
{
static constexpr const char* names[] = {"MIPTBP1", "AUTO"};
return (mtba < std::size(names)) ? names[mtba] : "";
}
const char* GSUtil::GetLCMName(u32 lcm)
{
static constexpr const char* names[] = {"Formula", "K"};
return (lcm < std::size(names)) ? names[lcm] : "";
}
const char* GSUtil::GetSCANMSKName(u32 scanmsk)
{
static constexpr const char* names[] = {"Normal", "Reserved", "Even prohibited", "Odd prohibited"};
return (scanmsk < std::size(names)) ? names[scanmsk] : "";
}
const char* GSUtil::GetDATMName(u32 datm)
{
static constexpr const char* names[] = {"0 pass", "1 pass"};
return (datm < std::size(names)) ? names[datm] : "";
}
const char* GSUtil::GetTFXName(u32 tfx)
{
static constexpr const char* names[] = {"MODULATE", "DECAL", "HIGHLIGHT", "HIGHLIGHT2"};
return (tfx < std::size(names)) ? names[tfx] : "";
}
const char* GSUtil::GetTCCName(u32 tcc)
{
static constexpr const char* names[] = {"RGB", "RGBA"};
return (tcc < std::size(names)) ? names[tcc] : "";
}
const char* GSUtil::GetACName(u32 ac)
{
static constexpr const char* names[] = {"PRMODE", "PRIM"};
return (ac < std::size(names)) ? names[ac] : "";
}
const u32* GSUtil::HasSharedBitsPtr(u32 dpsm)
{
return s_maps.SharedBitsField[dpsm];
+9
View File
@@ -15,6 +15,15 @@ public:
static const char* GetWMName(u32 wm);
static const char* GetZTSTName(u32 ztst);
static const char* GetPrimName(u32 prim);
static const char* GetMMAGName(u32 mmag);
static const char* GetMMINName(u32 mmin);
static const char* GetMTBAName(u32 mtba);
static const char* GetLCMName(u32 lcm);
static const char* GetSCANMSKName(u32 scanmsk);
static const char* GetDATMName(u32 datm);
static const char* GetTFXName(u32 tfx);
static const char* GetTCCName(u32 tcc);
static const char* GetACName(u32 ac);
static const u32* HasSharedBitsPtr(u32 dpsm);
static bool HasSharedBits(u32 spsm, const u32* ptr);
-4
View File
@@ -985,10 +985,6 @@ public:
__forceinline GSVector4i modulate16(const GSVector4i& f) const
{
// a * f << shift
if (shift == 0)
{
return mul16hrs(f);
}
return sll16<shift + 1>().mul16hs(f);
}
-4
View File
@@ -958,10 +958,6 @@ public:
__forceinline GSVector4i modulate16(const GSVector4i& f) const
{
// a * f << shift
if (shift == 0)
{
return mul16hrs(f);
}
return sll16<shift + 1>().mul16hs(f);
}
-5
View File
@@ -798,11 +798,6 @@ public:
{
// a * f << shift
if (shift == 0)
{
return mul16hrs(f);
}
return sll16<shift + 1>().mul16hs(f);
}
+35
View File
@@ -397,6 +397,41 @@ void GSDevice::ClearDepth(GSTexture* t, float d)
t->SetClearDepth(d);
}
bool GSDevice::ProcessClearsBeforeCopy(GSTexture* sTex, GSTexture* dTex, const bool full_copy)
{
pxAssert(sTex->GetState() == GSTexture::State::Cleared && dTex->IsRenderTargetOrDepthStencil());
// Pass it forward if we're clearing the whole thing.
if (full_copy)
{
if (dTex->IsDepthStencil())
dTex->SetClearDepth(sTex->GetClearDepth());
else
dTex->SetClearColor(sTex->GetClearColor());
dTex->SetState(GSTexture::State::Cleared);
return true;
}
// Destination is cleared, if it's the same colour and rect, we can just avoid this entirely.
if (dTex->GetState() == GSTexture::State::Cleared)
{
if (dTex->IsDepthStencil())
{
if (dTex->GetClearDepth() == sTex->GetClearDepth())
return true;
}
else
{
if (dTex->GetClearColor() == sTex->GetClearColor())
return true;
}
}
return false;
}
void GSDevice::InvalidateRenderTarget(GSTexture* t)
{
t->SetState(GSTexture::State::Invalidated);
+1
View File
@@ -1022,6 +1022,7 @@ public:
void ClearRenderTarget(GSTexture* t, u32 c);
void ClearDepth(GSTexture* t, float d);
bool ProcessClearsBeforeCopy(GSTexture* sTex, GSTexture* dTex, const bool full_copy);
void InvalidateRenderTarget(GSTexture* t);
virtual void PushDebugGroup(const char* fmt, ...) = 0;
+25 -16
View File
@@ -569,9 +569,17 @@ void GSRenderer::EndPresentFrame()
void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
{
if (GSConfig.SaveInfo && GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
if (GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
DumpGSPrivRegs(*m_regs, GetDrawDumpPath("%05d_f%05lld_vsync_gs_reg.txt", s_n, g_perfmon.GetFrame()));
if (GSConfig.SaveInfo)
{
DumpGSPrivRegs(*m_regs, GetDrawDumpPath("%05d_f%05lld_vsync_gs_reg.txt", s_n, g_perfmon.GetFrame()));
DumpDrawInfo(false, false, true);
}
if (GSConfig.SaveTransferImages)
DumpTransferImages();
}
const int fb_sprite_blits = g_perfmon.GetDisplayFramebufferSpriteBlits();
@@ -1088,7 +1096,7 @@ void DumpGSPrivRegs(const GSPrivRegSet& r, const std::string& filename)
if (i == 1 && !r.PMODE.EN2)
continue;
std::fprintf(fp.get(), "DISPFB[%d] BP=%05x BW=%u PSM=%u DBX=%u DBY=%u\n",
std::fprintf(fp.get(), "DISPFB%d: { BP: 0x%05x, BW: %u, PSM: %u, DBX: %u, DBY: %u }\n",
i,
r.DISP[i].DISPFB.Block(),
r.DISP[i].DISPFB.FBW,
@@ -1096,7 +1104,7 @@ void DumpGSPrivRegs(const GSPrivRegSet& r, const std::string& filename)
r.DISP[i].DISPFB.DBX,
r.DISP[i].DISPFB.DBY);
std::fprintf(fp.get(), "DISPLAY[%d] DX=%u DY=%u DW=%u DH=%u MAGH=%u MAGV=%u\n",
std::fprintf(fp.get(), "DISPLAY%d: { DX: %u, DY: %u, DW: %u, DH: %u, MAGH: %u, MAGV: %u }\n",
i,
r.DISP[i].DISPLAY.DX,
r.DISP[i].DISPLAY.DY,
@@ -1106,7 +1114,7 @@ void DumpGSPrivRegs(const GSPrivRegSet& r, const std::string& filename)
r.DISP[i].DISPLAY.MAGV);
}
std::fprintf(fp.get(), "PMODE EN1=%u EN2=%u CRTMD=%u MMOD=%u AMOD=%u SLBG=%u ALP=%u\n",
std::fprintf(fp.get(), "PMODE: { EN1: %u, EN2: %u, CRTMD: %u, MMOD: %u, AMOD: %u, SLBG: %u, ALP: %u }\n",
r.PMODE.EN1,
r.PMODE.EN2,
r.PMODE.CRTMD,
@@ -1115,7 +1123,8 @@ void DumpGSPrivRegs(const GSPrivRegSet& r, const std::string& filename)
r.PMODE.SLBG,
r.PMODE.ALP);
std::fprintf(fp.get(), "SMODE1 CLKSEL=%u CMOD=%u EX=%u GCONT=%u LC=%u NVCK=%u PCK2=%u PEHS=%u PEVS=%u PHS=%u PRST=%u PVS=%u RC=%u SINT=%u SLCK=%u SLCK2=%u SPML=%u T1248=%u VCKSEL=%u VHP=%u XPCK=%u\n",
std::fprintf(fp.get(),
"SMODE1: { CLKSEL: %u, CMOD: %u, EX: %u, GCONT: %u, LC: %u, NVCK: %u, PCK2: %u, PEHS: %u, PEVS: %u, PHS: %u, PRST: %u, PVS: %u, RC: %u, SINT: %u, SLCK: %u, SLCK2: %u, SPML: %u, T1248: %u, VCKSEL: %u, VHP: %u, XPCK: %u }\n",
r.SMODE1.CLKSEL,
r.SMODE1.CMOD,
r.SMODE1.EX,
@@ -1138,24 +1147,24 @@ void DumpGSPrivRegs(const GSPrivRegSet& r, const std::string& filename)
r.SMODE1.VHP,
r.SMODE1.XPCK);
std::fprintf(fp.get(), "SMODE2 INT=%u FFMD=%u DPMS=%u\n",
std::fprintf(fp.get(), "SMODE2: { INT: %u, FFMD: %u, DPMS: %u }\n",
r.SMODE2.INT,
r.SMODE2.FFMD,
r.SMODE2.DPMS);
std::fprintf(fp.get(), "SRFSH %08x_%08x\n",
std::fprintf(fp.get(), "SRFSH: { U32_0: 0x%08x, U32_1: 0x%08x }\n",
r.SRFSH.U32[0],
r.SRFSH.U32[1]);
std::fprintf(fp.get(), "SYNCH1 %08x_%08x\n",
std::fprintf(fp.get(), "SYNCH1: { U32_0: 0x%08x, U32_1: 0x%08x }\n",
r.SYNCH1.U32[0],
r.SYNCH1.U32[1]);
std::fprintf(fp.get(), "SYNCH2 %08x_%08x\n",
std::fprintf(fp.get(), "SYNCH2: { U32_0: 0x%08x, U32_1: 0x%08x }\n",
r.SYNCH2.U32[0],
r.SYNCH2.U32[1]);
std::fprintf(fp.get(), "SYNCV VBP=%u VBPE=%u VDP=%u VFP=%u VFPE=%u VS=%u\n",
std::fprintf(fp.get(), "SYNCV: { VBP: %u, VBPE: %u, VDP: %u, VFP: %u, VFPE: %u, VS: %u }\n",
r.SYNCV.VBP,
r.SYNCV.VBPE,
r.SYNCV.VDP,
@@ -1163,21 +1172,21 @@ void DumpGSPrivRegs(const GSPrivRegSet& r, const std::string& filename)
r.SYNCV.VFPE,
r.SYNCV.VS);
std::fprintf(fp.get(), "CSR %08x_%08x\n",
std::fprintf(fp.get(), "CSR: { U32_0: 0x%08x, U32_1: 0x%08x }\n",
r.CSR.U32[0],
r.CSR.U32[1]);
std::fprintf(fp.get(), "BGCOLOR B=%u G=%u R=%u\n",
std::fprintf(fp.get(), "BGCOLOR: { B: %u, G: %u, R: %u }\n",
r.BGCOLOR.B,
r.BGCOLOR.G,
r.BGCOLOR.R);
std::fprintf(fp.get(), "EXTBUF BP=0x%x BW=%u FBIN=%u WFFMD=%u EMODA=%u EMODC=%u WDX=%u WDY=%u\n",
std::fprintf(fp.get(), "EXTBUF: { BP: 0x%05x, BW: %u, FBIN: %u, WFFMD: %u, EMODA: %u, EMODC: %u, WDX: %u, WDY: %u }\n",
r.EXTBUF.EXBP, r.EXTBUF.EXBW, r.EXTBUF.FBIN, r.EXTBUF.WFFMD,
r.EXTBUF.EMODA, r.EXTBUF.EMODC, r.EXTBUF.WDX, r.EXTBUF.WDY);
std::fprintf(fp.get(), "EXTDATA SX=%u SY=%u SMPH=%u SMPV=%u WW=%u WH=%u\n",
std::fprintf(fp.get(), "EXTDATA: { SX: %u, SY: %u, SMPH: %u, SMPV: %u, WW: %u, WH: %u }\n",
r.EXTDATA.SX, r.EXTDATA.SY, r.EXTDATA.SMPH, r.EXTDATA.SMPV, r.EXTDATA.WW, r.EXTDATA.WH);
std::fprintf(fp.get(), "EXTWRITE EN=%u\n", r.EXTWRITE.WRITE);
std::fprintf(fp.get(), "EXTWRITE: { EN: %u }\n", r.EXTWRITE.WRITE);
}
+1 -1
View File
@@ -409,7 +409,7 @@ GSRendererType D3D::GetPreferredRenderer()
return true;
Host::AddIconOSDMessage("VKDriverUnsupported", ICON_FA_TV, TRANSLATE_STR("GS",
"The Vulkan renderer was automatically selected, but no compatible devices were found.\n"
"The Vulkan graphics API was automatically selected, but no compatible devices were found.\n"
" You should update all graphics drivers in your system, including any integrated GPUs\n"
" to use the Vulkan renderer."), Host::OSD_WARNING_DURATION);
return false;
+26 -7
View File
@@ -1229,22 +1229,41 @@ std::unique_ptr<GSDownloadTexture> GSDevice11::CreateDownloadTexture(u32 width,
void GSDevice11::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY)
{
CommitClear(sTex);
CommitClear(dTex);
const GSVector4i dst_rect(0, 0, dTex->GetWidth(), dTex->GetHeight());
const bool full_draw_copy = sTex->IsDepthStencil() || dst_rect.eq(r);
// Source is cleared, if destination is a render target, we can carry the clear forward.
if (sTex->GetState() == GSTexture::State::Cleared)
{
if (dTex->IsRenderTargetOrDepthStencil() && ProcessClearsBeforeCopy(sTex, dTex, full_draw_copy))
return;
// Commit clear for the source texture.
CommitClear(sTex);
}
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// Commit destination clear if partially overwritten (color only).
if (dTex->GetState() == GSTexture::State::Cleared && !full_draw_copy)
CommitClear(dTex);
// DX11 doesn't support partial depth copy so we need to
// either pass a nullptr D3D11_BOX for a full depth copy or use CopyResource instead.
// Optimization: Use CopyResource for depth copies, it's faster than CopySubresourceRegion.
if (sTex->GetType() == GSTexture::Type::DepthStencil)
// Optimization: Use CopyResource for depth copies or full rect color copies, it's faster than CopySubresourceRegion.
const GSVector4i src_rect(0, 0, sTex->GetWidth(), sTex->GetHeight());
const bool full_rt_copy = sTex->IsDepthStencil() || (destX == 0 && destY == 0 && r.eq(src_rect) && src_rect.eq(dst_rect));
if (full_rt_copy)
{
m_ctx->CopyResource(*static_cast<GSTexture11*>(dTex), *static_cast<GSTexture11*>(sTex));
return;
}
else
{
const D3D11_BOX box = {static_cast<UINT>(r.left), static_cast<UINT>(r.top), 0U, static_cast<UINT>(r.right), static_cast<UINT>(r.bottom), 1U};
m_ctx->CopySubresourceRegion(*static_cast<GSTexture11*>(dTex), 0, destX, destY, 0, *static_cast<GSTexture11*>(sTex), 0, &box);
}
D3D11_BOX box = {static_cast<UINT>(r.left), static_cast<UINT>(r.top), 0U, static_cast<UINT>(r.right), static_cast<UINT>(r.bottom), 1U};
m_ctx->CopySubresourceRegion(*static_cast<GSTexture11*>(dTex), 0, destX, destY, 0, *static_cast<GSTexture11*>(sTex), 0, &box);
dTex->SetState(GSTexture::State::Dirty);
}
void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader, bool linear)
+40 -51
View File
@@ -1337,77 +1337,66 @@ std::unique_ptr<GSDownloadTexture> GSDevice12::CreateDownloadTexture(u32 width,
void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GSTexture12* const sTex12 = static_cast<GSTexture12*>(sTex);
GSTexture12* const dTex12 = static_cast<GSTexture12*>(dTex);
const GSVector4i dst_rect(0, 0, dTex12->GetWidth(), dTex12->GetHeight());
const bool full_draw_copy = dst_rect.eq(r);
GSTexture12* const sTexVK = static_cast<GSTexture12*>(sTex);
GSTexture12* const dTexVK = static_cast<GSTexture12*>(dTex);
const GSVector4i dtex_rc(0, 0, dTexVK->GetWidth(), dTexVK->GetHeight());
if (sTexVK->GetState() == GSTexture::State::Cleared)
// Source is cleared, if destination is a render target, we can carry the clear forward.
if (sTex12->GetState() == GSTexture::State::Cleared)
{
// source is cleared. if destination is a render target, we can carry the clear forward
if (dTexVK->IsRenderTargetOrDepthStencil())
if (dTex12->IsRenderTargetOrDepthStencil() && ProcessClearsBeforeCopy(sTex, dTex, full_draw_copy))
return;
// Do an attachment clear.
EndRenderPass();
dTex12->SetState(GSTexture::State::Dirty);
if (dTex12->GetType() != GSTexture::Type::DepthStencil)
{
if (dtex_rc.eq(r))
{
// pass it forward if we're clearing the whole thing
if (sTexVK->IsDepthStencil())
dTexVK->SetClearDepth(sTexVK->GetClearDepth());
else
dTexVK->SetClearColor(sTexVK->GetClearColor());
return;
}
else
{
// otherwise we need to do an attachment clear
EndRenderPass();
dTexVK->SetState(GSTexture::State::Dirty);
if (dTexVK->GetType() != GSTexture::Type::DepthStencil)
{
dTexVK->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
GetCommandList()->ClearRenderTargetView(
dTexVK->GetWriteDescriptor(), sTexVK->GetUNormClearColor().v, 0, nullptr);
}
else
{
dTexVK->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
GetCommandList()->ClearDepthStencilView(
dTexVK->GetWriteDescriptor(), D3D12_CLEAR_FLAG_DEPTH, sTexVK->GetClearDepth(), 0, 0, nullptr);
}
return;
}
dTex12->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
GetCommandList()->ClearRenderTargetView(
dTex12->GetWriteDescriptor(), sTex12->GetUNormClearColor().v, 0, nullptr);
}
else
{
dTex12->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
GetCommandList()->ClearDepthStencilView(
dTex12->GetWriteDescriptor(), D3D12_CLEAR_FLAG_DEPTH, sTex12->GetClearDepth(), 0, 0, nullptr);
}
return;
// commit the clear to the source first, then do normal copy
sTexVK->CommitClear();
sTex12->CommitClear();
}
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// if the destination has been cleared, and we're not overwriting the whole thing, commit the clear first
// (the area outside of where we're copying to)
if (dTexVK->GetState() == GSTexture::State::Cleared && !dtex_rc.eq(r))
dTexVK->CommitClear();
if (dTex12->GetState() == GSTexture::State::Cleared && !full_draw_copy)
dTex12->CommitClear();
EndRenderPass();
sTexVK->TransitionToState(D3D12_RESOURCE_STATE_COPY_SOURCE);
sTexVK->SetUseFenceCounter(GetCurrentFenceValue());
if (m_tfx_textures[0] && sTexVK->GetSRVDescriptor() == m_tfx_textures[0])
sTex12->TransitionToState(D3D12_RESOURCE_STATE_COPY_SOURCE);
sTex12->SetUseFenceCounter(GetCurrentFenceValue());
if (m_tfx_textures[0] && sTex12->GetSRVDescriptor() == m_tfx_textures[0])
PSSetShaderResource(0, nullptr, false);
dTexVK->TransitionToState(D3D12_RESOURCE_STATE_COPY_DEST);
dTexVK->SetUseFenceCounter(GetCurrentFenceValue());
dTex12->TransitionToState(D3D12_RESOURCE_STATE_COPY_DEST);
dTex12->SetUseFenceCounter(GetCurrentFenceValue());
D3D12_TEXTURE_COPY_LOCATION srcloc;
srcloc.pResource = sTexVK->GetResource();
srcloc.pResource = sTex12->GetResource();
srcloc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
srcloc.SubresourceIndex = 0;
D3D12_TEXTURE_COPY_LOCATION dstloc;
dstloc.pResource = dTexVK->GetResource();
dstloc.pResource = dTex12->GetResource();
dstloc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dstloc.SubresourceIndex = 0;
@@ -1415,7 +1404,7 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
static_cast<UINT>(r.bottom), 1u};
GetCommandList()->CopyTextureRegion(&dstloc, destX, destY, 0, &srcloc, &srcbox);
dTexVK->SetState(GSTexture::State::Dirty);
dTex12->SetState(GSTexture::State::Dirty);
}
void GSDevice12::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
-15
View File
@@ -2317,21 +2317,6 @@ void GSRendererHW::RoundSpriteOffset()
void GSRendererHW::Draw()
{
if (GSConfig.SaveInfo && GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
std::string s;
// Dump Register state
s = GetDrawDumpPath("%05d_context.txt", s_n);
m_draw_env->Dump(s);
m_context->Dump(s);
// Dump vertices
s = GetDrawDumpPath("%05d_vertex.txt", s_n);
DumpVertices(s);
}
static u32 num_skipped_channel_shuffle_draws = 0;
// We mess with this state as an optimization, so take a copy and use that instead.
+3 -3
View File
@@ -6070,13 +6070,13 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
{
if (dst->m_rt_alpha_scale)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
const GSVector4 sRectF = GSVector4(sRect) / GSVector4(1, 1, sTex->GetWidth(), sTex->GetHeight());
g_gs_device->StretchRect(
sTex, sRectF, dTex, GSVector4(destX, destY, sRect.width(), sRect.height()), ShaderConvert::RTA_DECORRECTION, false);
}
else
g_gs_device->CopyRect(sTex, dTex, sRect, destX, destY);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
#ifdef PCSX2_DEVBUILD
if (GSConfig.UseDebugDevice)
@@ -7778,12 +7778,14 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca
{
// Can't do partial copies in DirectX for depth textures, and it's probably not ideal in other
// APIs either. So use a fullscreen quad setting depth instead.
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::DEPTH_COPY, false);
}
else
{
if (require_new_rect)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::COPY, false);
}
else
@@ -7792,8 +7794,6 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca
g_gs_device->CopyRect(m_texture, tex, rc, 0, 0);
}
}
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
else if (m_texture->GetState() == GSTexture::State::Cleared)
{
+15 -3
View File
@@ -1471,12 +1471,24 @@ void GSDeviceMTL::ClearSamplerCache()
void GSDeviceMTL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY)
{ @autoreleasepool {
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GSTextureMTL* sT = static_cast<GSTextureMTL*>(sTex);
GSTextureMTL* dT = static_cast<GSTextureMTL*>(dTex);
const GSVector4i dst_rect(0, 0, dT->GetWidth(), dT->GetHeight());
const bool full_draw_copy = dst_rect.eq(r);
// Process clears
// Source is cleared, if destination is a render target, we can carry the clear forward.
if (sT->GetState() == GSTexture::State::Cleared)
{
if (dT->IsRenderTargetOrDepthStencil() && ProcessClearsBeforeCopy(sTex, dTex, full_draw_copy))
return;
// Commit clear for the source texture.
sT->FlushClears();
}
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// Commit clear for the destination texture.
GSVector2i dsize = dTex->GetSize();
if (r.width() < dsize.x || r.height() < dsize.y)
dT->FlushClears();
+18 -3
View File
@@ -1430,12 +1430,25 @@ void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r
{
const GLuint& sid = static_cast<GSTextureOGL*>(sTex)->GetID();
const GLuint& did = static_cast<GSTextureOGL*>(dTex)->GetID();
CommitClear(sTex, false);
CommitClear(dTex, false);
const GSVector4i dst_rect(0, 0, dTex->GetWidth(), dTex->GetHeight());
const bool full_draw_copy = dst_rect.eq(r);
GL_PUSH("CopyRect from %d to %d", sid, did);
// Source is cleared, if destination is a render target, we can carry the clear forward.
if (sTex->GetState() == GSTexture::State::Cleared)
{
if (dTex->IsRenderTargetOrDepthStencil() && ProcessClearsBeforeCopy(sTex, dTex, full_draw_copy))
return;
// Commit clear for the source texture.
CommitClear(sTex, false);
}
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GL_PUSH("CopyRect from %d to %d", sid, did);
// Commit destination clear if partially overwritten (color only).
if (dTex->GetState() == GSTexture::State::Cleared && !full_draw_copy)
CommitClear(dTex, false);
if (GLAD_GL_VERSION_4_3 || GLAD_GL_ARB_copy_image)
{
@@ -1447,6 +1460,8 @@ void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r
glCopyImageSubDataEXT(sid, GL_TEXTURE_2D, 0, r.x, r.y, 0, did, GL_TEXTURE_2D,
0, destX, destY, 0, r.width(), r.height(), 1);
}
dTex->SetState(GSTexture::State::Dirty);
}
void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader, bool linear)
@@ -174,15 +174,8 @@ void GSDrawScanlineCodeGenerator::broadcastGPRToVec(const XYm& vec, const Xbyak:
void GSDrawScanlineCodeGenerator::modulate16(const XYm& a, const Operand& f, u8 shift)
{
if (shift == 0)
{
pmulhrsw(a, f);
}
else
{
psllw(a, shift + 1);
pmulhw(a, f);
}
psllw(a, shift + 1);
pmulhw(a, f);
}
void GSDrawScanlineCodeGenerator::lerp16(const XYm& a, const XYm& b, const XYm& f, u8 shift)
@@ -2352,14 +2352,15 @@ void GSDrawScanlineCodeGenerator::modulate16(const VRegister& a, const VRegister
void GSDrawScanlineCodeGenerator::modulate16(const VRegister& d, const VRegister& a, const VRegister& f, u8 shift)
{
// potentially going to cause issues due to saturation
armAsm->Shl(d.V8H(), a.V8H(), shift + 1);
if (shift != 0)
armAsm->Sqdmulh(a.V8H(), a.V8H(), f.V8H());
if (shift)
{
armAsm->Shl(d.V8H(), a.V8H(), shift);
armAsm->Sqdmulh(d.V8H(), d.V8H(), f.V8H());
}
else
armAsm->Sqrdmulh(a.V8H(), a.V8H(), f.V8H());
armAsm->Sshr(a.V8H(), a.V8H(), 1);
{
armAsm->Sqdmulh(a.V8H(), d.V8H(), f.V8H());
}
}
void GSDrawScanlineCodeGenerator::lerp16(const VRegister& a, const VRegister& b, const VRegister& f, u8 shift)
-15
View File
@@ -309,21 +309,6 @@ void GSRendererSW::Draw()
{
const GSDrawingContext* context = m_context;
if (GSConfig.SaveInfo && GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
{
std::string s;
// Dump Register state
s = GetDrawDumpPath("%05d_context.txt", s_n);
m_draw_env->Dump(s);
m_context->Dump(s);
// Dump vertices
s = GetDrawDumpPath("%05d_vertex.txt", s_n);
DumpVertices(s);
}
auto data = m_vertex_heap.make_shared<SharedData>().cast<GSRasterizerData>();
SharedData* sd = static_cast<SharedData*>(data.get());
+25 -50
View File
@@ -2746,69 +2746,44 @@ std::unique_ptr<GSDownloadTexture> GSDeviceVK::CreateDownloadTexture(u32 width,
void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GSTextureVK* const sTexVK = static_cast<GSTextureVK*>(sTex);
GSTextureVK* const dTexVK = static_cast<GSTextureVK*>(dTex);
const GSVector4i dtex_rc(0, 0, dTexVK->GetWidth(), dTexVK->GetHeight());
const GSVector4i dst_rect(0, 0, dTexVK->GetWidth(), dTexVK->GetHeight());
const bool full_draw_copy = dst_rect.eq(r);
// Source is cleared, if destination is a render target, we can carry the clear forward.
if (sTexVK->GetState() == GSTexture::State::Cleared)
{
// source is cleared. if destination is a render target, we can carry the clear forward
if (dTexVK->IsRenderTargetOrDepthStencil())
{
if (dtex_rc.eq(r))
{
// pass it forward if we're clearing the whole thing
if (sTexVK->IsDepthStencil())
dTexVK->SetClearDepth(sTexVK->GetClearDepth());
else
dTexVK->SetClearColor(sTexVK->GetClearColor());
return;
}
if (dTexVK->GetState() == GSTexture::State::Cleared)
{
// destination is cleared, if it's the same colour and rect, we can just avoid this entirely
if (dTexVK->IsDepthStencil())
{
if (dTexVK->GetClearDepth() == sTexVK->GetClearDepth())
return;
}
else
{
if (dTexVK->GetClearColor() == sTexVK->GetClearColor())
return;
}
}
// otherwise we need to do an attachment clear
const bool depth = (dTexVK->GetType() == GSTexture::Type::DepthStencil);
OMSetRenderTargets(depth ? nullptr : dTexVK, depth ? dTexVK : nullptr, dtex_rc);
BeginRenderPassForStretchRect(
dTexVK, dtex_rc, GSVector4i(destX, destY, destX + r.width(), destY + r.height()));
// so use an attachment clear
VkClearAttachment ca;
ca.aspectMask = depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
GSVector4::store<false>(ca.clearValue.color.float32, sTexVK->GetUNormClearColor());
ca.clearValue.depthStencil.depth = sTexVK->GetClearDepth();
ca.clearValue.depthStencil.stencil = 0;
ca.colorAttachment = 0;
const VkClearRect cr = {{{0, 0}, {static_cast<u32>(r.width()), static_cast<u32>(r.height())}}, 0u, 1u};
vkCmdClearAttachments(GetCurrentCommandBuffer(), 1, &ca, 1, &cr);
if (dTexVK->IsRenderTargetOrDepthStencil() && ProcessClearsBeforeCopy(sTex, dTex, full_draw_copy))
return;
}
// Do an attachment clear.
const bool depth = (dTexVK->GetType() == GSTexture::Type::DepthStencil);
OMSetRenderTargets(depth ? nullptr : dTexVK, depth ? dTexVK : nullptr, dst_rect);
BeginRenderPassForStretchRect(
dTexVK, dst_rect, GSVector4i(destX, destY, destX + r.width(), destY + r.height()));
// so use an attachment clear
VkClearAttachment ca;
ca.aspectMask = depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
GSVector4::store<false>(ca.clearValue.color.float32, sTexVK->GetUNormClearColor());
ca.clearValue.depthStencil.depth = sTexVK->GetClearDepth();
ca.clearValue.depthStencil.stencil = 0;
ca.colorAttachment = 0;
const VkClearRect cr = {{{0, 0}, {static_cast<u32>(r.width()), static_cast<u32>(r.height())}}, 0u, 1u};
vkCmdClearAttachments(GetCurrentCommandBuffer(), 1, &ca, 1, &cr);
return;
// commit the clear to the source first, then do normal copy
sTexVK->CommitClear();
}
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// if the destination has been cleared, and we're not overwriting the whole thing, commit the clear first
// (the area outside of where we're copying to)
if (dTexVK->GetState() == GSTexture::State::Cleared && !dtex_rc.eq(r))
if (dTexVK->GetState() == GSTexture::State::Cleared && !full_draw_copy)
dTexVK->CommitClear();
// *now* we can do a normal image copy.
+45 -45
View File
@@ -113,32 +113,37 @@ static bool UseSavestateSelector()
}
BEGIN_HOTKEY_LIST(g_common_hotkeys)
DEFINE_HOTKEY("OpenPauseMenu", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Open Pause Menu"),
DEFINE_HOTKEY("ToggleFullscreen", TRANSLATE_NOOP("Hotkeys", "Navigation"), TRANSLATE_NOOP("Hotkeys", "Toggle Fullscreen"),
[](s32 pressed) {
if (!pressed)
Host::SetFullscreen(!Host::IsFullscreen());
})
DEFINE_HOTKEY("OpenPauseMenu", TRANSLATE_NOOP("Hotkeys", "Navigation"), TRANSLATE_NOOP("Hotkeys", "Open Pause Menu"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM() && CanPause())
FullscreenUI::OpenPauseMenu();
})
DEFINE_HOTKEY("OpenAchievementsList", TRANSLATE_NOOP("Hotkeys", "System"),
DEFINE_HOTKEY("OpenAchievementsList", TRANSLATE_NOOP("Hotkeys", "Navigation"),
TRANSLATE_NOOP("Hotkeys", "Open Achievements List"), [](s32 pressed) {
if (!pressed && CanPause())
FullscreenUI::OpenAchievementsWindow();
})
DEFINE_HOTKEY("OpenLeaderboardsList", TRANSLATE_NOOP("Hotkeys", "System"),
DEFINE_HOTKEY("OpenLeaderboardsList", TRANSLATE_NOOP("Hotkeys", "Navigation"),
TRANSLATE_NOOP("Hotkeys", "Open Leaderboards List"), [](s32 pressed) {
if (!pressed && CanPause())
FullscreenUI::OpenLeaderboardsWindow();
})
DEFINE_HOTKEY(
"TogglePause", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Pause"), [](s32 pressed) {
"TogglePause", TRANSLATE_NOOP("Hotkeys", "Speed"), TRANSLATE_NOOP("Hotkeys", "Toggle Pause"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM() && CanPause())
VMManager::SetPaused(VMManager::GetState() != VMState::Paused);
})
DEFINE_HOTKEY("ToggleFullscreen", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Fullscreen"),
[](s32 pressed) {
if (!pressed)
Host::SetFullscreen(!Host::IsFullscreen());
DEFINE_HOTKEY(
"FrameAdvance", TRANSLATE_NOOP("Hotkeys", "Speed"), TRANSLATE_NOOP("Hotkeys", "Frame Advance"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::FrameAdvance(1);
})
DEFINE_HOTKEY("ToggleFrameLimit", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Frame Limit"),
DEFINE_HOTKEY("ToggleFrameLimit", TRANSLATE_NOOP("Hotkeys", "Speed"), TRANSLATE_NOOP("Hotkeys", "Toggle Frame Limit"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
{
@@ -147,7 +152,7 @@ DEFINE_HOTKEY("ToggleFrameLimit", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE
LimiterModeType::Nominal);
}
})
DEFINE_HOTKEY("ToggleTurbo", TRANSLATE_NOOP("Hotkeys", "System"),
DEFINE_HOTKEY("ToggleTurbo", TRANSLATE_NOOP("Hotkeys", "Speed"),
TRANSLATE_NOOP("Hotkeys", "Toggle Turbo / Fast Forward"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
{
@@ -155,15 +160,7 @@ DEFINE_HOTKEY("ToggleTurbo", TRANSLATE_NOOP("Hotkeys", "System"),
(VMManager::GetLimiterMode() != LimiterModeType::Turbo) ? LimiterModeType::Turbo : LimiterModeType::Nominal);
}
})
DEFINE_HOTKEY("ToggleSlowMotion", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Slow Motion"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
{
VMManager::SetLimiterMode(
(VMManager::GetLimiterMode() != LimiterModeType::Slomo) ? LimiterModeType::Slomo : LimiterModeType::Nominal);
}
})
DEFINE_HOTKEY("HoldTurbo", TRANSLATE_NOOP("Hotkeys", "System"),
DEFINE_HOTKEY("HoldTurbo", TRANSLATE_NOOP("Hotkeys", "Speed"),
TRANSLATE_NOOP("Hotkeys", "Turbo / Fast Forward (Hold)"), [](s32 pressed) {
if (!VMManager::HasValidVM())
return;
@@ -180,35 +177,24 @@ DEFINE_HOTKEY("HoldTurbo", TRANSLATE_NOOP("Hotkeys", "System"),
s_limiter_mode_prior_to_hold_interaction.reset();
}
})
DEFINE_HOTKEY("IncreaseSpeed", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Increase Target Speed"),
DEFINE_HOTKEY("ToggleSlowMotion", TRANSLATE_NOOP("Hotkeys", "Speed"), TRANSLATE_NOOP("Hotkeys", "Toggle Slow Motion"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
{
VMManager::SetLimiterMode(
(VMManager::GetLimiterMode() != LimiterModeType::Slomo) ? LimiterModeType::Slomo : LimiterModeType::Nominal);
}
})
DEFINE_HOTKEY("IncreaseSpeed", TRANSLATE_NOOP("Hotkeys", "Speed"), TRANSLATE_NOOP("Hotkeys", "Increase Target Speed"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustTargetSpeed(0.1);
})
DEFINE_HOTKEY("DecreaseSpeed", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Decrease Target Speed"),
DEFINE_HOTKEY("DecreaseSpeed", TRANSLATE_NOOP("Hotkeys", "Speed"), TRANSLATE_NOOP("Hotkeys", "Decrease Target Speed"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustTargetSpeed(-0.1);
})
DEFINE_HOTKEY("IncreaseVolume", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Increase Volume"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustVolume(-1, 5);
})
DEFINE_HOTKEY("DecreaseVolume", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Decrease Volume"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustVolume(-1, -5);
})
DEFINE_HOTKEY("Mute", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Mute"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustVolume((SPU2::GetOutputVolume() == 0) ? SPU2::GetResetVolume() : 0, 0);
})
DEFINE_HOTKEY(
"FrameAdvance", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Frame Advance"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
VMManager::FrameAdvance(1);
})
DEFINE_HOTKEY("ShutdownVM", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Shut Down Virtual Machine"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
@@ -219,11 +205,6 @@ DEFINE_HOTKEY("ResetVM", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Ho
if (!pressed && VMManager::HasValidVM())
VMManager::Reset();
})
DEFINE_HOTKEY("InputRecToggleMode", TRANSLATE_NOOP("Hotkeys", "System"),
TRANSLATE_NOOP("Hotkeys", "Toggle Input Recording Mode"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
g_InputRecording.getControls().toggleRecordMode();
})
DEFINE_HOTKEY("SwapMemCards", TRANSLATE_NOOP("Hotkeys", "System"),
TRANSLATE_NOOP("Hotkeys", "Swap Memory Cards"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
@@ -231,6 +212,11 @@ DEFINE_HOTKEY("SwapMemCards", TRANSLATE_NOOP("Hotkeys", "System"),
FileMcd_Swap();
});
})
DEFINE_HOTKEY("InputRecToggleMode", TRANSLATE_NOOP("Hotkeys", "System"),
TRANSLATE_NOOP("Hotkeys", "Toggle Input Recording Mode"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
g_InputRecording.getControls().toggleRecordMode();
})
DEFINE_HOTKEY("PreviousSaveStateSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
TRANSLATE_NOOP("Hotkeys", "Select Previous Save Slot"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
@@ -305,4 +291,18 @@ DEFINE_HOTKEY_SAVESTATE_X(10, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 10")
DEFINE_HOTKEY_LOADSTATE_X(10, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 10"))
#undef DEFINE_HOTKEY_SAVESTATE_X
#undef DEFINE_HOTKEY_LOADSTATE_X
DEFINE_HOTKEY("Mute", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOOP("Hotkeys", "Toggle Mute"), [](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustVolume((SPU2::GetOutputVolume() == 0) ? SPU2::GetResetVolume() : 0, 0);
})
DEFINE_HOTKEY("IncreaseVolume", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOOP("Hotkeys", "Increase Volume"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustVolume(-1, 5);
})
DEFINE_HOTKEY("DecreaseVolume", TRANSLATE_NOOP("Hotkeys", "Audio"), TRANSLATE_NOOP("Hotkeys", "Decrease Volume"),
[](s32 pressed) {
if (!pressed && VMManager::HasValidVM())
HotkeyAdjustVolume(-1, -5);
})
END_HOTKEY_LIST()
+41 -3
View File
@@ -3981,7 +3981,7 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
#ifdef __APPLE__
FSUI_NSTR("Metal"),
#endif
FSUI_NSTR("Software"),
FSUI_NSTR("Software Renderer"),
FSUI_NSTR("Null"),
};
static constexpr const char* s_renderer_values[] = {
@@ -4128,8 +4128,8 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
BeginMenuButtons();
MenuHeading(FSUI_CSTR("Renderer"));
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINTBRUSH, "Renderer"), FSUI_CSTR("Selects the API used to render the emulated GS."), "EmuCore/GS",
MenuHeading(FSUI_CSTR("Graphics API"));
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINTBRUSH, "Graphics API"), FSUI_CSTR("Selects the API used to render the emulated GS."), "EmuCore/GS",
"Renderer", "-1", s_renderer_names, s_renderer_values, std::size(s_renderer_names), true);
MenuHeading(FSUI_CSTR("Display"));
@@ -6443,6 +6443,44 @@ void FullscreenUI::DrawResumeStateSelector()
void FullscreenUI::DoLoadState(std::string path)
{
// Check for hardcore mode before loading state
if (Achievements::IsHardcoreModeActive())
{
Achievements::ConfirmHardcoreModeDisableAsync(TRANSLATE("VMManager", "Loading state"),
[path = std::move(path)](bool approved) {
if (approved)
DoLoadState(std::move(path));
});
return;
}
const std::string filename = std::string(Path::GetFileName(path));
s32 slot = -1;
bool is_backup = false;
std::string base_filename = filename;
if (filename.length() > 7 && filename.substr(filename.length() - 7) == ".backup")
{
is_backup = true;
base_filename = filename.substr(0, filename.length() - 7);
}
// Get slot number from filename (format: serial.crc.slot.p2s)
const size_t last_dot = base_filename.rfind('.');
const size_t second_last_dot = base_filename.rfind('.', last_dot - 1);
if (last_dot != std::string::npos && second_last_dot != std::string::npos)
{
const std::string slot_str = base_filename.substr(second_last_dot + 1, last_dot - second_last_dot - 1);
if (!slot_str.empty())
slot = std::atoi(slot_str.c_str());
}
const std::string message = (slot >= 0) ?
fmt::format(TRANSLATE_FS("VMManager", "Loading {} from slot {}..."), is_backup ? TRANSLATE("VMManager", "backup state") : TRANSLATE("VMManager", "state"), slot) :
TRANSLATE_STR("VMManager", "Loading save state...");
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN, message, Host::OSD_QUICK_DURATION);
Host::RunOnCPUThread([path = std::move(path)]()
{
const std::string boot_path = s_save_state_selector_game_path;
+1 -1
View File
@@ -467,7 +467,7 @@ ImFont* ImGuiManager::AddTextFont()
{
// Exclude FA and PF ranges
// clang-format off
static constexpr ImWchar range_exclude_icons[] = { 0x2198,0x2199,0x219e,0x21a7,0x21b0,0x21b3,0x21ba,0x21c3,0x21ce,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21e6,0x21e8,0x21f3,0x21f3,0x21f7,0x21fb,0x2206,0x2208,0x221a,0x221a,0x227a,0x227d,0x22bf,0x22c8,0x2349,0x2349,0x235a,0x2361,0x2364,0x2367,0x237a,0x237f,0x23b2,0x23b5,0x23cc,0x23cc,0x23f4,0x23f7,0x2427,0x243a,0x243d,0x243d,0x2443,0x2443,0x2460,0x246b,0x248f,0x248f,0x24f5,0x24ff,0x2605,0x2605,0x2699,0x2699,0x278a,0x278e,0xff21,0xff3a,0x0,0x0 };
static constexpr ImWchar range_exclude_icons[] = { 0x2198,0x2199,0x219e,0x21a7,0x21b0,0x21b3,0x21ba,0x21c3,0x21ce,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21e6,0x21e8,0x21f3,0x21f3,0x21f7,0x21fb,0x2206,0x2208,0x221a,0x221a,0x227a,0x227d,0x22bf,0x22c8,0x2349,0x2349,0x235a,0x2361,0x2364,0x2367,0x237a,0x237f,0x23b2,0x23b5,0x23cc,0x23cc,0x23f4,0x23f7,0x2427,0x243a,0x243d,0x243e,0x2441,0x2452,0x2460,0x246b,0x248f,0x248f,0x24f5,0x24ff,0x2605,0x2605,0x2699,0x2699,0x278a,0x278e,0xff21,0xff3a,0x0,0x0 };
// clang-format on
ImFontConfig cfg;
+4 -8
View File
@@ -670,7 +670,7 @@ __ri void ImGuiManager::DrawInputsOverlay(float scale, float margin, float spaci
for (u32 port = 0; port < USB::NUM_PORTS; port++)
{
if (EmuConfig.USB.Ports[port].DeviceType >= 0 && !USB::GetDeviceBindings(port).empty())
if (EmuConfig.USB.Ports[port].DeviceType >= 0)
num_ports++;
}
@@ -688,10 +688,7 @@ __ri void ImGuiManager::DrawInputsOverlay(float scale, float margin, float spaci
continue;
const Pad::ControllerInfo& cinfo = pad->GetInfo();
if (cinfo.icon_name)
text.format("{} {}", cinfo.icon_name, slot + 1u);
else
text.format("{} |", slot + 1u);
text.format("{} {} • {} |", ICON_FA_GAMEPAD, slot + 1u, cinfo.icon_name ? cinfo.icon_name : ICON_FA_TRIANGLE_EXCLAMATION);
for (u32 bind = 0; bind < static_cast<u32>(cinfo.bindings.size()); bind++)
{
@@ -744,10 +741,9 @@ __ri void ImGuiManager::DrawInputsOverlay(float scale, float margin, float spaci
continue;
const std::span<const InputBindingInfo> bindings(USB::GetDeviceBindings(port));
if (bindings.empty())
continue;
text.format("{} {} ", ICON_PF_USB, port + 1u);
const char* icon = USB::GetDeviceIconName(port);
text.format("{} {} • {} | ", ICON_PF_USB, port + 1u, icon ? icon : ICON_FA_TRIANGLE_EXCLAMATION);
for (const InputBindingInfo& bi : bindings)
{
+8 -4
View File
@@ -4,6 +4,8 @@
#pragma once
#include "vtlb.h"
#include "MemoryTypes.h"
#include "common/BitUtils.h"
// This is a table of default virtual map addresses for ps2vm components. These locations
// are provided and used to assist in debugging and possibly hacking; as it makes it possible
@@ -22,13 +24,15 @@ namespace HostMemoryMap
// Main
//////////////////////////////////////////////////////////////////////////
// PS2 main memory, SPR, and ROMs (approximately 138.5MB, but we round up to 139MB for simplicity).
// PS2 main memory, SPR, and ROMs (approximately 143MB).
// Needs to be big enough to fit the EEVM_MemoryAllocMess struct
static constexpr u32 EEmemOffset = 0x00000000;
static constexpr u32 EEmemSize = 0x8B00000;
static constexpr u32 EEmemSize = Common::AlignUp(sizeof(EEVM_MemoryAllocMess), _1mb);
// IOP main memory (2MB + 64K + 256b, rounded up to 3MB for simplicity).
// IOP main memory (approximately 3MB).
// Needs to be big enough to fit the IopVM_MemoryAllocMess struct
static constexpr u32 IOPmemOffset = EEmemOffset + EEmemSize;
static constexpr u32 IOPmemSize = 0x300000;
static constexpr u32 IOPmemSize = Common::AlignUp(sizeof(IopVM_MemoryAllocMess), _1mb);
// VU0 and VU1 memory (40KB, rounded up to 1MB for simplicity).
static constexpr u32 VUmemOffset = IOPmemOffset + IOPmemSize;
+2
View File
@@ -29,6 +29,7 @@ typedef u32 mem32_t;
typedef u64 mem64_t;
typedef u128 mem128_t;
// Needs to fit within EEmemSize of Memory.h
struct EEVM_MemoryAllocMess
{
u8 Main[Ps2MemSize::MainRam]; // Main memory (hard-wired to 32MB)
@@ -47,6 +48,7 @@ struct EEVM_MemoryAllocMess
u8 ZeroWrite[_1mb];
};
// Needs to fit within IOPmemSize of Memory.h
struct IopVM_MemoryAllocMess
{
u8 Main[Ps2MemSize::IopRam]; // Main memory (hard-wired to 2MB)
+75 -56
View File
@@ -19,7 +19,7 @@
#include "fmt/format.h"
#if _WIN32
#if defined(_WIN32)
#define read_portable(a, b, c) (recv(a, (char*)b, c, 0))
#define write_portable(a, b, c) (send(a, (const char*)b, c, 0))
#define safe_close_portable(a) \
@@ -31,9 +31,23 @@
(a) = INVALID_SOCKET; \
} \
} while (0)
#define bzero(b, len) (memset((b), '\0', (len)), (void)0)
#include "common/RedtapeWindows.h"
#include <WinSock2.h>
#elif defined(__linux__) || defined(__FreeBSD__)
#define read_portable(a, b, c) (read(a, b, c))
#define write_portable(a, b, c) (send(a, b, c, MSG_NOSIGNAL))
#define safe_close_portable(a) \
do \
{ \
if ((a) >= 0) \
{ \
close((a)); \
(a) = -1; \
} \
} while (0)
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#else
#define read_portable(a, b, c) (read(a, b, c))
#define write_portable(a, b, c) (write(a, b, c))
@@ -74,25 +88,25 @@ static bool InitializeWinsock()
namespace PINEServer
{
std::thread m_thread;
int m_slot;
static std::thread s_thread;
static int s_slot;
#ifdef _WIN32
// windows claim to have support for AF_UNIX sockets but that is a blatant lie,
// their SDK won't even run their own examples, so we go on TCP sockets.
static SOCKET m_sock = INVALID_SOCKET;
static SOCKET s_sock = INVALID_SOCKET;
// the message socket used in thread's accept().
static SOCKET m_msgsock = INVALID_SOCKET;
static SOCKET s_msgsock = INVALID_SOCKET;
#else
// absolute path of the socket. Stored in XDG_RUNTIME_DIR, if unset /tmp
static std::string m_socket_name;
static int m_sock = -1;
static std::string s_socket_name;
static int s_sock = -1;
// the message socket used in thread's accept().
static int m_msgsock = -1;
static int s_msgsock = -1;
#endif
// Whether the socket processing thread should stop executing/is stopped.
static std::atomic_bool m_end{true};
static std::atomic_bool s_end{true};
/**
* Maximum memory used by an IPC message request.
@@ -111,13 +125,13 @@ namespace PINEServer
* A preallocated buffer used to store all IPC replies.
* to the size of 50.000 MsgWrite64 IPC calls.
*/
static std::vector<u8> m_ret_buffer;
static std::vector<u8> s_ret_buffer;
/**
* IPC messages buffer.
* A preallocated buffer used to store all IPC messages.
*/
static std::vector<u8> m_ipc_buffer;
static std::vector<u8> s_ipc_buffer;
/**
* IPC Command messages opcodes.
@@ -246,8 +260,8 @@ namespace PINEServer
bool PINEServer::Initialize(int slot)
{
m_end.store(false, std::memory_order_release);
m_slot = slot;
s_end.store(false, std::memory_order_release);
s_slot = slot;
#ifdef _WIN32
if (!InitializeWinsock())
@@ -257,8 +271,8 @@ bool PINEServer::Initialize(int slot)
return false;
}
m_sock = socket(AF_INET, SOCK_STREAM, 0);
if ((m_sock == INVALID_SOCKET) || slot > 65536)
s_sock = socket(AF_INET, SOCK_STREAM, 0);
if ((s_sock == INVALID_SOCKET) || slot > 65536)
{
Console.WriteLn(Color_Red, "PINE: Cannot open socket! Shutting down...");
Deinitialize();
@@ -270,7 +284,7 @@ bool PINEServer::Initialize(int slot)
server.sin_addr.s_addr = htonl(INADDR_LOOPBACK); // localhost only
server.sin_port = htons(slot);
if (bind(m_sock, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
if (bind(s_sock, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
Console.WriteLn(Color_Red, "PINE: Error while binding to socket! Shutting down...");
Deinitialize();
@@ -287,32 +301,32 @@ bool PINEServer::Initialize(int slot)
// fallback in case macOS or other OSes don't implement the XDG base
// spec
if (runtime_dir == nullptr)
m_socket_name = "/tmp/" PINE_EMULATOR_NAME ".sock";
s_socket_name = "/tmp/" PINE_EMULATOR_NAME ".sock";
else
{
m_socket_name = runtime_dir;
m_socket_name += "/" PINE_EMULATOR_NAME ".sock";
s_socket_name = runtime_dir;
s_socket_name += "/" PINE_EMULATOR_NAME ".sock";
}
if (slot != PINE_DEFAULT_SLOT)
m_socket_name += "." + std::to_string(slot);
s_socket_name += "." + std::to_string(slot);
struct sockaddr_un server;
m_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (m_sock < 0)
s_sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (s_sock < 0)
{
Console.WriteLn(Color_Red, "PINE: Cannot open socket! Shutting down...");
Deinitialize();
return false;
}
server.sun_family = AF_UNIX;
StringUtil::Strlcpy(server.sun_path, m_socket_name, sizeof(server.sun_path));
StringUtil::Strlcpy(server.sun_path, s_socket_name, sizeof(server.sun_path));
// we unlink the socket so that when releasing this thread the socket gets
// freed even if we didn't close correctly the loop
unlink(m_socket_name.c_str());
if (bind(m_sock, (struct sockaddr*)&server, sizeof(struct sockaddr_un)))
unlink(s_socket_name.c_str());
if (bind(s_sock, (struct sockaddr*)&server, sizeof(struct sockaddr_un)))
{
Console.WriteLn(Color_Red, "PINE: Error while binding to socket! Shutting down...");
Deinitialize();
@@ -323,7 +337,7 @@ bool PINEServer::Initialize(int slot)
// maximum queue of 4096 commands before refusing, approximated to the
// nearest legal value. We do not use SOMAXCONN as windows have this idea
// that a "reasonable" value is 5, which is not.
if (listen(m_sock, 4096))
if (listen(s_sock, 4096))
{
Console.WriteLn(Color_Red, "PINE: Cannot listen for connections! Shutting down...");
Deinitialize();
@@ -332,23 +346,23 @@ bool PINEServer::Initialize(int slot)
// we allocate once buffers to not have to do mallocs for each IPC
// request, as malloc is expansive when we optimize for µs.
m_ret_buffer.resize(MAX_IPC_RETURN_SIZE);
m_ipc_buffer.resize(MAX_IPC_SIZE);
s_ret_buffer.resize(MAX_IPC_RETURN_SIZE);
s_ipc_buffer.resize(MAX_IPC_SIZE);
// we start the thread
m_thread = std::thread(&PINEServer::MainLoop);
s_thread = std::thread(&PINEServer::MainLoop);
return true;
}
bool PINEServer::IsInitialized()
{
return !m_end.load(std::memory_order_acquire);
return !s_end.load(std::memory_order_acquire);
}
int PINEServer::GetSlot()
{
return m_slot;
return s_slot;
}
std::vector<u8>& PINEServer::MakeOkIPC(std::vector<u8>& ret_buffer, uint32_t size = 5)
@@ -367,24 +381,29 @@ std::vector<u8>& PINEServer::MakeFailIPC(std::vector<u8>& ret_buffer, uint32_t s
bool PINEServer::AcceptClient()
{
m_msgsock = accept(m_sock, 0, 0);
if (m_msgsock >= 0)
s_msgsock = accept(s_sock, 0, 0);
if (s_msgsock >= 0)
{
// Gross C-style cast, but SOCKET is a handle on Windows.
Console.WriteLn("PINE: New client with FD %d connected.", (int)m_msgsock);
Console.WriteLn("PINE: New client with FD %d connected.", (int)s_msgsock);
return true;
}
#ifdef __APPLE__
int nosigpipe = 1;
setsockopt(s_msgsock, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe, sizeof(nosigpipe));
#endif
// everything else is non recoverable in our scope
// we also mark as recoverable socket errors where it would block a
// non blocking socket, even though our socket is blocking, in case
// we ever have to implement a non blocking socket.
#ifdef _WIN32
const int errno_w = WSAGetLastError();
if (!(errno_w == WSAECONNRESET || errno_w == WSAEINTR || errno_w == WSAEINPROGRESS || errno_w == WSAEMFILE || errno_w == WSAEWOULDBLOCK) && m_sock != INVALID_SOCKET)
if (!(errno_w == WSAECONNRESET || errno_w == WSAEINTR || errno_w == WSAEINPROGRESS || errno_w == WSAEMFILE || errno_w == WSAEWOULDBLOCK) && s_sock != INVALID_SOCKET)
Console.Error("PINE: accept() returned error %d", errno_w);
#else
if (!(errno == ECONNABORTED || errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) && m_sock >= 0)
if (!(errno == ECONNABORTED || errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) && s_sock >= 0)
Console.Error("PINE: accept() returned error %d", errno);
#endif
@@ -395,7 +414,7 @@ void PINEServer::MainLoop()
{
Threading::SetNameOfCurrentThread("PINE Server");
while (!m_end.load(std::memory_order_acquire))
while (!s_end.load(std::memory_order_acquire))
{
if (!AcceptClient())
continue;
@@ -403,25 +422,25 @@ void PINEServer::MainLoop()
ClientLoop();
Console.WriteLn("PINE: Client disconnected.");
safe_close_portable(m_msgsock);
safe_close_portable(s_msgsock);
}
}
void PINEServer::ClientLoop()
{
while (!m_end.load(std::memory_order_acquire))
while (!s_end.load(std::memory_order_acquire))
{
// either int or ssize_t depending on the platform, so we have to
// use a bunch of auto
auto receive_length = 0;
auto end_length = 4;
const std::span<u8> ipc_buffer_span(m_ipc_buffer);
const std::span<u8> ipc_buffer_span(s_ipc_buffer);
// while we haven't received the entire packet, maybe due to
// socket datagram splittage, we continue to read
while (receive_length < end_length)
{
const auto tmp_length = read_portable(m_msgsock, &ipc_buffer_span[receive_length], MAX_IPC_SIZE - receive_length);
const auto tmp_length = read_portable(s_msgsock, &ipc_buffer_span[receive_length], MAX_IPC_SIZE - receive_length);
// we recreate the socket if an error happens
if (tmp_length <= 0)
@@ -450,10 +469,10 @@ void PINEServer::ClientLoop()
// disconnects
if (receive_length != 0)
{
res = ParseCommand(ipc_buffer_span.subspan(4), m_ret_buffer, (u32)end_length - 4);
res = ParseCommand(ipc_buffer_span.subspan(4), s_ret_buffer, (u32)end_length - 4);
// if we cannot send back our answer restart the socket
if (write_portable(m_msgsock, res.buffer.data(), res.size) < 0)
if (write_portable(s_msgsock, res.buffer.data(), res.size) < 0)
return;
}
}
@@ -461,30 +480,30 @@ void PINEServer::ClientLoop()
void PINEServer::Deinitialize()
{
m_end.store(true, std::memory_order_release);
s_end.store(true, std::memory_order_release);
#ifndef _WIN32
if (!m_socket_name.empty())
if (!s_socket_name.empty())
{
unlink(m_socket_name.c_str());
m_socket_name = {};
unlink(s_socket_name.c_str());
s_socket_name = {};
}
#endif
// shutdown() is needed, otherwise accept() will still block.
#ifdef _WIN32
if (m_sock != INVALID_SOCKET)
shutdown(m_sock, SD_BOTH);
if (s_sock != INVALID_SOCKET)
shutdown(s_sock, SD_BOTH);
#else
if (m_sock >= 0)
shutdown(m_sock, SHUT_RDWR);
if (s_sock >= 0)
shutdown(s_sock, SHUT_RDWR);
#endif
safe_close_portable(m_sock);
safe_close_portable(m_msgsock);
safe_close_portable(s_sock);
safe_close_portable(s_msgsock);
if (m_thread.joinable())
m_thread.join();
if (s_thread.joinable())
s_thread.join();
}
PINEServer::IPCBuffer PINEServer::ParseCommand(std::span<u8> buf, std::vector<u8>& ret_buffer, u32 buf_size)
+3 -1
View File
@@ -708,7 +708,8 @@ std::optional<bool> Pcsx2Config::GSOptions::TriStateToOptionalBoolean(int value)
Pcsx2Config::GSOptions::GSOptions()
{
bitset = 0;
bitset[0] = 0;
bitset[1] = 0;
PCRTCAntiBlur = true;
DisableInterlaceOffset = false;
@@ -987,6 +988,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBoolEx(SaveDepth, "SaveDepth");
SettingsWrapBitBoolEx(SaveAlpha, "SaveAlpha");
SettingsWrapBitBoolEx(SaveInfo, "SaveInfo");
SettingsWrapBitBoolEx(SaveTransferImages, "SaveTransferImages");
SettingsWrapBitBool(DumpReplaceableTextures);
SettingsWrapBitBool(DumpReplaceableMipmaps);
SettingsWrapBitBool(DumpTexturesWithFMVActive);
+1 -1
View File
@@ -81,7 +81,7 @@ static const SettingInfo s_settings[] = {
};
const Pad::ControllerInfo PadDualshock2::ControllerInfo = {Pad::ControllerType::DualShock2, "DualShock2",
TRANSLATE_NOOP("Pad", "DualShock 2"), ICON_PF_GAMEPAD_ALT, s_bindings, s_settings, Pad::VibrationCapabilities::LargeSmallMotors};
TRANSLATE_NOOP("Pad", "DualShock 2"), ICON_PF_DUALSHOCK2, s_bindings, s_settings, Pad::VibrationCapabilities::LargeSmallMotors};
void PadDualshock2::ConfigLog()
{
+1 -1
View File
@@ -45,7 +45,7 @@ static const SettingInfo s_settings[] = {
};
const Pad::ControllerInfo PadJogcon::ControllerInfo = {Pad::ControllerType::Jogcon, "Jogcon",
TRANSLATE_NOOP("Pad", "Jogcon"), ICON_PF_GAMEPAD_ALT, s_bindings, s_settings, Pad::VibrationCapabilities::LargeSmallMotors};
TRANSLATE_NOOP("Pad", "Jogcon"), ICON_PF_JOGCON, s_bindings, s_settings, Pad::VibrationCapabilities::LargeSmallMotors};
void PadJogcon::ConfigLog()
{
+1 -1
View File
@@ -42,7 +42,7 @@ static const SettingInfo s_settings[] = {
};
const Pad::ControllerInfo PadNegcon::ControllerInfo = {Pad::ControllerType::Negcon, "NeGcon",
TRANSLATE_NOOP("Pad", "NeGcon"), ICON_PF_GAMEPAD_ALT, s_bindings, s_settings, Pad::VibrationCapabilities::LargeSmallMotors};
TRANSLATE_NOOP("Pad", "NeGcon"), ICON_PF_NEGCON, s_bindings, s_settings, Pad::VibrationCapabilities::LargeSmallMotors};
void PadNegcon::ConfigLog()
{
+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 = 72;
static constexpr u32 SHADER_CACHE_VERSION = 73;
+9
View File
@@ -561,6 +561,15 @@ const char* USB::GetDeviceName(const std::string_view device)
return dev ? dev->Name() : TRANSLATE_NOOP("USB", "Not Connected");
}
const char* USB::GetDeviceIconName(u32 port)
{
pxAssert(port < NUM_PORTS);
if (s_usb_device_proxy[port])
return s_usb_device_proxy[port]->IconName();
else
return nullptr;
}
const char* USB::GetDeviceSubtypeName(const std::string_view device, u32 subtype)
{
const DeviceProxy* dev = RegisterDevice::instance().Device(device);
+1
View File
@@ -27,6 +27,7 @@ namespace USB
std::vector<std::pair<const char*, const char*>> GetDeviceTypes();
const char* GetDeviceName(const std::string_view device);
const char* GetDeviceIconName(u32 port);
const char* GetDeviceSubtypeName(const std::string_view device, u32 subtype);
std::span<const char*> GetDeviceSubtypes(const std::string_view device);
std::span<const InputBindingInfo> GetDeviceBindings(const std::string_view device, u32 subtype);
+1
View File
@@ -51,6 +51,7 @@ public:
virtual const char* Name() const = 0;
virtual const char* TypeName() const = 0;
virtual const char* IconName() const = 0;
virtual std::span<const char*> SubTypes() const;
virtual std::span<const InputBindingInfo> Bindings(u32 subtype) const;
virtual std::span<const SettingInfo> Settings(u32 subtype) const;
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#include "Host.h"
#include "IconsPromptFont.h"
#include "videodev.h"
#include "usb-eyetoy-webcam.h"
#include "ov519.h"
@@ -491,6 +492,11 @@ namespace usb_eyetoy
return "webcam";
}
const char* EyeToyWebCamDevice::IconName() const
{
return ICON_PF_EYETOY_WEBCAM;
}
bool EyeToyWebCamDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
EYETOYState* s = USB_CONTAINER_OF(dev, EYETOYState, dev);
+1
View File
@@ -461,6 +461,7 @@ namespace usb_eyetoy
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override;
std::span<const char*> SubTypes() const override;
+11
View File
@@ -32,6 +32,7 @@
#include "USB/qemu-usb/desc.h"
#include "USB/usb-hid/usb-hid.h"
#include "IconsPromptFont.h"
#include "common/Console.h"
namespace usb_hid
@@ -826,6 +827,11 @@ namespace usb_hid
return "hidkbd";
}
const char* HIDKbdDevice::IconName() const
{
return ICON_PF_KEYBOARD_ALT;
}
std::span<const InputBindingInfo> HIDKbdDevice::Bindings(u32 subtype) const
{
static constexpr const InputBindingInfo info[] = {
@@ -899,6 +905,11 @@ namespace usb_hid
return "hidmouse";
}
const char* HIDMouseDevice::IconName() const
{
return ICON_PF_MOUSE;
}
bool HIDMouseDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
UsbHIDState* s = USB_CONTAINER_OF(dev, UsbHIDState, dev);
+2
View File
@@ -14,6 +14,7 @@ namespace usb_hid
public:
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
std::span<const InputBindingInfo> Bindings(u32 subtype) const override;
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
void SetBindingValue(USBDevice* dev, u32 bind, float value) const override;
@@ -25,6 +26,7 @@ namespace usb_hid
public:
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
std::span<const InputBindingInfo> Bindings(u32 subtype) const override;
float GetBindingValue(const USBDevice* dev, u32 bind) const override;
void SetBindingValue(USBDevice* dev, u32 bind, float value) const override;
+6
View File
@@ -3,6 +3,7 @@
#include "GS/GS.h"
#include "Host.h"
#include "IconsPromptFont.h"
#include "ImGui/ImGuiManager.h"
#include "Input/InputManager.h"
#include "StateWrapper.h"
@@ -444,6 +445,11 @@ namespace usb_lightgun
return "guncon2";
}
const char* GunCon2Device::IconName() const
{
return ICON_PF_GUNCON2;
}
USBDevice* GunCon2Device::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
{
GunCon2State* s = new GunCon2State(port);
+1
View File
@@ -12,6 +12,7 @@ namespace usb_lightgun
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override;
float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
+6
View File
@@ -34,6 +34,7 @@
#include "USB/USB.h"
#include "StateWrapper.h"
#include "IconsPromptFont.h"
#include "common/Console.h"
#define BUFFER_FRAMES 200
@@ -962,6 +963,11 @@ namespace usb_mic
return TRANSLATE_NOOP("USB", "Logitech USB Headset");
}
const char* HeadsetDevice::IconName() const
{
return ICON_PF_HEADSET;
}
bool HeadsetDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
HeadsetState* s = USB_CONTAINER_OF(dev, HeadsetState, dev);
+1
View File
@@ -11,6 +11,7 @@ namespace usb_mic
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
const char* TypeName() const override;
const char* Name() const override;
const char* IconName() const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override;
+6
View File
@@ -24,6 +24,7 @@
// Most stuff is based on Qemu 1.7 USB soundcard passthrough code.
#include "IconsPromptFont.h"
#include "USB/qemu-usb/qusb.h"
#include "USB/qemu-usb/desc.h"
#include "USB/qemu-usb/USBinternal.h"
@@ -1204,6 +1205,11 @@ namespace usb_mic
return "singstar";
}
const char* MicrophoneDevice::IconName() const
{
return ICON_PF_SINGSTAR_MIC;
}
bool MicrophoneDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
SINGSTARMICState* s = USB_CONTAINER_OF(dev, SINGSTARMICState, dev);
+1
View File
@@ -22,6 +22,7 @@ namespace usb_mic
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override;
std::span<const char*> SubTypes() const override;
+6
View File
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#include "IconsFontAwesome6.h"
#include "USB/qemu-usb/qusb.h"
#include "USB/qemu-usb/desc.h"
#include "USB/qemu-usb/USBinternal.h"
@@ -1189,6 +1190,11 @@ namespace usb_msd
return TRANSLATE_NOOP("USB", "Mass Storage Device");
}
const char* MsdDevice::IconName() const
{
return ICON_FA_HARD_DRIVE;
}
bool MsdDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
MSDState* s = USB_CONTAINER_OF(dev, MSDState, dev);
+1
View File
@@ -19,6 +19,7 @@ namespace usb_msd
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
const char* TypeName() const override;
const char* Name() const override;
const char* IconName() const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override;
std::span<const char*> SubTypes() const override;
+6
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#include "Host.h"
#include "IconsPromptFont.h"
#include "Input/InputManager.h"
#include "StateWrapper.h"
#include "USB/USB.h"
@@ -205,6 +206,11 @@ namespace usb_pad
return "BuzzDevice";
}
const char* BuzzDevice::IconName() const
{
return ICON_PF_BUZZ_CONTROLLER;
}
bool BuzzDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
return true;
+1
View File
@@ -84,6 +84,7 @@ namespace usb_pad
public:
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override;
+6
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#include "Host.h"
#include "IconsPromptFont.h"
#include "Input/InputManager.h"
#include "StateWrapper.h"
#include "USB/USB.h"
@@ -282,6 +283,11 @@ namespace usb_pad
return "Gametrak";
}
const char* GametrakDevice::IconName() const
{
return ICON_PF_GAMETRAK_DEVICE;
}
USBDevice* GametrakDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
{
GametrakState* s = new GametrakState(port);
+1
View File
@@ -74,6 +74,7 @@ namespace usb_pad
public:
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
+17
View File
@@ -2,6 +2,8 @@
// SPDX-License-Identifier: GPL-3.0+
#include "usb-pad.h"
#include "IconsFontAwesome6.h"
#include "IconsPromptFont.h"
#include "USB/qemu-usb/USBinternal.h"
#include "USB/usb-pad/usb-pad-sdl-ff.h"
#include "USB/USB.h"
@@ -814,6 +816,11 @@ namespace usb_pad
return "Pad";
}
const char* PadDevice::IconName() const
{
return ICON_PF_STEERING_WHEEL_ALT;
}
bool PadDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
PadState* s = USB_CONTAINER_OF(dev, PadState, dev);
@@ -887,6 +894,11 @@ namespace usb_pad
return "RBDrumKit";
}
const char* RBDrumKitDevice::IconName() const
{
return ICON_FA_DRUM;
}
USBDevice* RBDrumKitDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
{
PadState* s = new PadState(port, WT_ROCKBAND1_DRUMKIT);
@@ -949,6 +961,11 @@ namespace usb_pad
return "Keyboardmania";
}
const char* KeyboardmaniaDevice::IconName() const
{
return ICON_PF_KEYBOARDMANIA;
}
std::span<const char*> KeyboardmaniaDevice::SubTypes() const
{
return {};
+4
View File
@@ -72,6 +72,7 @@ namespace usb_pad
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override;
float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
@@ -88,6 +89,7 @@ namespace usb_pad
public:
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
std::span<const char*> SubTypes() const override;
std::span<const InputBindingInfo> Bindings(u32 subtype) const override;
std::span<const SettingInfo> Settings(u32 subtype) const override;
@@ -99,6 +101,7 @@ namespace usb_pad
public:
const char* Name() const;
const char* TypeName() const;
const char* IconName() const;
std::span<const char*> SubTypes() const;
std::span<const InputBindingInfo> Bindings(u32 subtype) const;
std::span<const SettingInfo> Settings(u32 subtype) const;
@@ -111,6 +114,7 @@ namespace usb_pad
public:
const char* Name() const;
const char* TypeName() const;
const char* IconName() const;
std::span<const char*> SubTypes() const;
std::span<const InputBindingInfo> Bindings(u32 subtype) const;
std::span<const SettingInfo> Settings(u32 subtype) const;
+6
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#include "Host.h"
#include "IconsPromptFont.h"
#include "Input/InputManager.h"
#include "StateWrapper.h"
#include "USB/USB.h"
@@ -285,6 +286,11 @@ namespace usb_pad
return "RealPlay";
}
const char* RealPlayDevice::IconName() const
{
return ICON_PF_REALPLAY_BOWLING;
}
USBDevice* RealPlayDevice::CreateDevice(SettingsInterface& si, u32 port, u32 type) const
{
RealPlayState* s = new RealPlayState(port, type);
+1
View File
@@ -80,6 +80,7 @@ namespace usb_pad
public:
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
+6
View File
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#include "Host.h"
#include "IconsPromptFont.h"
#include "USB/usb-pad/usb-pad.h"
#include "USB/qemu-usb/desc.h"
#include "USB/usb-mic/usb-mic.h"
@@ -341,6 +342,11 @@ namespace usb_pad
return "seamic";
}
const char* SeamicDevice::IconName() const
{
return ICON_PF_SEGA_SEAMIC;
}
std::span<const char*> SeamicDevice::SubTypes() const
{
return {};
+5
View File
@@ -26,6 +26,11 @@ namespace usb_pad
return "TrainController";
}
const char* TrainDevice::IconName() const
{
return ICON_FA_TRAIN;
}
std::span<const char*> TrainDevice::SubTypes() const
{
static const char* subtypes[] = {
+1
View File
@@ -23,6 +23,7 @@ namespace usb_pad
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
std::span<const char*> SubTypes() const override;
void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override;
std::span<const SettingInfo> Settings(u32 subtype) const override;
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0+
#include "Host.h"
#include "IconsPromptFont.h"
#include "Input/InputManager.h"
#include "StateWrapper.h"
#include "USB/USB.h"
@@ -129,6 +130,11 @@ namespace usb_pad
return "TranceVibrator";
}
const char* TranceVibratorDevice::IconName() const
{
return ICON_PF_REZ_VIBRATOR;
}
bool TranceVibratorDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
return true;
+1
View File
@@ -26,6 +26,7 @@ namespace usb_pad
public:
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override;
+7
View File
@@ -2,6 +2,8 @@
// SPDX-License-Identifier: GPL-3.0+
#include "Host.h"
#include "IconsFontAwesome6.h"
#include "IconsPromptFont.h"
#include "Input/InputManager.h"
#include "StateWrapper.h"
#include "USB/USB.h"
@@ -235,6 +237,11 @@ namespace usb_pad
return "DJTurntable";
}
const char* DJTurntableDevice::IconName() const
{
return ICON_PF_DJ_HERO_TURNTABLE;
}
USBDevice* DJTurntableDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
{
TurntableState* s = new TurntableState(port);
+1
View File
@@ -86,6 +86,7 @@ namespace usb_pad
public:
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
+6
View File
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#include "IconsPromptFont.h"
#include "USB/qemu-usb/qusb.h"
#include "USB/qemu-usb/USBinternal.h"
#include "USB/usb-printer/usb-printer.h"
@@ -331,6 +332,11 @@ namespace usb_printer
return "printer";
}
const char* PrinterDevice::IconName() const
{
return ICON_PF_PRINTER;
}
bool PrinterDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
PrinterState* s = USB_CONTAINER_OF(dev, PrinterState, dev);
+1
View File
@@ -114,6 +114,7 @@ namespace usb_printer
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
const char* Name() const override;
const char* TypeName() const override;
const char* IconName() const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
std::span<const char*> SubTypes() const override;
+25 -3
View File
@@ -2251,8 +2251,15 @@ bool VMManager::ChangeDisc(CDVD_SourceType source, std::string path)
{
if (source == CDVD_SourceType::NoDisc)
{
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC, TRANSLATE_SV("VMManager", "Disc removed."),
Host::OSD_INFO_DURATION);
if (old_path.empty())
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC, TRANSLATE_SV("VMManager", "No disc to remove."),
Host::OSD_INFO_DURATION);
else
{
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC, TRANSLATE_SV("VMManager", "Disc removed."),
Host::OSD_INFO_DURATION);
Console.WriteLnFmt("Removed disc: '{}'", old_path);
}
}
else
{
@@ -3192,6 +3199,21 @@ void VMManager::WarnAboutUnsafeSettings()
append(ICON_FA_BUG,
TRANSLATE_SV("VMManager", "Debug device is enabled. This will massively reduce performance."));
}
if (EmuConfig.GS.Dithering == 3)
{
append(ICON_FA_TV,
TRANSLATE_SV("VMManager", "Dithering is set to Force 32 bit. This will break rendering in some games."));
}
if (EmuConfig.GS.Dithering == 0)
{
append(ICON_FA_TV,
TRANSLATE_SV("VMManager", "Dithering is disabled. This will cause color banding in some games."));
}
if (EmuConfig.GS.IntegerScaling)
{
append(ICON_FA_TV,
TRANSLATE_SV("VMManager", "Integer scaling is enabled. This may shrink the image."));
}
static bool render_change_warn = false;
if (EmuConfig.GS.Renderer != GSRendererType::Auto && EmuConfig.GS.Renderer != GSRendererType::SW && !render_change_warn)
{
@@ -3199,7 +3221,7 @@ void VMManager::WarnAboutUnsafeSettings()
render_change_warn = true;
append(ICON_FA_CIRCLE_EXCLAMATION,
TRANSLATE_SV("VMManager", "Renderer is not set to Automatic. This may cause performance problems and graphical issues."));
TRANSLATE_SV("VMManager", "Graphics API is not set to Automatic. This may cause performance problems and graphical issues."));
}
}
if (EmuConfig.GS.TextureFiltering != BiFiltering::PS2)