Compare commits

...

74 Commits

Author SHA1 Message Date
lightningterror
98cdd3446b GS/HW: Properly check PABE with source alpha for blends that check for PABE. 2025-03-06 19:18:29 +01:00
lightningterror
9bcbf43695 GS/HW: Check if pabe sw is actually enabled for ate second pass.
No need to check for PABE if it's not enabled on sw blend.
In fact on ICO flag is enabled even if ABE is disabled which is pointless.
2025-03-06 19:18:29 +01:00
TheLastRar
e3c988aa8b FileSystem: Improve handling of relative paths in RealPath() 2025-03-06 13:08:32 -05:00
TheLastRar
06be543d32 FileSystem: Don't pass file access mode into GetWin32Path() 2025-03-06 13:08:32 -05:00
Ty
1fd22dcc1c Windows: Make PCSX2 long path aware 2025-03-04 09:14:25 -05:00
refractionpcsx2
e3afdde981 GSDumpRunner: Fix compilation 2025-03-04 13:28:42 +00:00
lightningterror
698df49e5e Qt: Fix -Wsign-compare warnings. 2025-03-04 13:29:13 +01:00
TheLastRar
ff5c90ec5e SDLInputSource: Correct joystick types 2025-03-04 05:07:56 +01:00
TheLastRar
1e075d23b2 Input: Fix warnings 2025-03-04 05:07:56 +01:00
PCSX2 Bot
2b172903b9 [ci skip] Qt: Update Base Translation. 2025-03-04 01:04:44 +01:00
TheLastRar
4654a3ef6c FSUI: Formatting 2025-03-04 00:34:14 +01:00
Ty
9996061f74 SIO: Bump savestate warning from 1 hour to 2 hours 2025-03-03 12:19:09 -05:00
Ty
247a4c40d1 SIO: Remove a debugging include I somehow missed 2025-03-03 12:19:09 -05:00
PCSX2 Bot
1ffbdd9c08 [ci skip] PAD: Update to latest controller database. 2025-03-03 17:30:19 +01:00
TheLastRar
f67c0cbd2e Input: Fix migration of input profiles 2025-03-03 13:38:55 +01:00
PCSX2 Bot
ff7cc0867b [ci skip] Qt: Update Base Translation. 2025-03-03 01:36:07 +01:00
TheLastRar
ac1a6d3348 Deps: Update to SDL3 (#12311)
Co-authored-by: TheTechnician27 <TheTechnician27@users.noreply.github.com>
2025-03-02 18:04:19 -05:00
TellowKrinkle
582bba6c91 microVU: Accurate CLIP 2025-03-02 18:19:52 +00:00
TellowKrinkle
aaf156478e Interpreter: Accurate CLIP 2025-03-02 18:19:52 +00:00
TellowKrinkle
0539c177ab x86emitter: Add pblend 2025-03-02 18:19:52 +00:00
TellowKrinkle
fb1323b72f MicroVU: Declare constants inline 2025-03-02 18:19:52 +00:00
TellowKrinkle
dc557dd0e5 Interpreter: Merge broadcast min/max into one implementation 2025-03-02 18:19:08 +00:00
TellowKrinkle
2d0cfc9c2c Interpreter: Merge MAC ops into a few template functions 2025-03-02 18:19:08 +00:00
TellowKrinkle
625a25cd50 Interpreter: Merge broadcast ops into one implementation each 2025-03-02 18:19:08 +00:00
TellowKrinkle
b8a29d1cd8 Interpreter: Accurate FTOI
Plus some ITOF cleanup
2025-03-02 18:17:36 +00:00
TellowKrinkle
0fabdf9a01 Interpreter: Accurate ABS 2025-03-02 18:17:36 +00:00
refractionpcsx2
9c3ae795c8 COP2/Int: Propagate CLIP_FLAG writes to the VU0.clipflag variable for use in COP2
This value was being updated then COP2 running VCLIP would have the wrong original clip flag value to work from.
2025-03-02 18:17:05 +00:00
refractionpcsx2
de26226fa1 Core: Delete constant regs when flushing to interpreter 2025-03-02 18:17:05 +00:00
KamFretoZ
121920c074 FSUI: Add Themes 2025-03-02 11:48:29 -05:00
TellowKrinkle
05e19470b2 FileSystem: Don't leak on directory scan cancel
Fixes: 7587581d1f
2025-03-02 09:41:51 -05:00
TheLastRar
b6680e4aca FSUI: Formatting 2025-03-02 09:36:07 -05:00
TheLastRar
f9d70af841 FSUI: Auto detect when to use circle as confirm 2025-03-02 09:36:07 -05:00
TellowKrinkle
7587581d1f GameList: Allow recursive scans to be cancelled 2025-03-02 04:20:01 +01:00
PCSX2 Bot
8f19976c10 [ci skip] Qt: Update Base Translation. 2025-03-02 01:43:09 +01:00
GovanifY
8567d68433 VMManager: initialize PINE with config-provided slot
Sten broke it during the port to Qt...
2025-03-02 00:01:18 +01:00
Glebux
6542301566 Input/PAD: Make macro chords work 2025-03-01 14:38:00 -05:00
refractionpcsx2
a359f77cf6 GameDB/Link: Fix validation limit for Half Pixel Offset to allow new option 2025-03-01 02:01:46 +00:00
PCSX2 Bot
4c9a81f3d8 [ci skip] Qt: Update Base Translation. 2025-02-28 19:54:36 -05:00
refractionpcsx2
9234b493a3 Testing further tweaks to bring it closer to SW 2025-02-28 21:59:19 +00:00
refractionpcsx2
f84425b67c GS/HW: Add new HPO - Align to Native With Texture Offset 2025-02-28 21:59:19 +00:00
PCSX2 Bot
8a0c1874dd [ci skip] Qt: Update Base Translation. 2025-02-27 01:05:14 +01:00
Light
fa23628ae2 Qt: Allow recording on game boot 2025-02-26 17:17:39 -05:00
Loy2up
8a594e673d Debugger: Fix 8 byte searches (#12362) 2025-02-26 14:41:49 -05:00
Loy2up
92b9390c51 Debugger: Set default breakpoint size to 4 2025-02-25 19:07:19 -05:00
PCSX2 Bot
c5c5b2a7b9 [ci skip] Qt: Update Base Translation. 2025-02-26 01:06:43 +01:00
refractionpcsx2
32a9d0e48b GameDB: Also add Tekken 5 CRC to Taiko No Tatsujin 9 2025-02-25 18:22:38 +01:00
refractionpcsx2
80a961bb25 GameDB: Add Tekken 5 CRC (Yes really) To Tales of the Abyss 2025-02-25 18:22:38 +01:00
TheLastRar
d4e227286e FSUI: Correct description of the "Swap OK/Cancel" option 2025-02-25 10:00:18 -05:00
github-actions[bot]
ba705c8c24 Qt: Update Base Translation (#12354)
Co-authored-by: PCSX2 Bot <PCSX2Bot@users.noreply.github.com>
2025-02-24 19:11:57 -05:00
dependabot[bot]
b6ae4b173e CI: Update dependencies in /.github/workflows/scripts/releases/generate-release-notes (#12315)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-24 17:54:41 -05:00
TJnotJT
23a28be346 GS/UI: Rename dumping variables and UI labels to be more consistent/clear. 2025-02-24 17:53:01 -05:00
TJnotJT
a0e24dd36f UI: Add debug UI options for new dumping options. 2025-02-24 17:53:01 -05:00
TheLastRar
a2cde5e17b FSUI: Add a config option to swap OK/Cancel within BPM 2025-02-24 17:45:46 -05:00
JordanTheToaster
ecc46e9294 Deps: Update ZSTD to 1.5.7 2025-02-24 17:44:22 -05:00
dreamsyntax
20b1190d47 Achievements: Fix leaderboard timers persisting
Removes setting the leaderboard timer to active on receiving an update
event. This fixes having multiple timers stuck on the screen.
2025-02-24 14:05:03 -05:00
Silent
29b736bcf7 GameDB: Add TOCA Race Driver 3 memcard filters 2025-02-24 12:04:05 -05:00
Silent
a48bc76ca6 GameDB: Add NFS Undercover memcard filters
Checks from NFS Carbon (incl. a bugged check for MW BE)
are in the code, but unused.
2025-02-24 12:04:05 -05:00
Silent
305c01cdfa GameDB: Add NFS ProStreet memcard filters 2025-02-24 12:04:05 -05:00
Silent
88bbdf4696 GameDB: Add NFS Carbon memcard filters 2025-02-24 12:04:05 -05:00
Silent
afc11279a9 GameDB: Improve NFS Most Wanted memcard filters 2025-02-24 12:04:05 -05:00
Silent
a3fb2a84d5 GameDB: SCUS-21494 doesn't exist 2025-02-24 12:04:05 -05:00
Ty
4db23e6677 Debugger Assembler: BC1(t|f) 24 bit immediates to 16 bit immediates 2025-02-24 11:39:30 -05:00
PCSX2 Bot
5dd36a7969 [ci skip] PAD: Update to latest controller database. 2025-02-24 17:02:04 +01:00
RedPanda4552
35a3d0027e Memcard: Apply filtering when checking all possible memcard options
Prevents log being flooded with warnings when large folder memcards exceed 8 MB size
2025-02-24 16:08:00 +01:00
refractionpcsx2
02789ebd86 GS/HW: Increase Merge Sprite paving sensitivity to avoid mismerges 2025-02-23 03:33:39 +00:00
JordanTheToaster
dfd1846b93 GameDB: Various fixes 2025-02-23 01:12:43 +00:00
refractionpcsx2
872205abc6 GS/HW: Maintain scale on subsequent downscale draws 2025-02-23 01:12:07 +00:00
PCSX2 Bot
c52cebd20a [ci skip] Qt: Update Base Translation. 2025-02-22 01:04:56 +01:00
GovanifY
f449b54f87 CI: enable wayland by default 2025-02-21 12:28:28 +01:00
GovanifY
ffcb6e2f6f QT/MainWindow: disable native window rendering in wayland
This is a workaround for QTBUG-133919
2025-02-21 12:28:28 +01:00
PCSX2 Bot
5daa1aa115 [ci skip] Qt: Update Base Translation. 2025-02-21 01:09:05 +01:00
GovanifY
1dc009f752 pcsx2/SIO: correctly detect whether format status of folder mcd 2025-02-20 16:00:40 +01:00
GovanifY
009b4ff5e7 QT/Settings: ensure that a memory card is formatted before conversion 2025-02-20 16:00:40 +01:00
PCSX2 Bot
f1a947af92 [ci skip] Qt: Update Base Translation. 2025-02-19 21:00:23 -05:00
91 changed files with 7266 additions and 5646 deletions

View File

@@ -187,17 +187,6 @@ echo "Generating AppStream metainfo..."
mkdir -p "$OUTDIR/usr/share/metainfo"
"$SCRIPTDIR/generate-metainfo.sh" "$OUTDIR/usr/share/metainfo/net.pcsx2.PCSX2.appdata.xml"
# Copy in AppRun hooks.
# Unfortunately linuxdeploy is a bit lame and doesn't let us provide our own AppRun hooks, instead
# they have to come from plugins.. and screw writing one of those just to disable Wayland.
echo "Copying AppRun hooks..."
mkdir -p "$OUTDIR/apprun-hooks"
for hookpath in "$SCRIPTDIR/apprun-hooks"/*; do
hookname=$(basename "$hookpath")
cp -v "$hookpath" "$OUTDIR/apprun-hooks/$hookname"
sed -i -e 's/exec /source "$this_dir"\/apprun-hooks\/"'"$hookname"'"\nexec /' "$OUTDIR/AppRun"
done
echo "Generating AppImage..."
GIT_VERSION=$(git tag --points-at HEAD)

View File

@@ -1,9 +0,0 @@
if [[ -z "$I_WANT_A_BROKEN_WAYLAND_UI" ]]; then
echo "Forcing X11 instead of Wayland, due to various protocol limitations"
echo "and Qt issues. If you want to use Wayland, launch PCSX2 with"
echo "I_WANT_A_BROKEN_WAYLAND_UI=YES set."
export QT_QPA_PLATFORM=xcb
else
echo "Wayland is not being disabled. Do not complain when things break."
fi

View File

@@ -19,9 +19,9 @@ LIBJPEG=9f
LIBPNG=1.6.45
LIBWEBP=1.5.0
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
SDL=SDL2-2.30.12
SDL=SDL3-3.2.6
QT=6.8.2
ZSTD=1.5.6
ZSTD=1.5.7
SHADERC=2024.1
SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
@@ -37,8 +37,8 @@ fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea $SDL.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
096a0b843dd1124afda41c24bd05034af75af37e9a1b9d205cc0a70193b27e1a $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05 qtbase-everywhere-src-$QT.tar.xz
d2a1bbb84707b8a0aec29227b170be00f04383fbf2361943596d09e7e443c8e1 qtimageformats-everywhere-src-$QT.tar.xz
aa2579f21ca66d19cbcf31d87e9067e07932635d36869c8239d4decd0a9dc1fa qtsvg-everywhere-src-$QT.tar.xz

View File

@@ -1,5 +1,5 @@
{
"name": "sdl2",
"name": "sdl3",
"buildsystem": "cmake-ninja",
"builddir": true,
"config-opts": [
@@ -14,8 +14,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL2-2.30.12.tar.gz",
"sha256": "ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea"
"url": "https://libsdl.org/release/SDL3-3.2.6.tar.gz",
"sha256": "096a0b843dd1124afda41c24bd05034af75af37e9a1b9d205cc0a70193b27e1a"
}
],
"cleanup": [

View File

@@ -19,14 +19,14 @@
"--device=all",
"--share=network",
"--share=ipc",
"--socket=x11",
"--socket=wayland",
"--socket=fallback-x11",
"--socket=pulseaudio",
"--talk-name=org.freedesktop.ScreenSaver",
"--env=QT_QPA_PLATFORM=xcb"
"--talk-name=org.freedesktop.ScreenSaver"
],
"modules": [
"modules/10-libpcap.json",
"modules/20-sdl2.json",
"modules/20-sdl3.json",
"modules/21-libbacktrace.json",
"modules/22-shaderc.json",
{

View File

@@ -40,8 +40,8 @@ fi
FREETYPE=2.13.3
HARFBUZZ=10.0.1
SDL=SDL2-2.30.12
ZSTD=1.5.6
SDL=SDL3-3.2.6
ZSTD=1.5.7
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
LIBPNG=1.6.45
LIBJPEG=9f
@@ -76,8 +76,8 @@ CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea $SDL.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
096a0b843dd1124afda41c24bd05034af75af37e9a1b9d205cc0a70193b27e1a $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz

View File

@@ -22,8 +22,8 @@ fi
FREETYPE=2.13.3
HARFBUZZ=10.0.1
SDL=SDL2-2.30.12
ZSTD=1.5.6
SDL=SDL3-3.2.6
ZSTD=1.5.7
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
LIBPNG=1.6.45
LIBJPEG=9f
@@ -56,8 +56,8 @@ CMAKE_COMMON=(
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea $SDL.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
096a0b843dd1124afda41c24bd05034af75af37e9a1b9d205cc0a70193b27e1a $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz

View File

@@ -1,22 +1,33 @@
{
"name": "generate-release-notes",
"version": "1.0.0",
"lockfileVersion": 1,
"lockfileVersion": 3,
"requires": true,
"dependencies": {
"@octokit/auth-token": {
"packages": {
"": {
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@octokit/plugin-retry": "^3.0.9",
"@octokit/plugin-throttling": "^3.5.2",
"@octokit/rest": "^21.1.1"
}
},
"node_modules/@octokit/auth-token": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
"integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
"requires": {
"peer": true,
"dependencies": {
"@octokit/types": "^6.0.3"
}
},
"@octokit/core": {
"node_modules/@octokit/core": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.1.tgz",
"integrity": "sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw==",
"requires": {
"peer": true,
"dependencies": {
"@octokit/auth-token": "^2.4.4",
"@octokit/graphql": "^4.5.8",
"@octokit/request": "^5.6.0",
@@ -26,76 +37,60 @@
"universal-user-agent": "^6.0.0"
}
},
"@octokit/endpoint": {
"node_modules/@octokit/endpoint": {
"version": "6.0.12",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
"integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
"requires": {
"peer": true,
"dependencies": {
"@octokit/types": "^6.0.3",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/graphql": {
"node_modules/@octokit/graphql": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
"integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"requires": {
"peer": true,
"dependencies": {
"@octokit/request": "^5.6.0",
"@octokit/types": "^6.0.3",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/openapi-types": {
"node_modules/@octokit/openapi-types": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.1.0.tgz",
"integrity": "sha512-dWZfYvCCdjZzDYA3lIAMF72Q0jld8xidqCq5Ryw09eBJXZdcM6he0vWBTvw/b5UnGYqexxOyHWgfrsTlUJL3Gw=="
},
"@octokit/plugin-paginate-rest": {
"version": "2.16.9",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.9.tgz",
"integrity": "sha512-gfSCMgz5scFKsR0dW4jaYsDJVt/UwCHp4dF7sHlmSekZvwzvLiOAGZ4MQkEsL5DW9hIk2W+UQkYZMTA1b6Wsqw==",
"requires": {
"@octokit/types": "^6.33.0"
}
},
"@octokit/plugin-request-log": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA=="
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "5.12.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.12.1.tgz",
"integrity": "sha512-0nY3htfl6x9UkPcqv8pm9vOC/bTA7f4IMDWln13neHRdNWQvOQgZ9fRxK7BAc74rye4yVINEFi9Yb9rnGUvosA==",
"requires": {
"@octokit/types": "^6.33.0",
"deprecation": "^2.3.1"
}
},
"@octokit/plugin-retry": {
"node_modules/@octokit/plugin-retry": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-3.0.9.tgz",
"integrity": "sha512-r+fArdP5+TG6l1Rv/C9hVoty6tldw6cE2pRHNGmFPdyfrc696R6JjrQ3d7HdVqGwuzfyrcaLAKD7K8TX8aehUQ==",
"requires": {
"dependencies": {
"@octokit/types": "^6.0.3",
"bottleneck": "^2.15.3"
}
},
"@octokit/plugin-throttling": {
"node_modules/@octokit/plugin-throttling": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-3.5.2.tgz",
"integrity": "sha512-Eu7kfJxU8vmHqWGNszWpg+GVp2tnAfax3XQV5CkYPEE69C+KvInJXW9WajgSeW+cxYe0UVdouzCtcreGNuJo7A==",
"requires": {
"dependencies": {
"@octokit/types": "^6.0.1",
"bottleneck": "^2.15.3"
},
"peerDependencies": {
"@octokit/core": "^3.5.0"
}
},
"@octokit/request": {
"node_modules/@octokit/request": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.2.tgz",
"integrity": "sha512-je66CvSEVf0jCpRISxkUcCa0UkxmFs6eGDRSbfJtAVwbLH5ceqF+YEyC8lj8ystKyZTy8adWr0qmkY52EfOeLA==",
"requires": {
"peer": true,
"dependencies": {
"@octokit/endpoint": "^6.0.1",
"@octokit/request-error": "^2.1.0",
"@octokit/types": "^6.16.1",
@@ -104,99 +99,295 @@
"universal-user-agent": "^6.0.0"
}
},
"@octokit/request-error": {
"node_modules/@octokit/request-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
"integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
"requires": {
"peer": true,
"dependencies": {
"@octokit/types": "^6.0.3",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"@octokit/rest": {
"version": "18.12.0",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz",
"integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==",
"requires": {
"@octokit/core": "^3.5.1",
"@octokit/plugin-paginate-rest": "^2.16.8",
"@octokit/plugin-request-log": "^1.0.4",
"@octokit/plugin-rest-endpoint-methods": "^5.12.0"
"node_modules/@octokit/rest": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-21.1.1.tgz",
"integrity": "sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg==",
"license": "MIT",
"dependencies": {
"@octokit/core": "^6.1.4",
"@octokit/plugin-paginate-rest": "^11.4.2",
"@octokit/plugin-request-log": "^5.3.1",
"@octokit/plugin-rest-endpoint-methods": "^13.3.0"
},
"engines": {
"node": ">= 18"
}
},
"@octokit/types": {
"node_modules/@octokit/rest/node_modules/@octokit/auth-token": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz",
"integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==",
"license": "MIT",
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/core": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.4.tgz",
"integrity": "sha512-lAS9k7d6I0MPN+gb9bKDt7X8SdxknYqAMh44S5L+lNqIN2NuV8nvv3g8rPp7MuRxcOpxpUIATWprO0C34a8Qmg==",
"license": "MIT",
"dependencies": {
"@octokit/auth-token": "^5.0.0",
"@octokit/graphql": "^8.1.2",
"@octokit/request": "^9.2.1",
"@octokit/request-error": "^6.1.7",
"@octokit/types": "^13.6.2",
"before-after-hook": "^3.0.2",
"universal-user-agent": "^7.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/endpoint": {
"version": "10.1.3",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.3.tgz",
"integrity": "sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.6.2",
"universal-user-agent": "^7.0.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/graphql": {
"version": "8.2.1",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.1.tgz",
"integrity": "sha512-n57hXtOoHrhwTWdvhVkdJHdhTv0JstjDbDRhJfwIRNfFqmSo1DaK/mD2syoNUoLCyqSjBpGAKOG0BuwF392slw==",
"license": "MIT",
"dependencies": {
"@octokit/request": "^9.2.2",
"@octokit/types": "^13.8.0",
"universal-user-agent": "^7.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/openapi-types": {
"version": "23.0.1",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-23.0.1.tgz",
"integrity": "sha512-izFjMJ1sir0jn0ldEKhZ7xegCTj/ObmEDlEfpFrx4k/JyZSMRHbO3/rBwgE7f3m2DHt+RrNGIVw4wSmwnm3t/g==",
"license": "MIT"
},
"node_modules/@octokit/rest/node_modules/@octokit/plugin-paginate-rest": {
"version": "11.4.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.4.2.tgz",
"integrity": "sha512-BXJ7XPCTDXFF+wxcg/zscfgw2O/iDPtNSkwwR1W1W5c4Mb3zav/M2XvxQ23nVmKj7jpweB4g8viMeCQdm7LMVA==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.7.0"
},
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"@octokit/core": ">=6"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/plugin-request-log": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-5.3.1.tgz",
"integrity": "sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw==",
"license": "MIT",
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"@octokit/core": ">=6"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "13.3.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.3.1.tgz",
"integrity": "sha512-o8uOBdsyR+WR8MK9Cco8dCgvG13H1RlM1nWnK/W7TEACQBFux/vPREgKucxUfuDQ5yi1T3hGf4C5ZmZXAERgwQ==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.8.0"
},
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"@octokit/core": ">=6"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/request": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz",
"integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==",
"license": "MIT",
"dependencies": {
"@octokit/endpoint": "^10.1.3",
"@octokit/request-error": "^6.1.7",
"@octokit/types": "^13.6.2",
"fast-content-type-parse": "^2.0.0",
"universal-user-agent": "^7.0.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/request-error": {
"version": "6.1.7",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz",
"integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.6.2"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/rest/node_modules/@octokit/types": {
"version": "13.8.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.8.0.tgz",
"integrity": "sha512-x7DjTIbEpEWXK99DMd01QfWy0hd5h4EN+Q7shkdKds3otGQP+oWE/y0A76i1OvH9fygo4ddvNf7ZvF0t78P98A==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^23.0.1"
}
},
"node_modules/@octokit/rest/node_modules/before-after-hook": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz",
"integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==",
"license": "Apache-2.0"
},
"node_modules/@octokit/rest/node_modules/universal-user-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz",
"integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==",
"license": "ISC"
},
"node_modules/@octokit/types": {
"version": "6.33.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.33.0.tgz",
"integrity": "sha512-0zffZ048M0UhthyPXQHLz4038Ak46nMWZXkzlXvXB/M/L1jYPBceq4iZj4qjKVrvveaJrrgKdJ9+3yUuITfcCw==",
"requires": {
"dependencies": {
"@octokit/openapi-types": "^11.1.0"
}
},
"before-after-hook": {
"node_modules/before-after-hook": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz",
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ=="
"integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==",
"peer": true
},
"bottleneck": {
"node_modules/bottleneck": {
"version": "2.19.5",
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
"integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="
},
"deprecation": {
"node_modules/deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
"peer": true
},
"is-plain-object": {
"node_modules/fast-content-type-parse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz",
"integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "MIT"
},
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node-fetch": {
"node_modules/node-fetch": {
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"peer": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"once": {
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"peer": true,
"dependencies": {
"wrappy": "1"
}
},
"tr46": {
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
"peer": true
},
"universal-user-agent": {
"node_modules/universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==",
"peer": true
},
"webidl-conversions": {
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
"peer": true
},
"whatwg-url": {
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
"requires": {
"peer": true,
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"wrappy": {
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"peer": true
}
}
}

View File

@@ -12,6 +12,6 @@
"dependencies": {
"@octokit/plugin-retry": "^3.0.9",
"@octokit/plugin-throttling": "^3.5.2",
"@octokit/rest": "^18.12.0"
"@octokit/rest": "^21.1.1"
}
}

View File

@@ -49,11 +49,11 @@ set LIBPNG=1645
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
set QT=6.8.2
set QTMINOR=6.8
set SDL=SDL2-2.30.12
set SDL=SDL3-3.2.6
set WEBP=1.5.0
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZSTD=1.5.6
set ZSTD=1.5.7
set SHADERC=2024.1
set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
@@ -66,15 +66,14 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" aa2808d0f2dc6b383c6689bf6d166e2de62db4d58be989e4b052acb31df0fba3 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 665e5aa2a613affe099a38d61257ecc5ef4bf38b109d915147aa8b005399d68a || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 102539447c1c76d206f24bcca2c911270cf53991548d9c3d7d0d01855f651e3b || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 33ccac9f99a357ffd83cb2d7179a0c0ffcba85a14d23d86619d5dc9721ded42f || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 6c9f42ed6bf42750f5369b089909abfdcf0101488b4a1f41116d5159d00af8e7 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 03ad8a6fa987af4653d0cfe6bdaed41bcf617f1366a151fb1574da75950cd3e8 || goto error
@@ -159,7 +158,6 @@ echo Building Zstandard...
rmdir /S /Q "zstd-%ZSTD%"
%SEVENZIP% x "-x^!zstd-%ZSTD%\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
cd "zstd-%ZSTD%"
%PATCH% -p1 < "..\zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" || goto error
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
cmake --build build --parallel || goto error
ninja -C build install || goto error
@@ -181,7 +179,7 @@ cd "%SDL%" || goto error
cmake -B build %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
copy build\SDL2.pdb "%INSTALLDIR%\bin" || goto error
copy build\SDL3.pdb "%INSTALLDIR%\bin" || goto error
cd .. || goto error
if %DEBUG%==1 (

View File

@@ -47,11 +47,11 @@ set LIBPNG=1645
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
set QT=6.8.2
set QTMINOR=6.8
set SDL=SDL2-2.30.12
set SDL=SDL3-3.2.6
set WEBP=1.5.0
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZSTD=1.5.6
set ZSTD=1.5.7
set SHADERC=2024.1
set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
@@ -64,15 +64,14 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" aa2808d0f2dc6b383c6689bf6d166e2de62db4d58be989e4b052acb31df0fba3 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 665e5aa2a613affe099a38d61257ecc5ef4bf38b109d915147aa8b005399d68a || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 102539447c1c76d206f24bcca2c911270cf53991548d9c3d7d0d01855f651e3b || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 33ccac9f99a357ffd83cb2d7179a0c0ffcba85a14d23d86619d5dc9721ded42f || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 8df152f4969b308546306c074628de761f0b80265de7de534e3822fab22d7535 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 7897bc5d620580d9b7cd3539c44b59d78f3657d33663fe97a145e07b4ebd69a4 || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 6c9f42ed6bf42750f5369b089909abfdcf0101488b4a1f41116d5159d00af8e7 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 03ad8a6fa987af4653d0cfe6bdaed41bcf617f1366a151fb1574da75950cd3e8 || goto error
@@ -156,7 +155,6 @@ echo Building Zstandard...
rmdir /S /Q "zstd-%ZSTD%"
%SEVENZIP% x "-x^!zstd-%ZSTD%\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
cd "zstd-%ZSTD%"
%PATCH% -p1 < "..\zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" || goto error
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
cmake --build build --parallel || goto error
ninja -C build install || goto error
@@ -178,7 +176,7 @@ cd "%SDL%" || goto error
cmake -B build -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
copy build\SDL2.pdb "%INSTALLDIR%\bin" || goto error
copy build\SDL3.pdb "%INSTALLDIR%\bin" || goto error
cd .. || goto error
if %DEBUG%==1 (

View File

@@ -1270,6 +1270,7 @@ SCAJ-10015:
region: "NTSC-Unk"
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
getSkipCount: "GSC_Tekken5" # Fixes upscaling grid, same engine.
SCAJ-20001:
name: "Ratchet & Clank"
region: "NTSC-Unk"
@@ -2015,7 +2016,6 @@ SCAJ-20132:
eeClampMode: 2 # Fixes wrong color on some characters and breakable objects.
gsHWFixes:
halfPixelOffset: 1 # Fixes ghosting characters.
mergeSprite: 1 # Align sprite fixes FMVs but not garbage in-game, so needs merge sprite instead.
texturePreloading: 1 # Performs better with partial preload because it is slow on locations outside gameplay foremost.
SCAJ-20133:
name: "Kagero 2 - Dark Illusion"
@@ -2237,6 +2237,7 @@ SCAJ-20163:
gsHWFixes:
halfPixelOffset: 2 # Fixes ghosting.
autoFlush: 2 # Fixes post lighting.
getSkipCount: "GSC_Tekken5" # Fixes upscaling grid, same engine.
SCAJ-20164:
name: "Kingdom Hearts II"
region: "NTSC-Unk"
@@ -10418,15 +10419,6 @@ SCUS-21295:
recommendedBlendingLevel: 3 # Fixes water and grass textures.
halfPixelOffset: 4 # Mostly aligns post processing.
nativeScaling: 1 # Fixes post processing smoothness and position.
SCUS-21494:
name: "Need for Speed - Carbon Collector's Edition"
region: "NTSC-U"
compat: 5
clampModes:
eeClampMode: 3 # Fixes game hang after opening intro.
gsHWFixes:
halfPixelOffset: 2 # Fixes blurriness.
roundSprite: 2 # Fixes blurriness.
SCUS-90174:
name: "Disney/Pixar Toy Story 3 [PlayStation 2 Bundle]"
region: "NTSC-U"
@@ -12805,9 +12797,7 @@ SLAJ-25075:
- "SLAJ-25075"
- "SLPM-66232"
- "SLPM-66562"
- "SLPM-65766"
- "SLPM-66051"
- "SLPM-66960"
- "SLAJ-25054" # Underground 2 save grants extra money.
SLAJ-25076:
name: "Harry Potter and the Goblet of Fire"
region: "NTSC-Unk"
@@ -12879,6 +12869,13 @@ SLAJ-25091:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLAJ-25091"
# Most Wanted save grants extra money.
- "SLAJ-25075"
- "SLPM-66232"
# UG2 saves can be detected, but the code is unused.
- "SLAJ-25054"
SLAJ-25092:
name: "Shin Sangoku Musou 4 [PlayStation2 the Best]"
region: "NTSC-Unk"
@@ -13630,7 +13627,7 @@ SLED-53954:
cpuSpriteRenderBW: 2 # Fixes some bad textures.
cpuCLUTRender: 1 # Fixes the rest of the bad textures.
roundSprite: 1 # Reduces misaligned bloom.
mergeSprite: 1 # Removes bloom explosion around electrical lights and other light sources such as moon/sun.
nativeScaling: 1 # Fixes post processing smoothness and position.
SLED-53977:
name: "Dragon Quest - The Journey of the Cursed King"
region: "PAL-E"
@@ -15351,7 +15348,6 @@ SLES-50723:
name: "TOCA Race Driver"
region: "PAL-M3"
gsHWFixes:
mergeSprite: 1 # Fixes lighting.
halfPixelOffset: 1 # Fixes vertical lines
SLES-50725:
name: "V-Rally 3"
@@ -15449,7 +15445,6 @@ SLES-50767:
name: "V8 Supercars Australia - Race Driver"
region: "PAL-A"
gsHWFixes:
mergeSprite: 1 # Fixes lighting.
halfPixelOffset: 1 # Fixes vertical lines
SLES-50768:
name: "Rally Championship"
@@ -15616,13 +15611,11 @@ SLES-50816:
region: "PAL-M3"
compat: 5
gsHWFixes:
mergeSprite: 1 # Fixes lighting.
halfPixelOffset: 1 # Fixes vertical lines
SLES-50818:
name: "Pro Race Driver"
region: "PAL-I"
gsHWFixes:
mergeSprite: 1 # Fixes lighting.
halfPixelOffset: 1 # Fixes vertical lines
SLES-50820:
name: "Micro Machines"
@@ -18283,7 +18276,7 @@ SLES-51914:
- "SLES-51914"
gsHWFixes:
halfPixelOffset: 4 # Mostly aligns post processing.
nativeScaling: 2 # Fixes post processing smoothness and position.
nativeScaling: 1 # Fixes post processing smoothness and position.
disablePartialInvalidation: 1 # Fixes textureless graphics ingame.
bilinearUpscale: 2 # Gets rid of center vertical line when upscaling.
SLES-51915:
@@ -20081,7 +20074,7 @@ SLES-52636:
autoFlush: 1 # Fixes incorrect colors.
alignSprite: 1 # Fixes vertical lines such as in FMVs.
SLES-52637:
name: "TOCA Racer Driver 2"
name: "TOCA Race Driver 2"
region: "PAL-M5"
gsHWFixes:
alignSprite: 1 # Fixes lighting and vertical lines, also works with normal vertex.
@@ -21524,6 +21517,9 @@ SLES-53087:
skipDrawEnd: 1 # Removes large black box around player car till we properly emulate it.
halfPixelOffset: 2 # Fixes depth of field alignment.
nativeScaling: 1 # Fixes depth of field.
memcardFilters:
- "SLES-53087"
- "SLES-52637" # Race Driver 2 save unlocks 'Class A 4WD Track Challenge' in career early.
SLES-53088:
name: "DTM Race Driver 3"
region: "PAL-M5"
@@ -21534,6 +21530,9 @@ SLES-53088:
skipDrawEnd: 1 # Removes large black box around player car till we properly emulate it.
halfPixelOffset: 2 # Fixes depth of field alignment.
nativeScaling: 1 # Fixes depth of field.
memcardFilters:
- "SLES-53088"
- "SLES-52638" # Race Driver 2 save unlocks 'Class A 4WD Track Challenge' in career early.
SLES-53089:
name: "V8 Supercars Australia 3"
region: "PAL-E"
@@ -21544,6 +21543,9 @@ SLES-53089:
skipDrawEnd: 1 # Removes large black box around player car till we properly emulate it.
halfPixelOffset: 2 # Fixes depth of field alignment.
nativeScaling: 1 # Fixes depth of field.
memcardFilters:
- "SLES-53089"
- "SLES-52639" # Race Driver 2 save unlocks 'Class A 4WD Track Challenge' in career early.
SLES-53090:
name: "Circuit Blasters"
region: "PAL-M5"
@@ -22913,7 +22915,7 @@ SLES-53556:
cpuSpriteRenderBW: 2 # Fixes some bad textures.
cpuCLUTRender: 1 # Fixes the rest of the bad textures.
roundSprite: 1 # Reduces misaligned bloom.
mergeSprite: 1 # Removes bloom explosion around electrical lights and other light sources such as moon/sun.
nativeScaling: 1 # Fixes post processing smoothness and position.
SLES-53557:
name: "Need for Speed - Most Wanted"
region: "PAL-E"
@@ -22923,12 +22925,12 @@ SLES-53557:
halfPixelOffset: 2 # Fixes blurriness.
cpuCLUTRender: 1 # Final colour adjustment LUT.
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
memcardFilters: # Reads Underground 2 save for extra money.
memcardFilters:
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857"
- "SLES-52725"
- "SLES-52725" # Underground 2 save grants extra money.
SLES-53558:
name: "Need for Speed - Most Wanted"
region: "PAL-M8"
@@ -22942,7 +22944,7 @@ SLES-53558:
- "SLES-53558"
- "SLES-53559"
- "SLES-53857"
- "SLES-52725"
- "SLES-52725" # Underground 2 save grants extra money.
SLES-53559:
name: "Need for Speed - Most Wanted"
region: "PAL-M7"
@@ -22956,7 +22958,7 @@ SLES-53559:
- "SLES-53558"
- "SLES-53559"
- "SLES-53857"
- "SLES-52725"
- "SLES-52725" # Underground 2 save grants extra money.
SLES-53560:
name: "Sonic Riders"
region: "PAL-M5"
@@ -23703,7 +23705,6 @@ SLES-53794:
gsHWFixes:
halfPixelOffset: 4 # Fix effects upscaling.
nativeScaling: 2 # Fixes post effects.
mergeSprite: 1 # Align sprite fixes FMVs but not garbage in-game, so needs merge sprite instead.
texturePreloading: 1 # Performs better with partial preload because it is slow on locations outside gameplay foremost.
SLES-53796:
name: "FIFA Street 2"
@@ -23895,7 +23896,7 @@ SLES-53857:
- "SLES-53558"
- "SLES-53559"
- "SLES-53857"
- "SLES-52725"
- "SLES-52725" # Underground 2 save grants extra money.
SLES-53860:
name: "Dynasty Warriors 5 - Xtreme Legends"
region: "PAL-E"
@@ -24385,7 +24386,7 @@ SLES-54027:
cpuSpriteRenderBW: 2 # Fixes some bad textures.
cpuCLUTRender: 1 # Fixes the rest of the bad textures.
roundSprite: 1 # Reduces misaligned bloom.
mergeSprite: 1 # Removes bloom explosion around electrical lights and other light sources such as moon/sun.
nativeScaling: 1 # Fixes post processing smoothness and position.
SLES-54030:
name: "Black"
region: "PAL-E"
@@ -25141,7 +25142,7 @@ SLES-54317:
region: "PAL-M5"
compat: 5
gsHWFixes:
mergeSprite: 1 # Fixes alignment on fire effects.
halfPixelOffset: 4 # Fixes alignment on fire effects.
SLES-54319:
name: "Biker Mice from Mars"
region: "PAL-M5"
@@ -25159,6 +25160,18 @@ SLES-54321:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-54321"
- "SLES-54322"
- "SLES-54323"
- "SLES-54324"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-54322:
name: "Need for Speed - Carbon"
region: "PAL-M8"
@@ -25167,6 +25180,18 @@ SLES-54322:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-54321"
- "SLES-54322"
- "SLES-54323"
- "SLES-54324"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-54323:
name: "Need for Speed - Carbon"
region: "PAL-I-S"
@@ -25175,6 +25200,18 @@ SLES-54323:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-54321"
- "SLES-54322"
- "SLES-54323"
- "SLES-54324"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-54324:
name: "Need for Speed - Carbon"
region: "PAL-R"
@@ -25183,6 +25220,18 @@ SLES-54324:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-54321"
- "SLES-54322"
- "SLES-54323"
- "SLES-54324"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-54326:
name: "Raceway - Drag Stock Racing"
region: "PAL-E"
@@ -25457,6 +25506,17 @@ SLES-54402:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-54402"
- "SLES-54492"
- "SLES-54493"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-54410:
name: "Monster Trux Arenas - Special Edition"
region: "PAL-Unk"
@@ -25713,7 +25773,6 @@ SLES-54483:
compat: 5
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes car reflections.
mergeSprite: 1 # Fixes bluriness.
halfPixelOffset: 4 # Fixes bluriness.
nativeScaling: 2 # Fixes post lighting.
autoFlush: 1 # Fixes post alignment.
@@ -25754,6 +25813,17 @@ SLES-54492:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-54402"
- "SLES-54492"
- "SLES-54493"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-54493:
name: "Need for Speed - Carbon [Collector's Edition]"
region: "PAL-F-G"
@@ -25762,6 +25832,17 @@ SLES-54493:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-54402"
- "SLES-54492"
- "SLES-54493"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-54494:
name: "Little Britain - The Video Game"
region: "PAL-E"
@@ -27325,26 +27406,132 @@ SLES-55002:
region: "PAL-E"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-55002"
- "SLES-55003"
- "SLES-55004"
- "SLES-55005"
- "SLES-55006"
# Carbon save grants extra money.
- "SLES-54321"
- "SLES-54322"
- "SLES-54323"
- "SLES-54324"
- "SLES-54402"
- "SLES-54492"
- "SLES-54493"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-55003:
name: "Need for Speed - ProStreet"
region: "PAL-F-G"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-55002"
- "SLES-55003"
- "SLES-55004"
- "SLES-55005"
- "SLES-55006"
# Carbon save grants extra money.
- "SLES-54321"
- "SLES-54322"
- "SLES-54323"
- "SLES-54324"
- "SLES-54402"
- "SLES-54492"
- "SLES-54493"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-55004:
name: "Need for Speed - ProStreet"
region: "PAL-I-S"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-55002"
- "SLES-55003"
- "SLES-55004"
- "SLES-55005"
- "SLES-55006"
# Carbon save grants extra money.
- "SLES-54321"
- "SLES-54322"
- "SLES-54323"
- "SLES-54324"
- "SLES-54402"
- "SLES-54492"
- "SLES-54493"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-55005:
name: "Need for Speed - ProStreet"
region: "PAL-M8"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-55002"
- "SLES-55003"
- "SLES-55004"
- "SLES-55005"
- "SLES-55006"
# Carbon save grants extra money.
- "SLES-54321"
- "SLES-54322"
- "SLES-54323"
- "SLES-54324"
- "SLES-54402"
- "SLES-54492"
- "SLES-54493"
# Most Wanted save grants extra money.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857" # Black Edition detection is bugged by default, can be fixed with a patch.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-55006:
name: "Need for Speed - ProStreet"
region: "PAL-R"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLES-55002"
- "SLES-55003"
- "SLES-55004"
- "SLES-55005"
- "SLES-55006"
# Carbon save grants extra money. Detection is bugged by default, can be fixed with a patch.
- "SLES-54321"
- "SLES-54322"
- "SLES-54323"
- "SLES-54324"
- "SLES-54402"
- "SLES-54492"
- "SLES-54493"
# Most Wanted save grants extra money. Detection is bugged by default, can be fixed with a patch.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857"
- "SLUS-21267" # Original wrong Most Wanted serial.
# UG2 saves can be detected, but the code is unused.
- "SLES-52725"
SLES-55007:
name: "Boogie"
region: "PAL-M7"
@@ -28289,6 +28476,18 @@ SLES-55349:
gpuTargetCLUT: 1 # Fixes sun penetration.
nativeScaling: 2 # Fixes post alignment.
getSkipCount: "GSC_NFSUndercover"
memcardFilters:
- "SLES-55349"
- "SLES-55350"
- "SLES-55351"
- "SLES-55352"
- "SLES-55353"
# Checks from Carbon are left in the code, unused.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857"
- "SLES-52725"
SLES-55350:
name: "Need for Speed - Undercover"
region: "PAL-F-G"
@@ -28299,6 +28498,18 @@ SLES-55350:
gpuTargetCLUT: 1 # Fixes sun penetration.
nativeScaling: 2 # Fixes post alignment.
getSkipCount: "GSC_NFSUndercover"
memcardFilters:
- "SLES-55349"
- "SLES-55350"
- "SLES-55351"
- "SLES-55352"
- "SLES-55353"
# Checks from Carbon are left in the code, unused.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857"
- "SLES-52725"
SLES-55351:
name: "Need for Speed - Undercover"
region: "PAL-I-S"
@@ -28309,6 +28520,18 @@ SLES-55351:
gpuTargetCLUT: 1 # Fixes sun penetration.
nativeScaling: 2 # Fixes post alignment.
getSkipCount: "GSC_NFSUndercover"
memcardFilters:
- "SLES-55349"
- "SLES-55350"
- "SLES-55351"
- "SLES-55352"
- "SLES-55353"
# Checks from Carbon are left in the code, unused.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857"
- "SLES-52725"
SLES-55352:
name: "Need for Speed - Undercover"
region: "PAL-SC"
@@ -28320,6 +28543,18 @@ SLES-55352:
gpuTargetCLUT: 1 # Fixes sun penetration.
nativeScaling: 2 # Fixes post alignment.
getSkipCount: "GSC_NFSUndercover"
memcardFilters:
- "SLES-55349"
- "SLES-55350"
- "SLES-55351"
- "SLES-55352"
- "SLES-55353"
# Checks from Carbon are left in the code, unused.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857"
- "SLES-52725"
SLES-55353:
name: "Need for Speed - Undercover"
region: "PAL-M6"
@@ -28330,6 +28565,18 @@ SLES-55353:
gpuTargetCLUT: 1 # Fixes sun penetration.
nativeScaling: 2 # Fixes post alignment.
getSkipCount: "GSC_NFSUndercover"
memcardFilters:
- "SLES-55349"
- "SLES-55350"
- "SLES-55351"
- "SLES-55352"
- "SLES-55353"
# Checks from Carbon are left in the code, unused.
- "SLES-53557"
- "SLES-53558"
- "SLES-53559"
- "SLES-53857"
- "SLES-52725"
SLES-55354:
name: "Shin Megami Tensei - Persona 3 FES"
region: "PAL-E"
@@ -29913,7 +30160,7 @@ SLKA-25093:
- "SLKA-25093"
gsHWFixes:
halfPixelOffset: 4 # Mostly aligns post processing.
nativeScaling: 2 # Fixes post processing smoothness and position.
nativeScaling: 1 # Fixes post processing smoothness and position.
disablePartialInvalidation: 1 # Fixes textureless graphics ingame.
bilinearUpscale: 2 # Gets rid of center vertical line when upscaling.
SLKA-25095:
@@ -30261,6 +30508,11 @@ SLKA-25185:
gsHWFixes:
halfPixelOffset: 2 # Fixes blurriness.
roundSprite: 2 # Fixes blurriness.
memcardFilters:
- "SLKA-25185"
- "SLKA-25334" # Most Wanted save grants extra money.
- "SLAJ-25075" # Original wrong Black Edition serial.
- "SLKA-25241" # UG2 saves can be detected, but the code is unused.
SLKA-25186:
name: "The King of Fighters - Maximum Impact [Limited Edition]"
name-sort: "King of Fighters, The - Maximum Impact [Limited Edition]"
@@ -30947,6 +31199,9 @@ SLKA-25334:
halfPixelOffset: 2 # Fixes blurriness.
cpuCLUTRender: 1 # Final colour adjustment LUT.
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
memcardFilters:
- "SLKA-25334"
- "SLKA-25241" # Underground 2 save grants extra money.
SLKA-25335:
name: "Shadow the Hedgehog"
region: "NTSC-K"
@@ -30986,7 +31241,7 @@ SLKA-25341:
cpuSpriteRenderBW: 2 # Fixes some bad textures.
cpuCLUTRender: 1 # Fixes the rest of the bad textures.
roundSprite: 1 # Reduces misaligned bloom.
mergeSprite: 1 # Removes bloom explosion around electrical lights and other light sources such as moon/sun.
nativeScaling: 1 # Fixes post processing smoothness and position.
SLKA-25342:
name: "Ryu ga Gotoku"
region: "NTSC-K"
@@ -31308,6 +31563,11 @@ SLKA-25411:
region: "NTSC-K"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLKA-25411"
- "SLKA-25185" # Carbon save grants extra money.
- "SLKA-25334" # Most Wanted save grants extra money.
- "SLKA-25241" # UG2 saves can be detected, but the code is unused.
SLKA-25412:
name: "Sengoku Basara 2 - Heroes"
region: "NTSC-K"
@@ -31424,6 +31684,13 @@ SLKA-25446:
recommendedBlendingLevel: 3 # Improves car reflections.
halfPixelOffset: 2 # Fixes blurriness.
getSkipCount: "GSC_NFSUndercover"
memcardFilters:
- "SLKA-25446"
# Checks from Carbon are left in the code, unused.
- "SLKA-25185"
- "SLKA-25334"
- "SLAJ-25075"
- "SLKA-25241"
SLKA-25447:
name: "FIFA 09"
region: "NTSC-K"
@@ -31619,6 +31886,9 @@ SLPM-55003:
halfPixelOffset: 2 # Fixes blurriness.
cpuCLUTRender: 1 # Final colour adjustment LUT.
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
memcardFilters:
- "SLPM-55003"
- "SLPM-65766" # Underground 2 save grants extra money.
SLPM-55004:
name: "バーンアウト リベンジ [EA:SY! 1980]"
name-sort: "ばーんあうと りべんじ [EA:SY! 1980])"
@@ -31872,6 +32142,9 @@ SLPM-55046:
skipDrawEnd: 1 # Removes large black box around player car till we properly emulate it.
halfPixelOffset: 2 # Fixes depth of field alignment.
nativeScaling: 1 # Fixes depth of field.
memcardFilters:
- "SLPM-55046"
- "SLPM-66498" # Race Driver 2 save unlocks 'Class A 4WD Track Challenge' in career early.
SLPM-55047:
name: "Sugar+Spice ~あの子のステキな何もかも~"
name-sort: "しゅがーすぱいす あのこのすてきななにもかも"
@@ -31946,6 +32219,13 @@ SLPM-55061:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLPM-55061"
# Most Wanted save grants extra money.
- "SLPM-66232"
- "SLPM-66562"
- "SLAJ-25075" # Original wrong Black Edition serial.
- "SLPM-65766" # UG2 saves can be detected, but the code is unused.
SLPM-55062:
name: "実況パワフルメジャーリーグ 3"
name-sort: "じっきょうぱわふるめじゃーりーぐ 3"
@@ -32048,7 +32328,6 @@ SLPM-55081:
eeClampMode: 2 # Fixes wrong color on some characters and breakable objects.
gsHWFixes:
halfPixelOffset: 1 # Fixes ghosting characters.
mergeSprite: 1 # Align sprite fixes FMVs but not garbage in-game, so needs merge sprite instead.
texturePreloading: 1 # Performs better with partial preload because it is slow on locations outside gameplay foremost.
SLPM-55082:
name: "真・三國無双5 Special [ディスク 1]"
@@ -32264,6 +32543,13 @@ SLPM-55127:
gpuTargetCLUT: 1 # Fixes sun penetration.
nativeScaling: 2 # Fixes post alignment.
getSkipCount: "GSC_NFSUndercover"
memcardFilters:
- "SLPM-55127"
# Checks from Carbon are left in the code, unused.
- "SLPM-66232"
- "SLPM-66562"
- "SLAJ-25075"
- "SLPM-65766"
SLPM-55128:
name: "ラグビー08 [英語版] [EA:SY! 1980]"
name-sort: "らぐびー08 [えいごばん] [EA:SY! 1980]"
@@ -32401,6 +32687,16 @@ SLPM-55151:
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLPM-55151"
# Carbon save grants extra money.
- "SLPM-55061"
- "SLPM-66617"
- "SLPM-66869"
# Most Wanted save grants extra money.
- "SLPM-66232"
- "SLPM-66562"
- "SLPM-65766" # UG2 saves can be detected, but the code is unused.
SLPM-55152:
name: "スロッターUPコア11 巨人の星Ⅳ 青春群像編"
name-sort: "すろったーUPこあ11 きょじんのほし4 せいしゅんぐんぞうへん"
@@ -32842,6 +33138,13 @@ SLPM-55244:
gpuTargetCLUT: 1 # Fixes sun penetration.
nativeScaling: 2 # Fixes post alignment.
getSkipCount: "GSC_NFSUndercover"
memcardFilters:
- "SLPM-55244"
# Checks from Carbon are left in the code, unused.
- "SLPM-66232"
- "SLPM-66562"
- "SLAJ-25075"
- "SLPM-65766"
SLPM-55245:
name: "ひまわり -Pebble in the Sky-"
name-sort: "ひまわり -Pebble in the Sky-"
@@ -34510,7 +34813,6 @@ SLPM-61120:
eeClampMode: 2 # Fixes wrong color on some characters and breakable objects.
gsHWFixes:
halfPixelOffset: 1 # Fixes ghosting characters.
mergeSprite: 1 # Align sprite fixes FMVs but not garbage in-game, so needs merge sprite instead.
texturePreloading: 1 # Performs better with partial preload because it is slow on locations outside gameplay foremost.
SLPM-61121:
name: "KAIDO ~峠の伝説~ [体験版]"
@@ -41214,7 +41516,7 @@ SLPM-65413:
- "SLPM-65413"
gsHWFixes:
halfPixelOffset: 4 # Mostly aligns post processing.
nativeScaling: 2 # Fixes post processing smoothness and position.
nativeScaling: 1 # Fixes post processing smoothness and position.
disablePartialInvalidation: 1 # Fixes textureless graphics ingame.
bilinearUpscale: 2 # Gets rid of center vertical line when upscaling.
SLPM-65414:
@@ -44547,7 +44849,6 @@ SLPM-65999:
eeClampMode: 2 # Fixes wrong color on some characters and breakable objects.
gsHWFixes:
halfPixelOffset: 1 # Fixes ghosting characters.
mergeSprite: 1 # Align sprite fixes FMVs but not garbage in-game, so needs merge sprite instead.
texturePreloading: 1 # Performs better with partial preload because it is slow on locations outside gameplay foremost.
SLPM-66000:
name: "コンフリクトデルタⅡ 湾岸戦争1991"
@@ -46063,7 +46364,8 @@ SLPM-66232:
- "SLAJ-25075"
- "SLPM-66232"
- "SLPM-66562"
- "SLPM-65766"
- "SLPM-65766" # Underground 2 save grants extra money.
# Unconfirmed UG2 serials.
- "SLPM-66051"
- "SLPM-66960"
SLPM-66233:
@@ -48094,7 +48396,8 @@ SLPM-66562:
- "SLAJ-25075"
- "SLPM-66232"
- "SLPM-66562"
- "SLPM-65766"
- "SLPM-65766" # Underground 2 save grants extra money.
# Unconfirmed UG2 serials.
- "SLPM-66051"
- "SLPM-66960"
SLPM-66563:
@@ -48135,7 +48438,7 @@ SLPM-66567:
cpuSpriteRenderBW: 2 # Fixes some bad textures.
cpuCLUTRender: 1 # Fixes the rest of the bad textures.
roundSprite: 1 # Reduces misaligned bloom.
mergeSprite: 1 # Removes bloom explosion around electrical lights and other light sources such as moon/sun.
nativeScaling: 1 # Fixes post processing smoothness and position.
SLPM-66568:
name: "ブラザー イン アームズ ロード トゥ ヒル サーティ [UBISOFT BEST]"
name-sort: "ぶらざー いん あーむず ろーど とぅ ひる さーてぃ [UBISOFT BEST]"
@@ -48443,6 +48746,13 @@ SLPM-66617:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLPM-66617"
# Most Wanted save grants extra money.
- "SLPM-66232"
- "SLPM-66562"
- "SLAJ-25075" # Original wrong Black Edition serial.
- "SLPM-65766" # UG2 saves can be detected, but the code is unused.
SLPM-66618:
name: "夢見師 [初回限定版]"
name-sort: "ゆめみし [しょかいげんていばん]"
@@ -49971,6 +50281,13 @@ SLPM-66869:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLPM-66869"
# Most Wanted save grants extra money.
- "SLPM-66232"
- "SLPM-66562"
- "SLAJ-25075" # Original wrong Black Edition serial.
- "SLPM-65766" # UG2 saves can be detected, but the code is unused.
SLPM-66870:
name: "星色のおくりもの [初回スペシャル限定版]"
name-sort: "ほしいろのおくりもの [しょかいすぺしゃるげんていばん]"
@@ -50039,6 +50356,9 @@ SLPM-66881:
skipDrawEnd: 1 # Removes large black box around player car till we properly emulate it.
halfPixelOffset: 2 # Fixes depth of field alignment.
nativeScaling: 1 # Fixes depth of field.
memcardFilters:
- "SLPM-66881"
- "SLPM-66498" # Race Driver 2 save unlocks 'Class A 4WD Track Challenge' in career early.
SLPM-66882:
name: "はかれなはーと ~君がために輝きを~ [限定版・サントラボイスCD付]"
name-sort: "はかれなはーと きみがためにかがやきを [げんていばん さんとらぼいすCDつき]"
@@ -50319,6 +50639,16 @@ SLPM-66932:
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLPM-66932"
# Carbon save grants extra money.
- "SLPM-55061"
- "SLPM-66617"
- "SLPM-66869"
# Most Wanted save grants extra money.
- "SLPM-66232"
- "SLPM-66562"
- "SLPM-65766" # UG2 saves can be detected, but the code is unused.
SLPM-66933:
name: "君が主で執事が俺で~お仕え日記~ [初回限定版]"
name-sort: "きみがあるじでしつじがおれで おつかえにっき [しょかいげんていばん]"
@@ -54359,6 +54689,7 @@ SLPS-20485:
region: "NTSC-J"
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
getSkipCount: "GSC_Tekken5" # Fixes upscaling grid, same engine.
SLPS-20486:
name: "太鼓の達人 ドカッ!と大盛り七代目 [ソフト単体]"
name-sort: "たいこのたつじん どかっ!とおおもりななだいめ [そふとたんたい]"
@@ -54366,6 +54697,7 @@ SLPS-20486:
region: "NTSC-J"
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
getSkipCount: "GSC_Tekken5" # Fixes upscaling grid, same engine.
SLPS-20487:
name: "パチスロキング! 科学忍者隊ガッチャマン"
name-sort: "ぱちすろきんぐ! かがくにんじゃたいがっちゃまん"
@@ -57943,6 +58275,7 @@ SLPS-25586:
halfPixelOffset: 4 # Fixes post positioning.
nativeScaling: 1 # Fixes post effects.
autoFlush: 2 # Fixes post lighting.
getSkipCount: "GSC_Tekken5" # Fixes upscaling grid, same engine.
SLPS-25587:
name: "シュガシュガルーン 恋もおしゃれもピックアップ!"
name-sort: "しゅがしゅがるーん こいもおしゃれもぴっくあっぷ!"
@@ -60976,6 +61309,7 @@ SLPS-73252:
halfPixelOffset: 4 # Fixes post positioning.
nativeScaling: 1 # Fixes post effects.
autoFlush: 2 # Fixes post lighting.
getSkipCount: "GSC_Tekken5" # Fixes upscaling grid, same engine.
SLPS-73253:
name: "るろうに剣心-明治剣客浪漫譚- 炎上!京都輪廻 [PlayStation2 the Best]"
name-sort: "るろうにけんしん めいじけんかくろまんたん えんじょう きょうとりんね [PlayStation2 the Best]"
@@ -62650,7 +62984,6 @@ SLUS-20329:
region: "NTSC-U"
compat: 5
gsHWFixes:
mergeSprite: 1 # Fixes lighting.
halfPixelOffset: 1 # Fixes vertical lines
SLUS-20330:
name: "NBA 2K2 - Sega Sports"
@@ -64556,7 +64889,7 @@ SLUS-20694:
- "SLUS-20710"
gsHWFixes:
halfPixelOffset: 4 # Mostly aligns post processing.
nativeScaling: 2 # Fixes post processing smoothness and position.
nativeScaling: 1 # Fixes post processing smoothness and position.
disablePartialInvalidation: 1 # Fixes textureless graphics ingame.
bilinearUpscale: 2 # Gets rid of center vertical line when upscaling.
SLUS-20695:
@@ -67351,6 +67684,9 @@ SLUS-21182:
skipDrawEnd: 1 # Removes large black box around player car till we properly emulate it.
halfPixelOffset: 2 # Fixes depth of field alignment.
nativeScaling: 1 # Fixes depth of field.
memcardFilters:
- "SLUS-21182"
- "SLUS-21039" # Race Driver 2 save unlocks 'Class A 4WD Track Challenge' in career early.
SLUS-21183:
name: "Teen Titans"
region: "NTSC-U"
@@ -67869,6 +68205,9 @@ SLUS-21257:
halfPixelOffset: 2 # Fixes blurriness.
cpuCLUTRender: 1 # Final colour adjustment LUT.
gpuTargetCLUT: 1 # Fixes sun penetrating bridges (along with HPO special).
memcardFilters:
- "SLUS-21257"
- "SLUS-21065" # Underground 2 save grants extra money.
SLUS-21258:
name: ".hack//G.U. Vol.1 - Rebirth"
region: "NTSC-U"
@@ -67955,7 +68294,7 @@ SLUS-21267:
memcardFilters:
- "SLUS-21267"
- "SLUS-21351"
- "SLUS-21065"
- "SLUS-21065" # Underground 2 save grants extra money.
SLUS-21268:
name: "24 - The Game"
region: "NTSC-U"
@@ -67988,7 +68327,7 @@ SLUS-21271:
cpuSpriteRenderBW: 2 # Fixes some bad textures.
cpuCLUTRender: 1 # Fixes the rest of the bad textures.
roundSprite: 1 # Reduces misaligned bloom.
mergeSprite: 1 # Removes bloom explosion around electrical lights and other light sources such as moon/sun.
nativeScaling: 1 # Fixes post processing smoothness and position.
SLUS-21272:
name: "Super Monkey Ball Adventure"
region: "NTSC-U"
@@ -68244,7 +68583,7 @@ SLUS-21306:
region: "NTSC-U"
compat: 5
gsHWFixes:
mergeSprite: 1 # Fixes alignment on fire effects.
halfPixelOffset: 4 # Fixes alignment on fire effects.
SLUS-21307:
name: "Ice Age 2 - The Meltdown"
region: "NTSC-U"
@@ -68544,7 +68883,7 @@ SLUS-21351:
memcardFilters:
- "SLUS-21267"
- "SLUS-21351"
- "SLUS-21065"
- "SLUS-21065" # Underground 2 save grants extra money.
SLUS-21352:
name: "Dai Senryaku VII Exceed"
region: "NTSC-U"
@@ -68706,7 +69045,6 @@ SLUS-21373:
gsHWFixes:
halfPixelOffset: 4 # Fix effects upscaling.
nativeScaling: 2 # Fixes post effects.
mergeSprite: 1 # Align sprite fixes FMVs but not garbage in-game, so needs merge sprite instead.
texturePreloading: 1 # Performs better with partial preload because it is slow on locations outside gameplay foremost.
SLUS-21374:
name: "Marvel - Ultimate Alliance"
@@ -68805,6 +69143,7 @@ SLUS-21386:
halfPixelOffset: 4 # Fixes post positioning.
nativeScaling: 1 # Fixes post effects.
autoFlush: 2 # Fixes post lighting.
getSkipCount: "GSC_Tekken5" # Fixes upscaling grid, same engine.
SLUS-21387:
name: "Warship Gunner 2"
region: "NTSC-U"
@@ -68886,7 +69225,7 @@ SLUS-21399:
cpuSpriteRenderBW: 2 # Fixes some bad textures.
cpuCLUTRender: 1 # Fixes the rest of the bad textures.
roundSprite: 1 # Reduces misaligned bloom.
mergeSprite: 1 # Removes bloom explosion around electrical lights and other light sources such as moon/sun.
nativeScaling: 1 # Fixes post processing smoothness and position.
SLUS-21400:
name: "Monster House"
region: "NTSC-U"
@@ -69212,7 +69551,6 @@ SLUS-21449:
compat: 5
gsHWFixes:
recommendedBlendingLevel: 4 # Fixes car reflections.
mergeSprite: 1 # Fixes bluriness.
halfPixelOffset: 4 # Fixes bluriness.
nativeScaling: 2 # Fixes post lighting.
autoFlush: 1 # Fixes post alignment.
@@ -69488,14 +69826,29 @@ SLUS-21493:
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLUS-21493"
# Most Wanted save grants extra money.
- "SLUS-21267"
- "SLUS-21351" # Black Edition detection is bugged by default, can be fixed with a patch.
- "SLAJ-25075" # Original wrong Black Edition serial.
- "SLUS-21065" # UG2 saves can be detected, but the code is unused.
SLUS-21494:
name: "Need for Speed - Carbon [Collector's Edition]"
region: "NTSC-U"
compat: 5
clampModes:
eeClampMode: 3 # Fixes game hang after opening intro.
gsHWFixes:
recommendedBlendingLevel: 3 # Fixes car headlights.
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLUS-21494"
# Most Wanted save grants extra money.
- "SLUS-21267"
- "SLUS-21351" # Black Edition detection is bugged by default, can be fixed with a patch.
- "SLAJ-25075" # Original wrong Black Edition serial.
- "SLUS-21065" # UG2 saves can be detected, but the code is unused.
SLUS-21495:
name: "Sudoku, Carol Vorderman's"
region: "NTSC-U"
@@ -70253,6 +70606,15 @@ SLUS-21658:
compat: 5
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
memcardFilters:
- "SLUS-21658"
# Carbon save grants extra money.
- "SLUS-21493"
- "SLUS-21494"
# Most Wanted save grants extra money.
- "SLUS-21267"
- "SLUS-21351"
- "SLUS-21065" # UG2 saves can be detected, but the code is unused.
SLUS-21660:
name: "Disney Princess - Enchanted Journey"
region: "NTSC-U"
@@ -71031,6 +71393,13 @@ SLUS-21801:
gpuTargetCLUT: 1 # Fixes sun penetration.
nativeScaling: 2 # Fixes post alignment.
getSkipCount: "GSC_NFSUndercover"
memcardFilters:
- "SLUS-21801"
# Checks from Carbon are left in the code, unused.
- "SLUS-21267"
- "SLUS-21351"
- "SLAJ-25075"
- "SLUS-21065"
SLUS-21802:
name: "Naked Brothers Band - The Video Game"
region: "NTSC-U"
@@ -72687,7 +73056,7 @@ SLUS-29185:
cpuSpriteRenderBW: 2 # Fixes some bad textures.
cpuCLUTRender: 1 # Fixes the rest of the bad textures.
roundSprite: 1 # Reduces misaligned bloom.
mergeSprite: 1 # Removes bloom explosion around electrical lights and other light sources such as moon/sun.
nativeScaling: 1 # Fixes post processing smoothness and position.
SLUS-29188:
name: "Steambot Chronicles [Regular Demo]"
region: "NTSC-U"

View File

@@ -480,6 +480,7 @@
030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
0300000009120000072f000000000000,OrangeFox86 DreamPicoPort,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:-a2,leftx:a0,lefty:a1,righttrigger:-a5,start:b11,x:b3,y:b4,platform:Windows,
03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows,
03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
03000000790000002201000000000000,PC 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,
@@ -665,7 +666,7 @@
03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,
03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a2,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows,
03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
@@ -967,6 +968,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,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:Mac OS X,
0300000049190000020400001b010000,Manba One,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X,
03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X,
@@ -998,7 +1000,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000790000001c18000000010000,PB Tails Choc,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,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,
@@ -1070,6 +1071,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000e40a00000307000001000000,Taito Egret II Mini Control Panel,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,
03000000e40a00000207000001000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,guide:b9,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Mac OS X,
03000000790000001c18000000010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X,
@@ -1519,6 +1521,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c62400001a54000001010000,PowerA Xbox One Mini 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,
03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,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,
03000000d62000000520000050010000,PowerA Xbox Series X 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,
03000000d62000000b20000001010000,PowerA Xbox Series X 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,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,

View File

@@ -17,7 +17,7 @@ find_package(ZLIB REQUIRED) # v1.3, but Mac uses the SDK version.
find_package(Zstd 1.5.5 REQUIRED)
find_package(LZ4 REQUIRED)
find_package(WebP REQUIRED) # v1.3.2, spews an error on Linux because no pkg-config.
find_package(SDL2 2.30.4 REQUIRED)
find_package(SDL3 3.2.6 REQUIRED)
find_package(Freetype 2.11.1 REQUIRED)
if(USE_VULKAN)

View File

@@ -288,8 +288,14 @@ std::string Path::RealPath(const std::string_view path)
{
// Resolve non-absolute paths first.
std::vector<std::string_view> components;
// We need to keep the full combined path in scope
// as SplitNativePath() returns string_views to it.
std::string buf;
if (!IsAbsolute(path))
components = Path::SplitNativePath(Path::Combine(FileSystem::GetWorkingDirectory(), path));
{
buf = Path::Combine(FileSystem::GetWorkingDirectory(), path);
components = Path::SplitNativePath(buf);
}
else
components = Path::SplitNativePath(path);
@@ -968,7 +974,7 @@ std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode, Error*
{
#ifdef _WIN32
const std::wstring wfilename = GetWin32Path(filename);
const std::wstring wmode = GetWin32Path(mode);
const std::wstring wmode = StringUtil::UTF8StringToWideString(mode);
if (!wfilename.empty() && !wmode.empty())
{
std::FILE* fp;
@@ -1060,7 +1066,7 @@ std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, F
{
#ifdef _WIN32
const std::wstring wfilename = GetWin32Path(filename);
const std::wstring wmode = GetWin32Path(mode);
const std::wstring wmode = StringUtil::UTF8StringToWideString(mode);
if (wfilename.empty() || wmode.empty())
return nullptr;
@@ -1354,8 +1360,11 @@ static u32 TranslateWin32Attributes(u32 Win32Attributes)
}
static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path, const char* path, const char* pattern,
u32 flags, FileSystem::FindResultsArray* results, std::vector<std::string>& visited)
u32 flags, FileSystem::FindResultsArray* results, std::vector<std::string>& visited, ProgressCallback* cancel)
{
if (cancel && cancel->IsCancelled())
return 0;
std::string search_dir;
if (path)
{
@@ -1427,11 +1436,11 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
if (parent_path)
{
const std::string recurse_dir = fmt::format("{}\\{}", parent_path, path);
nFiles += RecursiveFindFiles(origin_path, recurse_dir.c_str(), utf8_filename.c_str(), pattern, flags, results, visited);
nFiles += RecursiveFindFiles(origin_path, recurse_dir.c_str(), utf8_filename.c_str(), pattern, flags, results, visited, cancel);
}
else
{
nFiles += RecursiveFindFiles(origin_path, path, utf8_filename.c_str(), pattern, flags, results, visited);
nFiles += RecursiveFindFiles(origin_path, path, utf8_filename.c_str(), pattern, flags, results, visited, cancel);
}
}
}
@@ -1494,7 +1503,7 @@ static u32 RecursiveFindFiles(const char* origin_path, const char* parent_path,
return nFiles;
}
bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results)
bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results, ProgressCallback* cancel)
{
// has a path
if (path[0] == '\0')
@@ -1514,7 +1523,7 @@ bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, Fin
}
// enter the recursive function
if (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) == 0)
if (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited, cancel) == 0)
return false;
if (flags & FILESYSTEM_FIND_SORT_BY_NAME)
@@ -2046,8 +2055,11 @@ bool FileSystem::DeleteSymbolicLink(const char* path, Error* error)
static_assert(sizeof(off_t) == sizeof(s64));
static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, const char* Path, const char* Pattern,
u32 Flags, FileSystem::FindResultsArray* pResults, std::vector<std::string>& visited)
u32 Flags, FileSystem::FindResultsArray* pResults, std::vector<std::string>& visited, ProgressCallback* cancel)
{
if (cancel && cancel->IsCancelled())
return 0;
std::string tempStr;
if (Path)
{
@@ -2118,11 +2130,11 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
if (ParentPath)
{
const std::string recursive_dir = fmt::format("{}/{}", ParentPath, Path);
nFiles += RecursiveFindFiles(OriginPath, recursive_dir.c_str(), pDirEnt->d_name, Pattern, Flags, pResults, visited);
nFiles += RecursiveFindFiles(OriginPath, recursive_dir.c_str(), pDirEnt->d_name, Pattern, Flags, pResults, visited, cancel);
}
else
{
nFiles += RecursiveFindFiles(OriginPath, Path, pDirEnt->d_name, Pattern, Flags, pResults, visited);
nFiles += RecursiveFindFiles(OriginPath, Path, pDirEnt->d_name, Pattern, Flags, pResults, visited, cancel);
}
}
}
@@ -2177,7 +2189,7 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
return nFiles;
}
bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results)
bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results, ProgressCallback* cancel)
{
// has a path
if (path[0] == '\0')
@@ -2197,7 +2209,7 @@ bool FileSystem::FindFiles(const char* path, const char* pattern, u32 flags, Fin
}
// enter the recursive function
if (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited) == 0)
if (RecursiveFindFiles(path, nullptr, nullptr, pattern, flags, results, visited, cancel) == 0)
return false;
if (flags & FILESYSTEM_FIND_SORT_BY_NAME)

View File

@@ -67,7 +67,7 @@ namespace FileSystem
std::vector<std::string> GetRootDirectoryList();
/// Search for files
bool FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results);
bool FindFiles(const char* path, const char* pattern, u32 flags, FindResultsArray* results, ProgressCallback* cancel = nullptr);
/// Stat file
bool StatFile(const char* path, struct stat* st);

View File

@@ -119,6 +119,12 @@ namespace x86Emitter
xImplSimd_DestRegSSE VPD;
};
struct xImplSimd_PBlend
{
xImplSimd_DestRegImmSSE W;
xImplSimd_DestRegSSE VB;
};
// --------------------------------------------------------------------------------------
// xImplSimd_PMove
// --------------------------------------------------------------------------------------

View File

@@ -500,6 +500,7 @@ namespace x86Emitter
extern const xImplSimd_MovHL_RtoR xMOVLH;
extern const xImplSimd_MovHL_RtoR xMOVHL;
extern const xImplSimd_PBlend xPBLEND;
extern const xImplSimd_Blend xBLEND;
extern const xImplSimd_PMove xPMOVSX;
extern const xImplSimd_PMove xPMOVZX;

View File

@@ -556,12 +556,18 @@ namespace x86Emitter
const xImplSimd_MovHL_RtoR xMOVLH = {0x16};
const xImplSimd_MovHL_RtoR xMOVHL = {0x12};
const xImplSimd_PBlend xPBLEND =
{
{0x66, 0x0e3a}, // W
{0x66, 0x1038}, // VB
};
const xImplSimd_Blend xBLEND =
{
{0x66, 0x0c3a}, // PS
{0x66, 0x0d3a}, // PD
{0x66, 0x1438}, // VPS
{0x66, 0x1538}, // VPD
{
{0x66, 0x0c3a}, // PS
{0x66, 0x0d3a}, // PD
{0x66, 0x1438}, // VPS
{0x66, 0x1538}, // VPD
};
const xImplSimd_PMove xPMOVSX = {0x2038};

View File

@@ -4,7 +4,7 @@
<ItemDefinitionGroup>
<Link>
<AdditionalLibraryDirectories>$(DepsLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;libjpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL2.lib;zlib.lib;zstd.lib</AdditionalDependencies>
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;libjpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL3.lib;zlib.lib;zstd.lib</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
@@ -15,7 +15,7 @@
<DepsDLLs Include="$(DepsBinDir)libsharpyuv.dll" />
<DepsDLLs Include="$(DepsBinDir)libwebp.dll" />
<DepsDLLs Include="$(DepsBinDir)lz4.dll" />
<DepsDLLs Include="$(DepsBinDir)SDL2.dll" />
<DepsDLLs Include="$(DepsBinDir)SDL3.dll" />
<DepsDLLs Include="$(DepsBinDir)shaderc_shared.dll" />
<DepsDLLs Include="$(DepsBinDir)zlib1.dll" />
<DepsDLLs Include="$(DepsBinDir)zstd.dll" />

View File

@@ -169,11 +169,25 @@ void Host::SetDefaultUISettings(SettingsInterface& si)
// nothing
}
bool Host::LocaleCircleConfirm()
{
// not running any UI, so no settings requests will come in
return false;
}
std::unique_ptr<ProgressCallback> Host::CreateHostProgressCallback()
{
return ProgressCallback::CreateNullProgressCallback();
}
void Host::ReportInfoAsync(const std::string_view title, const std::string_view message)
{
if (!title.empty() && !message.empty())
INFO_LOG("ReportInfoAsync: {}: {}", title, message);
else if (!message.empty())
INFO_LOG("ReportInfoAsync: {}", message);
}
void Host::ReportErrorAsync(const std::string_view title, const std::string_view message)
{
if (!title.empty() && !message.empty())
@@ -517,17 +531,17 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
s_settings_interface.SetBoolValue("EmuCore/GS", "dump", true);
if (str.find("rt") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "save", true);
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveRT", true);
if (str.find("f") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "savef", true);
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveFrame", true);
if (str.find("tex") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "savet", true);
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveTexture", true);
if (str.find("z") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "savez", true);
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveDepth", true);
if (str.find("a") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "savea", true);
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveAlpha", true);
if (str.find("i") != std::string::npos)
s_settings_interface.SetBoolValue("EmuCore/GS", "savei", true);
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveInfo", true);
continue;
}
else if (CHECK_ARG_PARAM("-dumprange"))
@@ -550,9 +564,9 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
{
by = std::max(1, StringUtil::FromChars<int>(split[2]).value_or(1));
}
s_settings_interface.SetIntValue("EmuCore/GS", "saven", start);
s_settings_interface.SetIntValue("EmuCore/GS", "savel", num);
s_settings_interface.SetIntValue("EmuCore/GS", "saveb", by);
s_settings_interface.SetIntValue("EmuCore/GS", "SaveDrawStart", start);
s_settings_interface.SetIntValue("EmuCore/GS", "SaveDrawCount", num);
s_settings_interface.SetIntValue("EmuCore/GS", "SaveDrawBy", by);
continue;
}
else if (CHECK_ARG_PARAM("-dumprangef"))
@@ -575,9 +589,9 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
{
by = std::max(1, StringUtil::FromChars<int>(split[2]).value_or(1));
}
s_settings_interface.SetIntValue("EmuCore/GS", "savenf", start);
s_settings_interface.SetIntValue("EmuCore/GS", "savelf", num);
s_settings_interface.SetIntValue("EmuCore/GS", "savebf", by);
s_settings_interface.SetIntValue("EmuCore/GS", "SaveFrameStart", start);
s_settings_interface.SetIntValue("EmuCore/GS", "SaveFrameCount", num);
s_settings_interface.SetIntValue("EmuCore/GS", "SaveFrameBy", by);
continue;
}
else if (CHECK_ARG_PARAM("-dumpdirhw"))

View File

@@ -212,7 +212,7 @@
</size>
</property>
<property name="text">
<string>1</string>
<string>4</string>
</property>
</widget>
</item>

View File

@@ -453,7 +453,7 @@ std::vector<SearchResult> startWorker(DebugInterface* cpu, const SearchType type
isSigned ? searchWorker<s32>(cpu, searchResults, type, comparison, start, end, value.toInt(nullptr, base)) : searchWorker<u32>(cpu, searchResults, type, comparison, start, end, value.toUInt(nullptr, base));
break;
case SearchType::Int64Type:
isSigned ? searchWorker<s64>(cpu, searchResults, type, comparison, start, end, value.toLong(nullptr, base)) : searchWorker<s64>(cpu, searchResults, type, comparison, start, end, value.toULongLong(nullptr, base));
isSigned ? searchWorker<s64>(cpu, searchResults, type, comparison, start, end, value.toLongLong(nullptr, base)) : searchWorker<u64>(cpu, searchResults, type, comparison, start, end, value.toULongLong(nullptr, base));
break;
case SearchType::FloatType:
searchWorker<float>(cpu, searchResults, type, comparison, start, end, value.toFloat());

View File

@@ -99,11 +99,23 @@ static QString s_current_disc_serial;
static quint32 s_current_disc_crc;
static quint32 s_current_running_crc;
static bool s_record_on_start = false;
static QString s_path_to_recording_for_record_on_start;
MainWindow::MainWindow()
{
pxAssert(!g_main_window);
g_main_window = this;
// Native window rendering is broken in wayland.
// Let's work around it by disabling it for every widget besides
// DisplayWidget.
// Additionally, alien widget rendering is much more performant, so we
// should have a nice responsiveness boost in our UI :)
// QTBUG-133919, reported upstream by govanify
QGuiApplication::setAttribute(Qt::AA_NativeWindows, false);
QGuiApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
#if !defined(_WIN32) && !defined(__APPLE__)
s_use_central_widget = DisplayContainer::isRunningOnWayland();
#endif
@@ -729,7 +741,48 @@ void MainWindow::updateAdvancedSettingsVisibility()
void MainWindow::onVideoCaptureToggled(bool checked)
{
if (!s_vm_valid)
{
if (!s_record_on_start)
{
QMessageBox msgbox(this);
msgbox.setIcon(QMessageBox::Question);
msgbox.setWindowIcon(QtHost::GetAppIcon());
msgbox.setWindowTitle(tr("Record On Boot"));
msgbox.setWindowModality(Qt::WindowModal);
msgbox.setText(tr("Did you want to start recording on boot?"));
msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::No);
msgbox.setDefaultButton(QMessageBox::Yes);
if (msgbox.exec() == QMessageBox::Yes)
{
const QString container(QString::fromStdString(
Host::GetStringSettingValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER)));
const QString filter(tr("%1 Files (*.%2)").arg(container.toUpper()).arg(container));
QString temp(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseVideoFilename())).arg(container));
temp = QDir::toNativeSeparators(QFileDialog::getSaveFileName(this, tr("Video Capture"), temp, filter));
s_path_to_recording_for_record_on_start = temp;
if (s_path_to_recording_for_record_on_start.isEmpty())
return;
s_record_on_start = true;
}
}
else
{
QMessageBox msgbox(this);
msgbox.setIcon(QMessageBox::Question);
msgbox.setWindowIcon(QtHost::GetAppIcon());
msgbox.setWindowTitle(tr("Record On Boot"));
msgbox.setWindowModality(Qt::WindowModal);
msgbox.setText(tr("Did you want to cancel recording on boot?"));
msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::No);
msgbox.setDefaultButton(QMessageBox::Yes);
if (msgbox.exec() == QMessageBox::Yes)
s_record_on_start = false;
}
return;
}
// Reset the checked state, we'll get updated by the GS thread.
QSignalBlocker sb(m_ui.actionVideoCapture);
@@ -741,16 +794,26 @@ void MainWindow::onVideoCaptureToggled(bool checked)
return;
}
const QString container(QString::fromStdString(
Host::GetStringSettingValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER)));
const QString filter(tr("%1 Files (*.%2)").arg(container.toUpper()).arg(container));
if (s_record_on_start && !s_path_to_recording_for_record_on_start.isEmpty())
{
// We can't start recording immediately, this is called before full GS init (specifically the fps amount)
// and GSCapture ends up unhappy.
// TODO: Pass some sort of flag or callback to the GS thread to start recording on frame 0.
Host::AddOSDMessage(tr("Recording will start in a moment").toStdString(), 3.0f);
QTimer::singleShot(2000, []() { g_emu_thread->beginCapture(s_path_to_recording_for_record_on_start); });
}
else
{
const QString container(QString::fromStdString(
Host::GetStringSettingValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER)));
const QString filter(tr("%1 Files (*.%2)").arg(container.toUpper()).arg(container));
QString path(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseVideoFilename())).arg(container));
path = QDir::toNativeSeparators(QFileDialog::getSaveFileName(this, tr("Video Capture"), path, filter));
if (path.isEmpty())
return;
g_emu_thread->beginCapture(path);
QString path(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseVideoFilename())).arg(container));
path = QDir::toNativeSeparators(QFileDialog::getSaveFileName(this, tr("Video Capture"), path, filter));
if (path.isEmpty())
return;
g_emu_thread->beginCapture(path);
}
}
void MainWindow::onCaptureStarted(const QString& filename)
@@ -895,8 +958,6 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool stoppi
m_ui.actionToolbarSaveState->setEnabled(running);
m_ui.actionViewGameProperties->setEnabled(running);
m_ui.actionVideoCapture->setEnabled(running);
if (!running && m_ui.actionVideoCapture->isChecked())
{
QSignalBlocker sb(m_ui.actionVideoCapture);
@@ -1160,6 +1221,11 @@ void MainWindow::cancelGameListRefresh()
m_game_list_widget->cancelRefresh();
}
void MainWindow::reportInfo(const QString& title, const QString& message)
{
QMessageBox::information(this, title, message);
}
void MainWindow::reportError(const QString& title, const QString& message)
{
QMessageBox::critical(this, title, message);
@@ -1982,6 +2048,11 @@ void MainWindow::onVMStarted()
updateWindowTitle();
updateStatusBarWidgetVisibility();
updateInputRecordingActions(true);
if (s_record_on_start)
{
m_ui.actionVideoCapture->setChecked(true);
s_record_on_start = false;
}
}
void MainWindow::onVMPaused()

View File

@@ -109,6 +109,7 @@ public Q_SLOTS:
void checkForUpdates(bool display_message, bool force_check);
void refreshGameList(bool invalidate_cache);
void cancelGameListRefresh();
void reportInfo(const QString& title, const QString& message);
void reportError(const QString& title, const QString& message);
bool confirmMessage(const QString& title, const QString& message);
void onStatusMessage(const QString& message);

View File

@@ -1612,6 +1612,18 @@ bool QtHost::DownloadFile(QWidget* parent, const QString& title, std::string url
return true;
}
void Host::ReportInfoAsync(const std::string_view title, const std::string_view message)
{
if (!title.empty() && !message.empty())
INFO_LOG("ReportInfoAsync: {}: {}", title, message);
else if (!message.empty())
INFO_LOG("ReportInfoAsync: {}", message);
QMetaObject::invokeMethod(g_main_window, "reportInfo", Qt::QueuedConnection,
Q_ARG(const QString&, title.empty() ? QString() : QString::fromUtf8(title.data(), title.size())),
Q_ARG(const QString&, message.empty() ? QString() : QString::fromUtf8(message.data(), message.size())));
}
void Host::ReportErrorAsync(const std::string_view title, const std::string_view message)
{
if (!title.empty() && !message.empty())

View File

@@ -19,7 +19,7 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
SettingsInterface* sif = dialog->getProfileSettingsInterface();
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", true);
connect(m_ui.enableSDLSource, &QCheckBox::checkStateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
connect(m_ui.ledSettings, &QToolButton::clicked, this, &ControllerGlobalSettingsWidget::ledSettingsClicked);
@@ -146,7 +146,7 @@ ControllerLEDSettingsDialog::ControllerLEDSettingsDialog(QWidget* parent, Contro
SettingsInterface* sif = dialog->getProfileSettingsInterface();
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLPS5PlayerLED, "InputSources", "SDLPS5PlayerLED", false);
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLPS5PlayerLED, "InputSources", "SDLPS5PlayerLED", true);
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
}

View File

@@ -44,19 +44,23 @@ DebugSettingsWidget::DebugSettingsWidget(SettingsWindow* dialog, QWidget* parent
//////////////////////////////////////////////////////////////////////////
// GS Settings
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.dumpGSDraws, "EmuCore/GS", "dump", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveRT, "EmuCore/GS", "save", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveFrame, "EmuCore/GS", "savef", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveTexture, "EmuCore/GS", "savet", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveDepth, "EmuCore/GS", "savez", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.startDraw, "EmuCore/GS", "saven", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.dumpCount, "EmuCore/GS", "savel", 5000);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.dumpGSData, "EmuCore/GS", "DumpGSData", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveRT, "EmuCore/GS", "SaveRT", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveFrame, "EmuCore/GS", "SaveFrame", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveTexture, "EmuCore/GS", "SaveTexture", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveDepth, "EmuCore/GS", "SaveDepth", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveAlpha, "EmuCore/GS", "SaveAlpha", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveInfo, "EmuCore/GS", "SaveInfo", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.saveDrawStart, "EmuCore/GS", "SaveDrawStart", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.saveDrawCount, "EmuCore/GS", "SaveDrawCount", 5000);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.saveFrameStart, "EmuCore/GS", "SaveFrameStart", 0);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.saveFrameCount, "EmuCore/GS", "SaveFrameCount", 999999);
SettingWidgetBinder::BindWidgetToFolderSetting(
sif, m_ui.hwDumpDirectory, m_ui.hwDumpBrowse, m_ui.hwDumpOpen, nullptr, "EmuCore/GS", "HWDumpDirectory", std::string(), false);
SettingWidgetBinder::BindWidgetToFolderSetting(
sif, m_ui.swDumpDirectory, m_ui.swDumpBrowse, m_ui.swDumpOpen, nullptr, "EmuCore/GS", "SWDumpDirectory", std::string(), false);
connect(m_ui.dumpGSDraws, &QCheckBox::checkStateChanged, this, &DebugSettingsWidget::onDrawDumpingChanged);
connect(m_ui.dumpGSData, &QCheckBox::checkStateChanged, this, &DebugSettingsWidget::onDrawDumpingChanged);
onDrawDumpingChanged();
#ifdef PCSX2_DEVBUILD
@@ -146,13 +150,17 @@ DebugSettingsWidget::~DebugSettingsWidget() = default;
void DebugSettingsWidget::onDrawDumpingChanged()
{
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "dump", false);
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "DumpGSData", false);
m_ui.saveRT->setEnabled(enabled);
m_ui.saveFrame->setEnabled(enabled);
m_ui.saveTexture->setEnabled(enabled);
m_ui.saveDepth->setEnabled(enabled);
m_ui.startDraw->setEnabled(enabled);
m_ui.dumpCount->setEnabled(enabled);
m_ui.saveAlpha->setEnabled(enabled);
m_ui.saveInfo->setEnabled(enabled);
m_ui.saveDrawStart->setEnabled(enabled);
m_ui.saveDrawCount->setEnabled(enabled);
m_ui.saveFrameStart->setEnabled(enabled);
m_ui.saveFrameCount->setEnabled(enabled);
m_ui.hwDumpDirectory->setEnabled(enabled);
m_ui.hwDumpBrowse->setEnabled(enabled);
m_ui.hwDumpOpen->setEnabled(enabled);

View File

@@ -161,7 +161,7 @@
<item row="0" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="dumpGSDraws">
<widget class="QCheckBox" name="dumpGSData">
<property name="text">
<string>Dump GS Draws</string>
</property>
@@ -195,17 +195,31 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="saveAlpha">
<property name="text">
<string>Save Alpha</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="saveInfo">
<property name="text">
<string>Save Info</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<widget class="QLabel" name="label_1">
<property name="text">
<string>Start Draw Number:</string>
<string>Save Draw Start:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="startDraw">
<widget class="QSpinBox" name="saveDrawStart">
<property name="maximum">
<number>99999999</number>
</property>
@@ -214,12 +228,12 @@
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Draw Dump Count:</string>
<string>Save Draw Count:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="dumpCount">
<widget class="QSpinBox" name="saveDrawCount">
<property name="minimum">
<number>1</number>
</property>
@@ -231,39 +245,49 @@
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Hardware Dump Directory:</string>
<string>Save Frame Start:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="saveFrameStart">
<property name="maximum">
<number>99999999</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Software Dump Directory:</string>
<string>Save Frame Count:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,0">
<item>
<widget class="QLineEdit" name="swDumpDirectory"/>
</item>
<item>
<widget class="QPushButton" name="swDumpBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="swDumpOpen">
<property name="text">
<string>Open...</string>
</property>
</widget>
</item>
</layout>
<widget class="QSpinBox" name="saveFrameCount">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>99999999</number>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Hardware Dump Directory:</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Software Dump Directory:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0,0">
<item>
<widget class="QLineEdit" name="hwDumpDirectory"/>
@@ -284,6 +308,27 @@
</item>
</layout>
</item>
<item row="6" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,0">
<item>
<widget class="QLineEdit" name="swDumpDirectory"/>
</item>
<item>
<widget class="QPushButton" name="swDumpBrowse">
<property name="text">
<string>Browse...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="swDumpOpen">
<property name="text">
<string>Open...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

@@ -1055,7 +1055,12 @@
</item>
<item>
<property name="text">
<string>Align To Native</string>
<string>Align to Native</string>
</property>
</item>
<item>
<property name="text">
<string>Align to Native - with Texture Offset</string>
</property>
</item>
</widget>

View File

@@ -16,13 +16,14 @@
#include <bit>
InputBindingDialog::InputBindingDialog(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name,
std::string key_name, std::vector<std::string> bindings, QWidget* parent)
std::string key_name, std::vector<std::string> bindings_settings, std::vector<std::string> bindings_ui, QWidget* parent)
: QDialog(parent)
, m_sif(sif)
, m_bind_type(bind_type)
, m_section_name(std::move(section_name))
, m_key_name(std::move(key_name))
, m_bindings(std::move(bindings))
, m_bindings_settings(std::move(bindings_settings))
, m_bindings_ui(std::move(bindings_ui))
{
m_ui.setupUi(this);
m_ui.title->setText(tr("Bindings for %1 %2").arg(QString::fromStdString(m_section_name)).arg(QString::fromStdString(m_key_name)));
@@ -32,6 +33,8 @@ InputBindingDialog::InputBindingDialog(SettingsInterface* sif, InputBindingInfo:
connect(m_ui.removeBinding, &QPushButton::clicked, this, &InputBindingDialog::onRemoveBindingButtonClicked);
connect(m_ui.clearBindings, &QPushButton::clicked, this, &InputBindingDialog::onClearBindingsButtonClicked);
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, [this]() { done(0); });
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &InputBindingDialog::onInputDeviceConnected);
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this, &InputBindingDialog::onInputDeviceDisconnected);
updateList();
// Only show the sensitivity controls for binds where it's applicable.
@@ -210,11 +213,17 @@ void InputBindingDialog::addNewBinding()
const std::string new_binding(InputManager::ConvertInputBindingKeysToString(m_bind_type, m_new_bindings.data(), m_new_bindings.size()));
if (!new_binding.empty())
{
if (std::find(m_bindings.begin(), m_bindings.end(), new_binding) != m_bindings.end())
if (std::find(m_bindings_settings.begin(), m_bindings_settings.end(), new_binding) != m_bindings_settings.end())
return;
m_ui.bindingList->addItem(QString::fromStdString(new_binding));
m_bindings.push_back(std::move(new_binding));
m_bindings_settings.push_back(std::move(new_binding));
SmallString new_binding_temp{std::string_view{new_binding}};
InputManager::PrettifyInputBinding(new_binding_temp, false);
std::string new_binding_ui{new_binding_temp};
m_bindings_ui.push_back(new_binding_ui);
m_ui.bindingList->addItem(QString::fromStdString(new_binding_ui));
saveListToSettings();
}
}
@@ -230,17 +239,19 @@ void InputBindingDialog::onAddBindingButtonClicked()
void InputBindingDialog::onRemoveBindingButtonClicked()
{
const int row = m_ui.bindingList->currentRow();
if (row < 0 || static_cast<size_t>(row) >= m_bindings.size())
if (row < 0 || static_cast<size_t>(row) >= m_bindings_ui.size())
return;
m_bindings.erase(m_bindings.begin() + row);
m_bindings_settings.erase(m_bindings_settings.begin() + row);
m_bindings_ui.erase(m_bindings_ui.begin() + row);
delete m_ui.bindingList->takeItem(row);
saveListToSettings();
}
void InputBindingDialog::onClearBindingsButtonClicked()
{
m_bindings.clear();
m_bindings_settings.clear();
m_bindings_ui.clear();
m_ui.bindingList->clear();
saveListToSettings();
}
@@ -248,7 +259,7 @@ void InputBindingDialog::onClearBindingsButtonClicked()
void InputBindingDialog::updateList()
{
m_ui.bindingList->clear();
for (const std::string& binding : m_bindings)
for (const std::string& binding : m_bindings_ui)
m_ui.bindingList->addItem(QString::fromStdString(binding));
}
@@ -256,8 +267,8 @@ void InputBindingDialog::saveListToSettings()
{
if (m_sif)
{
if (!m_bindings.empty())
m_sif->SetStringList(m_section_name.c_str(), m_key_name.c_str(), m_bindings);
if (!m_bindings_settings.empty())
m_sif->SetStringList(m_section_name.c_str(), m_key_name.c_str(), m_bindings_settings);
else
m_sif->DeleteValue(m_section_name.c_str(), m_key_name.c_str());
m_sif->Save();
@@ -265,8 +276,8 @@ void InputBindingDialog::saveListToSettings()
}
else
{
if (!m_bindings.empty())
Host::SetBaseStringListSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_bindings);
if (!m_bindings_settings.empty())
Host::SetBaseStringListSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_bindings_settings);
else
Host::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
Host::CommitBaseSettingChanges();
@@ -337,6 +348,16 @@ void InputBindingDialog::onDeadzoneChanged(int value)
m_ui.deadzoneValue->setText(tr("%1%").arg(value));
}
void InputBindingDialog::onInputDeviceConnected(const QString& identifier, const QString& device_name)
{
ReloadBindNames();
}
void InputBindingDialog::onInputDeviceDisconnected(const QString& identifier)
{
ReloadBindNames();
}
void InputBindingDialog::hookInputManager()
{
InputManager::SetHook([this](InputBindingKey key, float value) {
@@ -349,3 +370,17 @@ void InputBindingDialog::unhookInputManager()
{
InputManager::RemoveHook();
}
void InputBindingDialog::ReloadBindNames()
{
m_bindings_ui.clear();
m_bindings_ui.reserve(m_bindings_settings.size());
for (size_t i = 0; i < m_bindings_settings.size(); i++)
{
SmallString binding{std::string_view{m_bindings_settings[i]}};
InputManager::PrettifyInputBinding(binding, false);
m_bindings_ui.push_back(std::string{binding});
}
updateList();
}

View File

@@ -22,7 +22,7 @@ class InputBindingDialog : public QDialog
public:
InputBindingDialog(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name, std::string key_name,
std::vector<std::string> bindings, QWidget* parent);
std::vector<std::string> bindings_settings, std::vector<std::string> bindings_ui, QWidget* parent);
~InputBindingDialog();
protected Q_SLOTS:
@@ -35,6 +35,9 @@ protected Q_SLOTS:
void onSensitivityChanged(int value);
void onDeadzoneChanged(int value);
void onInputDeviceConnected(const QString& identifier, const QString& device_name);
void onInputDeviceDisconnected(const QString& identifier);
protected:
enum : u32
{
@@ -55,13 +58,16 @@ protected:
void hookInputManager();
void unhookInputManager();
void ReloadBindNames();
Ui::InputBindingDialog m_ui;
SettingsInterface* m_sif;
InputBindingInfo::Type m_bind_type;
std::string m_section_name;
std::string m_key_name;
std::vector<std::string> m_bindings;
std::vector<std::string> m_bindings_settings;
std::vector<std::string> m_bindings_ui;
std::vector<InputBindingKey> m_new_bindings;
std::vector<std::pair<InputBindingKey, std::pair<float, float>>> m_value_ranges;

View File

@@ -23,6 +23,8 @@ InputBindingWidget::InputBindingWidget(QWidget* parent)
: QPushButton(parent)
{
connect(this, &QPushButton::clicked, this, &InputBindingWidget::onClicked);
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &InputBindingWidget::onInputDeviceConnected);
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this, &InputBindingWidget::onInputDeviceDisconnected);
}
InputBindingWidget::InputBindingWidget(
@@ -33,6 +35,8 @@ InputBindingWidget::InputBindingWidget(
setMaximumWidth(225);
connect(this, &QPushButton::clicked, this, &InputBindingWidget::onClicked);
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &InputBindingWidget::onInputDeviceConnected);
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this, &InputBindingWidget::onInputDeviceDisconnected);
initialize(sif, bind_type, std::move(section_name), std::move(key_name));
}
@@ -62,20 +66,20 @@ void InputBindingWidget::updateText()
const QString binding_tip(tr("\n\nLeft click to assign a new button\nShift + left click for additional bindings"));
const QString binding_clear_tip(tr("\nRight click to clear binding"));
if (m_bindings.empty())
if (m_bindings_ui.empty())
{
setText(QString());
setToolTip(tr("No bindings registered") + binding_tip);
}
else if (m_bindings.size() > 1)
else if (m_bindings_ui.size() > 1)
{
setText(tr("%n bindings", "", static_cast<int>(m_bindings.size())));
setText(tr("%n bindings", "", static_cast<int>(m_bindings_ui.size())));
// keep the full thing for the tooltip
std::stringstream ss;
bool first = true;
for (const std::string& binding : m_bindings)
for (const std::string& binding : m_bindings_ui)
{
if (first)
first = false;
@@ -87,7 +91,7 @@ void InputBindingWidget::updateText()
}
else
{
QString binding_text(QString::fromStdString(m_bindings[0]));
QString binding_text(QString::fromStdString(m_bindings_ui[0]));
setToolTip(binding_text + binding_tip + binding_clear_tip);
// fix up accelerators, and if it's too long, ellipsise it
@@ -232,13 +236,12 @@ void InputBindingWidget::setNewBinding()
}
}
m_bindings.clear();
m_bindings.push_back(std::move(new_binding));
m_bindings_ui.clear();
m_bindings_ui.push_back(std::move(new_binding));
}
void InputBindingWidget::clearBinding()
{
m_bindings.clear();
if (m_sif)
{
m_sif->DeleteValue(m_section_name.c_str(), m_key_name.c_str());
@@ -256,14 +259,24 @@ void InputBindingWidget::clearBinding()
void InputBindingWidget::reloadBinding()
{
m_bindings = m_sif ? m_sif->GetStringList(m_section_name.c_str(), m_key_name.c_str()) :
Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
m_bindings_settings = m_sif ? m_sif->GetStringList(m_section_name.c_str(), m_key_name.c_str()) :
Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
m_bindings_ui.clear();
m_bindings_ui.reserve(m_bindings_settings.size());
for (size_t i = 0; i < m_bindings_settings.size(); i++)
{
SmallString binding{std::string_view{m_bindings_settings[i]}};
InputManager::PrettifyInputBinding(binding, false);
m_bindings_ui.push_back(std::string{binding});
}
updateText();
}
void InputBindingWidget::onClicked()
{
if (m_bindings.size() > 1)
if (m_bindings_ui.size() > 1)
{
openDialog();
return;
@@ -376,6 +389,16 @@ void InputBindingWidget::inputManagerHookCallback(InputBindingKey key, float val
}
}
void InputBindingWidget::onInputDeviceConnected(const QString& identifier, const QString& device_name)
{
reloadBinding();
}
void InputBindingWidget::onInputDeviceDisconnected(const QString& identifier)
{
reloadBinding();
}
void InputBindingWidget::hookInputManager()
{
InputManager::SetHook([this](InputBindingKey key, float value) {
@@ -391,7 +414,7 @@ void InputBindingWidget::unhookInputManager()
void InputBindingWidget::openDialog()
{
InputBindingDialog binding_dialog(m_sif, m_bind_type, m_section_name, m_key_name, m_bindings, QtUtils::GetRootWidget(this));
InputBindingDialog binding_dialog(m_sif, m_bind_type, m_section_name, m_key_name, m_bindings_settings, m_bindings_ui, QtUtils::GetRootWidget(this));
binding_dialog.exec();
reloadBinding();
}
@@ -422,6 +445,12 @@ void InputVibrationBindingWidget::setKey(ControllerSettingsWindow* dialog, std::
m_section_name = std::move(section_name);
m_key_name = std::move(key_name);
m_binding = Host::GetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str());
SmallString binding{std::string_view{m_binding}};
if (InputManager::PrettifyInputBinding(binding, false))
m_binding = binding;
setText(QString::fromStdString(m_binding));
}
@@ -440,12 +469,22 @@ void InputVibrationBindingWidget::onClicked()
const QString full_key(QStringLiteral("%1/%2").arg(QString::fromStdString(m_section_name)).arg(QString::fromStdString(m_key_name)));
const QString current(QString::fromStdString(m_binding));
QStringList input_options(m_dialog->getVibrationMotors());
if (!current.isEmpty() && input_options.indexOf(current) < 0)
QStringList input_setting_options(m_dialog->getVibrationMotors());
QStringList input_ui_options;
input_ui_options.reserve(input_setting_options.count());
for (QString motor : input_setting_options)
{
input_options.append(current);
SmallStringBase motor_ui(motor.toStdString());
InputManager::PrettifyInputBinding(motor_ui, false);
input_ui_options.push_back(QString(motor_ui));
}
else if (input_options.isEmpty())
if (!current.isEmpty() && input_ui_options.indexOf(current) < 0)
{
input_setting_options.append(current);
}
else if (input_setting_options.isEmpty())
{
QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Error"), tr("No devices with vibration motors were detected."));
return;
@@ -457,16 +496,25 @@ void InputVibrationBindingWidget::onClicked()
input_dialog.setInputMode(QInputDialog::TextInput);
input_dialog.setOptions(QInputDialog::UseListViewForComboBoxItems);
input_dialog.setComboBoxEditable(false);
input_dialog.setComboBoxItems(std::move(input_options));
input_dialog.setComboBoxItems(std::move(input_ui_options));
input_dialog.setTextValue(current);
if (input_dialog.exec() == 0)
return;
const QString new_value(input_dialog.textValue());
m_binding = new_value.toStdString();
Host::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_binding.c_str());
Host::CommitBaseSettingChanges();
setText(new_value);
// If a controller is unplugged, we won't have the setting string to save
// Skip saving if selected is an existing bind from an unplugged controller
const int selected = input_setting_options.indexOf(input_dialog.textValue());
if (selected >= 0)
{
// Update config
const std::string new_setting_value(input_setting_options[selected].toStdString());
Host::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), new_setting_value.c_str());
Host::CommitBaseSettingChanges();
// Update ui
const QString new_ui_value(input_dialog.textValue());
m_binding = new_ui_value.toStdString();
setText(new_ui_value);
}
}
void InputVibrationBindingWidget::mouseReleaseEvent(QMouseEvent* e)

View File

@@ -39,6 +39,9 @@ protected Q_SLOTS:
void onInputListenTimerTimeout();
void inputManagerHookCallback(InputBindingKey key, float value);
void onInputDeviceConnected(const QString& identifier, const QString& device_name);
void onInputDeviceDisconnected(const QString& identifier);
protected:
enum : u32
{
@@ -65,7 +68,8 @@ protected:
InputBindingInfo::Type m_bind_type = InputBindingInfo::Type::Unknown;
std::string m_section_name;
std::string m_key_name;
std::vector<std::string> m_bindings;
std::vector<std::string> m_bindings_settings;
std::vector<std::string> m_bindings_ui;
std::vector<InputBindingKey> m_new_bindings;
std::vector<std::pair<InputBindingKey, std::pair<float, float>>> m_value_ranges;
QTimer* m_input_listen_timer = nullptr;

View File

@@ -183,6 +183,14 @@ QString MemoryCardSettingsWidget::getSelectedCard() const
return ret;
}
bool MemoryCardSettingsWidget::isSelectedCardFormatted() const
{
const QList<QTreeWidgetItem*> selection(m_ui.cardList->selectedItems());
if (!selection.empty())
return selection[0]->data(0, Qt::UserRole).toBool();
return false;
}
void MemoryCardSettingsWidget::updateCardActions()
{
QString selectedCard = getSelectedCard();
@@ -263,6 +271,12 @@ void MemoryCardSettingsWidget::convertCard()
if (selectedCard.isEmpty())
return;
if (!isSelectedCardFormatted())
{
QMessageBox::critical(this, tr("Error"), tr("Cannot convert an unformatted memory card."));
return;
}
MemoryCardConvertDialog dialog(QtUtils::GetRootWidget(this), selectedCard);
if (dialog.IsSetup() && dialog.exec() == QDialog::Accepted)
@@ -442,6 +456,10 @@ void MemoryCardListWidget::refresh(SettingsWindow* dialog)
item->setText(1, getSizeSummary(mcd));
item->setText(2, mcd.formatted ? tr("Yes") : tr("No"));
item->setText(3, mtime.toString(QLocale::system().dateTimeFormat(QLocale::ShortFormat)));
// store formatted metadata
item->setData(0, Qt::UserRole, mcd.formatted);
addTopLevelItem(item);
}
}

View File

@@ -97,6 +97,7 @@ private:
void createCard();
QString getSelectedCard() const;
bool isSelectedCardFormatted() const;
void updateCardActions();
void deleteCard();
void renameCard();

View File

@@ -11,6 +11,7 @@
#include "common/SmallString.h"
#include "common/StringUtil.h"
#include "pcsx2/ImGui/FullscreenUI.h"
#include "pcsx2/ImGui/ImGuiManager.h"
#include "pcsx2/MTGS.h"
@@ -191,6 +192,13 @@ void QtHost::InstallTranslator(QWidget* dialog_parent)
}
UpdateGlyphRangesAndClearCache(dialog_parent, language.toStdString());
if (FullscreenUI::IsInitialized())
{
MTGS::RunOnGSThread([]() mutable {
FullscreenUI::LocaleChanged();
});
}
}
const char* QtHost::GetDefaultLanguage()
@@ -220,6 +228,12 @@ std::string Host::TranslatePluralToString(const char* context, const char* msg,
return qApp->translate(context, msg, disambiguation, count).toStdString();
}
bool Host::LocaleCircleConfirm()
{
QLocale& loc = QtHost::s_current_locale;
return (loc.language() == QLocale::Japanese) || (loc.language() == QLocale::Chinese) || (loc.language() == QLocale::Korean);
}
std::vector<std::pair<QString, QString>> QtHost::GetAvailableLanguageList()
{
return {

File diff suppressed because it is too large Load Diff

View File

@@ -36,7 +36,7 @@
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DepsIncludeDir)\SDL2</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DepsIncludeDir)\SDL3</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\lzma\include</AdditionalIncludeDirectories>

View File

@@ -1268,7 +1268,6 @@ void Achievements::HandleLeaderboardTrackerUpdateEvent(const rc_client_event_t*
"Achievements: Updating leaderboard tracker: %u: %s", event->leaderboard_tracker->id, event->leaderboard_tracker->display);
it->text = event->leaderboard_tracker->display;
it->active = true;
}
void Achievements::HandleAchievementChallengeIndicatorShowEvent(const rc_client_event_t* event)

View File

@@ -1146,7 +1146,7 @@ target_link_libraries(PCSX2_FLAGS INTERFACE
discord-rpc
simpleini
freesurround
SDL2::SDL2
SDL3::SDL3
ZLIB::ZLIB
LZ4::LZ4
SoundTouch::SoundTouch
@@ -1282,7 +1282,7 @@ function(setup_main_executable target)
# Copy dependency libraries.
set(DEPS_BINDIR "${CMAKE_SOURCE_DIR}/deps/bin")
set(DEPS_TO_COPY freetype.dll harfbuzz.dll libjpeg.dll libpng16.dll libsharpyuv.dll libwebp.dll lz4.dll SDL2.dll shaderc_shared.dll zlib1.dll zstd.dll)
set(DEPS_TO_COPY freetype.dll harfbuzz.dll libjpeg.dll libpng16.dll libsharpyuv.dll libwebp.dll lz4.dll SDL3.dll shaderc_shared.dll zlib1.dll zstd.dll)
foreach(DEP_TO_COPY ${DEPS_TO_COPY})
install(FILES "${DEPS_BINDIR}/${DEP_TO_COPY}" DESTINATION "${CMAKE_SOURCE_DIR}/bin")
endforeach()

View File

@@ -440,6 +440,7 @@ enum class GSHalfPixelOffset : u8
Special,
SpecialAggressive,
Native,
NativeWTexOffset,
MaxCount
};
@@ -822,12 +823,12 @@ struct Pcsx2Config
u16 SWExtraThreads = 2;
u16 SWExtraThreadsHeight = 4;
int SaveN = 0;
int SaveL = 5000;
int SaveB = 1;
int SaveNF = 0;
int SaveLF = -1;
int SaveBF = 1;
int SaveDrawStart = 0;
int SaveDrawCount = 5000;
int SaveDrawBy = 1;
int SaveFrameStart = 0;
int SaveFrameCount = -1;
int SaveFrameBy = 1;
s8 ExclusiveFullscreenControl = -1;
GSScreenshotSize ScreenshotSize = GSScreenshotSize::WindowResolution;

View File

@@ -599,7 +599,11 @@ bool parsePostfixExpression(PostfixExpression& exp, IExpressionFunctions* funcs,
}
}
if (valueStack.size() != 1) return false;
if (valueStack.size() != 1)
{
error = TRANSLATE("ExpressionParser", "Invalid expression (Too many constants?)");
return false;
}
dest = valueStack[0];
return true;
}

View File

@@ -637,14 +637,14 @@ bool CMipsInstruction::Validate()
immediate.value = (immediate.value >> 2) & 0x3FFFFFF;
} else if (Opcode.flags & MO_IPCR) // relative 16 bit value
{
int num = (immediate.value-RamPos-4);
const int num = (immediate.value-RamPos-4) >> 2;
if (num > 0x20000 || num < (-0x20000))
if (num > std::numeric_limits<short>::max() || num < std::numeric_limits<short>::min())
{
Logger::queueError(Logger::Error,L"Branch target %08X out of range",immediate.value);
return false;
}
immediate.value = num >> 2;
immediate.value = num;
}
int immediateBits = getImmediateBits(immediateType);

View File

@@ -596,10 +596,10 @@ const tMipsOpcode MipsOpcodes[] = {
// 10 | --- | --- | --- | --- | --- | --- | --- | --- | 10..17
// 11 | --- | --- | --- | --- | --- | --- | --- | --- | 18..1F
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
{ "bc1f", "I", MIPS_COP1BC(0x00), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
{ "bc1t", "I", MIPS_COP1BC(0x01), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
{ "bc1fl", "I", MIPS_COP1BC(0x02), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
{ "bc1tl", "I", MIPS_COP1BC(0x03), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
{ "bc1f", "i", MIPS_COP1BC(0x00), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
{ "bc1t", "i", MIPS_COP1BC(0x01), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
{ "bc1fl", "i", MIPS_COP1BC(0x02), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
{ "bc1tl", "i", MIPS_COP1BC(0x03), MA_MIPS2, MO_IPCR|MO_DELAY|MO_NODELAYSLOT },
// 31---------21------------------------------------------5--------0
// |= COP1S | | function|

View File

@@ -179,7 +179,7 @@ The clamp modes are also numerically based.
* bilinearUpscale [`0` or `1` or `2`] {Automatic, Force Bilinear, Force Nearest} Default: Automatic
* skipDrawStart [Value between `0` to `10000`] {0-10000} Default: Off (`0`)
* skipDrawEnd [Value between `0` to `10000`] {0-10000} Default: Off (`0`)
* halfPixelOffset [`0` or `1` or `2` or `3` or `4`] {Off, Normal Vertex, Special (Texture), Special (Texture Aggressive), Align to Native} Default: Off (`0`)
* halfPixelOffset [`0` or `1` or `2` or `3` or `4` or `5`] {Off, Normal Vertex, Special (Texture), Special (Texture Aggressive), Align to Native, Align to Native with Texture Offsets} Default: Off (`0`)
* nativeScaling [`0` or `1` or `2`] {Normal, Aggressive or Off} Default: Normal (`0`)
* nativePaletteDraw [`0` or `1`] {Off, On} Default: Off (`0`)
* roundSprite [`0` or `1` or `2`] {Off, Half or Full} Default: Off (`0`)

View File

@@ -237,7 +237,7 @@
"halfPixelOffset": {
"type": "integer",
"minimum": 0,
"maximum": 4
"maximum": 5
},
"nativeScaling": {
"type": "integer",

View File

@@ -212,10 +212,8 @@ bool GSHwHack::GSC_Tekken5(GSRendererHW& r, int& skip)
{
if (skip == 0)
{
if (r.IsPossibleChannelShuffle())
if (r.IsPossibleChannelShuffle() && (RTBP0 & 31))
{
pxAssertMsg((RTBP0 & 31) == 0, "TEX0 should be page aligned");
GSVertex* v = &r.m_vertex.buff[0];
// Make sure we're detecting the right effect.

View File

@@ -732,7 +732,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(u32& process_rg, u32& process_ba,
GSVector4 GSRendererHW::RealignTargetTextureCoordinate(const GSTextureCache::Source* tex)
{
if (GSConfig.UserHacks_HalfPixelOffset <= GSHalfPixelOffset::Normal ||
GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::Native ||
GSConfig.UserHacks_HalfPixelOffset >= GSHalfPixelOffset::Native ||
GetUpscaleMultiplier() == 1.0f || m_downscale_source || tex->GetScale() == 1.0f)
{
return GSVector4(0.0f);
@@ -826,20 +826,34 @@ void GSRendererHW::MergeSprite(GSTextureCache::Source* tex)
// Tested on Tekken 5.
const GSVertex* v = &m_vertex.buff[0];
bool is_paving = true;
bool is_paving_h = true;
bool is_paving_v = true;
// SSE optimization: shuffle m[1] to have (4*32 bits) X, Y, U, V
const int first_dpX = v[1].XYZ.X - v[0].XYZ.X;
const int first_dpU = v[1].U - v[0].U;
const int first_dpY = v[1].XYZ.Y - v[0].XYZ.Y;
const int first_dpV = v[1].V - v[0].V;
for (u32 i = 0; i < m_vertex.next; i += 2)
{
const int dpX = v[i + 1].XYZ.X - v[i].XYZ.X;
const int dpU = v[i + 1].U - v[i].U;
const int dpY = v[i + 1].XYZ.Y - v[i].XYZ.Y;
const int dpV = v[i + 1].V - v[i].V;
if (dpX != first_dpX || dpU != first_dpU)
{
is_paving = false;
break;
is_paving_h = false;
}
}
if (dpY != first_dpY || dpV != first_dpV)
{
is_paving_v = false;
}
if (!is_paving_h && !is_paving_v)
break;
}
is_paving = is_paving_h || is_paving_v;
#if 0
const GSVector4 delta_p = m_vt.m_max.p - m_vt.m_min.p;
const GSVector4 delta_t = m_vt.m_max.t - m_vt.m_min.t;
@@ -850,20 +864,92 @@ void GSRendererHW::MergeSprite(GSTextureCache::Source* tex)
if (is_paving)
{
// Replace all sprite with a single fullscreen sprite.
u32 unique_verts = 2;
GSVertex* s = &m_vertex.buff[0];
if (is_paving_h)
{
s[0].XYZ.X = static_cast<u16>((16.0f * m_vt.m_min.p.x) + m_context->XYOFFSET.OFX);
s[1].XYZ.X = static_cast<u16>((16.0f * m_vt.m_max.p.x) + m_context->XYOFFSET.OFX);
s[0].XYZ.X = static_cast<u16>((16.0f * m_vt.m_min.p.x) + m_context->XYOFFSET.OFX);
s[1].XYZ.X = static_cast<u16>((16.0f * m_vt.m_max.p.x) + m_context->XYOFFSET.OFX);
s[0].XYZ.Y = static_cast<u16>((16.0f * m_vt.m_min.p.y) + m_context->XYOFFSET.OFY);
s[1].XYZ.Y = static_cast<u16>((16.0f * m_vt.m_max.p.y) + m_context->XYOFFSET.OFY);
s[0].U = static_cast<u16>(16.0f * m_vt.m_min.t.x);
s[1].U = static_cast<u16>(16.0f * m_vt.m_max.t.x);
}
else
{
for (u32 i = 2; i < (m_vertex.tail & ~1); i++)
{
bool unique_found = false;
s[0].U = static_cast<u16>(16.0f * m_vt.m_min.t.x);
s[0].V = static_cast<u16>(16.0f * m_vt.m_min.t.y);
s[1].U = static_cast<u16>(16.0f * m_vt.m_max.t.x);
s[1].V = static_cast<u16>(16.0f * m_vt.m_max.t.y);
for (u32 j = i & 1; j < unique_verts; i += 2)
{
if (s[i].XYZ.X != s[j].XYZ.X)
{
unique_found = true;
break;
}
}
if (unique_found)
{
unique_verts += 2;
s[unique_verts - 2].XYZ.X = s[i & ~1].XYZ.X;
s[unique_verts - 1].XYZ.X = s[i | 1].XYZ.X;
s[unique_verts - 2].U = s[i & ~1].U;
s[unique_verts - 1].U = s[i | 1].U;
m_vertex.head = m_vertex.tail = m_vertex.next = 2;
m_index.tail = 2;
s[unique_verts - 2].XYZ.Y = static_cast<u16>((16.0f * m_vt.m_min.p.y) + m_context->XYOFFSET.OFY);
s[unique_verts - 1].XYZ.Y = static_cast<u16>((16.0f * m_vt.m_max.p.y) + m_context->XYOFFSET.OFY);
s[unique_verts - 2].V = static_cast<u16>(16.0f * m_vt.m_min.t.y);
s[unique_verts - 1].V = static_cast<u16>(16.0f * m_vt.m_max.t.y);
i |= 1;
}
}
}
if (is_paving_v)
{
s[0].XYZ.Y = static_cast<u16>((16.0f * m_vt.m_min.p.y) + m_context->XYOFFSET.OFY);
s[1].XYZ.Y = static_cast<u16>((16.0f * m_vt.m_max.p.y) + m_context->XYOFFSET.OFY);
s[0].V = static_cast<u16>(16.0f * m_vt.m_min.t.y);
s[1].V = static_cast<u16>(16.0f * m_vt.m_max.t.y);
}
else
{
for (u32 i = 2; i < (m_vertex.tail & ~1); i++)
{
bool unique_found = false;
for (u32 j = i & 1; j < unique_verts; i+=2)
{
if (s[i].XYZ.Y != s[j].XYZ.Y)
{
unique_found = true;
break;
}
}
if (unique_found)
{
unique_verts += 2;
s[unique_verts - 2].XYZ.Y = s[i & ~1].XYZ.Y;
s[unique_verts - 1].XYZ.Y = s[i | 1].XYZ.Y;
s[unique_verts - 2].V = s[i & ~1].V;
s[unique_verts - 1].V = s[i | 1].V;
s[unique_verts - 2].XYZ.X = static_cast<u16>((16.0f * m_vt.m_min.p.x) + m_context->XYOFFSET.OFX);
s[unique_verts - 1].XYZ.X = static_cast<u16>((16.0f * m_vt.m_max.p.x) + m_context->XYOFFSET.OFX);
s[unique_verts - 2].U = static_cast<u16>(16.0f * m_vt.m_min.t.x);
s[unique_verts - 1].U = static_cast<u16>(16.0f * m_vt.m_max.t.x);
i |= 1;
}
}
}
m_vertex.head = m_vertex.tail = m_vertex.next = unique_verts;
m_index.tail = unique_verts;
}
}
}
@@ -2750,7 +2836,7 @@ void GSRendererHW::Draw()
// Preserve downscaled target when copying directly from a downscaled target, or it's a normal draw using a downscaled target. Clears that are drawing to the target can also preserve size.
// Of course if this size is different (in width) or this is a shuffle happening, this will be bypassed.
const bool preserve_downscale_draw = scale_draw < 0 || (scale_draw == 0 && ((src && src->m_from_target && src->m_from_target->m_downscaled) || is_possible_mem_clear == ClearType::ClearWithDraw));
const bool preserve_downscale_draw = std::abs(scale_draw) == 1 || (scale_draw == 0 && ((src && src->m_from_target && src->m_from_target->m_downscaled) || is_possible_mem_clear == ClearType::ClearWithDraw));
rt = g_texture_cache->LookupTarget(FRAME_TEX0, t_size, ((src && src->m_scale != 1) && GSConfig.UserHacks_NativeScaling == GSNativeScaling::Normal && !possible_shuffle) ? GetTextureScaleFactor() : target_scale, GSTextureCache::RenderTarget, true,
fm, false, force_preload, preserve_rt_rgb, preserve_rt_alpha, unclamped_draw_rect, possible_shuffle, is_possible_mem_clear && FRAME_TEX0.TBP0 != m_cached_ctx.ZBUF.Block(), GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && preserve_downscale_draw && is_possible_mem_clear != ClearType::NormalClear);
@@ -4119,14 +4205,14 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
const bool AA1 = PRIM->AA1 && (m_vt.m_primclass == GS_LINE_CLASS || m_vt.m_primclass == GS_TRIANGLE_CLASS);
// PABE: Check condition early as an optimization, no blending when As < 128.
// For Cs*As + Cd*(1 - As) if As is 128 then blending can be disabled as well.
const bool PABE = PRIM->ABE && m_draw_env->PABE.PABE &&
const bool PABE_skip = PRIM->ABE && m_draw_env->PABE.PABE &&
((GetAlphaMinMax().max < 128) || (GetAlphaMinMax().max == 128 && ALPHA.A == 0 && ALPHA.B == 1 && ALPHA.C == 0 && ALPHA.D == 1));
// FBMASK: Color is not written, no need to do blending.
const u32 temp_fbmask = m_conf.ps.dst_fmt == GSLocalMemory::PSM_FMT_16 ? 0x00F8F8F8 : 0x00FFFFFF;
const bool FBMASK = (m_cached_ctx.FRAME.FBMSK & temp_fbmask) == temp_fbmask;
const bool FBMASK_skip = (m_cached_ctx.FRAME.FBMSK & temp_fbmask) == temp_fbmask;
// No blending or coverage anti-aliasing so early exit
if (FBMASK || PABE || !(PRIM->ABE || AA1))
if (FBMASK_skip || PABE_skip || !(PRIM->ABE || AA1))
{
m_conf.blend = {};
m_conf.ps.no_color1 = true;
@@ -4288,11 +4374,14 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
// HW blend can handle Cd output.
bool color_dest_blend = !!(blend_flag & BLEND_CD);
// Per pixel alpha blending.
const bool PABE = m_draw_env->PABE.PABE && GetAlphaMinMax().min < 128;
// HW blend can handle it, no need for sw or hdr colclip, Cd*Alpha or Cd*(1 - Alpha) where Alpha <= 128.
bool color_dest_blend2 = !m_draw_env->PABE.PABE && ((m_conf.ps.blend_a == 1 && m_conf.ps.blend_b == 2 && m_conf.ps.blend_d == 2) || (m_conf.ps.blend_a == 2 && m_conf.ps.blend_b == 1 && m_conf.ps.blend_d == 1)) &&
bool color_dest_blend2 = !PABE && ((m_conf.ps.blend_a == 1 && m_conf.ps.blend_b == 2 && m_conf.ps.blend_d == 2) || (m_conf.ps.blend_a == 2 && m_conf.ps.blend_b == 1 && m_conf.ps.blend_d == 1)) &&
(alpha_eq_less_one || (alpha_c1_eq_less_max_one && new_rt_alpha_scale));
// HW blend can handle it, no need for sw or hdr colclip, Cs*Alpha + Cd*(1 - Alpha) or Cd*Alpha + Cs*(1 - Alpha) where Alpha <= 128.
bool blend_zero_to_one_range = !m_draw_env->PABE.PABE && ((m_conf.ps.blend_a == 0 && m_conf.ps.blend_b == 1 && m_conf.ps.blend_d == 1) || (blend_flag & BLEND_MIX3)) &&
bool blend_zero_to_one_range = !PABE && ((m_conf.ps.blend_a == 0 && m_conf.ps.blend_b == 1 && m_conf.ps.blend_d == 1) || (blend_flag & BLEND_MIX3)) &&
(alpha_eq_less_one || (alpha_c1_eq_less_max_one && new_rt_alpha_scale));
// Do the multiplication in shader for blending accumulation: Cs*As + Cd or Cs*Af + Cd
@@ -4511,7 +4600,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
}
// Per pixel alpha blending
if (m_draw_env->PABE.PABE && GetAlphaMinMax().min < 128)
if (PABE)
{
// Breath of Fire Dragon Quarter, Strawberry Shortcake, Super Robot Wars, Cartoon Network Racing, Simple 2000 Series Vol.81, SOTC.
@@ -4541,7 +4630,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
// HDR mode should be disabled when doing sw blend, swap with sw colclip.
if (m_conf.ps.hdr)
{
bool has_HDR_texture = g_gs_device->GetHDRTexture() != nullptr;
const bool has_HDR_texture = g_gs_device->GetHDRTexture() != nullptr;
m_conf.ps.hdr = 0;
m_conf.ps.colclip = 1;
m_conf.hdr_mode = has_HDR_texture ? GSHWDrawConfig::HDRMode::EarlyResolve : GSHWDrawConfig::HDRMode::NoModify;
@@ -5074,6 +5163,26 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
const GSVector4 half_pixel = RealignTargetTextureCoordinate(tex);
m_conf.cb_vs.texture_offset = GSVector2(half_pixel.x, half_pixel.y);
// Can be seen with the cabin part of the ship in God of War, offsets are required when using FST.
// ST uses a normalized position so doesn't need an offset here, will break Bionicle Heroes.
if (GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::NativeWTexOffset)
{
if (!m_downscale_source && tex->m_scale > 1.0f)
{
const GSVertex* v = &m_vertex.buff[0];
if (PRIM->FST)
{
const int x1_frac = ((v[1].XYZ.X - m_context->XYOFFSET.OFX) & 0xf);
const int y1_frac = ((v[1].XYZ.Y - m_context->XYOFFSET.OFY) & 0xf);
if (!(x1_frac & 8))
m_conf.cb_vs.texture_offset.x = 6.0f + (0.25f * tex->m_scale);
if (!(y1_frac & 8))
m_conf.cb_vs.texture_offset.y = 6.0f + (0.25f * tex->m_scale);
}
}
}
}
else if (tex->m_target)
{
@@ -5125,6 +5234,33 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
const GSVector4 half_pixel = RealignTargetTextureCoordinate(tex);
m_conf.cb_vs.texture_offset = GSVector2(half_pixel.x, half_pixel.y);
if (GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::NativeWTexOffset)
{
if (!m_downscale_source && tex->m_scale > 1.0f)
{
const GSVertex* v = &m_vertex.buff[0];
if (PRIM->FST)
{
const int x1_frac = ((v[1].XYZ.X - m_context->XYOFFSET.OFX) & 0xf);
const int y1_frac = ((v[1].XYZ.Y - m_context->XYOFFSET.OFY) & 0xf);
if (!(x1_frac & 8))
m_conf.cb_vs.texture_offset.x = 6.0f + (0.25f * tex->m_scale);
if (!(y1_frac & 8))
m_conf.cb_vs.texture_offset.y = 6.0f + (0.25f * tex->m_scale);
}
else
{
const float tw = static_cast<float>(1 << m_cached_ctx.TEX0.TW);
const float th = static_cast<float>(1 << m_cached_ctx.TEX0.TH);
const float q = v[0].RGBAQ.Q;
m_conf.cb_vs.texture_offset.x = 0.5f * q / tw;
m_conf.cb_vs.texture_offset.y = 0.5f * q / th;
}
}
}
if (m_vt.m_primclass == GS_SPRITE_CLASS && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal > 0 && m_index.tail >= 4)
{
HandleManualDeswizzle();
@@ -5454,7 +5590,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
// When using native HPO, the top-left column/row of pixels are often not drawn. Clamp these away to avoid sampling black,
// causing bleeding into the edges of the downsampled texture.
const u32 downsample_factor = static_cast<u32>(src_target->GetScale());
const GSVector2i clamp_min = (GSConfig.UserHacks_HalfPixelOffset != GSHalfPixelOffset::Native) ?
const GSVector2i clamp_min = (GSConfig.UserHacks_HalfPixelOffset < GSHalfPixelOffset::Native) ?
GSVector2i(0, 0) :
GSVector2i(downsample_factor, downsample_factor);
GSVector4i copy_rect = tmm.coverage;
@@ -6186,7 +6322,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
float sx, sy, ox2, oy2;
const float ox = static_cast<float>(static_cast<int>(m_context->XYOFFSET.OFX));
const float oy = static_cast<float>(static_cast<int>(m_context->XYOFFSET.OFY));
if (GSConfig.UserHacks_HalfPixelOffset != GSHalfPixelOffset::Native && rtscale > 1.0f)
if ((GSConfig.UserHacks_HalfPixelOffset < GSHalfPixelOffset::Native || m_channel_shuffle) && rtscale > 1.0f)
{
sx = 2.0f * rtscale / (rtsize.x << 4);
sy = 2.0f * rtscale / (rtsize.y << 4);
@@ -6215,8 +6352,31 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
const int unscaled_y = rt_or_ds ? rt_or_ds->GetUnscaledHeight() : 0;
sx = 2.0f / (unscaled_x << 4);
sy = 2.0f / (unscaled_y << 4);
ox2 = -1.0f / unscaled_x;
oy2 = -1.0f / unscaled_y;
if (GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::NativeWTexOffset)
{
ox2 = (-1.0f / (unscaled_x * rtscale));
oy2 = (-1.0f / (unscaled_y * rtscale));
// Having the vertex negatively offset is a common thing for copying sprites but this causes problems when upscaling, so we need to further adjust the offset.
// This kinda screws things up when using ST, so let's not.
if (m_vt.m_primclass == GS_SPRITE_CLASS && rtscale > 1.0f && (!tex || PRIM->FST))
{
const GSVertex* v = &m_vertex.buff[0];
const int x1_frac = ((v[1].XYZ.X - m_context->XYOFFSET.OFX) & 0xf);
const int y1_frac = ((v[1].XYZ.Y - m_context->XYOFFSET.OFY) & 0xf);
if (x1_frac & 8)
ox2 *= 1.0f + ((static_cast<float>(16 - x1_frac) / 8.0f) * rtscale);
if (y1_frac & 8)
oy2 *= 1.0f + ((static_cast<float>(16 - y1_frac) / 8.0f) * rtscale);
}
}
else
{
ox2 = -1.0f / unscaled_x;
oy2 = -1.0f / unscaled_y;
}
}
m_conf.cb_vs.vertex_scale = GSVector2(sx, sy);
@@ -6333,7 +6493,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
if (ate_second_pass)
{
pxAssert(!env.PABE.PABE);
pxAssert(!m_conf.ps.pabe);
std::memcpy(&m_conf.alpha_second_pass.ps, &m_conf.ps, sizeof(m_conf.ps));
std::memcpy(&m_conf.alpha_second_pass.colormask, &m_conf.colormask, sizeof(m_conf.colormask));

View File

@@ -2132,8 +2132,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
// And invalidate the target, we're drawing over it so we don't care what's there.
// We can't do this when upscaling, because of the vertex offset, the top/left rows often aren't drawn.
GL_INS("TC: Invalidating%s target %s[%x] because it's completely overwritten.", to_string(type),
(scale > 1.0f && GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::Native) ? "[clearing] " : "", dst->m_TEX0.TBP0);
if (scale > 1.0f && GSConfig.UserHacks_HalfPixelOffset != GSHalfPixelOffset::Native)
(scale > 1.0f && GSConfig.UserHacks_HalfPixelOffset >= GSHalfPixelOffset::Native) ? "[clearing] " : "", dst->m_TEX0.TBP0);
if (scale > 1.0f && GSConfig.UserHacks_HalfPixelOffset < GSHalfPixelOffset::Native)
{
if (dst->m_type == RenderTarget)
g_gs_device->ClearRenderTarget(dst->m_texture, 0);

View File

@@ -593,15 +593,14 @@ void GameList::ScanDirectory(const char* path, bool recursive, bool only_cache,
progress->PushState();
progress->SetStatusText(fmt::format(
recursive ? TRANSLATE_FS("GameList", "Scanning directory {} (recursively)...") :
TRANSLATE_FS("GameList", "Scanning directory {}..."),
path)
.c_str());
TRANSLATE_FS("GameList", "Scanning directory {}..."),
path).c_str());
FileSystem::FindResultsArray files;
FileSystem::FindFiles(path, "*",
recursive ? (FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RECURSIVE) :
(FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES),
&files);
(FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES),
&files, progress);
u32 files_scanned = 0;
progress->SetProgressRange(static_cast<u32>(files.size()));

View File

@@ -138,6 +138,15 @@ void Host::ClearTranslationCache()
s_translation_string_mutex.unlock();
}
void Host::ReportFormattedInfoAsync(const std::string_view title, const char* format, ...)
{
std::va_list ap;
va_start(ap, format);
std::string message(StringUtil::StdStringFromFormatV(format, ap));
va_end(ap);
ReportInfoAsync(title, message);
}
void Host::ReportFormattedErrorAsync(const std::string_view title, const char* format, ...)
{
std::va_list ap;

View File

@@ -55,6 +55,10 @@ namespace Host
void RemoveKeyedOSDMessage(std::string key);
void ClearOSDMessages();
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller.
void ReportInfoAsync(const std::string_view title, const std::string_view message);
void ReportFormattedInfoAsync(const std::string_view title, const char* format, ...);
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller.
void ReportErrorAsync(const std::string_view title, const std::string_view message);
void ReportFormattedErrorAsync(const std::string_view title, const char* format, ...);

View File

@@ -7,7 +7,7 @@
#include "common/Console.h"
#include "common/Error.h"
#include <SDL.h>
#include <SDL3/SDL.h>
namespace
{
@@ -23,11 +23,11 @@ namespace
void CloseDevice();
protected:
__fi bool IsOpen() const { return (m_device_id != 0); }
__fi bool IsOpen() const { return (m_stream != nullptr); }
static void AudioCallback(void* userdata, uint8_t* stream, int len);
static void AudioCallback(void* userdata, SDL_AudioStream* stream, int additional_amount, int total_amount);
u32 m_device_id = 0;
SDL_AudioStream* m_stream = nullptr;
};
} // namespace
@@ -41,7 +41,7 @@ static bool InitializeSDLAudio(Error* error)
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "PCSX2");
// May as well keep it alive until the process exits.
if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0)
if (!SDL_InitSubSystem(SDL_INIT_AUDIO))
{
Error::SetStringFmt(error, "SDL_InitSubSystem(SDL_INIT_AUDIO) failed: {}", SDL_GetError());
return false;
@@ -102,27 +102,24 @@ bool SDLAudioStream::OpenDevice(bool stretch_enabled, Error* error)
READ_CHANNEL_REAR_LEFT, READ_CHANNEL_REAR_RIGHT>,
}};
SDL_AudioSpec spec = {};
spec.freq = m_sample_rate;
spec.channels = m_output_channels;
spec.format = AUDIO_S16;
spec.samples = static_cast<Uint16>(GetBufferSizeForMS(
m_sample_rate, (m_parameters.minimal_output_latency) ? m_parameters.buffer_ms : m_parameters.output_latency_ms));
spec.callback = AudioCallback;
spec.userdata = static_cast<void*>(this);
uint samples = GetBufferSizeForMS(
m_sample_rate, (m_parameters.minimal_output_latency) ? m_parameters.buffer_ms : m_parameters.output_latency_ms);
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES, fmt::format("{}", samples).c_str());
const SDL_AudioSpec spec = {SDL_AUDIO_S16LE, m_output_channels, static_cast<int>(m_sample_rate)};
m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, AudioCallback, static_cast<void*>(this));
SDL_AudioSpec obtained_spec = {};
m_device_id = SDL_OpenAudioDevice(nullptr, 0, &spec, &obtained_spec, SDL_AUDIO_ALLOW_SAMPLES_CHANGE);
if (m_device_id == 0)
{
Error::SetStringFmt(error, "SDL_OpenAudioDevice() failed: {}", SDL_GetError());
return false;
}
int obtained_samples = 0;
DEV_LOG("Requested {} frame buffer, got {} frame buffer", spec.samples, obtained_spec.samples);
if (SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &obtained_spec, &obtained_samples))
DEV_LOG("Requested {} frame buffer, got {} frame buffer", samples, obtained_samples);
else
DEV_LOG("SDL_GetAudioDeviceFormat() failed {}", SDL_GetError());
BaseInitialize(sample_readers[static_cast<size_t>(m_parameters.expansion_mode)], stretch_enabled);
SDL_PauseAudioDevice(m_device_id, 0);
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream));
return true;
}
@@ -132,20 +129,33 @@ void SDLAudioStream::SetPaused(bool paused)
if (m_paused == paused)
return;
SDL_PauseAudioDevice(m_device_id, paused ? 1 : 0);
if (paused)
SDL_PauseAudioDevice(SDL_GetAudioStreamDevice(m_stream));
else
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream));
m_paused = paused;
}
void SDLAudioStream::CloseDevice()
{
SDL_CloseAudioDevice(m_device_id);
m_device_id = 0;
SDL_DestroyAudioStream(m_stream);
m_stream = nullptr;
}
void SDLAudioStream::AudioCallback(void* userdata, uint8_t* stream, int len)
void SDLAudioStream::AudioCallback(void* userdata, SDL_AudioStream* stream, int additional_amount, int total_amount)
{
SDLAudioStream* const this_ptr = static_cast<SDLAudioStream*>(userdata);
const u32 num_frames = len / sizeof(SampleType) / this_ptr->m_output_channels;
if (additional_amount > 0)
{
SDLAudioStream* const this_ptr = static_cast<SDLAudioStream*>(userdata);
this_ptr->ReadFrames(reinterpret_cast<SampleType*>(stream), num_frames);
const u32 num_frames = additional_amount / sizeof(SampleType) / this_ptr->m_output_channels;
SampleType* buffer = SDL_stack_alloc(SampleType, additional_amount / sizeof(SampleType));
if (buffer)
{
this_ptr->ReadFrames(buffer, num_frames);
SDL_PutAudioStreamData(stream, buffer, additional_amount);
SDL_stack_free(buffer);
}
}
}

View File

@@ -237,6 +237,7 @@ namespace FullscreenUI
static void DrawAboutWindow();
static void OpenAboutWindow();
static void GetStandardSelectionFooterText(SmallStringBase& dest, bool back_instead_of_cancel);
static void ApplyConfirmSetting(const SettingsInterface* bsi = nullptr);
static MainWindowType s_current_main_window = MainWindowType::None;
static PauseSubMenu s_current_pause_submenu = PauseSubMenu::None;
@@ -504,18 +505,23 @@ void FullscreenUI::GetStandardSelectionFooterText(SmallStringBase& dest, bool ba
{
if (IsGamepadInputSource())
{
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
ImGuiFullscreen::CreateFooterTextString(
dest,
std::array{std::make_pair(ICON_PF_DPAD_UP_DOWN, FSUI_VSTR("Change Selection")),
std::make_pair(ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_BUTTON_CIRCLE, back_instead_of_cancel ? FSUI_VSTR("Back") : FSUI_VSTR("Cancel"))});
std::array{
std::make_pair(ICON_PF_DPAD_UP_DOWN, FSUI_VSTR("Change Selection")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, back_instead_of_cancel ? FSUI_VSTR("Back") : FSUI_VSTR("Cancel")),
});
}
else
{
ImGuiFullscreen::CreateFooterTextString(
dest, std::array{std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN, FSUI_VSTR("Change Selection")),
dest, std::array{
std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN, FSUI_VSTR("Change Selection")),
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_ESC, back_instead_of_cancel ? FSUI_VSTR("Back") : FSUI_VSTR("Cancel"))});
std::make_pair(ICON_PF_ESC, back_instead_of_cancel ? FSUI_VSTR("Back") : FSUI_VSTR("Cancel")),
});
}
}
@@ -535,19 +541,25 @@ void ImGuiFullscreen::GetFileSelectorHelpText(SmallStringBase& dest)
{
if (IsGamepadInputSource())
{
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
ImGuiFullscreen::CreateFooterTextString(
dest, std::array{std::make_pair(ICON_PF_DPAD_UP_DOWN, FSUI_VSTR("Change Selection")),
dest, std::array{
std::make_pair(ICON_PF_DPAD_UP_DOWN, FSUI_VSTR("Change Selection")),
std::make_pair(ICON_PF_BUTTON_TRIANGLE, FSUI_VSTR("Parent Directory")),
std::make_pair(ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Cancel"))});
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Cancel")),
});
}
else
{
ImGuiFullscreen::CreateFooterTextString(
dest,
std::array{std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN, FSUI_VSTR("Change Selection")),
std::array{
std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN, FSUI_VSTR("Change Selection")),
std::make_pair(ICON_PF_BACKSPACE, FSUI_VSTR("Parent Directory")),
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")), std::make_pair(ICON_PF_ESC, FSUI_VSTR("Cancel"))});
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Cancel")),
});
}
}
@@ -555,18 +567,81 @@ void ImGuiFullscreen::GetInputDialogHelpText(SmallStringBase& dest)
{
if (IsGamepadInputSource())
{
CreateFooterTextString(dest, std::array{std::make_pair(ICON_PF_KEYBOARD, FSUI_VSTR("Enter Value")),
std::make_pair(ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Cancel"))});
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
CreateFooterTextString(dest, std::array{
std::make_pair(ICON_PF_KEYBOARD, FSUI_VSTR("Enter Value")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Cancel")),
});
}
else
{
CreateFooterTextString(dest, std::array{std::make_pair(ICON_PF_KEYBOARD, FSUI_VSTR("Enter Value")),
CreateFooterTextString(dest, std::array{
std::make_pair(ICON_PF_KEYBOARD, FSUI_VSTR("Enter Value")),
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Cancel"))});
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Cancel")),
});
}
}
void FullscreenUI::ApplyConfirmSetting(const SettingsInterface* bsi)
{
ImGuiIO& io = ImGui::GetIO();
SmallString swap_mode;
if (bsi)
swap_mode = bsi->GetSmallStringValue("UI", "SwapOKFullscreenUI", "auto");
else
swap_mode = Host::GetBaseSmallStringSettingValue("UI", "SwapOKFullscreenUI", "auto");
if (swap_mode == "true")
io.ConfigNavSwapGamepadButtons = true;
else if (swap_mode == "false")
io.ConfigNavSwapGamepadButtons = false;
else if (swap_mode == "auto")
{
// Check language
if (Host::LocaleCircleConfirm())
{
io.ConfigNavSwapGamepadButtons = true;
return;
}
// Check BIOS
SmallString bios_selection;
if (bsi)
bios_selection = bsi->GetSmallStringValue("Filenames", "BIOS", "");
else
bios_selection = Host::GetBaseSmallStringSettingValue("Filenames", "BIOS", "");
if (bios_selection != "")
{
u32 bios_version, bios_region;
std::string bios_description, bios_zone;
if (IsBIOS(Path::Combine(EmuFolders::Bios, bios_selection).c_str(), bios_version, bios_description, bios_region, bios_zone))
{
// Japan, Asia, China
if (bios_region == 0 || bios_region == 4 || bios_region == 6)
{
io.ConfigNavSwapGamepadButtons = true;
return;
}
}
}
// X is confirm
io.ConfigNavSwapGamepadButtons = false;
return;
}
// Invalid setting
else
io.ConfigNavSwapGamepadButtons = false;
}
void FullscreenUI::LocaleChanged()
{
ApplyConfirmSetting();
}
//////////////////////////////////////////////////////////////////////////
// Main
//////////////////////////////////////////////////////////////////////////
@@ -579,8 +654,9 @@ bool FullscreenUI::Initialize()
if (s_tried_to_initialize)
return false;
ImGuiFullscreen::SetTheme(Host::GetBaseBoolSettingValue("UI", "UseLightFullscreenUITheme", false));
ImGuiFullscreen::SetTheme(Host::GetBaseStringSettingValue("UI", "FullscreenUITheme", "Dark"));
ImGuiFullscreen::UpdateLayoutScale();
ApplyConfirmSetting();
if (!ImGuiManager::AddFullscreenFontsIfMissing() || !ImGuiFullscreen::Initialize("fullscreenui/placeholder.png") || !LoadResources())
{
@@ -632,6 +708,8 @@ void FullscreenUI::CheckForConfigChanges(const Pcsx2Config& old_config)
if (!IsInitialized())
return;
ImGuiFullscreen::SetTheme(Host::GetBaseStringSettingValue("UI", "FullscreenUITheme", "Dark"));
// If achievements got disabled, we might have the menu open...
// That means we're going to be reaching achievement state.
if (old_config.Achievements.Enabled && !EmuConfig.Achievements.Enabled)
@@ -645,6 +723,13 @@ void FullscreenUI::CheckForConfigChanges(const Pcsx2Config& old_config)
});
MTGS::WaitGS(false, false, false);
}
if (old_config.FullpathToBios() != EmuConfig.FullpathToBios())
{
MTGS::RunOnGSThread([]() {
ApplyConfirmSetting();
});
}
}
void FullscreenUI::OnVMStarted()
@@ -1306,13 +1391,14 @@ void FullscreenUI::DrawLandingWindow()
if (IsGamepadInputSource())
{
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_SELECT_SHARE, FSUI_VSTR("About")),
std::make_pair(ICON_PF_DPAD_LEFT_RIGHT, FSUI_VSTR("Navigate")),
std::make_pair(ICON_PF_BUTTON_TRIANGLE, FSUI_VSTR("Game List")),
std::make_pair(ICON_PF_BUTTON_SQUARE, FSUI_VSTR("Toggle Fullscreen")),
std::make_pair(ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Exit"))
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Exit")),
});
}
else
@@ -1323,7 +1409,7 @@ void FullscreenUI::DrawLandingWindow()
std::make_pair(ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, FSUI_VSTR("Navigate")),
std::make_pair(ICON_PF_SPACE, FSUI_VSTR("Game List")),
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Exit"))
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Exit")),
});
}
}
@@ -1378,17 +1464,22 @@ void FullscreenUI::DrawStartGameWindow()
if (IsGamepadInputSource())
{
SetFullscreenFooterText(std::array{std::make_pair(ICON_PF_DPAD_LEFT_RIGHT, FSUI_VSTR("Navigate")),
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_DPAD_LEFT_RIGHT, FSUI_VSTR("Navigate")),
std::make_pair(ICON_PF_BUTTON_SQUARE, FSUI_VSTR("Load Global State")),
std::make_pair(ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Back"))});
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Back")),
});
}
else
{
SetFullscreenFooterText(std::array{std::make_pair(ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, FSUI_VSTR("Navigate")),
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, FSUI_VSTR("Navigate")),
std::make_pair(ICON_PF_F1, FSUI_VSTR("Load Global State")),
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Back"))});
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Back")),
});
}
}
@@ -1430,19 +1521,20 @@ void FullscreenUI::DrawExitWindow()
if (IsGamepadInputSource())
{
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_DPAD_LEFT_RIGHT, FSUI_VSTR("Navigate")),
std::make_pair(ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Back"))}
);
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Back")),
});
}
else
{
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, FSUI_VSTR("Navigate")),
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Back"))}
);
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Back")),
});
}
}
@@ -1518,7 +1610,9 @@ void FullscreenUI::DrawInputBindingButton(
return;
if (oneline)
InputManager::PrettifyInputBinding(value);
InputManager::PrettifyInputBinding(value, true);
else
InputManager::PrettifyInputBinding(value, false);
if (show_type)
{
@@ -3008,11 +3102,13 @@ void FullscreenUI::DrawSettingsWindow()
if (IsGamepadInputSource())
{
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_DPAD_LEFT_RIGHT, FSUI_VSTR("Change Page")),
std::make_pair(ICON_PF_DPAD_UP_DOWN, FSUI_VSTR("Navigate")),
std::make_pair(ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Back"))});
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Back")),
});
}
else
{
@@ -3020,7 +3116,8 @@ void FullscreenUI::DrawSettingsWindow()
std::make_pair(ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, FSUI_VSTR("Change Page")),
std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN, FSUI_VSTR("Navigate")),
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Back"))});
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Back")),
});
}
}
@@ -3139,17 +3236,50 @@ void FullscreenUI::DrawSummarySettingsPage()
void FullscreenUI::DrawInterfaceSettingsPage()
{
static constexpr const char* s_theme_name[] = {
FSUI_NSTR("Dark"),
FSUI_NSTR("Light"),
FSUI_NSTR("Grey Matter"),
FSUI_NSTR("Untouched Lagoon"),
FSUI_NSTR("Baby Pastel"),
FSUI_NSTR("Pizza Time!"),
FSUI_NSTR("PCSX2 Blue"),
FSUI_NSTR("Scarlet Devil"),
FSUI_NSTR("Violet Angel"),
FSUI_NSTR("Cobalt Sky"),
FSUI_NSTR("AMOLED"),
};
static constexpr const char* s_theme_value[] = {
"Dark",
"Light",
"GreyMatter",
"UntouchedLagoon",
"BabyPastel",
"PizzaBrown",
"PCSX2Blue",
"ScarletDevil",
"VioletAngel",
"CobaltSky",
"AMOLED",
};
SettingsInterface* bsi = GetEditingSettingsInterface();
BeginMenuButtons();
MenuHeading(FSUI_CSTR("Behaviour"));
MenuHeading(FSUI_CSTR("Appearance"));
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINT_BRUSH, "Theme"),
FSUI_CSTR("Selects the color style to be used for Big Picture Mode."),
"UI", "FullscreenUITheme", "Dark", s_theme_name, s_theme_value, std::size(s_theme_name), true);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_INFO_CIRCLE, "Use Save State Selector"),
FSUI_CSTR("Show a save state selector UI when switching slots instead of showing a notification bubble."),
"EmuCore", "UseSavestateSelector", true);
MenuHeading(FSUI_CSTR("Behaviour"));
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_SNOOZE, "Inhibit Screensaver"),
FSUI_CSTR("Prevents the screen saver from activating and the host from sleeping while emulation is running."), "EmuCore",
"InhibitScreensaver", true);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_USER_CIRCLE, "Enable Discord Presence"),
FSUI_CSTR("Shows the game you are currently playing as part of your profile on Discord."), "UI", "DiscordPresence", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_PAUSE, "Pause On Start"), FSUI_CSTR("Pauses the emulator when a game is started."), "UI",
"StartPaused", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_EYE, "Pause On Focus Loss"),
@@ -3169,15 +3299,56 @@ void FullscreenUI::DrawInterfaceSettingsPage()
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_ARCHIVE, "Create Save State Backups"),
FSUI_CSTR("Creates a backup copy of a save state if it already exists when the save is created. The backup copy has a .backup suffix"),
"EmuCore", "BackupSavestate", true);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_INFO_CIRCLE, "Use Save State Selector"),
FSUI_CSTR("Show a save state selector UI when switching slots instead of showing a notification bubble."),
"EmuCore", "UseSavestateSelector", true);
if (DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LIGHTBULB, "Use Light Theme"),
FSUI_CSTR("Uses a light coloured theme instead of the default dark theme."), "UI", "UseLightFullscreenUITheme", false))
// DrawStringListSetting dosn't have a callback for applying settings
const SmallString swap_mode = bsi->GetSmallStringValue("UI", "SwapOKFullscreenUI", "auto");
static constexpr const char* swap_names[] = {
FSUI_NSTR("Automatic"),
FSUI_NSTR("Enabled"),
FSUI_NSTR("Disabled"),
};
static constexpr const char* swap_values[] = {
"auto",
"true",
"false",
};
size_t swap_index = std::size(swap_values);
for (size_t i = 0; i < std::size(swap_values); i++)
{
ImGuiFullscreen::SetTheme(bsi->GetBoolValue("UI", "UseLightFullscreenUITheme", false));
if (swap_mode == swap_values[i])
{
swap_index = i;
break;
}
}
SmallStackString<256> swap_summery;
swap_summery.format(FSUI_FSTR("Uses {} as confirm when using a controller"), ICON_PF_BUTTON_CIRCLE);
if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Swap OK/Cancel in Big Picture Mode"), swap_summery.c_str(),
(swap_index < std::size(swap_values)) ? Host::TranslateToCString(TR_CONTEXT, swap_names[swap_index]) : FSUI_CSTR("Unknown")))
{
ImGuiFullscreen::ChoiceDialogOptions cd_options;
cd_options.reserve(std::size(swap_values));
for (size_t i = 0; i < std::size(swap_values); i++)
cd_options.emplace_back(Host::TranslateToString(TR_CONTEXT, swap_names[i]), i == static_cast<size_t>(swap_index));
OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Swap OK/Cancel in Big Picture Mode"), false, std::move(cd_options), [](s32 index, const std::string& title, bool checked) {
if (index >= 0)
{
auto lock = Host::GetSettingsLock();
SettingsInterface* bsi = GetEditingSettingsInterface(false);
bsi->SetStringValue("UI", "SwapOKFullscreenUI", swap_values[index]);
SetSettingsChanged(bsi);
ApplyConfirmSetting(bsi);
}
CloseChoiceDialog();
});
}
MenuHeading(FSUI_CSTR("Integration"));
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_USER_CIRCLE, "Enable Discord Presence"),
FSUI_CSTR("Shows the game you are currently playing as part of your profile on Discord."), "UI", "DiscordPresence", false);
MenuHeading(FSUI_CSTR("Game Display"));
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TV, "Start Fullscreen"),
FSUI_CSTR("Automatically switches to fullscreen mode when a game is started."), "UI", "StartFullscreen", false);
@@ -3291,6 +3462,7 @@ void FullscreenUI::DrawBIOSSettingsPage()
SettingsInterface* bsi = GetEditingSettingsInterface(game_settings);
bsi->SetStringValue("Filenames", "BIOS", values[index].c_str());
SetSettingsChanged(bsi);
ApplyConfirmSetting(bsi);
CloseChoiceDialog();
});
}
@@ -3809,7 +3981,8 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
FSUI_NSTR("Normal (Vertex)"),
FSUI_NSTR("Special (Texture)"),
FSUI_NSTR("Special (Texture - Aggressive)"),
FSUI_NSTR("Align To Native"),
FSUI_NSTR("Align to Native"),
FSUI_NSTR("Align to Native - with Texture Offset"),
};
static constexpr const char* s_native_scaling_options[] = {
FSUI_NSTR("Normal (Default)"),
@@ -3977,8 +4150,8 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
static constexpr const char* s_gsdump_compression[] = {
FSUI_NSTR("Uncompressed"),
FSUI_NSTR("LZMA (xz)"),
FSUI_NSTR("Zstandard (zst)")
};
FSUI_NSTR("Zstandard (zst)"),
};
if (show_advanced_settings)
{
@@ -4314,11 +4487,11 @@ void FullscreenUI::DrawControllerSettingsPage()
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COG, "Enable SDL Input Source"),
FSUI_CSTR("The SDL input source supports most controllers."), "InputSources", "SDL", true, true, false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_WIFI, "SDL DualShock 4 / DualSense Enhanced Mode"),
FSUI_CSTR("Provides vibration and LED control support over Bluetooth."), "InputSources", "SDLControllerEnhancedMode", false,
FSUI_CSTR("Provides vibration and LED control support over Bluetooth."), "InputSources", "SDLControllerEnhancedMode", true,
bsi->GetBoolValue("InputSources", "SDL", true), false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LIGHTBULB, "SDL DualSense Player LED"),
FSUI_CSTR("Enable/Disable the Player LED on DualSense controllers."), "InputSources", "SDLPS5PlayerLED", false,
bsi->GetBoolValue("InputSources", "SDLControllerEnhancedMode", true), false);
FSUI_CSTR("Enable/Disable the Player LED on DualSense controllers."), "InputSources", "SDLPS5PlayerLED", true,
bsi->GetBoolValue("InputSources", "SDLControllerEnhancedMode", true), true);
#ifdef _WIN32
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COG, "SDL Raw Input"), FSUI_CSTR("Allow SDL to use raw access to input devices."),
"InputSources", "SDLRawInput", false, bsi->GetBoolValue("InputSources", "SDL", true), false);
@@ -4768,14 +4941,14 @@ void FullscreenUI::DrawAdvancedSettingsPage()
FSUI_NSTR("Uncompressed"),
FSUI_NSTR("Deflate64"),
FSUI_NSTR("Zstandard"),
FSUI_NSTR("LZMA2")
FSUI_NSTR("LZMA2"),
};
static constexpr const char* s_savestate_compression_ratio[] = {
FSUI_NSTR("Low (Fast)"),
FSUI_NSTR("Medium (Recommended)"),
FSUI_NSTR("High"),
FSUI_NSTR("Very High (Slow, Not Recommended)")
FSUI_NSTR("Very High (Slow, Not Recommended)"),
};
if (show_advanced_settings)
@@ -5252,15 +5425,20 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
if (IsGamepadInputSource())
{
SetFullscreenFooterText(std::array{std::make_pair(ICON_PF_DPAD_UP_DOWN, FSUI_VSTR("Change Selection")),
std::make_pair(ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Return To Game"))});
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_DPAD_UP_DOWN, FSUI_VSTR("Change Selection")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Return To Game")),
});
}
else
{
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN, FSUI_VSTR("Change Selection")),
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")), std::make_pair(ICON_PF_ESC, FSUI_VSTR("Return To Game"))});
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Return To Game")),
});
}
}
@@ -5685,18 +5863,22 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
{
if (IsGamepadInputSource())
{
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_DPAD, FSUI_VSTR("Select State")),
std::make_pair(ICON_PF_BUTTON_SQUARE, FSUI_VSTR("Options")),
std::make_pair(ICON_PF_BUTTON_CROSS, FSUI_VSTR("Load/Save State")),
std::make_pair(ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Cancel"))});
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Load/Save State")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Cancel")),
});
}
else
{
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, FSUI_VSTR("Select State")),
std::make_pair(ICON_PF_F1, FSUI_VSTR("Options")), std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Load/Save State")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Cancel"))});
std::make_pair(ICON_PF_F1, FSUI_VSTR("Options")),
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Load/Save State")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Cancel")),
});
}
}
}
@@ -5980,21 +6162,26 @@ void FullscreenUI::DrawGameListWindow()
if (IsGamepadInputSource())
{
const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons;
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_DPAD, FSUI_VSTR("Select Game")),
std::make_pair(ICON_PF_START, FSUI_VSTR("Settings")),
std::make_pair(ICON_PF_BUTTON_TRIANGLE, FSUI_VSTR("Change View")),
std::make_pair(ICON_PF_BUTTON_SQUARE, FSUI_VSTR("Launch Options")),
std::make_pair(ICON_PF_BUTTON_CROSS, FSUI_VSTR("Start Game")),
std::make_pair(ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Back"))});
std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Start Game")),
std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Back")),
});
}
else
{
SetFullscreenFooterText(std::array{
std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, FSUI_VSTR("Select Game")),
std::make_pair(ICON_PF_F1, FSUI_VSTR("Change View")), std::make_pair(ICON_PF_F2, FSUI_VSTR("Settings")),
std::make_pair(ICON_PF_F3, FSUI_VSTR("Launch Options")), std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Start Game")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Back"))});
std::make_pair(ICON_PF_F1, FSUI_VSTR("Change View")),
std::make_pair(ICON_PF_F2, FSUI_VSTR("Settings")),
std::make_pair(ICON_PF_F3, FSUI_VSTR("Launch Options")),
std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Start Game")),
std::make_pair(ICON_PF_ESC, FSUI_VSTR("Back")),
});
}
}
@@ -6966,9 +7153,11 @@ TRANSLATE_NOOP("FullscreenUI", "Input Profile");
TRANSLATE_NOOP("FullscreenUI", "Options");
TRANSLATE_NOOP("FullscreenUI", "Copies the current global settings to this game.");
TRANSLATE_NOOP("FullscreenUI", "Clears all settings set for this game.");
TRANSLATE_NOOP("FullscreenUI", "Appearance");
TRANSLATE_NOOP("FullscreenUI", "Selects the color style to be used for Big Picture Mode.");
TRANSLATE_NOOP("FullscreenUI", "Show a save state selector UI when switching slots instead of showing a notification bubble.");
TRANSLATE_NOOP("FullscreenUI", "Behaviour");
TRANSLATE_NOOP("FullscreenUI", "Prevents the screen saver from activating and the host from sleeping while emulation is running.");
TRANSLATE_NOOP("FullscreenUI", "Shows the game you are currently playing as part of your profile on Discord.");
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a game is started.");
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you minimize the window or switch to another application, and unpauses when you switch back.");
TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a controller with bindings is disconnected.");
@@ -6976,8 +7165,8 @@ TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you open the quick menu
TRANSLATE_NOOP("FullscreenUI", "Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed.");
TRANSLATE_NOOP("FullscreenUI", "Automatically saves the emulator state when powering down or exiting. You can then resume directly from where you left off next time.");
TRANSLATE_NOOP("FullscreenUI", "Creates a backup copy of a save state if it already exists when the save is created. The backup copy has a .backup suffix");
TRANSLATE_NOOP("FullscreenUI", "Show a save state selector UI when switching slots instead of showing a notification bubble.");
TRANSLATE_NOOP("FullscreenUI", "Uses a light coloured theme instead of the default dark theme.");
TRANSLATE_NOOP("FullscreenUI", "Integration");
TRANSLATE_NOOP("FullscreenUI", "Shows the game you are currently playing as part of your profile on Discord.");
TRANSLATE_NOOP("FullscreenUI", "Game Display");
TRANSLATE_NOOP("FullscreenUI", "Automatically switches to fullscreen mode when a game is started.");
TRANSLATE_NOOP("FullscreenUI", "Switches between full screen and windowed when the window is double-clicked.");
@@ -7384,6 +7573,7 @@ TRANSLATE_NOOP("FullscreenUI", "Automatic mapping completed for {}.");
TRANSLATE_NOOP("FullscreenUI", "Automatic mapping failed for {}.");
TRANSLATE_NOOP("FullscreenUI", "Game settings initialized with global settings for '{}'.");
TRANSLATE_NOOP("FullscreenUI", "Game settings have been cleared for '{}'.");
TRANSLATE_NOOP("FullscreenUI", "Uses {} as confirm when using a controller");
TRANSLATE_NOOP("FullscreenUI", "Slot {}");
TRANSLATE_NOOP("FullscreenUI", "{} (Current)");
TRANSLATE_NOOP("FullscreenUI", "{} (Folder)");
@@ -7428,6 +7618,19 @@ TRANSLATE_NOOP("FullscreenUI", "Folder Settings");
TRANSLATE_NOOP("FullscreenUI", "Advanced Settings");
TRANSLATE_NOOP("FullscreenUI", "Patches");
TRANSLATE_NOOP("FullscreenUI", "Cheats");
TRANSLATE_NOOP("FullscreenUI", "Dark");
TRANSLATE_NOOP("FullscreenUI", "Light");
TRANSLATE_NOOP("FullscreenUI", "Grey Matter");
TRANSLATE_NOOP("FullscreenUI", "Untouched Lagoon");
TRANSLATE_NOOP("FullscreenUI", "Baby Pastel");
TRANSLATE_NOOP("FullscreenUI", "Pizza Time!");
TRANSLATE_NOOP("FullscreenUI", "PCSX2 Blue");
TRANSLATE_NOOP("FullscreenUI", "Scarlet Devil");
TRANSLATE_NOOP("FullscreenUI", "Violet Angel");
TRANSLATE_NOOP("FullscreenUI", "Cobalt Sky");
TRANSLATE_NOOP("FullscreenUI", "AMOLED");
TRANSLATE_NOOP("FullscreenUI", "Enabled");
TRANSLATE_NOOP("FullscreenUI", "Disabled");
TRANSLATE_NOOP("FullscreenUI", "2% [1 FPS (NTSC) / 1 FPS (PAL)]");
TRANSLATE_NOOP("FullscreenUI", "10% [6 FPS (NTSC) / 5 FPS (PAL)]");
TRANSLATE_NOOP("FullscreenUI", "25% [15 FPS (NTSC) / 12 FPS (PAL)]");
@@ -7550,13 +7753,13 @@ TRANSLATE_NOOP("FullscreenUI", "Sprites/Triangles");
TRANSLATE_NOOP("FullscreenUI", "Blended Sprites/Triangles");
TRANSLATE_NOOP("FullscreenUI", "1 (Normal)");
TRANSLATE_NOOP("FullscreenUI", "2 (Aggressive)");
TRANSLATE_NOOP("FullscreenUI", "Disabled");
TRANSLATE_NOOP("FullscreenUI", "Inside Target");
TRANSLATE_NOOP("FullscreenUI", "Merge Targets");
TRANSLATE_NOOP("FullscreenUI", "Normal (Vertex)");
TRANSLATE_NOOP("FullscreenUI", "Special (Texture)");
TRANSLATE_NOOP("FullscreenUI", "Special (Texture - Aggressive)");
TRANSLATE_NOOP("FullscreenUI", "Align To Native");
TRANSLATE_NOOP("FullscreenUI", "Align to Native");
TRANSLATE_NOOP("FullscreenUI", "Align to Native - with Texture Offset");
TRANSLATE_NOOP("FullscreenUI", "Aggressive");
TRANSLATE_NOOP("FullscreenUI", "Half");
TRANSLATE_NOOP("FullscreenUI", "Force Bilinear");
@@ -7630,8 +7833,9 @@ TRANSLATE_NOOP("FullscreenUI", "Select Disc Path");
TRANSLATE_NOOP("FullscreenUI", "Cannot show details for games which were not scanned in the game list.");
TRANSLATE_NOOP("FullscreenUI", "Copy Settings");
TRANSLATE_NOOP("FullscreenUI", "Clear Settings");
TRANSLATE_NOOP("FullscreenUI", "Theme");
TRANSLATE_NOOP("FullscreenUI", "Use Save State Selector");
TRANSLATE_NOOP("FullscreenUI", "Inhibit Screensaver");
TRANSLATE_NOOP("FullscreenUI", "Enable Discord Presence");
TRANSLATE_NOOP("FullscreenUI", "Pause On Start");
TRANSLATE_NOOP("FullscreenUI", "Pause On Focus Loss");
TRANSLATE_NOOP("FullscreenUI", "Pause On Controller Disconnection");
@@ -7639,8 +7843,8 @@ TRANSLATE_NOOP("FullscreenUI", "Pause On Menu");
TRANSLATE_NOOP("FullscreenUI", "Confirm Shutdown");
TRANSLATE_NOOP("FullscreenUI", "Save State On Shutdown");
TRANSLATE_NOOP("FullscreenUI", "Create Save State Backups");
TRANSLATE_NOOP("FullscreenUI", "Use Save State Selector");
TRANSLATE_NOOP("FullscreenUI", "Use Light Theme");
TRANSLATE_NOOP("FullscreenUI", "Swap OK/Cancel in Big Picture Mode");
TRANSLATE_NOOP("FullscreenUI", "Enable Discord Presence");
TRANSLATE_NOOP("FullscreenUI", "Start Fullscreen");
TRANSLATE_NOOP("FullscreenUI", "Double-Click Toggles Fullscreen");
TRANSLATE_NOOP("FullscreenUI", "Hide Cursor In Fullscreen");

View File

@@ -32,6 +32,7 @@ namespace FullscreenUI
void ReturnToPreviousWindow();
void ReturnToMainWindow();
void SetStandardSelectionFooterText(bool back_instead_of_cancel);
void LocaleChanged();
void Shutdown(bool clear_state);
void Render();
@@ -51,4 +52,7 @@ namespace Host
void OnCoverDownloaderOpenRequested();
void OnCreateMemoryCardOpenRequested();
/// Did Playstation in the currently selected locale use circle as confirm
bool LocaleCircleConfirm();
} // namespace Host

View File

@@ -86,7 +86,6 @@ namespace ImGuiFullscreen
static u32 s_menu_button_index = 0;
static u32 s_close_button_state = 0;
static FocusResetType s_focus_reset_queued = FocusResetType::None;
static bool s_light_theme = false;
static LRUCache<std::string, std::shared_ptr<GSTexture>> s_texture_cache(128, true);
static std::shared_ptr<GSTexture> s_placeholder_texture;
@@ -2668,10 +2667,10 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
ImFont* const title_font = ImGuiFullscreen::g_large_font;
ImFont* const text_font = ImGuiFullscreen::g_medium_font;
const u32 toast_background_color = s_light_theme ? IM_COL32(241, 241, 241, 255) : IM_COL32(0x21, 0x21, 0x21, 255);
const u32 toast_border_color = s_light_theme ? IM_COL32(0x88, 0x88, 0x88, 255) : IM_COL32(0x48, 0x48, 0x48, 255);
const u32 toast_title_color = s_light_theme ? IM_COL32(1, 1, 1, 255) : IM_COL32(0xff, 0xff, 0xff, 255);
const u32 toast_text_color = s_light_theme ? IM_COL32(0, 0, 0, 255) : IM_COL32(0xff, 0xff, 0xff, 255);
const u32 toast_background_color = IM_COL32(0x21, 0x21, 0x21, 255);
const u32 toast_border_color = IM_COL32(0x48, 0x48, 0x48, 255);
const u32 toast_title_color = IM_COL32(0xff, 0xff, 0xff, 255);
const u32 toast_text_color = IM_COL32(0xff, 0xff, 0xff, 255);
for (u32 index = 0; index < static_cast<u32>(s_notifications.size());)
{
@@ -2839,13 +2838,10 @@ void ImGuiFullscreen::DrawToast()
}
}
void ImGuiFullscreen::SetTheme(bool light)
void ImGuiFullscreen::SetTheme(std::string_view theme)
{
s_light_theme = light;
if (!light)
if (theme == "Dark")
{
// dark
UIBackgroundColor = HEX_TO_IMVEC4(0x212121, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff);
@@ -2863,9 +2859,8 @@ void ImGuiFullscreen::SetTheme(bool light)
UISecondaryWeakColor = HEX_TO_IMVEC4(0x002171, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
}
else
else if (theme == "Light")
{
// light
UIBackgroundColor = HEX_TO_IMVEC4(0xc8c8c8, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0xe1e2e1, 0xff);
@@ -2883,4 +2878,175 @@ void ImGuiFullscreen::SetTheme(bool light)
UISecondaryWeakColor = HEX_TO_IMVEC4(0xc0cfff, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
}
else if (theme == "AMOLED")
{
UIBackgroundColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff);
UIBackgroundHighlightColor = HEX_TO_IMVEC4(0x0c0c0c, 0xff);
UIPopupBackgroundColor = HEX_TO_IMVEC4(0x212121, 0xf2);
UIPrimaryColor = HEX_TO_IMVEC4(0x0a0a0a, 0xff);
UIPrimaryLightColor = HEX_TO_IMVEC4(0xb5b5b5, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIPrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIDisabledColor = HEX_TO_IMVEC4(0x8d8d8d, 0xff);
UITextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff);
UIPrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UISecondaryColor = HEX_TO_IMVEC4(0x969696, 0xff);
UISecondaryStrongColor = HEX_TO_IMVEC4(0x191919, 0xff);
UISecondaryWeakColor = HEX_TO_IMVEC4(0x474747, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
}
else if (theme == "CobaltSky")
{
UIBackgroundColor = HEX_TO_IMVEC4(0x2b3760, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff);
UIBackgroundHighlightColor = HEX_TO_IMVEC4(0x3b54ac, 0xff);
UIPopupBackgroundColor = HEX_TO_IMVEC4(0x2b3760, 0xf2);
UIPrimaryColor = HEX_TO_IMVEC4(0x202e5a, 0xff);
UIPrimaryLightColor = HEX_TO_IMVEC4(0xb5b5b5, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0x222c4d, 0xff);
UIPrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIDisabledColor = HEX_TO_IMVEC4(0x8d8d8d, 0xff);
UITextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff);
UIPrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UISecondaryColor = HEX_TO_IMVEC4(0x969696, 0xff);
UISecondaryStrongColor = HEX_TO_IMVEC4(0x245dda, 0xff);
UISecondaryWeakColor = HEX_TO_IMVEC4(0x3a3d7b, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
}
else if (theme == "GreyMatter")
{
UIBackgroundColor = HEX_TO_IMVEC4(0x353944, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff);
UIBackgroundHighlightColor = HEX_TO_IMVEC4(0x484d57, 0xff);
UIPopupBackgroundColor = HEX_TO_IMVEC4(0x212121, 0xf2);
UIPrimaryColor = HEX_TO_IMVEC4(0x292d35, 0xff);
UIPrimaryLightColor = HEX_TO_IMVEC4(0xb5b5b5, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0x212121, 0xff);
UIPrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIDisabledColor = HEX_TO_IMVEC4(0x8d8d8d, 0xff);
UITextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff);
UIPrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UISecondaryColor = HEX_TO_IMVEC4(0x969696, 0xff);
UISecondaryStrongColor = HEX_TO_IMVEC4(0x191919, 0xff);
UISecondaryWeakColor = HEX_TO_IMVEC4(0x2a2e36, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
}
else if (theme == "UntouchedLagoon")
{
UIBackgroundColor = HEX_TO_IMVEC4(0x9db1bb, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff);
UIBackgroundHighlightColor = HEX_TO_IMVEC4(0x1b7f7f, 0xff);
UIPopupBackgroundColor = HEX_TO_IMVEC4(0x488c8c, 0xf2);
UIPrimaryColor = HEX_TO_IMVEC4(0xa2c2bc, 0xff);
UIPrimaryLightColor = HEX_TO_IMVEC4(0xadcfc8, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0x488c8c, 0xff);
UIPrimaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIDisabledColor = HEX_TO_IMVEC4(0x4b4b4b, 0xff);
UITextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff);
UIPrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UISecondaryColor = HEX_TO_IMVEC4(0x969696, 0xff);
UISecondaryStrongColor = HEX_TO_IMVEC4(0x2a5151, 0xff);
UISecondaryWeakColor = HEX_TO_IMVEC4(0x475055, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
}
else if (theme == "BabyPastel")
{
UIBackgroundColor = HEX_TO_IMVEC4(0xf1d9ee, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0xe05885, 0xff);
UIBackgroundHighlightColor = HEX_TO_IMVEC4(0xe05885, 0xff);
UIPopupBackgroundColor = HEX_TO_IMVEC4(0xeba0b9, 0xf2);
UIPrimaryColor = HEX_TO_IMVEC4(0xffaec9, 0xff);
UIPrimaryLightColor = HEX_TO_IMVEC4(0xe05885, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0xc3859a, 0xff);
UIPrimaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIDisabledColor = HEX_TO_IMVEC4(0x4b4b4b, 0xff);
UITextHighlightColor = HEX_TO_IMVEC4(0xeba0b9, 0xff);
UIPrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UISecondaryColor = HEX_TO_IMVEC4(0xe05885, 0xff);
UISecondaryStrongColor = HEX_TO_IMVEC4(0xdc6c68, 0xff);
UISecondaryWeakColor = HEX_TO_IMVEC4(0xab5451, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
}
else if (theme == "PizzaBrown")
{
UIBackgroundColor = HEX_TO_IMVEC4(0xd9c9ba, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff);
UIBackgroundHighlightColor = HEX_TO_IMVEC4(0xaa5a36, 0xff);
UIPopupBackgroundColor = HEX_TO_IMVEC4(0xefad42, 0xf2);
UIPrimaryColor = HEX_TO_IMVEC4(0xe9bb93, 0xff);
UIPrimaryLightColor = HEX_TO_IMVEC4(0xf9e7ac, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0xefad42, 0xff);
UIPrimaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIDisabledColor = HEX_TO_IMVEC4(0x4b4b4b, 0xff);
UITextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff);
UIPrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UISecondaryColor = HEX_TO_IMVEC4(0x969696, 0xff);
UISecondaryStrongColor = HEX_TO_IMVEC4(0xaf1c2f, 0xff);
UISecondaryWeakColor = HEX_TO_IMVEC4(0xab5451, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
}
else if (theme == "ScarletDevil")
{
UIBackgroundColor = HEX_TO_IMVEC4(0x782c44, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff);
UIBackgroundHighlightColor = HEX_TO_IMVEC4(0xa73e5f, 0xff);
UIPopupBackgroundColor = HEX_TO_IMVEC4(0x88475d, 0xf2);
UIPrimaryColor = HEX_TO_IMVEC4(0x4f2c44, 0xff);
UIPrimaryLightColor = HEX_TO_IMVEC4(0xb5b5b5, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0x632438, 0xff);
UIPrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIDisabledColor = HEX_TO_IMVEC4(0x969696, 0xff);
UITextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff);
UIPrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UISecondaryColor = HEX_TO_IMVEC4(0x969696, 0xff);
UISecondaryStrongColor = HEX_TO_IMVEC4(0xc80000, 0xff);
UISecondaryWeakColor = HEX_TO_IMVEC4(0x8a334e, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
}
else if (theme == "VioletAngel")
{
UIBackgroundColor = HEX_TO_IMVEC4(0x6e1e7d, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0x862c9c, 0xff);
UIBackgroundHighlightColor = HEX_TO_IMVEC4(0x862c9c, 0xff);
UIPopupBackgroundColor = HEX_TO_IMVEC4(0x502657, 0xf2);
UIPrimaryColor = HEX_TO_IMVEC4(0x321846, 0xff);
UIPrimaryLightColor = HEX_TO_IMVEC4(0x9833d6, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0x70269e, 0xff);
UIPrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIDisabledColor = HEX_TO_IMVEC4(0x969696, 0xff);
UITextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff);
UIPrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UISecondaryColor = HEX_TO_IMVEC4(0xe200cb, 0xff);
UISecondaryStrongColor = HEX_TO_IMVEC4(0xff00e6, 0xff);
UISecondaryWeakColor = HEX_TO_IMVEC4(0x561d79, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
}
else if (theme == "PCSX2Blue")
{
UIBackgroundColor = HEX_TO_IMVEC4(0x819af0, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0x89a5ff, 0xff);
UIBackgroundHighlightColor = HEX_TO_IMVEC4(0xfefffe, 0xff);
UIPopupBackgroundColor = HEX_TO_IMVEC4(0xb4cffe, 0xf2);
UIPrimaryColor = HEX_TO_IMVEC4(0x92b6fe, 0xff);
UIPrimaryLightColor = HEX_TO_IMVEC4(0x89a5ff, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0x7c8ef3, 0xff);
UIPrimaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIDisabledColor = HEX_TO_IMVEC4(0x4b4b4b, 0xff);
UITextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff);
UIPrimaryLineColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UISecondaryColor = HEX_TO_IMVEC4(0x92b6fe, 0xff);
UISecondaryStrongColor = HEX_TO_IMVEC4(0x0c53c5, 0xff);
UISecondaryWeakColor = HEX_TO_IMVEC4(0x819af0, 0xff);
UISecondaryTextColor = HEX_TO_IMVEC4(0x000000, 0xff);
}
}

View File

@@ -91,7 +91,7 @@ namespace ImGuiFullscreen
/// Initializes, setting up any state.
bool Initialize(const char* placeholder_image_path);
void SetTheme(bool light);
void SetTheme(std::string_view theme);
void SetFonts(ImFont* standard_font, ImFont* medium_font, ImFont* large_font);
bool UpdateLayoutScale();

View File

@@ -489,7 +489,7 @@ bool ImGuiManager::AddIconFonts(float size)
{
// clang-format off
static constexpr ImWchar range_fa[] = { 0xe06f,0xe06f,0xf002,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf021,0xf023,0xf025,0xf028,0xf02b,0xf02b,0xf02e,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03e,0xf04b,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf05a,0xf05a,0xf05e,0xf05e,0xf063,0xf063,0xf067,0xf067,0xf06a,0xf06a,0xf06e,0xf06e,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf084,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c8,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf11b,0xf11c,0xf120,0xf121,0xf129,0xf12a,0xf140,0xf140,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf187,0xf188,0xf191,0xf192,0xf1b3,0xf1b3,0xf1de,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf21e,0xf21e,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2bd,0xf2bd,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf462,0xf462,0xf466,0xf466,0xf4e2,0xf4e2,0xf51f,0xf51f,0xf545,0xf545,0xf54c,0xf54c,0xf553,0xf553,0xf56d,0xf56d,0xf5a2,0xf5a2,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf70e,0xf70e,0xf756,0xf756,0xf780,0xf780,0xf794,0xf794,0xf815,0xf815,0xf84c,0xf84c,0xf8cc,0xf8cc,0x0,0x0 };
static constexpr ImWchar range_pf[] = { 0x2198,0x2199,0x219e,0x21a3,0x21b0,0x21b3,0x21ba,0x21c3,0x21ce,0x21ce,0x21d0,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21f3,0x21f3,0x21f7,0x21f8,0x21fa,0x21fb,0x221a,0x221a,0x227a,0x227d,0x22bf,0x22c8,0x2349,0x2349,0x235a,0x235e,0x2360,0x2361,0x2364,0x2367,0x237a,0x237b,0x237d,0x237d,0x237f,0x237f,0x23b2,0x23b5,0x23cc,0x23cc,0x23f4,0x23f7,0x2427,0x243a,0x243d,0x243d,0x2443,0x2443,0x2460,0x246b,0x248f,0x248f,0x24f5,0x24fd,0x24ff,0x24ff,0x2605,0x2605,0x2699,0x2699,0x278a,0x278e,0xe001,0xe001,0xff21,0xff3a,0x0,0x0 };
static constexpr ImWchar range_pf[] = { 0x2198,0x2199,0x219e,0x21a7,0x21b0,0x21b3,0x21ba,0x21c3,0x21ce,0x21ce,0x21d0,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21e6,0x21e8,0x21f3,0x21f3,0x21f7,0x21f8,0x21fa,0x21fb,0x2206,0x2208,0x221a,0x221a,0x227a,0x227d,0x22bf,0x22c8,0x2349,0x2349,0x235a,0x235e,0x2360,0x2361,0x2364,0x2367,0x237a,0x237b,0x237d,0x237d,0x237f,0x237f,0x23b2,0x23b5,0x23cc,0x23cc,0x23f4,0x23f7,0x2427,0x243a,0x243d,0x243d,0x2443,0x2443,0x2460,0x246b,0x248f,0x248f,0x24f5,0x24fd,0x24ff,0x24ff,0x2605,0x2605,0x2699,0x2699,0x278a,0x278e,0xe000,0xe001,0xff21,0xff3a,0x0,0x0 };
// clang-format on
{

View File

@@ -45,6 +45,17 @@ std::string DInputSource::GetDeviceIdentifier(u32 index)
return fmt::format("DInput-{}", index);
}
static constexpr const char* s_dinput_axis_names[] = {
"X Axis",
"Y Axis",
"Z Axis",
"Z Rotation",
"X Rotation",
"Y Rotation",
"Slider 1",
"Slider 2",
};
static constexpr std::array<const char*, DInputSource::NUM_HAT_DIRECTIONS> s_hat_directions = {{"Up", "Down", "Left", "Right"}};
bool DInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock)
@@ -150,6 +161,15 @@ void DInputSource::Shutdown()
GetDeviceIdentifier(index));
m_controllers.pop_back();
}
m_toplevel_window = nullptr;
m_dinput.reset();
m_dinput_module.reset();
}
bool DInputSource::IsInitialized()
{
return m_toplevel_window;
}
bool DInputSource::AddDevice(ControllerData& cd, const std::string& name)
@@ -379,7 +399,7 @@ std::optional<InputBindingKey> DInputSource::ParseKeyString(const std::string_vi
return std::nullopt;
}
TinyString DInputSource::ConvertKeyToString(InputBindingKey key)
TinyString DInputSource::ConvertKeyToString(InputBindingKey key, bool display, bool migration)
{
TinyString ret;
@@ -387,18 +407,33 @@ TinyString DInputSource::ConvertKeyToString(InputBindingKey key)
{
if (key.source_subtype == InputSubclass::ControllerAxis)
{
const char* modifier = (key.modifier == InputModifier::FullAxis ? "Full" : (key.modifier == InputModifier::Negate ? "-" : "+"));
ret.format("DInput-{}/{}Axis{}{}", u32(key.source_index), modifier, u32(key.data), (key.invert && !ShouldIgnoreInversion()) ? "~" : "");
const char* modifier = (key.modifier == InputModifier::FullAxis ? (display ? "Full " : "Full") : (key.modifier == InputModifier::Negate ? "-" : "+"));
if (display)
{
if (key.data < std::size(s_dinput_axis_names))
ret.format("DInput-{} {}{}{}", u32(key.source_index), modifier, s_dinput_axis_names[key.data], key.invert ? "~" : "");
else
ret.format("DInput-{} {}Axis {}{}", u32(key.source_index), modifier, u32(key.data) + 1, key.invert ? "~" : "");
}
else
ret.format("DInput-{}/{}Axis{}{}", u32(key.source_index), modifier, u32(key.data), (key.invert && (migration || !ShouldIgnoreInversion())) ? "~" : "");
}
else if (key.source_subtype == InputSubclass::ControllerButton && key.data >= MAX_NUM_BUTTONS)
{
// Note, hats currently get mapped to buttons
const u32 hat_num = (key.data - MAX_NUM_BUTTONS) / NUM_HAT_DIRECTIONS;
const u32 hat_dir = (key.data - MAX_NUM_BUTTONS) % NUM_HAT_DIRECTIONS;
ret.format("DInput-{}/Hat{}{}", u32(key.source_index), hat_num, s_hat_directions[hat_dir]);
if (display)
ret.format("DInput-{} Hat {} {}", u32(key.source_index), hat_num + 1, s_hat_directions[hat_dir]);
else
ret.format("DInput-{}/Hat{}{}", u32(key.source_index), hat_num, s_hat_directions[hat_dir]);
}
else if (key.source_subtype == InputSubclass::ControllerButton)
{
ret.format("DInput-{}/Button{}", u32(key.source_index), u32(key.data));
if (display)
ret.format("DInput-{} Button {}", u32(key.source_index), u32(key.data) + 1);
else
ret.format("DInput-{}/Button{}", u32(key.source_index), u32(key.data));
}
}

View File

@@ -38,6 +38,7 @@ public:
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
bool ReloadDevices() override;
void Shutdown() override;
bool IsInitialized() override;
void PollEvents() override;
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
@@ -47,7 +48,7 @@ public:
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity, float small_intensity) override;
std::optional<InputBindingKey> ParseKeyString(const std::string_view device, const std::string_view binding) override;
TinyString ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToString(InputBindingKey key, bool display = false, bool migration = false) override;
TinyString ConvertKeyToIcon(InputBindingKey key) override;
private:

View File

@@ -8,6 +8,7 @@
#include "SIO/Sio.h"
#include "USB/USB.h"
#include "VMManager.h"
#include "LayeredSettingsInterface.h"
#include "common/Assertions.h"
#include "common/Console.h"
@@ -92,19 +93,23 @@ namespace InputManager
static std::optional<InputBindingKey> ParseHostKeyboardKey(const std::string_view source, const std::string_view sub_binding);
static std::optional<InputBindingKey> ParsePointerKey(const std::string_view source, const std::string_view sub_binding);
static std::vector<std::string_view> SplitChord(const std::string_view binding);
static TinyString ConvertKeyboardKeyToString(InputBindingKey key, bool display = false);
static TinyString ConvertPointerKeyToString(InputBindingKey key, bool display = false);
static bool SplitBinding(const std::string_view binding, std::string_view* source, std::string_view* sub_binding);
static void PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed);
static void AddBinding(const std::string_view binding, const InputEventHandler& handler);
static void AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler);
static void PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed, bool use_icons);
static std::shared_ptr<InputBinding> AddBinding(const std::string_view binding, const InputEventHandler& handler);
// Will also apply SDL2-SDL3 migrations and update the provided section & key
static void AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler,
InputBindingInfo::Type binding_type, SettingsInterface& si, const char* section, const char* key, bool is_profile);
static bool ParseBindingAndGetSource(const std::string_view binding, InputBindingKey* key, InputSource** source);
static bool IsAxisHandler(const InputEventHandler& handler);
static float ApplySingleBindingScale(float sensitivity, float deadzone, float value);
static void AddHotkeyBindings(SettingsInterface& si);
static void AddPadBindings(SettingsInterface& si, u32 pad);
static void AddUSBBindings(SettingsInterface& si, u32 port);
static void AddHotkeyBindings(SettingsInterface& si, bool is_profile);
static void AddPadBindings(SettingsInterface& si, u32 pad, bool is_profile);
static void AddUSBBindings(SettingsInterface& si, u32 port, bool is_profile);
static void UpdateContinuedVibration();
static void GenerateRelativeMouseEvents();
@@ -143,9 +148,12 @@ static const HotkeyInfo* const s_hotkey_list[] = {g_common_hotkeys, g_gs_hotkeys
// Tracking host mouse movement and turning into relative events
// 4 axes: pointer left/right, wheel vertical/horizontal. Last/Next/Normalized.
// ------------------------------------------------------------------------
static constexpr const std::array<const char*, static_cast<u8>(InputPointerAxis::Count)> s_pointer_axis_names = {
static constexpr const std::array<const char*, static_cast<u8>(InputPointerAxis::Count)> s_pointer_axis_setting_names = {
{"X", "Y", "WheelX", "WheelY"}};
static constexpr const std::array<const char*, 3> s_pointer_button_names = {{"LeftButton", "RightButton", "MiddleButton"}};
static constexpr const std::array<const char*, static_cast<u8>(InputPointerAxis::Count)> s_pointer_axis_names = {
{"X", "Y", "Wheel X", "Wheel Y"}};
static constexpr const std::array<const char*, 3> s_pointer_button_setting_names = {{"LeftButton", "RightButton", "MiddleButton"}};
static constexpr const std::array<const char*, 3> s_pointer_button_names = {{"Left Button", "Right Button", "Middle Button"}};
struct PointerAxisState
{
@@ -233,7 +241,7 @@ std::optional<InputBindingKey> InputManager::ParseInputBindingKey(const std::str
{
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i])
if (s_input_sources[i]->IsInitialized())
{
std::optional<InputBindingKey> key = s_input_sources[i]->ParseKeyString(source, sub_binding);
if (key.has_value())
@@ -253,7 +261,7 @@ bool InputManager::ParseBindingAndGetSource(const std::string_view binding, Inpu
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i])
if (s_input_sources[i]->IsInitialized())
{
std::optional<InputBindingKey> parsed_key = s_input_sources[i]->ParseKeyString(source_string, sub_binding);
if (parsed_key.has_value())
@@ -268,7 +276,64 @@ bool InputManager::ParseBindingAndGetSource(const std::string_view binding, Inpu
return false;
}
std::string InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key)
TinyString InputManager::ConvertKeyboardKeyToString(InputBindingKey key, bool display)
{
TinyString ret;
if (key.source_type == InputSourceType::Keyboard)
{
const std::optional<std::string> str(ConvertHostKeyboardCodeToString(key.data));
if (str.has_value() && !str->empty())
{
if (display)
// Keyboard keys arn't spaced out for display yet
ret.format("Keyboard {}", str->c_str());
else
ret.format("Keyboard/{}", str->c_str());
}
}
return ret;
}
TinyString InputManager::ConvertPointerKeyToString(InputBindingKey key, bool display)
{
TinyString ret;
if (key.source_type == InputSourceType::Pointer)
{
if (key.source_subtype == InputSubclass::PointerButton)
{
if (display)
{
if (key.data < s_pointer_button_setting_names.size())
ret.format("Pointer-{} {}", u32{key.source_index}, s_pointer_button_names[key.data]);
else
ret.format("Pointer-{} Button{}", u32{key.source_index}, key.data + 1);
}
else
{
if (key.data < s_pointer_button_setting_names.size())
ret.format("Pointer-{}/{}", u32{key.source_index}, s_pointer_button_setting_names[key.data]);
else
ret.format("Pointer-{}/Button{}", u32{key.source_index}, key.data);
}
}
else if (key.source_subtype == InputSubclass::PointerAxis)
{
if (display)
ret.format("Pointer-{} {}{:c}", u32{key.source_index}, s_pointer_axis_names[key.data],
key.modifier == InputModifier::Negate ? '-' : '+');
else
ret.format("Pointer-{}/{}{:c}", u32{key.source_index}, s_pointer_axis_setting_names[key.data],
key.modifier == InputModifier::Negate ? '-' : '+');
}
}
return ret;
}
std::string InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key, bool migration)
{
if (binding_type == InputBindingInfo::Type::Pointer || binding_type == InputBindingInfo::Type::Device)
{
@@ -295,48 +360,35 @@ std::string InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type
{
if (key.source_type == InputSourceType::Keyboard)
{
const std::optional<std::string> str(ConvertHostKeyboardCodeToString(key.data));
if (str.has_value() && !str->empty())
return fmt::format("Keyboard/{}", str->c_str());
return std::string(ConvertKeyboardKeyToString(key));
}
else if (key.source_type == InputSourceType::Pointer)
{
if (key.source_subtype == InputSubclass::PointerButton)
{
if (key.data < s_pointer_button_names.size())
return fmt::format("Pointer-{}/{}", u32{key.source_index}, s_pointer_button_names[key.data]);
else
return fmt::format("Pointer-{}/Button{}", u32{key.source_index}, key.data);
}
else if (key.source_subtype == InputSubclass::PointerAxis)
{
return fmt::format("Pointer-{}/{}{:c}", u32{key.source_index}, s_pointer_axis_names[key.data],
key.modifier == InputModifier::Negate ? '-' : '+');
}
return std::string(ConvertPointerKeyToString(key));
}
else if (key.source_type < InputSourceType::Count && s_input_sources[static_cast<u32>(key.source_type)])
{
return std::string(s_input_sources[static_cast<u32>(key.source_type)]->ConvertKeyToString(key));
return std::string(s_input_sources[static_cast<u32>(key.source_type)]->ConvertKeyToString(key, false, migration));
}
}
return {};
}
std::string InputManager::ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys, size_t num_keys)
std::string InputManager::ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys, size_t num_keys, bool migration)
{
// can't have a chord of devices/pointers
if (binding_type == InputBindingInfo::Type::Pointer || binding_type == InputBindingInfo::Type::Device)
{
// so only take the first
if (num_keys > 0)
return ConvertInputBindingKeyToString(binding_type, keys[0]);
return ConvertInputBindingKeyToString(binding_type, keys[0], migration);
}
std::stringstream ss;
for (size_t i = 0; i < num_keys; i++)
{
const std::string keystr(ConvertInputBindingKeyToString(binding_type, keys[i]));
const std::string keystr(ConvertInputBindingKeyToString(binding_type, keys[i], migration));
if (keystr.empty())
return std::string();
@@ -349,7 +401,7 @@ std::string InputManager::ConvertInputBindingKeysToString(InputBindingInfo::Type
return ss.str();
}
bool InputManager::PrettifyInputBinding(SmallStringBase& binding)
bool InputManager::PrettifyInputBinding(SmallStringBase& binding, bool use_icons)
{
if (binding.empty())
return false;
@@ -370,7 +422,7 @@ bool InputManager::PrettifyInputBinding(SmallStringBase& binding)
{
if (!ret.empty())
ret.append(" + ");
PrettifyInputBindingPart(part, ret, changed);
PrettifyInputBindingPart(part, ret, changed, use_icons);
}
}
last = next + 1;
@@ -382,7 +434,7 @@ bool InputManager::PrettifyInputBinding(SmallStringBase& binding)
{
if (!ret.empty())
ret.append(" + ");
PrettifyInputBindingPart(part, ret, changed);
PrettifyInputBindingPart(part, ret, changed, use_icons);
}
}
@@ -392,7 +444,7 @@ bool InputManager::PrettifyInputBinding(SmallStringBase& binding)
return changed;
}
void InputManager::PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed)
void InputManager::PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed, bool use_icons)
{
std::string_view source, sub_binding;
if (!SplitBinding(binding, &source, &sub_binding))
@@ -402,12 +454,30 @@ void InputManager::PrettifyInputBindingPart(const std::string_view binding, Smal
if (source.starts_with("Keyboard"))
{
std::optional<InputBindingKey> key = ParseHostKeyboardKey(source, sub_binding);
const char* icon = key.has_value() ? ConvertHostKeyboardCodeToIcon(key->data) : nullptr;
if (icon)
if (key.has_value())
{
ret.append(icon);
changed = true;
return;
if (use_icons)
{
const char* icon = ConvertHostKeyboardCodeToIcon(key->data);
if (icon)
{
ret.append(icon);
changed = true;
return;
}
else
{
ret.append(ConvertKeyboardKeyToString(key.value(), true));
changed = true;
return;
}
}
else
{
ret.append(ConvertKeyboardKeyToString(key.value(), true));
changed = true;
return;
}
}
}
else if (source.starts_with("Pointer"))
@@ -415,7 +485,7 @@ void InputManager::PrettifyInputBindingPart(const std::string_view binding, Smal
const std::optional<InputBindingKey> key = ParsePointerKey(source, sub_binding);
if (key.has_value())
{
if (key->source_subtype == InputSubclass::PointerButton)
if (use_icons && key->source_subtype == InputSubclass::PointerButton)
{
static constexpr const char* button_icons[] = {
ICON_PF_MOUSE_BUTTON_1,
@@ -425,32 +495,41 @@ void InputManager::PrettifyInputBindingPart(const std::string_view binding, Smal
ICON_PF_MOUSE_BUTTON_5,
};
if (key->data < std::size(button_icons))
{
ret.append(button_icons[key->data]);
changed = true;
return;
}
else
ret.append(ConvertPointerKeyToString(key.value(), true));
}
else
ret.append(ConvertPointerKeyToString(key.value(), true));
changed = true;
return;
}
}
else
{
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
// We call ConvertKeyToIcon/String() even on disabled sources
// This ensures consistant appearance between enabled and disabled sources
if (s_input_sources[i])
{
std::optional<InputBindingKey> key = s_input_sources[i]->ParseKeyString(source, sub_binding);
if (key.has_value())
{
const TinyString icon = s_input_sources[i]->ConvertKeyToIcon(key.value());
if (!icon.empty())
if (use_icons)
{
ret.append(icon);
changed = true;
return;
const TinyString icon = s_input_sources[i]->ConvertKeyToIcon(key.value());
if (!icon.empty())
ret.append(icon);
else
ret.append(s_input_sources[i]->ConvertKeyToString(key.value(), true));
}
else
ret.append(s_input_sources[i]->ConvertKeyToString(key.value(), true));
break;
changed = true;
return;
}
}
}
@@ -460,7 +539,7 @@ void InputManager::PrettifyInputBindingPart(const std::string_view binding, Smal
}
void InputManager::AddBinding(const std::string_view binding, const InputEventHandler& handler)
std::shared_ptr<InputBinding> InputManager::AddBinding(const std::string_view binding, const InputEventHandler& handler)
{
std::shared_ptr<InputBinding> ibinding;
const std::vector<std::string_view> chord_bindings(SplitChord(binding));
@@ -494,17 +573,74 @@ void InputManager::AddBinding(const std::string_view binding, const InputEventHa
}
if (!ibinding)
return;
return nullptr;
// plop it in the input map for all the keys
for (u32 i = 0; i < ibinding->num_keys; i++)
s_binding_map.emplace(ibinding->keys[i].MaskDirection(), ibinding);
return ibinding;
}
void InputManager::AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler)
void InputManager::AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler,
InputBindingInfo::Type binding_type, SettingsInterface& si, const char* section, const char* key, bool is_profile)
{
std::vector<std::shared_ptr<InputBinding>> ibindings;
bool migrate = false;
for (const std::string& binding : bindings)
AddBinding(binding, handler);
{
std::shared_ptr<InputBinding> ibinding = AddBinding(binding, handler);
ibindings.push_back(ibinding);
if (ibinding)
{
// Check for SDL2-3 migrations
for (u32 i = 0; i < ibinding->num_keys; i++)
{
if (ibinding->keys[i].needs_migration)
migrate = true;
}
}
}
// Save migrations
if (migrate)
{
std::vector<std::string> new_bindings;
new_bindings.reserve(bindings.size());
for (size_t i = 0; i < bindings.size(); i++)
{
if (ibindings[i])
new_bindings.push_back(ConvertInputBindingKeysToString(binding_type, ibindings[i]->keys, ibindings[i]->num_keys, true));
else
// Retain invalid bindings as is
new_bindings.push_back(bindings[i]);
}
if (is_profile)
{
// INISettingsInterface, can just update directly
si.SetStringList(section, key, new_bindings);
si.Save();
}
else
{
// LayeredSettingsInterface, Need to find which layer our binding came from
LayeredSettingsInterface& lsi = static_cast<LayeredSettingsInterface&>(si);
for (u32 i = 0; i < LayeredSettingsInterface::NUM_LAYERS; i++)
{
SettingsInterface* layer = lsi.GetLayer(static_cast<LayeredSettingsInterface::Layer>(i));
if (layer && layer->GetStringList(section, key) == bindings)
{
// Layer found, update settings
layer->SetStringList(section, key, new_bindings);
layer->Save();
}
}
}
}
}
// ------------------------------------------------------------------------
@@ -632,14 +768,14 @@ std::optional<InputBindingKey> InputManager::ParsePointerKey(const std::string_v
return key;
}
for (u32 i = 0; i < s_pointer_axis_names.size(); i++)
for (u32 i = 0; i < s_pointer_axis_setting_names.size(); i++)
{
if (sub_binding.starts_with(s_pointer_axis_names[i]))
if (sub_binding.starts_with(s_pointer_axis_setting_names[i]))
{
key.source_subtype = InputSubclass::PointerAxis;
key.data = i;
const std::string_view dir_part(sub_binding.substr(std::strlen(s_pointer_axis_names[i])));
const std::string_view dir_part(sub_binding.substr(std::strlen(s_pointer_axis_setting_names[i])));
if (dir_part == "+")
key.modifier = InputModifier::None;
else if (dir_part == "-")
@@ -651,9 +787,9 @@ std::optional<InputBindingKey> InputManager::ParsePointerKey(const std::string_v
}
}
for (u32 i = 0; i < s_pointer_button_names.size(); i++)
for (u32 i = 0; i < s_pointer_button_setting_names.size(); i++)
{
if (sub_binding == s_pointer_button_names[i])
if (sub_binding == s_pointer_button_setting_names[i])
{
key.source_subtype = InputSubclass::PointerButton;
key.data = i;
@@ -702,7 +838,7 @@ std::vector<const HotkeyInfo*> InputManager::GetHotkeyList()
return ret;
}
void InputManager::AddHotkeyBindings(SettingsInterface& si)
void InputManager::AddHotkeyBindings(SettingsInterface& si, bool is_profile)
{
for (const HotkeyInfo* hotkey_list : s_hotkey_list)
{
@@ -712,12 +848,12 @@ void InputManager::AddHotkeyBindings(SettingsInterface& si)
if (bindings.empty())
continue;
AddBindings(bindings, InputButtonEventHandler{hotkey->handler});
AddBindings(bindings, InputButtonEventHandler{hotkey->handler}, InputBindingInfo::Type::Button, si, "Hotkeys", hotkey->name, is_profile);
}
}
}
void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index)
void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, bool is_profile)
{
const Pad::ControllerType type = EmuConfig.Pad.Ports[pad_index].Type;
@@ -752,9 +888,10 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index)
const float sensitivity = si.GetFloatValue(section.c_str(), fmt::format("{}Scale", bi.name).c_str(), 1.0f);
const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("{}Deadzone", bi.name).c_str(), 0.0f);
AddBindings(
bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index, sensitivity, deadzone](float value) {
bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index, sensitivity, deadzone](InputBindingKey key, float value) {
Pad::SetControllerState(pad_index, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
}});
}},
bi.bind_type, si, section.c_str(), bi.name, is_profile);
}
}
break;
@@ -772,10 +909,12 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index)
if (!bindings.empty())
{
const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("Macro{}Deadzone", macro_button_index + 1).c_str(), 0.0f);
AddBindings(bindings, InputAxisEventHandler{[pad_index, macro_button_index, deadzone](float value) {
const bool state = (value > deadzone);
Pad::SetMacroButtonState(pad_index, macro_button_index, state);
}});
AddBindings(
bindings, InputAxisEventHandler{[pad_index, macro_button_index, deadzone](InputBindingKey key, float value) {
const bool state = (value > deadzone);
Pad::SetMacroButtonState(key, pad_index, macro_button_index, state);
}},
InputBindingInfo::Type::Macro, si, section.c_str(), fmt::format("Macro{}", macro_button_index + 1).c_str(), is_profile);
}
}
@@ -812,7 +951,7 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index)
}
}
void InputManager::AddUSBBindings(SettingsInterface& si, u32 port)
void InputManager::AddUSBBindings(SettingsInterface& si, u32 port, bool is_profile)
{
const std::string device(USB::GetConfigDevice(si, port));
if (device.empty() || device == "None")
@@ -836,9 +975,11 @@ void InputManager::AddUSBBindings(SettingsInterface& si, u32 port)
{
const float sensitivity = si.GetFloatValue(section.c_str(), fmt::format("{}Scale", bi.name).c_str(), 1.0f);
const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("{}Deadzone", bi.name).c_str(), 0.0f);
AddBindings(bindings, InputAxisEventHandler{[port, bind_index = bi.bind_index, sensitivity, deadzone](float value) {
USB::SetDeviceBindValue(port, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
}});
AddBindings(
bindings, InputAxisEventHandler{[port, bind_index = bi.bind_index, sensitivity, deadzone](InputBindingKey key, float value) {
USB::SetDeviceBindValue(port, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
}},
bi.bind_type, si, section.c_str(), bind_name.c_str(), is_profile);
}
}
break;
@@ -977,7 +1118,7 @@ bool InputManager::ProcessEvent(InputBindingKey key, float value, bool skip_butt
if (IsAxisHandler(binding->handler))
{
if (value_to_pass >= 0.0f && (!skip_button_handlers || value_to_pass == 0.0f))
std::get<InputAxisEventHandler>(binding->handler)(value_to_pass);
std::get<InputAxisEventHandler>(binding->handler)(key, value_to_pass);
}
else if (binding->num_keys >= min_num_keys)
{
@@ -1056,7 +1197,7 @@ void InputManager::ClearBindStateFromSource(InputBindingKey key)
if (binding->keys[i].MaskDirection() != match_key)
continue;
std::get<InputAxisEventHandler>(binding->handler)(0.0f);
std::get<InputAxisEventHandler>(binding->handler)(key, 0.0f);
break;
}
}
@@ -1392,7 +1533,7 @@ bool InputManager::DoEventHook(InputBindingKey key, float value)
// Binding Updater
// ------------------------------------------------------------------------
void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si, SettingsInterface& hotkey_binding_si)
void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si, SettingsInterface& hotkey_binding_si, bool is_binding_profile, bool is_hotkey_profile)
{
PauseVibration();
@@ -1404,28 +1545,28 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
s_pointer_move_callbacks.clear();
// Hotkeys use the base configuration, except if the custom hotkeys option is enabled.
AddHotkeyBindings(hotkey_binding_si);
AddHotkeyBindings(hotkey_binding_si, is_hotkey_profile);
// If there's an input profile, we load pad bindings from it alone, rather than
// falling back to the base configuration.
for (u32 pad = 0; pad < Pad::NUM_CONTROLLER_PORTS; pad++)
AddPadBindings(binding_si, pad);
AddPadBindings(binding_si, pad, is_binding_profile);
constexpr float ui_ctrl_range = 100.0f;
constexpr float pointer_sensitivity = 0.05f;
for (u32 axis = 0; axis <= static_cast<u32>(InputPointerAxis::Y); axis++)
{
s_pointer_axis_speed[axis] = si.GetFloatValue("Pad", fmt::format("Pointer{}Speed", s_pointer_axis_names[axis]).c_str(), 40.0f) /
s_pointer_axis_speed[axis] = si.GetFloatValue("Pad", fmt::format("Pointer{}Speed", s_pointer_axis_setting_names[axis]).c_str(), 40.0f) /
ui_ctrl_range * pointer_sensitivity;
s_pointer_axis_dead_zone[axis] = std::min(
si.GetFloatValue("Pad", fmt::format("Pointer{}DeadZone", s_pointer_axis_names[axis]).c_str(), 20.0f) / ui_ctrl_range, 1.0f);
si.GetFloatValue("Pad", fmt::format("Pointer{}DeadZone", s_pointer_axis_setting_names[axis]).c_str(), 20.0f) / ui_ctrl_range, 1.0f);
s_pointer_axis_range[axis] = 1.0f - s_pointer_axis_dead_zone[axis];
}
s_pointer_inertia = si.GetFloatValue("Pad", "PointerInertia", 10.0f) / ui_ctrl_range;
s_pointer_pos = {};
for (u32 port = 0; port < USB::NUM_PORTS; port++)
AddUSBBindings(binding_si, port);
AddUSBBindings(binding_si, port, is_binding_profile);
UpdateHostMouseMode();
}
@@ -1462,7 +1603,7 @@ bool InputManager::ReloadDevices()
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i])
if (s_input_sources[i]->IsInitialized())
changed |= s_input_sources[i]->ReloadDevices();
}
@@ -1473,11 +1614,11 @@ void InputManager::CloseSources()
{
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i])
if (s_input_sources[i]->IsInitialized())
{
s_input_sources[i]->Shutdown();
s_input_sources[i].reset();
}
s_input_sources[i].reset();
}
}
@@ -1485,7 +1626,7 @@ void InputManager::PollSources()
{
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i])
if (s_input_sources[i]->IsInitialized())
s_input_sources[i]->PollEvents();
}
@@ -1505,7 +1646,7 @@ std::vector<std::pair<std::string, std::string>> InputManager::EnumerateDevices(
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i])
if (s_input_sources[i]->IsInitialized())
{
std::vector<std::pair<std::string, std::string>> devs(s_input_sources[i]->EnumerateDevices());
if (ret.empty())
@@ -1524,7 +1665,7 @@ std::vector<InputBindingKey> InputManager::EnumerateMotors()
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i])
if (s_input_sources[i]->IsInitialized())
{
std::vector<InputBindingKey> devs(s_input_sources[i]->EnumerateMotors());
if (ret.empty())
@@ -1584,7 +1725,7 @@ InputManager::GenericInputBindingMapping InputManager::GetGenericBindingMapping(
{
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
{
if (s_input_sources[i] && s_input_sources[i]->GetGenericBindingMapping(device, &mapping))
if (s_input_sources[i]->IsInitialized() && s_input_sources[i]->GetGenericBindingMapping(device, &mapping))
break;
}
}
@@ -1600,34 +1741,34 @@ bool InputManager::IsInputSourceEnabled(SettingsInterface& si, InputSourceType t
template <typename T>
void InputManager::UpdateInputSourceState(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock, InputSourceType type)
{
if (!s_input_sources[static_cast<u32>(type)])
{
std::unique_ptr<InputSource> source = std::make_unique<T>();
if (!source->Initialize(si, settings_lock))
Console.Error("(InputManager) Source '%s' failed to initialize.", InputSourceToString(type));
s_input_sources[static_cast<u32>(type)] = std::move(source);
}
const bool enabled = IsInputSourceEnabled(si, type);
if (enabled)
{
if (s_input_sources[static_cast<u32>(type)])
if (s_input_sources[static_cast<u32>(type)]->IsInitialized())
{
s_input_sources[static_cast<u32>(type)]->UpdateSettings(si, settings_lock);
}
else
else if (!s_input_sources[static_cast<u32>(type)]->Initialize(si, settings_lock))
{
std::unique_ptr<InputSource> source = std::make_unique<T>();
if (!source->Initialize(si, settings_lock))
{
Console.Error("(InputManager) Source '%s' failed to initialize.", InputSourceToString(type));
return;
}
s_input_sources[static_cast<u32>(type)] = std::move(source);
Console.Error("(InputManager) Source '%s' failed to initialize.", InputSourceToString(type));
}
}
else
{
if (s_input_sources[static_cast<u32>(type)])
if (s_input_sources[static_cast<u32>(type)]->IsInitialized())
{
settings_lock.unlock();
s_input_sources[static_cast<u32>(type)]->Shutdown();
settings_lock.lock();
s_input_sources[static_cast<u32>(type)].reset();
}
}
}

View File

@@ -63,7 +63,8 @@ union InputBindingKey
InputSubclass source_subtype : 3; ///< if 1, binding is for an axis and not a button (used for controllers)
InputModifier modifier : 2;
u32 invert : 1; ///< if 1, value is inverted prior to being sent to the sink
u32 unused : 14;
u32 needs_migration : 1; //< Used for SDL2-3 Migration, binding should be saved to complete migration
u32 unused : 13;
u32 data;
};
@@ -80,6 +81,7 @@ union InputBindingKey
r.bits = bits;
r.modifier = InputModifier::None;
r.invert = 0;
r.needs_migration = false;
return r;
}
};
@@ -95,7 +97,7 @@ struct InputBindingKeyHash
using InputButtonEventHandler = std::function<void(s32 value)>;
/// Callback types for a normalized event. Usually used for pads.
using InputAxisEventHandler = std::function<void(float value)>;
using InputAxisEventHandler = std::function<void(InputBindingKey key, float value)>;
/// Input monitoring for external access.
struct InputInterceptHook
@@ -203,13 +205,16 @@ namespace InputManager
std::optional<InputBindingKey> ParseInputBindingKey(const std::string_view binding);
/// Converts a input key to a string.
std::string ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key);
std::string ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key, bool migration = false);
/// Converts a chord of binding keys to a string.
std::string ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys, size_t num_keys);
std::string ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys, size_t num_keys, bool migration = false);
/// Represents a binding with icon fonts, if available.
bool PrettifyInputBinding(SmallStringBase& binding);
bool PrettifyInputBinding(SmallStringBase& binding, bool use_icons = true);
/// Splits a chord into individual bindings.
std::vector<std::string_view> SplitChord(const std::string_view binding);
/// Returns a list of all hotkeys.
std::vector<const HotkeyInfo*> GetHotkeyList();
@@ -228,7 +233,7 @@ namespace InputManager
bool IsInputSourceEnabled(SettingsInterface& si, InputSourceType type);
/// Re-parses the config and registers all hotkey and pad bindings.
void ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si, SettingsInterface& hotkey_binding_si);
void ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si, SettingsInterface& hotkey_binding_si, bool is_binding_profile, bool is_hotkey_profile);
/// Re-parses the sources part of the config and initializes any backends.
void ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock);

View File

@@ -24,11 +24,13 @@ public:
virtual void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) = 0;
virtual bool ReloadDevices() = 0;
virtual void Shutdown() = 0;
virtual bool IsInitialized() = 0;
virtual void PollEvents() = 0;
/// InputBinding functions can be called while uninitialized
virtual std::optional<InputBindingKey> ParseKeyString(const std::string_view device, const std::string_view binding) = 0;
virtual TinyString ConvertKeyToString(InputBindingKey key) = 0;
virtual TinyString ConvertKeyToString(InputBindingKey key, bool display = false, bool migration = false) = 0;
virtual TinyString ConvertKeyToIcon(InputBindingKey key) = 0;
/// Enumerates available devices. Returns a pair of the prefix (e.g. SDL-0) and the device name.

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
#include "Input/InputSource.h"
#include <SDL.h>
#include <SDL3/SDL.h>
#include <array>
#include <functional>
@@ -26,6 +26,7 @@ public:
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
bool ReloadDevices() override;
void Shutdown() override;
bool IsInitialized() override;
void PollEvents() override;
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
@@ -35,7 +36,7 @@ public:
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity, float small_intensity) override;
std::optional<InputBindingKey> ParseKeyString(const std::string_view device, const std::string_view binding) override;
TinyString ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToString(InputBindingKey key, bool display = false, bool migration = false) override;
TinyString ConvertKeyToIcon(InputBindingKey key) override;
bool ProcessSDLEvent(const SDL_Event* event);
@@ -50,17 +51,17 @@ private:
struct ControllerData
{
SDL_Haptic* haptic;
SDL_GameController* game_controller;
SDL_Gamepad* gamepad;
SDL_Joystick* joystick;
u16 rumble_intensity[2];
int haptic_left_right_effect;
int joystick_id;
SDL_JoystickID joystick_id;
int player_id;
bool use_game_controller_rumble;
bool use_gamepad_rumble;
// Used to disable Joystick controls that are used in GameController inputs so we don't get double events
std::vector<bool> joy_button_used_in_gc;
std::vector<bool> joy_axis_used_in_gc;
// Used to disable Joystick controls that are used in Gamepad inputs so we don't get double events
std::vector<bool> joy_button_used_in_pad;
std::vector<bool> joy_axis_used_in_pad;
// Track last hat state so we can send "unpressed" events.
std::vector<u8> last_hat_state;
@@ -73,14 +74,14 @@ private:
void LoadSettings(SettingsInterface& si);
void SetHints();
ControllerDataVector::iterator GetControllerDataForJoystickId(int id);
ControllerDataVector::iterator GetControllerDataForJoystickId(SDL_JoystickID id);
ControllerDataVector::iterator GetControllerDataForPlayerId(int id);
int GetFreePlayerId() const;
bool OpenDevice(int index, bool is_gamecontroller);
bool CloseDevice(int joystick_index);
bool HandleControllerAxisEvent(const SDL_ControllerAxisEvent* ev);
bool HandleControllerButtonEvent(const SDL_ControllerButtonEvent* ev);
bool OpenDevice(SDL_JoystickID index, bool is_gamepad);
bool CloseDevice(SDL_JoystickID joystick_index);
bool HandleGamepadAxisEvent(const SDL_GamepadAxisEvent* ev);
bool HandleGamepadButtonEvent(const SDL_GamepadButtonEvent* ev);
bool HandleJoystickAxisEvent(const SDL_JoyAxisEvent* ev);
bool HandleJoystickButtonEvent(const SDL_JoyButtonEvent* ev);
bool HandleJoystickHatEvent(const SDL_JoyHatEvent* ev);
@@ -88,13 +89,22 @@ private:
ControllerDataVector m_controllers;
// ConvertKeyToString and ConvertKeyToIcon can inspect the
// currently connected gamepad to provide matching labels
// ParseKeyString can also inspect the gamepad for migrations
// Those functions can be called on the main thread, while
// gamepad addition/removal is done on the CPU thread
std::mutex m_controllers_key_mutex;
std::vector<u32> m_gamepads_needing_migration;
std::array<u32, MAX_LED_COLORS> m_led_colors{};
std::vector<std::pair<std::string, std::string>> m_sdl_hints;
bool m_sdl_subsystem_initialized = false;
bool m_controller_enhanced_mode = false;
bool m_controller_raw_mode = false;
bool m_controller_ps5_player_led = false;
bool m_enable_enhanced_reports = false;
bool m_use_raw_input = false;
bool m_enable_ps5_player_leds = false;
#ifdef __APPLE__
bool m_enable_iokit_driver = false;

View File

@@ -14,7 +14,7 @@
#include <cmath>
static const char* s_axis_names[XInputSource::NUM_AXES] = {
static const char* s_axis_setting_names[XInputSource::NUM_AXES] = {
"LeftX", // AXIS_LEFTX
"LeftY", // AXIS_LEFTY
"RightX", // AXIS_RIGHTX
@@ -22,6 +22,14 @@ static const char* s_axis_names[XInputSource::NUM_AXES] = {
"LeftTrigger", // AXIS_TRIGGERLEFT
"RightTrigger", // AXIS_TRIGGERRIGHT
};
static const char* s_axis_names[XInputSource::NUM_AXES] = {
"Left X", // AXIS_LEFTX
"Left Y", // AXIS_LEFTY
"Right X", // AXIS_RIGHTX
"Right Y", // AXIS_RIGHTY
"Left Trigger", // AXIS_TRIGGERLEFT
"Right Trigger", // AXIS_TRIGGERRIGHT
};
static constexpr const char* s_axis_icons[][2] = {
{ICON_PF_LEFT_ANALOG_LEFT, ICON_PF_LEFT_ANALOG_RIGHT}, // AXIS_LEFTX
{ICON_PF_LEFT_ANALOG_UP, ICON_PF_LEFT_ANALOG_DOWN}, // AXIS_LEFTY
@@ -39,7 +47,7 @@ static const GenericInputBinding s_xinput_generic_binding_axis_mapping[][2] = {
{GenericInputBinding::Unknown, GenericInputBinding::R2}, // AXIS_TRIGGERRIGHT
};
static const char* s_button_names[XInputSource::NUM_BUTTONS] = {
static const char* s_button_setting_names[XInputSource::NUM_BUTTONS] = {
"DPadUp", // XINPUT_GAMEPAD_DPAD_UP
"DPadDown", // XINPUT_GAMEPAD_DPAD_DOWN
"DPadLeft", // XINPUT_GAMEPAD_DPAD_LEFT
@@ -56,6 +64,24 @@ static const char* s_button_names[XInputSource::NUM_BUTTONS] = {
"Y", // XINPUT_GAMEPAD_Y
"Guide", // XINPUT_GAMEPAD_GUIDE
};
static const char* s_button_names[XInputSource::NUM_BUTTONS] = {
"D-Pad Up", // XINPUT_GAMEPAD_DPAD_UP
"D-Pad Down", // XINPUT_GAMEPAD_DPAD_DOWN
"D-Pad Left", // XINPUT_GAMEPAD_DPAD_LEFT
"D-Pad Right", // XINPUT_GAMEPAD_DPAD_RIGHT
"Start", // XINPUT_GAMEPAD_START
"Back", // XINPUT_GAMEPAD_BACK
"Left Stick", // XINPUT_GAMEPAD_LEFT_THUMB
"Right Stick", // XINPUT_GAMEPAD_RIGHT_THUMB
"Left Shoulder", // XINPUT_GAMEPAD_LEFT_SHOULDER
"Right Shoulder", // XINPUT_GAMEPAD_RIGHT_SHOULDER
"A", // XINPUT_GAMEPAD_A
"B", // XINPUT_GAMEPAD_B
"X", // XINPUT_GAMEPAD_X
"Y", // XINPUT_GAMEPAD_Y
"Guide", // XINPUT_GAMEPAD_GUIDE
};
static const u16 s_button_masks[XInputSource::NUM_BUTTONS] = {
XINPUT_GAMEPAD_DPAD_UP, XINPUT_GAMEPAD_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_RIGHT, XINPUT_GAMEPAD_START,
XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB, XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER,
@@ -133,6 +159,8 @@ bool XInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex
if (!m_xinput_get_state || !m_xinput_set_state || !m_xinput_get_capabilities)
{
Console.Error("Failed to get XInput function pointers.");
FreeLibrary(m_xinput_module);
m_xinput_module = nullptr;
return false;
}
@@ -196,6 +224,11 @@ void XInputSource::Shutdown()
m_xinput_get_extended = nullptr;
}
bool XInputSource::IsInitialized()
{
return m_xinput_module;
}
void XInputSource::PollEvents()
{
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
@@ -287,9 +320,9 @@ std::optional<InputBindingKey> XInputSource::ParseKeyString(const std::string_vi
{
// likely an axis
const std::string_view axis_name(binding.substr(1));
for (u32 i = 0; i < std::size(s_axis_names); i++)
for (u32 i = 0; i < std::size(s_axis_setting_names); i++)
{
if (axis_name == s_axis_names[i])
if (axis_name == s_axis_setting_names[i])
{
// found an axis!
key.source_subtype = InputSubclass::ControllerAxis;
@@ -302,9 +335,9 @@ std::optional<InputBindingKey> XInputSource::ParseKeyString(const std::string_vi
else
{
// must be a button
for (u32 i = 0; i < std::size(s_button_names); i++)
for (u32 i = 0; i < std::size(s_button_setting_names); i++)
{
if (binding == s_button_names[i])
if (binding == s_button_setting_names[i])
{
key.source_subtype = InputSubclass::ControllerButton;
key.data = i;
@@ -317,24 +350,33 @@ std::optional<InputBindingKey> XInputSource::ParseKeyString(const std::string_vi
return std::nullopt;
}
TinyString XInputSource::ConvertKeyToString(InputBindingKey key)
TinyString XInputSource::ConvertKeyToString(InputBindingKey key, bool display, bool migration)
{
TinyString ret;
if (key.source_type == InputSourceType::XInput)
{
if (key.source_subtype == InputSubclass::ControllerAxis && key.data < std::size(s_axis_names))
if (key.source_subtype == InputSubclass::ControllerAxis && key.data < std::size(s_axis_setting_names))
{
const char modifier = key.modifier == InputModifier::Negate ? '-' : '+';
ret.format("XInput-{}/{}{}", static_cast<u32>(key.source_index), modifier, s_axis_names[key.data]);
if (display)
ret.format("XInput-{} {}{}", static_cast<u32>(key.source_index), modifier, s_axis_names[key.data]);
else
ret.format("XInput-{}/{}{}", static_cast<u32>(key.source_index), modifier, s_axis_setting_names[key.data]);
}
else if (key.source_subtype == InputSubclass::ControllerButton && key.data < std::size(s_button_names))
else if (key.source_subtype == InputSubclass::ControllerButton && key.data < std::size(s_button_setting_names))
{
ret.format("XInput-{}/{}", static_cast<u32>(key.source_index), s_button_names[key.data]);
if (display)
ret.format("XInput-{} {}", static_cast<u32>(key.source_index), s_button_names[key.data]);
else
ret.format("XInput-{}/{}", static_cast<u32>(key.source_index), s_button_setting_names[key.data]);
}
else if (key.source_subtype == InputSubclass::ControllerMotor)
{
ret.format("XInput-{}/{}Motor", static_cast<u32>(key.source_index), key.data ? "Large" : "Small");
if (display)
ret.format("XInput-{} {} Motor", static_cast<u32>(key.source_index), key.data ? "Large" : "Small");
else
ret.format("XInput-{}/{}Motor", static_cast<u32>(key.source_index), key.data ? "Large" : "Small");
}
}
@@ -404,16 +446,16 @@ bool XInputSource::GetGenericBindingMapping(const std::string_view device, Input
const GenericInputBinding negative = s_xinput_generic_binding_axis_mapping[i][0];
const GenericInputBinding positive = s_xinput_generic_binding_axis_mapping[i][1];
if (negative != GenericInputBinding::Unknown)
mapping->emplace_back(negative, fmt::format("XInput-{}/-{}", pid, s_axis_names[i]));
mapping->emplace_back(negative, fmt::format("XInput-{}/-{}", pid, s_axis_setting_names[i]));
if (positive != GenericInputBinding::Unknown)
mapping->emplace_back(positive, fmt::format("XInput-{}/+{}", pid, s_axis_names[i]));
mapping->emplace_back(positive, fmt::format("XInput-{}/+{}", pid, s_axis_setting_names[i]));
}
for (u32 i = 0; i < std::size(s_xinput_generic_binding_button_mapping); i++)
{
const GenericInputBinding binding = s_xinput_generic_binding_button_mapping[i];
if (binding != GenericInputBinding::Unknown)
mapping->emplace_back(binding, fmt::format("XInput-{}/{}", pid, s_button_names[i]));
mapping->emplace_back(binding, fmt::format("XInput-{}/{}", pid, s_button_setting_names[i]));
}
if (m_controllers[pid].has_small_motor)

View File

@@ -75,6 +75,7 @@ public:
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
bool ReloadDevices() override;
void Shutdown() override;
bool IsInitialized() override;
void PollEvents() override;
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
@@ -84,7 +85,7 @@ public:
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity, float small_intensity) override;
std::optional<InputBindingKey> ParseKeyString(const std::string_view device, const std::string_view binding) override;
TinyString ConvertKeyToString(InputBindingKey key) override;
TinyString ConvertKeyToString(InputBindingKey key, bool display = false, bool migration = false) override;
TinyString ConvertKeyToIcon(InputBindingKey key) override;
private:

View File

@@ -838,12 +838,12 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
OpEqu(ShadeBoost_Contrast) &&
OpEqu(ShadeBoost_Saturation) &&
OpEqu(PNGCompressionLevel) &&
OpEqu(SaveN) &&
OpEqu(SaveL) &&
OpEqu(SaveB) &&
OpEqu(SaveNF) &&
OpEqu(SaveLF) &&
OpEqu(SaveBF) &&
OpEqu(SaveDrawStart) &&
OpEqu(SaveDrawCount) &&
OpEqu(SaveDrawBy) &&
OpEqu(SaveFrameStart) &&
OpEqu(SaveFrameCount) &&
OpEqu(SaveFrameBy) &&
OpEqu(ExclusiveFullscreenControl) &&
OpEqu(ScreenshotSize) &&
@@ -965,13 +965,13 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBoolEx(UserHacks_EstimateTextureRegion, "UserHacks_EstimateTextureRegion");
SettingsWrapBitBoolEx(FXAA, "fxaa");
SettingsWrapBitBool(ShadeBoost);
SettingsWrapBitBoolEx(DumpGSData, "dump");
SettingsWrapBitBoolEx(SaveRT, "save");
SettingsWrapBitBoolEx(SaveFrame, "savef");
SettingsWrapBitBoolEx(SaveTexture, "savet");
SettingsWrapBitBoolEx(SaveDepth, "savez");
SettingsWrapBitBoolEx(SaveAlpha, "savea");
SettingsWrapBitBoolEx(SaveInfo, "savei");
SettingsWrapBitBoolEx(DumpGSData, "DumpGSData");
SettingsWrapBitBoolEx(SaveRT, "SaveRT");
SettingsWrapBitBoolEx(SaveFrame, "SaveFrame");
SettingsWrapBitBoolEx(SaveTexture, "SaveTexture");
SettingsWrapBitBoolEx(SaveDepth, "SaveDepth");
SettingsWrapBitBoolEx(SaveAlpha, "SaveAlpha");
SettingsWrapBitBoolEx(SaveInfo, "SaveInfo");
SettingsWrapBitBool(DumpReplaceableTextures);
SettingsWrapBitBool(DumpReplaceableMipmaps);
SettingsWrapBitBool(DumpTexturesWithFMVActive);
@@ -1030,12 +1030,12 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitfield(ShadeBoost_Saturation);
SettingsWrapBitfield(ExclusiveFullscreenControl);
SettingsWrapBitfieldEx(PNGCompressionLevel, "png_compression_level");
SettingsWrapBitfieldEx(SaveN, "saven");
SettingsWrapBitfieldEx(SaveL, "savel");
SettingsWrapBitfieldEx(SaveB, "saveb");
SettingsWrapBitfieldEx(SaveNF, "savenf");
SettingsWrapBitfieldEx(SaveLF, "savelf");
SettingsWrapBitfieldEx(SaveBF, "savebf");
SettingsWrapBitfieldEx(SaveDrawStart, "SaveDrawStart");
SettingsWrapBitfieldEx(SaveDrawCount, "SaveDrawCount");
SettingsWrapBitfieldEx(SaveDrawBy, "SaveDrawBy");
SettingsWrapBitfieldEx(SaveFrameStart, "SaveFrameStart");
SettingsWrapBitfieldEx(SaveFrameCount, "SaveFrameCount");
SettingsWrapBitfieldEx(SaveFrameBy, "SaveFrameBy");
SettingsWrapEntryEx(CaptureContainer, "CaptureContainer");
SettingsWrapEntryEx(VideoCaptureCodec, "VideoCaptureCodec");
@@ -1122,9 +1122,11 @@ bool Pcsx2Config::GSOptions::UseHardwareRenderer() const
bool Pcsx2Config::GSOptions::ShouldDump(int draw, int frame) const
{
int drawOffset = draw - SaveDrawStart;
int frameOffset = frame - SaveFrameStart;
return DumpGSData &&
(SaveN <= draw) && ((SaveL < 0) || (draw < SaveN + SaveL)) && (draw % SaveB == 0) &&
(SaveNF <= frame) && ((SaveLF < 0) || (frame < SaveNF + SaveLF)) && (frame % SaveBF == 0);
(drawOffset >= 0) && ((SaveDrawCount < 0) || (drawOffset < SaveDrawCount)) && (drawOffset % SaveDrawBy == 0) &&
(frameOffset >= 0) && ((SaveFrameCount < 0) || (frameOffset < SaveFrameCount)) && (frameOffset % SaveFrameBy == 0);
}
static constexpr const std::array s_spu2_sync_mode_names = {

View File

@@ -865,8 +865,15 @@ std::vector<AvailableMcdInfo> FileMcd_GetAvailableCards(bool include_in_use_card
if (!IsMemoryCardFolder(fd.FileName))
continue;
FolderMemoryCard sourceFolderMemoryCard;
Pcsx2Config::McdOptions config;
config.Enabled = true;
config.Type = MemoryCardType::Folder;
sourceFolderMemoryCard.Open(fd.FileName, config, (8 * 1024 * 1024) / FolderMemoryCard::ClusterSize, EmuConfig.McdFolderAutoManage, "");
mcds.push_back({std::move(basename), std::move(fd.FileName), fd.ModificationTime,
MemoryCardType::Folder, MemoryCardFileType::Unknown, 0u, true});
MemoryCardType::Folder, MemoryCardFileType::Unknown, 0u, sourceFolderMemoryCard.IsFormatted()});
sourceFolderMemoryCard.Close(false);
}
else
{

View File

@@ -318,6 +318,8 @@ public:
void Open(std::string fullPath, const Pcsx2Config::McdOptions& mcdOptions, const u32 sizeInClusters, const bool enableFiltering, std::string filter, bool simulateFileWrites = false);
// Close the memory card and flush changes to the file system. Set flush to false to not store changes.
void Close(bool flush = true);
// Checks whether the Memory Card is formatted.
bool IsFormatted() const;
// Closes and reopens card with given filter options if they differ from the current ones (returns true),
// or does nothing if they match already (returns false).
@@ -363,8 +365,6 @@ protected:
// initializes memory card data, as if it was fresh from the factory
void InitializeInternalData();
bool IsFormatted() const;
// returns the in-memory address of data the given memory card adr corresponds to
// returns nullptr if adr corresponds to a folder or file entry
u8* GetSystemBlockPointer(const u32 adr);
@@ -558,4 +558,4 @@ public:
u64 GetCRC(uint slot);
void NextFrame(uint slot);
bool ReIndex(uint slot, const bool enableFiltering, const std::string& filter);
};
};

View File

@@ -28,11 +28,15 @@
#include <vector>
//Map of actively pressed keys so that chords work
using KeyMap = std::unordered_multimap<u64, bool>;
namespace Pad
{
struct MacroButton
{
std::vector<u32> buttons; ///< Buttons to activate.
KeyMap active_buttons; ///< Currently active buttons.
float pressure; ///< Pressure to apply when macro is active.
u16 toggle_frequency; ///< Interval at which the buttons will be toggled, if not 0.
u16 toggle_counter; ///< When this counter reaches zero, buttons will be toggled.
@@ -163,8 +167,8 @@ void Pad::SetDefaultControllerConfig(SettingsInterface& si)
InputManager::InputSourceToString(static_cast<InputSourceType>(i)),
InputManager::GetInputSourceDefaultEnabled(static_cast<InputSourceType>(i)));
}
si.SetBoolValue("InputSources", "SDLControllerEnhancedMode", false);
si.SetBoolValue("InputSources", "SDLPS5PlayerLED", false);
si.SetBoolValue("InputSources", "SDLControllerEnhancedMode", true);
si.SetBoolValue("InputSources", "SDLPS5PlayerLED", true);
si.SetBoolValue("Pad", "MultitapPort1", false);
si.SetBoolValue("Pad", "MultitapPort2", false);
si.SetFloatValue("Pad", "PointerXScale", 8.0f);
@@ -670,8 +674,12 @@ void Pad::LoadMacroButtonConfig(const SettingsInterface& si, u32 pad, const Cont
}
}
void Pad::SetMacroButtonState(u32 pad, u32 index, bool state)
void Pad::SetMacroButtonState(InputBindingKey& key, u32 pad, u32 index, bool state)
{
//0 appears for some reason and breaks mb.active_buttons.size() != binding_count
if (key.bits == 0)
return;
if (pad >= Pad::NUM_CONTROLLER_PORTS || index >= NUM_MACRO_BUTTONS_PER_CONTROLLER)
return;
@@ -679,6 +687,30 @@ void Pad::SetMacroButtonState(u32 pad, u32 index, bool state)
if (mb.buttons.empty())
return;
SettingsInterface& sif = *Host::GetSettingsInterface();
std::vector<std::string> data = sif.GetStringList(fmt::format("Pad{}", pad+1).c_str(), fmt::format("Macro{}", index+1).c_str());
size_t binding_count = 0;
//just in case there's more than one index
for (std::string bind : data)
{
binding_count += InputManager::SplitChord(bind).size();
}
if (mb.active_buttons.find(key.bits) != mb.active_buttons.end())
mb.active_buttons.erase(key.bits);
mb.active_buttons.emplace(key.bits, state);
if (mb.active_buttons.size() != binding_count)
return;
if (mb.active_buttons.size() > 1 && state)
{
for (auto it = mb.active_buttons.begin(); it != mb.active_buttons.end(); ++it)
{
if (!it->second)
return;
}
}
const bool trigger_state = (mb.trigger_toggle ? (state ? !mb.trigger_state : mb.trigger_state) : state);
if (mb.trigger_state == trigger_state)
return;

View File

@@ -4,6 +4,7 @@
#pragma once
#include "Config.h"
#include "Input/InputManager.h"
#include "SIO/Pad/PadTypes.h"
#include <memory>
@@ -68,6 +69,6 @@ namespace Pad
bool Freeze(StateWrapper& sw);
// Sets the state of the specified macro button.
void SetMacroButtonState(u32 pad, u32 index, bool state);
void SetMacroButtonState(InputBindingKey& key, u32 pad, u32 index, bool state);
void UpdateMacroButtons();
}; // namespace Pad

View File

@@ -156,7 +156,6 @@ void MemcardBusy::ClearBusy()
sioLastFrameMcdBusy = 0;
}
#include "common/Console.h"
void MemcardBusy::CheckSaveStateDependency()
{
if (g_FrameCount - sioLastFrameMcdBusy > NUM_FRAMES_BEFORE_SAVESTATE_DEPENDENCY_WARNING)

View File

@@ -118,8 +118,8 @@ namespace AutoEject
extern void ClearAll();
} // namespace AutoEject
// ~1 hour of memory card inactivity.
constexpr u32 NUM_FRAMES_BEFORE_SAVESTATE_DEPENDENCY_WARNING = 60 * 60 * 60;
// ~2 hours of memory card inactivity.
constexpr u32 NUM_FRAMES_BEFORE_SAVESTATE_DEPENDENCY_WARNING = 60 * 60 * 60 * 2;
// Set to the current frame count when there is memory card activity.
// Used to detect the last frame when memory card activity was detected,

View File

@@ -27,7 +27,7 @@ namespace usb_pad
{
DestroyEffects();
SDL_HapticClose(m_haptic);
SDL_CloseHaptic(m_haptic);
m_haptic = nullptr;
}
}
@@ -45,7 +45,7 @@ namespace usb_pad
return nullptr;
}
SDL_Haptic* haptic = SDL_HapticOpenFromJoystick(joystick);
SDL_Haptic* haptic = SDL_OpenHapticFromJoystick(joystick);
if (!haptic)
{
Console.Error(fmt::format("Haptic is not supported on {}.", device));
@@ -77,16 +77,16 @@ namespace usb_pad
// - Simagic Alpha Mini: Does NOT implement infinite durations (stops after some time, seeking hard numbers)
constexpr u32 length = SDL_HAPTIC_INFINITY;
const unsigned int supported = SDL_HapticQuery(m_haptic);
const unsigned int supported = SDL_GetHapticFeatures(m_haptic);
if (supported & SDL_HAPTIC_CONSTANT)
{
m_constant_effect.type = SDL_HAPTIC_CONSTANT;
m_constant_effect.constant.direction.type = SDL_HAPTIC_STEERING_AXIS;
m_constant_effect.constant.length = length;
m_constant_effect_id = SDL_HapticNewEffect(m_haptic, &m_constant_effect);
m_constant_effect_id = SDL_CreateHapticEffect(m_haptic, &m_constant_effect);
if (m_constant_effect_id < 0)
Console.Error("SDL_HapticNewEffect() for constant failed: %s", SDL_GetError());
Console.Error("SDL_CreateHapticEffect() for constant failed: %s", SDL_GetError());
}
else
{
@@ -99,9 +99,9 @@ namespace usb_pad
m_spring_effect.condition.direction.type = SDL_HAPTIC_STEERING_AXIS;
m_spring_effect.condition.length = length;
m_spring_effect_id = SDL_HapticNewEffect(m_haptic, &m_spring_effect);
m_spring_effect_id = SDL_CreateHapticEffect(m_haptic, &m_spring_effect);
if (m_spring_effect_id < 0)
Console.Error("SDL_HapticNewEffect() for spring failed: %s", SDL_GetError());
Console.Error("SDL_CreateHapticEffect() for spring failed: %s", SDL_GetError());
}
else
{
@@ -114,9 +114,9 @@ namespace usb_pad
m_damper_effect.condition.direction.type = SDL_HAPTIC_STEERING_AXIS;
m_damper_effect.condition.length = length;
m_damper_effect_id = SDL_HapticNewEffect(m_haptic, &m_damper_effect);
m_damper_effect_id = SDL_CreateHapticEffect(m_haptic, &m_damper_effect);
if (m_damper_effect_id < 0)
Console.Error("SDL_HapticNewEffect() for damper failed: %s", SDL_GetError());
Console.Error("SDL_CreateHapticEffect() for damper failed: %s", SDL_GetError());
}
else
{
@@ -129,9 +129,9 @@ namespace usb_pad
m_friction_effect.condition.direction.type = SDL_HAPTIC_STEERING_AXIS;
m_friction_effect.condition.length = length;
m_friction_effect_id = SDL_HapticNewEffect(m_haptic, &m_friction_effect);
m_friction_effect_id = SDL_CreateHapticEffect(m_haptic, &m_friction_effect);
if (m_friction_effect_id < 0)
Console.Error("SDL_HapticNewEffect() for friction failed: %s", SDL_GetError());
Console.Error("SDL_CreateHapticEffect() for friction failed: %s", SDL_GetError());
}
else
{
@@ -149,10 +149,10 @@ namespace usb_pad
{
if (m_friction_effect_running)
{
SDL_HapticStopEffect(m_haptic, m_friction_effect_id);
SDL_StopHapticEffect(m_haptic, m_friction_effect_id);
m_friction_effect_running = false;
}
SDL_HapticDestroyEffect(m_haptic, m_friction_effect_id);
SDL_DestroyHapticEffect(m_haptic, m_friction_effect_id);
m_friction_effect_id = -1;
}
@@ -160,10 +160,10 @@ namespace usb_pad
{
if (m_damper_effect_running)
{
SDL_HapticStopEffect(m_haptic, m_damper_effect_id);
SDL_StopHapticEffect(m_haptic, m_damper_effect_id);
m_damper_effect_running = false;
}
SDL_HapticDestroyEffect(m_haptic, m_damper_effect_id);
SDL_DestroyHapticEffect(m_haptic, m_damper_effect_id);
m_damper_effect_id = -1;
}
@@ -171,10 +171,10 @@ namespace usb_pad
{
if (m_spring_effect_running)
{
SDL_HapticStopEffect(m_haptic, m_spring_effect_id);
SDL_StopHapticEffect(m_haptic, m_spring_effect_id);
m_spring_effect_running = false;
}
SDL_HapticDestroyEffect(m_haptic, m_spring_effect_id);
SDL_DestroyHapticEffect(m_haptic, m_spring_effect_id);
m_spring_effect_id = -1;
}
@@ -182,10 +182,10 @@ namespace usb_pad
{
if (m_constant_effect_running)
{
SDL_HapticStopEffect(m_haptic, m_constant_effect_id);
SDL_StopHapticEffect(m_haptic, m_constant_effect_id);
m_constant_effect_running = false;
}
SDL_HapticDestroyEffect(m_haptic, m_constant_effect_id);
SDL_DestroyHapticEffect(m_haptic, m_constant_effect_id);
m_constant_effect_id = -1;
}
}
@@ -199,8 +199,8 @@ namespace usb_pad
if (m_constant_effect.constant.level != new_level)
{
m_constant_effect.constant.level = new_level;
if (SDL_HapticUpdateEffect(m_haptic, m_constant_effect_id, &m_constant_effect) != 0)
Console.Warning("SDL_HapticUpdateEffect() for constant failed: %s", SDL_GetError());
if (!SDL_UpdateHapticEffect(m_haptic, m_constant_effect_id, &m_constant_effect))
Console.Warning("SDL_UpdateHapticEffect() for constant failed: %s", SDL_GetError());
}
// Avoid re-running already-running effects by default. Re-running a running effect
@@ -217,10 +217,10 @@ namespace usb_pad
// This is the reason for use_ffb_dropout_workaround.
if (!m_constant_effect_running || use_ffb_dropout_workaround)
{
if (SDL_HapticRunEffect(m_haptic, m_constant_effect_id, SDL_HAPTIC_INFINITY) == 0)
if (SDL_RunHapticEffect(m_haptic, m_constant_effect_id, SDL_HAPTIC_INFINITY))
m_constant_effect_running = true;
else
Console.Error("SDL_HapticRunEffect() for constant failed: %s", SDL_GetError());
Console.Error("SDL_RunHapticEffect() for constant failed: %s", SDL_GetError());
}
}
@@ -248,15 +248,15 @@ namespace usb_pad
m_spring_effect.condition.deadband[0] = ClampU16(ff.u.condition.deadband);
m_spring_effect.condition.center[0] = ClampS16(ff.u.condition.center);
if (SDL_HapticUpdateEffect(m_haptic, m_spring_effect_id, &m_spring_effect) != 0)
Console.Warning("SDL_HapticUpdateEffect() for spring failed: %s", SDL_GetError());
if (!SDL_UpdateHapticEffect(m_haptic, m_spring_effect_id, &m_spring_effect))
Console.Warning("SDL_UpdateHapticEffect() for spring failed: %s", SDL_GetError());
if (!m_spring_effect_running)
{
if (SDL_HapticRunEffect(m_haptic, m_spring_effect_id, SDL_HAPTIC_INFINITY) == 0)
if (SDL_RunHapticEffect(m_haptic, m_spring_effect_id, SDL_HAPTIC_INFINITY))
m_spring_effect_running = true;
else
Console.Error("SDL_HapticRunEffect() for spring failed: %s", SDL_GetError());
Console.Error("SDL_RunHapticEffect() for spring failed: %s", SDL_GetError());
}
}
@@ -272,15 +272,15 @@ namespace usb_pad
m_damper_effect.condition.deadband[0] = ClampU16(ff.u.condition.deadband);
m_damper_effect.condition.center[0] = ClampS16(ff.u.condition.center);
if (SDL_HapticUpdateEffect(m_haptic, m_damper_effect_id, &m_damper_effect) != 0)
Console.Warning("SDL_HapticUpdateEffect() for damper failed: %s", SDL_GetError());
if (!SDL_UpdateHapticEffect(m_haptic, m_damper_effect_id, &m_damper_effect))
Console.Warning("SDL_UpdateHapticEffect() for damper failed: %s", SDL_GetError());
if (!m_damper_effect_running)
{
if (SDL_HapticRunEffect(m_haptic, m_damper_effect_id, SDL_HAPTIC_INFINITY) == 0)
if (SDL_RunHapticEffect(m_haptic, m_damper_effect_id, SDL_HAPTIC_INFINITY))
m_damper_effect_running = true;
else
Console.Error("SDL_HapticRunEffect() for damper failed: %s", SDL_GetError());
Console.Error("SDL_RunHapticEffect() for damper failed: %s", SDL_GetError());
}
}
@@ -296,12 +296,12 @@ namespace usb_pad
m_friction_effect.condition.deadband[0] = ClampU16(ff.u.condition.deadband);
m_friction_effect.condition.center[0] = ClampS16(ff.u.condition.center);
if (SDL_HapticUpdateEffect(m_haptic, m_friction_effect_id, &m_friction_effect) != 0)
if (!SDL_UpdateHapticEffect(m_haptic, m_friction_effect_id, &m_friction_effect))
{
if (!m_friction_effect_running && SDL_HapticRunEffect(m_haptic, m_friction_effect_id, SDL_HAPTIC_INFINITY) == 0)
if (!m_friction_effect_running && SDL_RunHapticEffect(m_haptic, m_friction_effect_id, SDL_HAPTIC_INFINITY))
m_friction_effect_running = true;
else
Console.Error("SDL_HapticUpdateEffect() for friction failed: %s", SDL_GetError());
Console.Error("SDL_UpdateHapticEffect() for friction failed: %s", SDL_GetError());
}
}
@@ -309,8 +309,8 @@ namespace usb_pad
{
if (m_autocenter_supported)
{
if (SDL_HapticSetAutocenter(m_haptic, value) != 0)
Console.Warning("SDL_HapticSetAutocenter() failed: %s", SDL_GetError());
if (!SDL_SetHapticAutocenter(m_haptic, value))
Console.Warning("SDL_SetHapticAutocenter() failed: %s", SDL_GetError());
}
}
@@ -322,7 +322,7 @@ namespace usb_pad
{
if (m_constant_effect_running)
{
SDL_HapticStopEffect(m_haptic, m_constant_effect_id);
SDL_StopHapticEffect(m_haptic, m_constant_effect_id);
m_constant_effect_running = false;
}
}
@@ -332,7 +332,7 @@ namespace usb_pad
{
if (m_spring_effect_running)
{
SDL_HapticStopEffect(m_haptic, m_spring_effect_id);
SDL_StopHapticEffect(m_haptic, m_spring_effect_id);
m_spring_effect_running = false;
}
}
@@ -342,7 +342,7 @@ namespace usb_pad
{
if (m_damper_effect_running)
{
SDL_HapticStopEffect(m_haptic, m_damper_effect_id);
SDL_StopHapticEffect(m_haptic, m_damper_effect_id);
m_damper_effect_running = false;
}
}
@@ -352,7 +352,7 @@ namespace usb_pad
{
if (m_friction_effect_running)
{
SDL_HapticStopEffect(m_haptic, m_friction_effect_id);
SDL_StopHapticEffect(m_haptic, m_friction_effect_id);
m_friction_effect_running = false;
}
}

View File

@@ -624,10 +624,10 @@ void VMManager::ReloadInputSources()
LoadInputBindings(*si, lock);
}
void VMManager::ReloadInputBindings()
void VMManager::ReloadInputBindings(bool force)
{
// skip loading bindings if we're not running, since it'll get done on startup anyway
if (!HasValidVM())
if (!force && !HasValidVM())
return;
FPControlRegisterBackup fpcr_backup(FPControlRegister::GetDefault());
@@ -662,19 +662,19 @@ void VMManager::LoadInputBindings(SettingsInterface& si, std::unique_lock<std::m
const bool use_profile_hotkeys = isi->GetBoolValue("Pad", "UseProfileHotkeyBindings", false);
if (use_profile_hotkeys)
{
InputManager::ReloadBindings(si, *isi, *isi);
InputManager::ReloadBindings(si, *isi, *isi, true, true);
}
else
{
// Temporarily disable the input profile layer, so it doesn't take precedence.
Host::Internal::SetInputSettingsLayer(nullptr, lock);
InputManager::ReloadBindings(si, *isi, si);
InputManager::ReloadBindings(si, *isi, si, true, false);
Host::Internal::SetInputSettingsLayer(s_input_settings_interface.get(), lock);
}
}
else
{
InputManager::ReloadBindings(si, si, si);
InputManager::ReloadBindings(si, si, si, false, false);
}
}
@@ -3610,7 +3610,7 @@ void VMManager::ReloadPINE()
PINEServer::Deinitialize();
if (EmuConfig.EnablePINE)
PINEServer::Initialize();
PINEServer::Initialize(EmuConfig.PINESlot);
}
void VMManager::InitializeDiscordPresence()

View File

@@ -114,7 +114,8 @@ namespace VMManager
void ReloadInputSources();
/// Reloads input bindings.
void ReloadInputBindings();
/// Can be forced to load even when there is not an active virtual machine.
void ReloadInputBindings(bool force = false);
/// Returns the save state filename for the given game serial/crc.
std::string GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot);

View File

@@ -198,6 +198,8 @@ void CTC2() {
vu1Finish(true);
vu1ExecMicro(cpuRegs.GPR.r[_Rt_].US[0]); // Execute VU1 Micro SubRoutine
break;
case REG_CLIP_FLAG:
VU0.clipflag = cpuRegs.GPR.r[_Rt_].UL[0];
default:
VU0.VI[_Fs_].UL = cpuRegs.GPR.r[_Rt_].UL[0];
break;

File diff suppressed because it is too large Load Diff

View File

@@ -5,14 +5,6 @@
#include "VU.h"
#include "VUflags.h"
#define float_to_int4(x) ((float)x * (1.0f / 0.0625f))
#define float_to_int12(x) ((float)x * (1.0f / 0.000244140625f))
#define float_to_int15(x) ((float)x * (1.0f / 0.000030517578125))
#define int4_to_float(x) (float)((float)x * 0.0625f)
#define int12_to_float(x) (float)((float)x * 0.000244140625f)
#define int15_to_float(x) (float)((float)x * 0.000030517578125)
struct _VURegsNum {
u8 pipe; // if 0xff, COP2
u8 VFwrite;

View File

@@ -31,7 +31,7 @@
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DepsIncludeDir)\SDL2</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DepsIncludeDir)\SDL3</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\include</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\winwil\include</AdditionalIncludeDirectories>

View File

@@ -11,4 +11,9 @@
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware>
</windowsSettings>
</application>
</assembly>

View File

@@ -109,7 +109,7 @@ void _freeX86reg(int x86reg);
void _freeX86regWithoutWriteback(int x86reg);
void _freeX86regs();
void _flushX86regs();
void _flushConstRegs();
void _flushConstRegs(bool delete_const);
void _flushConstReg(int reg);
void _validateRegs();
void _writebackX86Reg(int x86reg);

View File

@@ -105,7 +105,7 @@ void _flushConstReg(int reg)
}
}
void _flushConstRegs()
void _flushConstRegs(bool delete_const)
{
int zero_reg_count = 0;
int minusone_reg_count = 0;
@@ -134,6 +134,8 @@ void _flushConstRegs()
{
xMOV(ptr64[&cpuRegs.GPR.r[i].UD[0]], rax);
g_cpuFlushedConstReg |= 1u << i;
if (delete_const)
g_cpuHasConstReg &= ~(1u << i);
}
}
rax_is_zero = true;
@@ -154,6 +156,8 @@ void _flushConstRegs()
{
xMOV(ptr64[&cpuRegs.GPR.r[i].UD[0]], rax);
g_cpuFlushedConstReg |= 1u << i;
if (delete_const)
g_cpuHasConstReg &= ~(1u << i);
}
}
}
@@ -166,6 +170,8 @@ void _flushConstRegs()
xWriteImm64ToMem(&cpuRegs.GPR.r[i].UD[0], rax, g_cpuConstRegs[i].UD[0]);
g_cpuFlushedConstReg |= 1u << i;
if (delete_const)
g_cpuHasConstReg &= ~(1u << i);
}
}

View File

@@ -227,7 +227,7 @@ void _eeFlushAllDirty()
_flushX86regs();
// flush constants, do them all at once for slightly better codegen
_flushConstRegs();
_flushConstRegs(false);
}
void _eeMoveGPRtoR(const xRegister32& to, int fromgpr, bool allow_preload)
@@ -1225,7 +1225,7 @@ void iFlushCall(int flushtype)
_flushXMMregs();
if (flushtype & FLUSH_CONSTANT_REGS)
_flushConstRegs();
_flushConstRegs(true);
if ((flushtype & FLUSH_PC) && !g_cpuFlushedPC)
{

View File

@@ -16,49 +16,42 @@ struct microVU;
struct mVU_Globals
{
u32 absclip[4], signbit[4], minvals[4], maxvals[4];
u32 one[4];
u32 Pi4[4];
u32 T1[4], T2[4], T3[4], T4[4], T5[4], T6[4], T7[4], T8[4];
u32 S2[4], S3[4], S4[4], S5[4];
u32 E1[4], E2[4], E3[4], E4[4], E5[4], E6[4];
float FTOI_4[4], FTOI_12[4], FTOI_15[4];
float ITOF_4[4], ITOF_12[4], ITOF_15[4];
#define __four(val) { val, val, val, val }
u32 absclip [4] = __four(0x7fffffff);
u32 signbit [4] = __four(0x80000000);
u32 minvals [4] = __four(0xff7fffff);
u32 maxvals [4] = __four(0x7f7fffff);
u32 exponent[4] = __four(0x7f800000);
u32 one [4] = __four(0x3f800000);
u32 Pi4 [4] = __four(0x3f490fdb);
u32 T1 [4] = __four(0x3f7ffff5);
u32 T5 [4] = __four(0xbeaaa61c);
u32 T2 [4] = __four(0x3e4c40a6);
u32 T3 [4] = __four(0xbe0e6c63);
u32 T4 [4] = __four(0x3dc577df);
u32 T6 [4] = __four(0xbd6501c4);
u32 T7 [4] = __four(0x3cb31652);
u32 T8 [4] = __four(0xbb84d7e7);
u32 S2 [4] = __four(0xbe2aaaa4);
u32 S3 [4] = __four(0x3c08873e);
u32 S4 [4] = __four(0xb94fb21f);
u32 S5 [4] = __four(0x362e9c14);
u32 E1 [4] = __four(0x3e7fffa8);
u32 E2 [4] = __four(0x3d0007f4);
u32 E3 [4] = __four(0x3b29d3ff);
u32 E4 [4] = __four(0x3933e553);
u32 E5 [4] = __four(0x36b63510);
u32 E6 [4] = __four(0x353961ac);
float FTOI_4 [4] = __four(16.0);
float FTOI_12 [4] = __four(4096.0);
float FTOI_15 [4] = __four(32768.0);
float ITOF_4 [4] = __four(0.0625f);
float ITOF_12 [4] = __four(0.000244140625);
float ITOF_15 [4] = __four(0.000030517578125);
#undef __four
};
#define __four(val) { val, val, val, val }
alignas(32) static const mVU_Globals mVUglob = {
__four(0x7fffffff), // absclip
__four(0x80000000), // signbit
__four(0xff7fffff), // minvals
__four(0x7f7fffff), // maxvals
__four(0x3f800000), // ONE!
__four(0x3f490fdb), // PI4!
__four(0x3f7ffff5), // T1
__four(0xbeaaa61c), // T5
__four(0x3e4c40a6), // T2
__four(0xbe0e6c63), // T3
__four(0x3dc577df), // T4
__four(0xbd6501c4), // T6
__four(0x3cb31652), // T7
__four(0xbb84d7e7), // T8
__four(0xbe2aaaa4), // S2
__four(0x3c08873e), // S3
__four(0xb94fb21f), // S4
__four(0x362e9c14), // S5
__four(0x3e7fffa8), // E1
__four(0x3d0007f4), // E2
__four(0x3b29d3ff), // E3
__four(0x3933e553), // E4
__four(0x36b63510), // E5
__four(0x353961ac), // E6
__four(16.0), // FTOI_4
__four(4096.0), // FTOI_12
__four(32768.0), // FTOI_15
__four(0.0625f), // ITOF_4
__four(0.000244140625), // ITOF_12
__four(0.000030517578125) // ITOF_15
};
alignas(32) static constexpr struct mVU_Globals mVUglob;
static const uint _Ibit_ = 1 << 31;
static const uint _Ebit_ = 1 << 30;

View File

@@ -544,36 +544,36 @@ mVUop(mVU_CLIP)
const xmm& Fs = mVU.regAlloc->allocReg(_Fs_, 0, 0xf);
const xmm& Ft = mVU.regAlloc->allocReg(_Ft_, 0, 0x1);
const xmm& t1 = mVU.regAlloc->allocReg();
const xmm& t2 = mVU.regAlloc->allocReg();
mVUunpack_xyzw(Ft, Ft, 0);
mVUallocCFLAGa(mVU, gprT1, cFLAG.lastWrite);
xSHL(gprT1, 6);
xAND.PS(Ft, ptr128[mVUglob.absclip]);
xMOVAPS(t1, Ft);
xPOR(t1, ptr128[mVUglob.signbit]);
xMOVAPS (t1, ptr128[mVUglob.exponent]);
xPAND (t1, Fs);
xPXOR (t2, t2);
xPCMP.EQD(t1, t2); // Denormal check
xPANDN (t1, Fs); // If denormal, set to zero, which can't be greater than any nonnegative denormal in Ft
xPAND (Ft, ptr128[mVUglob.absclip]);
xCMPNLE.PS(t1, Fs); // -w, -z, -y, -x
xCMPLT.PS(Ft, Fs); // +w, +z, +y, +x
xMOVAPS (Fs, ptr128[mVUglob.signbit]);
xPXOR (Fs, t1); // Negate
xPCMP.GTD(t1, Ft); // +w, +z, +y, +x
xPCMP.GTD(Fs, Ft); // -w, -z, -y, -x
xMOVAPS(Fs, Ft); // Fs = +w, +z, +y, +x
xUNPCK.LPS(Ft, t1); // Ft = -y,+y,-x,+x
xUNPCK.HPS(Fs, t1); // Fs = -w,+w,-z,+z
xMOVMSKPS(gprT2, Fs); // -w,+w,-z,+z
xAND(gprT2, 0x3);
xSHL(gprT2, 4);
xOR(gprT1, gprT2);
xMOVMSKPS(gprT2, Ft); // -y,+y,-x,+x
xAND(gprT2, 0xf);
xOR(gprT1, gprT2);
xAND(gprT1, 0xffffff);
xPBLEND.W (Fs, t1, 0x55); // Squish together
xPACK.SSWB(Fs, Fs); // Convert u16 to u8
xPMOVMSKB (gprT2, Fs); // Get bitmask
xAND (gprT2, 0x3f); // Mask unused stuff
xAND (gprT1, 0xffffff);
xOR (gprT1, gprT2);
mVUallocCFLAGb(mVU, gprT1, cFLAG.write);
mVU.regAlloc->clearNeeded(Fs);
mVU.regAlloc->clearNeeded(Ft);
mVU.regAlloc->clearNeeded(t1);
mVU.regAlloc->clearNeeded(t2);
mVU.profiler.EmitOp(opCLIP);
}
pass3

View File

@@ -153,6 +153,8 @@ TEST(CodegenTests, SSETest)
CODEGEN_TEST(xMOVAPS(ptr128[rax+r9], xmm8), "46 0f 29 04 08");
CODEGEN_TEST(xBLEND.PS(xmm0, xmm1, 0x55), "66 0f 3a 0c c1 55");
CODEGEN_TEST(xBLEND.PD(xmm8, xmm9, 0xaa), "66 45 0f 3a 0d c1 aa");
CODEGEN_TEST(xPBLEND.W(xmm0, xmm1, 0x55), "66 0f 3a 0e c1 55");
CODEGEN_TEST(xPBLEND.VB(xmm1, xmm2), "66 0f 38 10 ca");
CODEGEN_TEST(xEXTRACTPS(ptr32[base], xmm1, 2), "66 0f 3a 17 0d f6 ff ff ff 02");
CODEGEN_TEST(xMOVD(eax, xmm1), "66 0f 7e c8");
CODEGEN_TEST(xMOVD(eax, xmm10), "66 44 0f 7e d0");

View File

@@ -60,16 +60,16 @@ else()
target_sources(core_test PRIVATE ${multi_isa_sources})
endif()
if(WIN32 AND TARGET SDL2::SDL2)
# Copy SDL2 DLL to binary directory.
if(WIN32 AND TARGET SDL3::SDL3)
# Copy SDL3 DLL to binary directory.
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
get_property(SDL2_DLL_PATH TARGET SDL2::SDL2 PROPERTY IMPORTED_LOCATION_DEBUG)
get_property(SDL3_DLL_PATH TARGET SDL3::SDL3 PROPERTY IMPORTED_LOCATION_DEBUG)
else()
get_property(SDL2_DLL_PATH TARGET SDL2::SDL2 PROPERTY IMPORTED_LOCATION_RELEASE)
get_property(SDL3_DLL_PATH TARGET SDL3::SDL3 PROPERTY IMPORTED_LOCATION_RELEASE)
endif()
if(SDL2_DLL_PATH)
if(SDL3_DLL_PATH)
add_custom_command(TARGET core_test POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E make_directory "$<TARGET_FILE_DIR:core_test>"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${SDL2_DLL_PATH}" "$<TARGET_FILE_DIR:core_test>")
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${SDL3_DLL_PATH}" "$<TARGET_FILE_DIR:core_test>")
endif()
endif()

View File

@@ -39,6 +39,10 @@ std::unique_ptr<ProgressCallback> Host::CreateHostProgressCallback()
return ProgressCallback::CreateNullProgressCallback();
}
void Host::ReportInfoAsync(const std::string_view title, const std::string_view message)
{
}
void Host::ReportErrorAsync(const std::string_view title, const std::string_view message)
{
}
@@ -238,6 +242,11 @@ void Host::OnCreateMemoryCardOpenRequested()
{
}
bool Host::LocaleCircleConfirm()
{
return false;
}
bool Host::ShouldPreferHostFileSelector()
{
return false;