Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6740fff179 | ||
|
|
25e24d1d09 | ||
|
|
76cc9c8b21 | ||
|
|
7dcf6b70d9 | ||
|
|
f26b26b73e | ||
|
|
055beaa27a | ||
|
|
a4623c3c63 | ||
|
|
4e3a94809d | ||
|
|
5ff64899e6 | ||
|
|
971f172c91 | ||
|
|
4671167a2c | ||
|
|
7aff4ee4cb | ||
|
|
30f7685435 | ||
|
|
341f377e6d | ||
|
|
fe4788ae3f | ||
|
|
e133e89b6b | ||
|
|
bf6a0a035a | ||
|
|
790447ecc9 | ||
|
|
47506d1433 | ||
|
|
933e6aa62e | ||
|
|
6736ef1d44 | ||
|
|
3e631e047f | ||
|
|
dd2d4edffc | ||
|
|
fd2960c9cb | ||
|
|
c2907ea58f | ||
|
|
41f62cf53d | ||
|
|
e462f1ff9c | ||
|
|
5b0b6191d8 | ||
|
|
ab9a1e4307 | ||
|
|
029c11c8d2 | ||
|
|
e221d31b45 | ||
|
|
dfbdaa651c | ||
|
|
9de152b8ee | ||
|
|
360f9afb70 | ||
|
|
1b81825218 | ||
|
|
b3e6e28827 | ||
|
|
eaceb27879 | ||
|
|
cd9b6c7ac3 | ||
|
|
d3e527f2a4 | ||
|
|
b47fdcdfab | ||
|
|
2550ad7fd1 | ||
|
|
1717f584a0 | ||
|
|
0822d3e3e5 | ||
|
|
ec41af760a | ||
|
|
a5ed24ca88 | ||
|
|
b3697579c0 | ||
|
|
388da2058b | ||
|
|
aa9a0dca4b | ||
|
|
2a892da0da | ||
|
|
9237bf9429 | ||
|
|
10533dce02 | ||
|
|
b5ebc19eff | ||
|
|
6535e7e43a | ||
|
|
5f9473ef02 | ||
|
|
fbb1c7cb8e | ||
|
|
2d97d85ca5 | ||
|
|
ecd7d0fc35 | ||
|
|
0c389789f3 | ||
|
|
d8239664a8 | ||
|
|
c06d4f477a | ||
|
|
cdd88a6e5c | ||
|
|
5a73fa2d23 | ||
|
|
0367851b8e | ||
|
|
33b2f6331c | ||
|
|
befbf57191 | ||
|
|
20d040d5d1 | ||
|
|
06fdc75945 | ||
|
|
ded971a3ec | ||
|
|
abc0f99ddd | ||
|
|
b3a88d6ea7 | ||
|
|
76014b7cb9 | ||
|
|
0ab6eb6587 | ||
|
|
a4e99366fb | ||
|
|
a32ab4cc97 | ||
|
|
e7f3c42f9d | ||
|
|
d76a0d7416 | ||
|
|
79f4af8ab5 | ||
|
|
a5f83329cb | ||
|
|
267479f31d | ||
|
|
164462e510 | ||
|
|
6331df306f | ||
|
|
027ceebcbd | ||
|
|
edb2c0080c | ||
|
|
caafc87b29 | ||
|
|
5d37cac4a0 | ||
|
|
8f68e096d4 | ||
|
|
430cad48e3 | ||
|
|
757a9532e6 | ||
|
|
f26f8cafa9 | ||
|
|
128a79e355 | ||
|
|
cc2d99db3a | ||
|
|
30a31d931a | ||
|
|
1c30d449bf | ||
|
|
dc4ce58248 | ||
|
|
dc93e861c7 | ||
|
|
960daf27e2 | ||
|
|
844f21344d | ||
|
|
535ad110e3 | ||
|
|
0e0d7a5441 | ||
|
|
ed63221c7e | ||
|
|
f9c2d7767d | ||
|
|
cb91478590 | ||
|
|
5dec7fe27d | ||
|
|
575d487c65 | ||
|
|
2b9289f402 | ||
|
|
9273683d3c | ||
|
|
88f8465e7e | ||
|
|
f26031cada | ||
|
|
3352d71515 | ||
|
|
999f9532ee | ||
|
|
d1f62ca9bf | ||
|
|
ef9f0cf635 | ||
|
|
d745564451 | ||
|
|
d37ac992fc | ||
|
|
e7fc3de90c | ||
|
|
bde81380c3 | ||
|
|
839b482cb5 | ||
|
|
72f70d4789 | ||
|
|
d646bbf5c1 | ||
|
|
e68aaf6540 | ||
|
|
20ab5ed0fa | ||
|
|
8590e390a2 | ||
|
|
ab1d558420 | ||
|
|
53c9021455 | ||
|
|
8bd00e2433 | ||
|
|
c045feae50 | ||
|
|
7531080e51 | ||
|
|
bf57ab3e39 | ||
|
|
dfcb96a4b6 | ||
|
|
5c4fad6725 | ||
|
|
988b1ad03b | ||
|
|
79705a2514 | ||
|
|
0919b15183 | ||
|
|
8162c87884 | ||
|
|
09394ee4b7 | ||
|
|
7f7dd60587 | ||
|
|
6877abb2ec | ||
|
|
ce5dd88790 | ||
|
|
5bc9d625e7 | ||
|
|
1d7a69ad40 | ||
|
|
f7d87076a3 | ||
|
|
9d20b4d6a6 | ||
|
|
128cf9b57d | ||
|
|
e5b7adb228 | ||
|
|
bd5ae66fbe | ||
|
|
a3af4155f8 | ||
|
|
1ec83dc790 | ||
|
|
f26cc38b80 | ||
|
|
d9f537e9dc | ||
|
|
94c75df0d0 | ||
|
|
423a8884e8 | ||
|
|
1f26502c64 | ||
|
|
f61f7bb711 | ||
|
|
971acd3fdb | ||
|
|
bba070bdbf | ||
|
|
6c4152a7e0 | ||
|
|
f569ad0970 | ||
|
|
f16a291412 | ||
|
|
e0cfa2dff3 | ||
|
|
bf9d087e74 | ||
|
|
b245dd55d6 | ||
|
|
1e3f429169 | ||
|
|
8d429c7e5a | ||
|
|
b9be3ad3b8 | ||
|
|
3099090e6a | ||
|
|
5e27c65615 | ||
|
|
8b32382e1b | ||
|
|
60047e8029 | ||
|
|
e37fff1213 | ||
|
|
64a6d8027b | ||
|
|
cd4434135e | ||
|
|
747e11d7dd | ||
|
|
3cae728aba | ||
|
|
7f24a5cf82 | ||
|
|
1b8f5f232a | ||
|
|
77d37de18c | ||
|
|
5ea3fb8e1e | ||
|
|
d683aa43d8 | ||
|
|
d4c3501bb8 | ||
|
|
f2229a0007 | ||
|
|
2a06bb6e2c | ||
|
|
a06f890ab9 | ||
|
|
bbe22f95d1 | ||
|
|
631f75a79c | ||
|
|
c121aae8f1 | ||
|
|
fed7629632 | ||
|
|
0825ca736f | ||
|
|
660974c9d1 | ||
|
|
4404b06d2a | ||
|
|
daef69099b | ||
|
|
6362994fd8 | ||
|
|
398cf43782 | ||
|
|
77f8a0f5f6 | ||
|
|
d7e54ccbed | ||
|
|
53a8855696 | ||
|
|
bd16ed1340 | ||
|
|
dd365fe334 | ||
|
|
2a6ba739bc | ||
|
|
a863466f70 | ||
|
|
32f07f4aae | ||
|
|
3ed0e010be | ||
|
|
fb3c0c8138 |
@@ -20,11 +20,14 @@ body:
|
||||
|
||||
### Please Avoid Issues Pertaining to the Following:
|
||||
- We are **not** accepting bug reports for **PSX mode** at this time
|
||||
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use a [proper PSX emulator](https://emulation.gametechwiki.com/index.php/PlayStation_emulators)
|
||||
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use [Duckstation](https://github.com/stenzek/duckstation/releases/tag/latest)
|
||||
- We do **not** accept issues relating to **upscaling** at this time
|
||||
- We are aware of the various problems with upscaling. The issue spans many games and having hundreds of issues for the same fundamental issues isn't particularly helpful. There are several workarounds for graphical problems that come as a result of upscaling
|
||||
- Please try your game at native resolution before creating an issue
|
||||
- If your bug is the result of upscaling please use the forums or discord for assistance with various upscaling workarounds. Additionally, the unofficial PCSX2 [Wiki](https://wiki.pcsx2.net/Main_Page) often lists various fixes for upscaling issues
|
||||
- We do **not** accept issues relating to Widescreen/no-interlace patches at this time
|
||||
- Any issues pertaining to Widescreen/no-interlace patches please forward them to the [patches repository](https://github.com/PCSX2/pcsx2_patches).
|
||||
|
||||
- type: textarea
|
||||
id: desc
|
||||
attributes:
|
||||
|
||||
@@ -20,11 +20,14 @@ body:
|
||||
|
||||
### Please Avoid Issues Pertaining to the Following:
|
||||
- We are **not** accepting bug reports for **PSX mode** at this time
|
||||
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use a [proper PSX emulator](https://emulation.gametechwiki.com/index.php/PlayStation_emulators)
|
||||
- If you are interested in helping contribute to PSX mode please do so on the forums. Otherwise our recommendation is that you use [Duckstation](https://github.com/stenzek/duckstation/releases/tag/latest)
|
||||
- We do **not** accept issues relating to **upscaling** at this time
|
||||
- We are aware of the various problems with upscaling. The issue spans many games and having hundreds of issues for the same fundamental issues isn't particularly helpful. There are several workarounds for graphical problems that come as a result of upscaling
|
||||
- Please try your game at native resolution before creating an issue
|
||||
- If your bug is the result of upscaling please use the forums or discord for assistance with various upscaling workarounds. Additionally, the unofficial PCSX2 [Wiki](https://wiki.pcsx2.net/Main_Page) often lists various fixes for upscaling issues
|
||||
- We do **not** accept issues relating to Widescreen/no-interlace patches at this time
|
||||
- Any issues pertaining to Widescreen/no-interlace patches please forward them to the [patches repository](https://github.com/PCSX2/pcsx2_patches).
|
||||
|
||||
- type: textarea
|
||||
id: desc
|
||||
attributes:
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
'Debugger':
|
||||
- 'pcsx2/DebugTools/*'
|
||||
- 'pcsx2/DebugTools/**/*'
|
||||
- 'pcsx2/gui/Debugger/*'
|
||||
- 'pcsx2/gui/Debugger/**/*'
|
||||
- 'pcsx2-qt/Debugger/*'
|
||||
- 'pcsx2-qt/Debugger/**/*'
|
||||
'IPC':
|
||||
- 'pcsx2/IPC*'
|
||||
- 'pcsx2/**/IPC*'
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
mv ./game_controller_db.txt ${{github.workspace}}/bin/resources/game_controller_db.txt
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
title: "PAD: Update to latest controller database"
|
||||
commit-message: "PAD: Update to latest controller database."
|
||||
|
||||
@@ -87,6 +87,7 @@ declare -a SYSLIBS=(
|
||||
"libvorbis.so.0"
|
||||
"libvorbisenc.so.2"
|
||||
"libxcb.so.1"
|
||||
"libxcb-cursor.so.0"
|
||||
"libxcb-render.so.0"
|
||||
"libxcb-shm.so.0"
|
||||
"libxkbcommon.so.0"
|
||||
@@ -157,6 +158,7 @@ declare -a SYSLIBS=(
|
||||
"libhx509.so.5"
|
||||
"libsqlite3.so.0"
|
||||
"libcrypt.so.1"
|
||||
"libdbus-1.so.3"
|
||||
)
|
||||
|
||||
declare -a DEPLIBS=(
|
||||
@@ -206,6 +208,9 @@ mkdir "$OUTDIR/usr"
|
||||
echo "Copying binary and resources..."
|
||||
cp -a "$BUILDDIR/bin" "$OUTDIR/usr"
|
||||
|
||||
# Get rid of unit tests, we don't want them bloating the squashfs.
|
||||
rm -fv "$OUTDIR"/usr/bin/*_test
|
||||
|
||||
# Patch RPATH so the binary goes hunting for shared libraries in the AppDir instead of system.
|
||||
echo "Patching RPATH in ${BINARY}..."
|
||||
patchelf --set-rpath '$ORIGIN/../lib' "$OUTDIR/usr/bin/$BINARY"
|
||||
|
||||
@@ -4,21 +4,21 @@ set -e
|
||||
|
||||
INSTALLDIR="$HOME/deps"
|
||||
NPROCS="$(getconf _NPROCESSORS_ONLN)"
|
||||
SDL=SDL2-2.26.4
|
||||
QT=6.4.3
|
||||
SDL=SDL2-2.26.5
|
||||
QT=6.5.0
|
||||
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
|
||||
|
||||
mkdir -p deps-build
|
||||
cd deps-build
|
||||
|
||||
cat > SHASUMS <<EOF
|
||||
1a0f686498fb768ad9f3f80b39037a7d006eac093aad39cb4ebcc832a8887231 $SDL.tar.gz
|
||||
ad8fea3da1be64c83c45b1d363a6b4ba8fd60f5bde3b23ec73855709ec5eabf7 $SDL.tar.gz
|
||||
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
|
||||
5087c9e5b0165e7bc3c1a4ab176b35d0cd8f52636aea903fa377bdba00891a60 qtbase-everywhere-src-$QT.tar.xz
|
||||
88315f886cf81898705e487cedba6e6160724359d23c518c92c333c098879a4a qtsvg-everywhere-src-$QT.tar.xz
|
||||
867df829cd5cd3ae8efe62e825503123542764b13c96953511e567df70c5a091 qttools-everywhere-src-$QT.tar.xz
|
||||
79e56b7800d49649a8a8010818538c367a829e0b7a09d5f60bd3aecf5abe972c qttranslations-everywhere-src-$QT.tar.xz
|
||||
c6b161da8f4c01e48c10b7b558a0a01ac07dba9b907b13a98ff5d89f46bc4789 qtwayland-everywhere-src-$QT.tar.xz
|
||||
fde1aa7b4fbe64ec1b4fc576a57f4688ad1453d2fab59cbadd948a10a6eaf5ef qtbase-everywhere-src-$QT.tar.xz
|
||||
64ca7e61f44d51e28bcbb4e0509299b53a9a7e38879e00a7fe91643196067a4f qtsvg-everywhere-src-$QT.tar.xz
|
||||
49c33d96b0a44988be954269b8ce3d1a495b439726e03a6be7c0d50a686369c4 qttools-everywhere-src-$QT.tar.xz
|
||||
fc85d0fd8393f518653ccada1014177a56df6e73f30f3b64eea0c2e4a0067a3d qttranslations-everywhere-src-$QT.tar.xz
|
||||
ccc57fa277fc5f1c1c2c4733eae80a60996b67a067233c47809e542aa31759a3 qtwayland-everywhere-src-$QT.tar.xz
|
||||
EOF
|
||||
|
||||
curl -L \
|
||||
|
||||
@@ -6,11 +6,11 @@ export MACOSX_DEPLOYMENT_TARGET=10.14
|
||||
|
||||
INSTALLDIR="$HOME/deps"
|
||||
NPROCS="$(getconf _NPROCESSORS_ONLN)"
|
||||
SDL=SDL2-2.26.0
|
||||
SDL=SDL2-2.26.5
|
||||
PNG=1.6.37
|
||||
JPG=9e
|
||||
SOUNDTOUCH=soundtouch-2.3.1
|
||||
QT=6.3.1
|
||||
QT=6.4.3
|
||||
|
||||
mkdir deps-build
|
||||
cd deps-build
|
||||
@@ -21,14 +21,14 @@ export CFLAGS="-I$INSTALLDIR/include -Os $CFLAGS"
|
||||
export CXXFLAGS="-I$INSTALLDIR/include -Os $CXXFLAGS"
|
||||
|
||||
cat > SHASUMS <<EOF
|
||||
8000d7169febce93c84b6bdf376631f8179132fd69f7015d4dadb8b9c2bdb295 $SDL.tar.gz
|
||||
ad8fea3da1be64c83c45b1d363a6b4ba8fd60f5bde3b23ec73855709ec5eabf7 $SDL.tar.gz
|
||||
505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca libpng-$PNG.tar.xz
|
||||
4077d6a6a75aeb01884f708919d25934c93305e49f7e3f36db9129320e6f4f3d jpegsrc.v$JPG.tar.gz
|
||||
6900996607258496ce126924a19fe9d598af9d892cf3f33d1e4daaa9b42ae0b1 $SOUNDTOUCH.tar.gz
|
||||
0a64421d9c2469c2c48490a032ab91d547017c9cc171f3f8070bc31888f24e03 qtbase-everywhere-src-$QT.tar.xz
|
||||
7b19f418e6f7b8e23344082dd04440aacf5da23c5a73980ba22ae4eba4f87df7 qtsvg-everywhere-src-$QT.tar.xz
|
||||
c412750f2aa3beb93fce5f30517c607f55daaeb7d0407af206a8adf917e126c1 qttools-everywhere-src-$QT.tar.xz
|
||||
d7bdd55e2908ded901dcc262157100af2a490bf04d31e32995f6d91d78dfdb97 qttranslations-everywhere-src-$QT.tar.xz
|
||||
5087c9e5b0165e7bc3c1a4ab176b35d0cd8f52636aea903fa377bdba00891a60 qtbase-everywhere-src-$QT.tar.xz
|
||||
88315f886cf81898705e487cedba6e6160724359d23c518c92c333c098879a4a qtsvg-everywhere-src-$QT.tar.xz
|
||||
867df829cd5cd3ae8efe62e825503123542764b13c96953511e567df70c5a091 qttools-everywhere-src-$QT.tar.xz
|
||||
79e56b7800d49649a8a8010818538c367a829e0b7a09d5f60bd3aecf5abe972c qttranslations-everywhere-src-$QT.tar.xz
|
||||
EOF
|
||||
|
||||
curl -L \
|
||||
|
||||
@@ -32,11 +32,11 @@ on:
|
||||
qt_binary_url:
|
||||
required: false
|
||||
type: string
|
||||
default: https://github.com/PCSX2/pcsx2-windows-dependencies/releases/download/2022-11-20/qt-6.4.0-x64.7z
|
||||
default: https://github.com/PCSX2/pcsx2-windows-dependencies/releases/download/2023-04-25/qt-6.5.0-x64.7z
|
||||
qt_dir:
|
||||
required: false
|
||||
type: string
|
||||
default: 3rdparty\qt\6.4.0\msvc2022_64
|
||||
default: 3rdparty\qt\6.5.0\msvc2022_64
|
||||
cheats_url:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
@@ -186,6 +186,7 @@
|
||||
03000000ad1b000028f0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000ad1b00002ef0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000ad1b000038f0000000000000,Fightpad TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03005036852100000000000000000000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000f806000001a3000000000000,Firestorm,a:b9,b:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b10,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b12,x:b8,y:b4,platform:Windows,
|
||||
03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows,
|
||||
03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows,
|
||||
@@ -536,6 +537,7 @@
|
||||
030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
|
||||
030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
|
||||
030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,
|
||||
030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
|
||||
030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,
|
||||
030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows,
|
||||
030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
@@ -662,6 +664,7 @@
|
||||
03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,
|
||||
03000000790000002601000000000000,TGZ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,platform:Windows,
|
||||
030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
|
||||
030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000004f0400000ed0000000000000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -982,6 +985,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X,
|
||||
030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,
|
||||
030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,
|
||||
@@ -1140,6 +1144,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006e0500000720000010010000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
|
||||
030000007d0400000640000010010000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Linux,
|
||||
03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
@@ -1149,6 +1154,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
@@ -1268,6 +1274,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000b50700004f00000000010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux,
|
||||
030000005e0400000300000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
|
||||
@@ -1328,8 +1335,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
|
||||
030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
|
||||
030000007e0500001920000011810000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux,
|
||||
050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux,
|
||||
050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
|
||||
050000007e0500001920000001800000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux,
|
||||
030000007e0500001720000011810000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
|
||||
050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux,
|
||||
050000007e0500001720000001800000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux,
|
||||
03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
|
||||
05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux,
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
cbuffer vertexBuffer : register(b0)
|
||||
{
|
||||
float4x4 ProjectionMatrix;
|
||||
};
|
||||
|
||||
struct VS_INPUT
|
||||
{
|
||||
float2 pos : POSITION;
|
||||
float4 col : COLOR0;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 pos : SV_POSITION;
|
||||
float4 col : COLOR0;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
PS_INPUT vs_main(VS_INPUT input)
|
||||
{
|
||||
PS_INPUT output;
|
||||
output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));
|
||||
output.col = input.col;
|
||||
output.uv = input.uv;
|
||||
return output;
|
||||
}
|
||||
|
||||
sampler sampler0 : register(s0);
|
||||
Texture2D texture0 : register(t0);
|
||||
|
||||
float4 ps_main(PS_INPUT input) : SV_Target
|
||||
{
|
||||
float4 out_col = input.col * texture0.Sample(sampler0, input.uv);
|
||||
return out_col;
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
#ifdef SHADER_MODEL // make safe to include in resource file to enforce dependency
|
||||
|
||||
#define FMT_32 0
|
||||
#define FMT_24 1
|
||||
#define FMT_16 2
|
||||
@@ -113,6 +111,8 @@ struct PS_INPUT
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef PIXEL_SHADER
|
||||
|
||||
struct PS_OUTPUT
|
||||
{
|
||||
#if !PS_NO_COLOR
|
||||
@@ -136,21 +136,6 @@ Texture2D<float4> RtTexture : register(t2);
|
||||
Texture2D<float> PrimMinTexture : register(t3);
|
||||
SamplerState TextureSampler : register(s0);
|
||||
|
||||
#ifdef DX12
|
||||
cbuffer cb0 : register(b0)
|
||||
#else
|
||||
cbuffer cb0
|
||||
#endif
|
||||
{
|
||||
float2 VertexScale;
|
||||
float2 VertexOffset;
|
||||
float2 TextureScale;
|
||||
float2 TextureOffset;
|
||||
float2 PointSize;
|
||||
uint MaxDepth;
|
||||
uint pad_cb0;
|
||||
};
|
||||
|
||||
#ifdef DX12
|
||||
cbuffer cb1 : register(b1)
|
||||
#else
|
||||
@@ -437,8 +422,12 @@ int2 clamp_wrap_uv_depth(int2 uv)
|
||||
float4 sample_depth(float2 st, float2 pos)
|
||||
{
|
||||
float2 uv_f = (float2)clamp_wrap_uv_depth(int2(st)) * (float2)ScaledScaleFactor;
|
||||
int2 uv = (int2)uv_f;
|
||||
|
||||
#if PS_REGION_RECT == 1
|
||||
uv_f = clamp(uv_f + STRange.xy, STRange.xy, STRange.zw);
|
||||
#endif
|
||||
|
||||
int2 uv = (int2)uv_f;
|
||||
float4 t = (float4)(0.0f);
|
||||
|
||||
if (PS_TALES_OF_ABYSS_HLE == 1)
|
||||
@@ -1058,10 +1047,29 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif // PIXEL_SHADER
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Vertex Shader
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
|
||||
#ifdef DX12
|
||||
cbuffer cb0 : register(b0)
|
||||
#else
|
||||
cbuffer cb0
|
||||
#endif
|
||||
{
|
||||
float2 VertexScale;
|
||||
float2 VertexOffset;
|
||||
float2 TextureScale;
|
||||
float2 TextureOffset;
|
||||
float2 PointSize;
|
||||
uint MaxDepth;
|
||||
uint BaseVertex; // Only used in DX11.
|
||||
};
|
||||
|
||||
VS_OUTPUT vs_main(VS_INPUT input)
|
||||
{
|
||||
// Clamp to max depth, gs doesn't wrap
|
||||
@@ -1114,156 +1122,101 @@ VS_OUTPUT vs_main(VS_INPUT input)
|
||||
return output;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Geometry Shader
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
#if VS_EXPAND != 0
|
||||
|
||||
#if GS_FORWARD_PRIMID
|
||||
#define PRIMID_IN , uint primid : SV_PrimitiveID
|
||||
#define VS2PS(x) vs2ps_impl(x, primid)
|
||||
PS_INPUT vs2ps_impl(VS_OUTPUT vs, uint primid)
|
||||
struct VS_RAW_INPUT
|
||||
{
|
||||
PS_INPUT o;
|
||||
o.p = vs.p;
|
||||
o.t = vs.t;
|
||||
o.ti = vs.ti;
|
||||
o.c = vs.c;
|
||||
o.primid = primid;
|
||||
return o;
|
||||
}
|
||||
float2 ST;
|
||||
uint RGBA;
|
||||
float Q;
|
||||
uint XY;
|
||||
uint Z;
|
||||
uint UV;
|
||||
uint FOG;
|
||||
};
|
||||
|
||||
StructuredBuffer<VS_RAW_INPUT> vertices : register(t0);
|
||||
|
||||
VS_INPUT load_vertex(uint index)
|
||||
{
|
||||
#ifdef DX12
|
||||
VS_RAW_INPUT raw = vertices.Load(index);
|
||||
#else
|
||||
#define PRIMID_IN
|
||||
#define VS2PS(x) vs2ps_impl(x)
|
||||
PS_INPUT vs2ps_impl(VS_OUTPUT vs)
|
||||
{
|
||||
PS_INPUT o;
|
||||
o.p = vs.p;
|
||||
o.t = vs.t;
|
||||
o.ti = vs.ti;
|
||||
o.c = vs.c;
|
||||
return o;
|
||||
}
|
||||
VS_RAW_INPUT raw = vertices.Load(BaseVertex + index);
|
||||
#endif
|
||||
|
||||
#if GS_PRIM == 0
|
||||
|
||||
[maxvertexcount(6)]
|
||||
void gs_main(point VS_OUTPUT input[1], inout TriangleStream<PS_INPUT> stream PRIMID_IN)
|
||||
{
|
||||
// Transform a point to a NxN sprite
|
||||
PS_INPUT Point = VS2PS(input[0]);
|
||||
|
||||
// Get new position
|
||||
float4 lt_p = input[0].p;
|
||||
float4 rb_p = input[0].p + float4(PointSize.x, PointSize.y, 0.0f, 0.0f);
|
||||
float4 lb_p = rb_p;
|
||||
float4 rt_p = rb_p;
|
||||
lb_p.x = lt_p.x;
|
||||
rt_p.y = lt_p.y;
|
||||
|
||||
// Triangle 1
|
||||
Point.p = lt_p;
|
||||
stream.Append(Point);
|
||||
|
||||
Point.p = lb_p;
|
||||
stream.Append(Point);
|
||||
|
||||
Point.p = rt_p;
|
||||
stream.Append(Point);
|
||||
|
||||
// Triangle 2
|
||||
Point.p = lb_p;
|
||||
stream.Append(Point);
|
||||
|
||||
Point.p = rt_p;
|
||||
stream.Append(Point);
|
||||
|
||||
Point.p = rb_p;
|
||||
stream.Append(Point);
|
||||
VS_INPUT vert;
|
||||
vert.st = raw.ST;
|
||||
vert.c = uint4(raw.RGBA & 0xFFu, (raw.RGBA >> 8) & 0xFFu, (raw.RGBA >> 16) & 0xFFu, raw.RGBA >> 24);
|
||||
vert.q = raw.Q;
|
||||
vert.p = uint2(raw.XY & 0xFFFFu, raw.XY >> 16);
|
||||
vert.z = raw.Z;
|
||||
vert.uv = uint2(raw.UV & 0xFFFFu, raw.UV >> 16);
|
||||
vert.f = float4(float(raw.FOG & 0xFFu), float((raw.FOG >> 8) & 0xFFu), float((raw.FOG >> 16) & 0xFFu), float(raw.FOG >> 24)) / 255.0f;
|
||||
return vert;
|
||||
}
|
||||
|
||||
#elif GS_PRIM == 1
|
||||
|
||||
[maxvertexcount(6)]
|
||||
void gs_main(line VS_OUTPUT input[2], inout TriangleStream<PS_INPUT> stream PRIMID_IN)
|
||||
VS_OUTPUT vs_main_expand(uint vid : SV_VertexID)
|
||||
{
|
||||
// Transform a line to a thick line-sprite
|
||||
PS_INPUT left = VS2PS(input[0]);
|
||||
PS_INPUT right = VS2PS(input[1]);
|
||||
float2 lt_p = input[0].p.xy;
|
||||
float2 rt_p = input[1].p.xy;
|
||||
#if VS_EXPAND == 1 // Point
|
||||
|
||||
// Potentially there is faster math
|
||||
float2 line_vector = normalize(rt_p.xy - lt_p.xy);
|
||||
VS_OUTPUT vtx = vs_main(load_vertex(vid >> 2));
|
||||
|
||||
vtx.p.x += ((vid & 1u) != 0u) ? PointSize.x : 0.0f;
|
||||
vtx.p.y += ((vid & 2u) != 0u) ? PointSize.y : 0.0f;
|
||||
|
||||
return vtx;
|
||||
|
||||
#elif VS_EXPAND == 2 // Line
|
||||
|
||||
uint vid_base = vid >> 2;
|
||||
bool is_bottom = vid & 2;
|
||||
bool is_right = vid & 1;
|
||||
// All lines will be a pair of vertices next to each other
|
||||
// Since DirectX uses provoking vertex first, the bottom point will be the lower of the two
|
||||
uint vid_other = is_bottom ? vid_base + 1 : vid_base - 1;
|
||||
VS_OUTPUT vtx = vs_main(load_vertex(vid_base));
|
||||
VS_OUTPUT other = vs_main(load_vertex(vid_other));
|
||||
|
||||
float2 line_vector = normalize(vtx.p.xy - other.p.xy);
|
||||
float2 line_normal = float2(line_vector.y, -line_vector.x);
|
||||
float2 line_width = (line_normal * PointSize) / 2;
|
||||
// line_normal is inverted for bottom point
|
||||
float2 offset = (is_bottom ^ is_right) ? line_width : -line_width;
|
||||
vtx.p.xy += offset;
|
||||
|
||||
lt_p -= line_width;
|
||||
rt_p -= line_width;
|
||||
float2 lb_p = input[0].p.xy + line_width;
|
||||
float2 rb_p = input[1].p.xy + line_width;
|
||||
// Lines will be run as (0 1 2) (1 2 3)
|
||||
// This means that both triangles will have a point based off the top line point as their first point
|
||||
// So we don't have to do anything for !IIP
|
||||
|
||||
#if GS_IIP == 0
|
||||
left.c = right.c;
|
||||
#endif
|
||||
return vtx;
|
||||
|
||||
// Triangle 1
|
||||
left.p.xy = lt_p;
|
||||
stream.Append(left);
|
||||
#elif VS_EXPAND == 3 // Sprite
|
||||
|
||||
left.p.xy = lb_p;
|
||||
stream.Append(left);
|
||||
// Sprite points are always in pairs
|
||||
uint vid_base = vid >> 1;
|
||||
uint vid_lt = vid_base & ~1u;
|
||||
uint vid_rb = vid_base | 1u;
|
||||
|
||||
right.p.xy = rt_p;
|
||||
stream.Append(right);
|
||||
stream.RestartStrip();
|
||||
VS_OUTPUT lt = vs_main(load_vertex(vid_lt));
|
||||
VS_OUTPUT rb = vs_main(load_vertex(vid_rb));
|
||||
VS_OUTPUT vtx = rb;
|
||||
|
||||
// Triangle 2
|
||||
left.p.xy = lb_p;
|
||||
stream.Append(left);
|
||||
bool is_right = ((vid & 1u) != 0u);
|
||||
vtx.p.x = is_right ? lt.p.x : vtx.p.x;
|
||||
vtx.t.x = is_right ? lt.t.x : vtx.t.x;
|
||||
vtx.ti.xz = is_right ? lt.ti.xz : vtx.ti.xz;
|
||||
|
||||
right.p.xy = rt_p;
|
||||
stream.Append(right);
|
||||
bool is_bottom = ((vid & 2u) != 0u);
|
||||
vtx.p.y = is_bottom ? lt.p.y : vtx.p.y;
|
||||
vtx.t.y = is_bottom ? lt.t.y : vtx.t.y;
|
||||
vtx.ti.yw = is_bottom ? lt.ti.yw : vtx.ti.yw;
|
||||
|
||||
right.p.xy = rb_p;
|
||||
stream.Append(right);
|
||||
stream.RestartStrip();
|
||||
}
|
||||
|
||||
#elif GS_PRIM == 3
|
||||
|
||||
[maxvertexcount(4)]
|
||||
void gs_main(line VS_OUTPUT input[2], inout TriangleStream<PS_INPUT> stream PRIMID_IN)
|
||||
{
|
||||
PS_INPUT lt = VS2PS(input[0]);
|
||||
PS_INPUT rb = VS2PS(input[1]);
|
||||
|
||||
// flat depth
|
||||
lt.p.z = rb.p.z;
|
||||
// flat fog and texture perspective
|
||||
lt.t.zw = rb.t.zw;
|
||||
|
||||
// flat color
|
||||
lt.c = rb.c;
|
||||
|
||||
// Swap texture and position coordinate
|
||||
PS_INPUT lb = rb;
|
||||
lb.p.x = lt.p.x;
|
||||
lb.t.x = lt.t.x;
|
||||
lb.ti.x = lt.ti.x;
|
||||
lb.ti.z = lt.ti.z;
|
||||
|
||||
PS_INPUT rt = rb;
|
||||
rt.p.y = lt.p.y;
|
||||
rt.t.y = lt.t.y;
|
||||
rt.ti.y = lt.ti.y;
|
||||
rt.ti.w = lt.ti.w;
|
||||
|
||||
stream.Append(lt);
|
||||
stream.Append(lb);
|
||||
stream.Append(rt);
|
||||
stream.Append(rb);
|
||||
}
|
||||
return vtx;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // VS_EXPAND
|
||||
|
||||
#endif // VERTEX_SHADER
|
||||
|
||||
@@ -30,7 +30,7 @@ layout(binding=0, rgba8) uniform writeonly image2D imgDst;
|
||||
|
||||
AF3 CasLoad(ASU2 p)
|
||||
{
|
||||
return texelFetch(imgSrc, srcOffset + ivec2(p), 0).rgb;
|
||||
return texelFetch(imgSrc, srcOffset + ivec2(p), 0).rgb;
|
||||
}
|
||||
|
||||
// Lets you transform input from the load into a linear color space between 0 and 1. See ffx_cas.h
|
||||
@@ -42,23 +42,23 @@ void CasInput(inout AF1 r, inout AF1 g, inout AF1 b) {}
|
||||
layout(local_size_x=64) in;
|
||||
void main()
|
||||
{
|
||||
// Do remapping of local xy in workgroup for a more PS-like swizzle pattern.
|
||||
AU2 gxy = ARmp8x8(gl_LocalInvocationID.x)+AU2(gl_WorkGroupID.x<<4u,gl_WorkGroupID.y<<4u);
|
||||
// Do remapping of local xy in workgroup for a more PS-like swizzle pattern.
|
||||
AU2 gxy = ARmp8x8(gl_LocalInvocationID.x)+AU2(gl_WorkGroupID.x<<4u,gl_WorkGroupID.y<<4u);
|
||||
|
||||
// Filter.
|
||||
AF4 c;
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
|
||||
imageStore(imgDst, ASU2(gxy), c);
|
||||
gxy.x += 8u;
|
||||
// Filter.
|
||||
AF4 c;
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
|
||||
imageStore(imgDst, ASU2(gxy), c);
|
||||
gxy.x += 8u;
|
||||
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
|
||||
imageStore(imgDst, ASU2(gxy), c);
|
||||
gxy.y += 8u;
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
|
||||
imageStore(imgDst, ASU2(gxy), c);
|
||||
gxy.y += 8u;
|
||||
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
|
||||
imageStore(imgDst, ASU2(gxy), c);
|
||||
gxy.x -= 8u;
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
|
||||
imageStore(imgDst, ASU2(gxy), c);
|
||||
gxy.x -= 8u;
|
||||
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
|
||||
imageStore(imgDst, ASU2(gxy), c);
|
||||
CasFilter(c.r, c.g, c.b, gxy, const0, const1, CAS_SHARPEN_ONLY);
|
||||
imageStore(imgDst, ASU2(gxy), c);
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ out vec4 PSin_c;
|
||||
|
||||
void vs_main()
|
||||
{
|
||||
PSin_p = vec4(POSITION, 0.5f, 1.0f);
|
||||
PSin_t = TEXCOORD0;
|
||||
PSin_c = COLOR;
|
||||
gl_Position = vec4(POSITION, 0.5f, 1.0f); // NOTE I don't know if it is possible to merge POSITION_OUT and gl_Position
|
||||
PSin_p = vec4(POSITION, 0.5f, 1.0f);
|
||||
PSin_t = TEXCOORD0;
|
||||
PSin_c = COLOR;
|
||||
gl_Position = vec4(POSITION, 0.5f, 1.0f); // NOTE I don't know if it is possible to merge POSITION_OUT and gl_Position
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -46,13 +46,13 @@ layout(location = 0) out vec4 SV_Target0;
|
||||
|
||||
vec4 sample_c()
|
||||
{
|
||||
return texture(TextureSampler, PSin_t);
|
||||
return texture(TextureSampler, PSin_t);
|
||||
}
|
||||
|
||||
#ifdef ps_copy
|
||||
void ps_copy()
|
||||
{
|
||||
SV_Target0 = sample_c();
|
||||
SV_Target0 = sample_c();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -67,20 +67,20 @@ void ps_depth_copy()
|
||||
// Need to be careful with precision here, it can break games like Spider-Man 3 and Dogs Life
|
||||
void ps_convert_rgba8_16bits()
|
||||
{
|
||||
highp uvec4 i = uvec4(sample_c() * vec4(255.5f, 255.5f, 255.5f, 255.5f));
|
||||
highp uvec4 i = uvec4(sample_c() * vec4(255.5f, 255.5f, 255.5f, 255.5f));
|
||||
|
||||
SV_Target1 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
|
||||
SV_Target1 = ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float32_32bits
|
||||
void ps_convert_float32_32bits()
|
||||
{
|
||||
// Convert a GL_FLOAT32 depth texture into a 32 bits UINT texture
|
||||
// Convert a GL_FLOAT32 depth texture into a 32 bits UINT texture
|
||||
#if HAS_CLIP_CONTROL
|
||||
SV_Target1 = uint(exp2(32.0f) * sample_c().r);
|
||||
SV_Target1 = uint(exp2(32.0f) * sample_c().r);
|
||||
#else
|
||||
SV_Target1 = uint(exp2(24.0f) * sample_c().r);
|
||||
SV_Target1 = uint(exp2(24.0f) * sample_c().r);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -88,150 +88,150 @@ void ps_convert_float32_32bits()
|
||||
#ifdef ps_convert_float32_rgba8
|
||||
void ps_convert_float32_rgba8()
|
||||
{
|
||||
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
|
||||
// Convert a GL_FLOAT32 depth texture into a RGBA color texture
|
||||
#if HAS_CLIP_CONTROL
|
||||
uint d = uint(sample_c().r * exp2(32.0f));
|
||||
uint d = uint(sample_c().r * exp2(32.0f));
|
||||
#else
|
||||
uint d = uint(sample_c().r * exp2(24.0f));
|
||||
uint d = uint(sample_c().r * exp2(24.0f));
|
||||
#endif
|
||||
SV_Target0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0);
|
||||
SV_Target0 = vec4(uvec4((d & 0xFFu), ((d >> 8) & 0xFFu), ((d >> 16) & 0xFFu), (d >> 24))) / vec4(255.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_float16_rgb5a1
|
||||
void ps_convert_float16_rgb5a1()
|
||||
{
|
||||
// Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
|
||||
// Convert a GL_FLOAT32 (only 16 lsb) depth into a RGB5A1 color texture
|
||||
#if HAS_CLIP_CONTROL
|
||||
uint d = uint(sample_c().r * exp2(32.0f));
|
||||
uint d = uint(sample_c().r * exp2(32.0f));
|
||||
#else
|
||||
uint d = uint(sample_c().r * exp2(24.0f));
|
||||
uint d = uint(sample_c().r * exp2(24.0f));
|
||||
#endif
|
||||
SV_Target0 = vec4(uvec4((d & 0x1Fu), ((d >> 5) & 0x1Fu), ((d >> 10) & 0x1Fu), (d >> 15) & 0x01u)) / vec4(32.0f, 32.0f, 32.0f, 1.0f);
|
||||
SV_Target0 = vec4(uvec4((d & 0x1Fu), ((d >> 5) & 0x1Fu), ((d >> 10) & 0x1Fu), (d >> 15) & 0x01u)) / vec4(32.0f, 32.0f, 32.0f, 1.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
float rgba8_to_depth32(vec4 unorm)
|
||||
{
|
||||
uvec4 c = uvec4(unorm * vec4(255.5f));
|
||||
uvec4 c = uvec4(unorm * vec4(255.5f));
|
||||
#if HAS_CLIP_CONTROL
|
||||
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
|
||||
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-32.0f);
|
||||
#else
|
||||
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-24.0f);
|
||||
return float(c.r | (c.g << 8) | (c.b << 16) | (c.a << 24)) * exp2(-24.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
float rgba8_to_depth24(vec4 unorm)
|
||||
{
|
||||
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
|
||||
uvec3 c = uvec3(unorm.rgb * vec3(255.5f));
|
||||
#if HAS_CLIP_CONTROL
|
||||
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
|
||||
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-32.0f);
|
||||
#else
|
||||
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-24.0f);
|
||||
return float(c.r | (c.g << 8) | (c.b << 16)) * exp2(-24.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
float rgba8_to_depth16(vec4 unorm)
|
||||
{
|
||||
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
|
||||
uvec2 c = uvec2(unorm.rg * vec2(255.5f));
|
||||
#if HAS_CLIP_CONTROL
|
||||
return float(c.r | (c.g << 8)) * exp2(-32.0f);
|
||||
return float(c.r | (c.g << 8)) * exp2(-32.0f);
|
||||
#else
|
||||
return float(c.r | (c.g << 8)) * exp2(-24.0f);
|
||||
return float(c.r | (c.g << 8)) * exp2(-24.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
float rgb5a1_to_depth16(vec4 unorm)
|
||||
{
|
||||
uvec4 c = uvec4(unorm * vec4(255.5f));
|
||||
uvec4 c = uvec4(unorm * vec4(255.5f));
|
||||
#if HAS_CLIP_CONTROL
|
||||
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
|
||||
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-32.0f);
|
||||
#else
|
||||
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-24.0f);
|
||||
return float(((c.r & 0xF8u) >> 3) | ((c.g & 0xF8u) << 2) | ((c.b & 0xF8u) << 7) | ((c.a & 0x80u) << 8)) * exp2(-24.0f);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ps_convert_rgba8_float32
|
||||
void ps_convert_rgba8_float32()
|
||||
{
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth32(sample_c());
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth32(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float24
|
||||
void ps_convert_rgba8_float24()
|
||||
{
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth24(sample_c());
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth24(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float16
|
||||
void ps_convert_rgba8_float16()
|
||||
{
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth16(sample_c());
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
gl_FragDepth = rgba8_to_depth16(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgb5a1_float16
|
||||
void ps_convert_rgb5a1_float16()
|
||||
{
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
gl_FragDepth = rgb5a1_to_depth16(sample_c());
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
gl_FragDepth = rgb5a1_to_depth16(sample_c());
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SAMPLE_RGBA_DEPTH_BILN(CONVERT_FN) \
|
||||
ivec2 dims = textureSize(TextureSampler, 0); \
|
||||
vec2 top_left_f = PSin_t * vec2(dims) - 0.5f; \
|
||||
ivec2 top_left = ivec2(floor(top_left_f)); \
|
||||
ivec4 coords = clamp(ivec4(top_left, top_left + 1), ivec4(0), dims.xyxy - 1); \
|
||||
vec2 mix_vals = fract(top_left_f); \
|
||||
float depthTL = CONVERT_FN(texelFetch(TextureSampler, coords.xy, 0)); \
|
||||
float depthTR = CONVERT_FN(texelFetch(TextureSampler, coords.zy, 0)); \
|
||||
float depthBL = CONVERT_FN(texelFetch(TextureSampler, coords.xw, 0)); \
|
||||
float depthBR = CONVERT_FN(texelFetch(TextureSampler, coords.zw, 0)); \
|
||||
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
|
||||
ivec2 dims = textureSize(TextureSampler, 0); \
|
||||
vec2 top_left_f = PSin_t * vec2(dims) - 0.5f; \
|
||||
ivec2 top_left = ivec2(floor(top_left_f)); \
|
||||
ivec4 coords = clamp(ivec4(top_left, top_left + 1), ivec4(0), dims.xyxy - 1); \
|
||||
vec2 mix_vals = fract(top_left_f); \
|
||||
float depthTL = CONVERT_FN(texelFetch(TextureSampler, coords.xy, 0)); \
|
||||
float depthTR = CONVERT_FN(texelFetch(TextureSampler, coords.zy, 0)); \
|
||||
float depthBL = CONVERT_FN(texelFetch(TextureSampler, coords.xw, 0)); \
|
||||
float depthBR = CONVERT_FN(texelFetch(TextureSampler, coords.zw, 0)); \
|
||||
gl_FragDepth = mix(mix(depthTL, depthTR, mix_vals.x), mix(depthBL, depthBR, mix_vals.x), mix_vals.y);
|
||||
|
||||
#ifdef ps_convert_rgba8_float32_biln
|
||||
void ps_convert_rgba8_float32_biln()
|
||||
{
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth32);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float24_biln
|
||||
void ps_convert_rgba8_float24_biln()
|
||||
{
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
// Same as above but without the alpha channel (24 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth24);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba8_float16_biln
|
||||
void ps_convert_rgba8_float16_biln()
|
||||
{
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
// Same as above but without the A/B channels (16 bits Z)
|
||||
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
|
||||
// Convert an RGBA texture into a float depth texture
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgba8_to_depth16);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgb5a1_float16_biln
|
||||
void ps_convert_rgb5a1_float16_biln()
|
||||
{
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
|
||||
// Convert an RGB5A1 (saved as RGBA8) color to a 16 bit Z
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -242,51 +242,51 @@ uniform float ScaleFactor;
|
||||
|
||||
void ps_convert_rgba_8i()
|
||||
{
|
||||
// Convert a RGBA texture into a 8 bits packed texture
|
||||
// Input column: 8x2 RGBA pixels
|
||||
// 0: 8 RGBA
|
||||
// 1: 8 RGBA
|
||||
// Output column: 16x4 Index pixels
|
||||
// 0: 8 R | 8 B
|
||||
// 1: 8 R | 8 B
|
||||
// 2: 8 G | 8 A
|
||||
// 3: 8 G | 8 A
|
||||
uvec2 pos = uvec2(gl_FragCoord.xy);
|
||||
// Convert a RGBA texture into a 8 bits packed texture
|
||||
// Input column: 8x2 RGBA pixels
|
||||
// 0: 8 RGBA
|
||||
// 1: 8 RGBA
|
||||
// Output column: 16x4 Index pixels
|
||||
// 0: 8 R | 8 B
|
||||
// 1: 8 R | 8 B
|
||||
// 2: 8 G | 8 A
|
||||
// 3: 8 G | 8 A
|
||||
uvec2 pos = uvec2(gl_FragCoord.xy);
|
||||
|
||||
// Collapse separate R G B A areas into their base pixel
|
||||
uvec2 block = (pos & ~uvec2(15u, 3u)) >> 1;
|
||||
uvec2 subblock = pos & uvec2(7u, 1u);
|
||||
uvec2 coord = block | subblock;
|
||||
// Collapse separate R G B A areas into their base pixel
|
||||
uvec2 block = (pos & ~uvec2(15u, 3u)) >> 1;
|
||||
uvec2 subblock = pos & uvec2(7u, 1u);
|
||||
uvec2 coord = block | subblock;
|
||||
|
||||
// Compensate for potentially differing page pitch.
|
||||
// Compensate for potentially differing page pitch.
|
||||
uvec2 block_xy = coord / uvec2(64u, 32u);
|
||||
uint block_num = (block_xy.y * (DBW / 128u)) + block_xy.x;
|
||||
uvec2 block_offset = uvec2((block_num % (SBW / 64u)) * 64u, (block_num / (SBW / 64u)) * 32u);
|
||||
coord = (coord % uvec2(64u, 32u)) + block_offset;
|
||||
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
|
||||
if (floor(ScaleFactor) != ScaleFactor)
|
||||
coord = uvec2(vec2(coord) * ScaleFactor);
|
||||
else
|
||||
coord *= uvec2(ScaleFactor);
|
||||
if (floor(ScaleFactor) != ScaleFactor)
|
||||
coord = uvec2(vec2(coord) * ScaleFactor);
|
||||
else
|
||||
coord *= uvec2(ScaleFactor);
|
||||
|
||||
vec4 pixel = texelFetch(TextureSampler, ivec2(coord), 0);
|
||||
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
|
||||
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
|
||||
SV_Target0 = vec4(sel1);
|
||||
vec4 pixel = texelFetch(TextureSampler, ivec2(coord), 0);
|
||||
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
|
||||
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
|
||||
SV_Target0 = vec4(sel1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_filter_transparency
|
||||
void ps_filter_transparency()
|
||||
{
|
||||
vec4 c = sample_c();
|
||||
SV_Target0 = vec4(c.rgb, 1.0);
|
||||
vec4 c = sample_c();
|
||||
SV_Target0 = vec4(c.rgb, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -295,8 +295,8 @@ void ps_filter_transparency()
|
||||
#ifdef ps_datm1
|
||||
void ps_datm1()
|
||||
{
|
||||
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
discard;
|
||||
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -305,24 +305,24 @@ void ps_datm1()
|
||||
#ifdef ps_datm0
|
||||
void ps_datm0()
|
||||
{
|
||||
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
|
||||
discard;
|
||||
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_hdr_init
|
||||
void ps_hdr_init()
|
||||
{
|
||||
vec4 value = sample_c();
|
||||
SV_Target0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a);
|
||||
vec4 value = sample_c();
|
||||
SV_Target0 = vec4(round(value.rgb * 255.0f) / 65535.0f, value.a);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_hdr_resolve
|
||||
void ps_hdr_resolve()
|
||||
{
|
||||
vec4 value = sample_c();
|
||||
SV_Target0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a);
|
||||
vec4 value = sample_c();
|
||||
SV_Target0 = vec4(vec3(uvec3(value.rgb * 65535.0f) & 255u) / 255.0f, value.a);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -366,51 +366,51 @@ uniform ivec2 EMOD;
|
||||
|
||||
void ps_yuv()
|
||||
{
|
||||
vec4 i = sample_c();
|
||||
vec4 o;
|
||||
vec4 i = sample_c();
|
||||
vec4 o;
|
||||
|
||||
mat3 rgb2yuv; // Value from GS manual
|
||||
rgb2yuv[0] = vec3(0.587, -0.311, -0.419);
|
||||
rgb2yuv[1] = vec3(0.114, 0.500, -0.081);
|
||||
rgb2yuv[2] = vec3(0.299, -0.169, 0.500);
|
||||
mat3 rgb2yuv; // Value from GS manual
|
||||
rgb2yuv[0] = vec3(0.587, -0.311, -0.419);
|
||||
rgb2yuv[1] = vec3(0.114, 0.500, -0.081);
|
||||
rgb2yuv[2] = vec3(0.299, -0.169, 0.500);
|
||||
|
||||
vec3 yuv = rgb2yuv * i.gbr;
|
||||
vec3 yuv = rgb2yuv * i.gbr;
|
||||
|
||||
float Y = float(0xDB)/255.0f * yuv.x + float(0x10)/255.0f;
|
||||
float Cr = float(0xE0)/255.0f * yuv.y + float(0x80)/255.0f;
|
||||
float Cb = float(0xE0)/255.0f * yuv.z + float(0x80)/255.0f;
|
||||
float Y = float(0xDB)/255.0f * yuv.x + float(0x10)/255.0f;
|
||||
float Cr = float(0xE0)/255.0f * yuv.y + float(0x80)/255.0f;
|
||||
float Cb = float(0xE0)/255.0f * yuv.z + float(0x80)/255.0f;
|
||||
|
||||
switch(EMOD.x) {
|
||||
case 0:
|
||||
o.a = i.a;
|
||||
break;
|
||||
case 1:
|
||||
o.a = Y;
|
||||
break;
|
||||
case 2:
|
||||
o.a = Y/2.0f;
|
||||
break;
|
||||
case 3:
|
||||
o.a = 0.0f;
|
||||
break;
|
||||
}
|
||||
switch(EMOD.x) {
|
||||
case 0:
|
||||
o.a = i.a;
|
||||
break;
|
||||
case 1:
|
||||
o.a = Y;
|
||||
break;
|
||||
case 2:
|
||||
o.a = Y/2.0f;
|
||||
break;
|
||||
case 3:
|
||||
o.a = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(EMOD.y) {
|
||||
case 0:
|
||||
o.rgb = i.rgb;
|
||||
break;
|
||||
case 1:
|
||||
o.rgb = vec3(Y);
|
||||
break;
|
||||
case 2:
|
||||
o.rgb = vec3(Y, Cb, Cr);
|
||||
break;
|
||||
case 3:
|
||||
o.rgb = vec3(i.a);
|
||||
break;
|
||||
}
|
||||
switch(EMOD.y) {
|
||||
case 0:
|
||||
o.rgb = i.rgb;
|
||||
break;
|
||||
case 1:
|
||||
o.rgb = vec3(Y);
|
||||
break;
|
||||
case 2:
|
||||
o.rgb = vec3(Y, Cb, Cr);
|
||||
break;
|
||||
case 3:
|
||||
o.rgb = vec3(i.a);
|
||||
break;
|
||||
}
|
||||
|
||||
SV_Target0 = o;
|
||||
SV_Target0 = o;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -418,16 +418,16 @@ void ps_yuv()
|
||||
|
||||
void main()
|
||||
{
|
||||
SV_Target0 = vec4(0x7FFFFFFF);
|
||||
SV_Target0 = vec4(0x7FFFFFFF);
|
||||
|
||||
#ifdef ps_stencil_image_init_0
|
||||
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
|
||||
SV_Target0 = vec4(-1);
|
||||
#endif
|
||||
#ifdef ps_stencil_image_init_1
|
||||
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
SV_Target0 = vec4(-1);
|
||||
#endif
|
||||
#ifdef ps_stencil_image_init_0
|
||||
if((127.5f / 255.0f) < sample_c().a) // < 0x80 pass (== 0x80 should not pass)
|
||||
SV_Target0 = vec4(-1);
|
||||
#endif
|
||||
#ifdef ps_stencil_image_init_1
|
||||
if(sample_c().a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
SV_Target0 = vec4(-1);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifdef VERTEX_SHADER
|
||||
|
||||
layout(location = 0) in vec2 Position;
|
||||
layout(location = 1) in vec2 UV;
|
||||
layout(location = 2) in vec4 Color;
|
||||
|
||||
uniform mat4 ProjMtx;
|
||||
|
||||
out vec2 Frag_UV;
|
||||
out vec4 Frag_Color;
|
||||
|
||||
void vs_main()
|
||||
{
|
||||
Frag_UV = UV;
|
||||
Frag_Color = Color;
|
||||
gl_Position = ProjMtx * vec4(Position.xy, 0.0, 1.0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FRAGMENT_SHADER
|
||||
|
||||
layout(binding = 0) uniform sampler2D Texture;
|
||||
|
||||
in vec2 Frag_UV;
|
||||
in vec4 Frag_Color;
|
||||
|
||||
layout(location = 0) out vec4 Out_Color;
|
||||
|
||||
void ps_main()
|
||||
{
|
||||
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -14,17 +14,17 @@ layout(location = 0) out vec4 SV_Target0;
|
||||
|
||||
void ps_main0()
|
||||
{
|
||||
vec4 c = texture(TextureSampler, PSin_t);
|
||||
// Note: clamping will be done by fixed unit
|
||||
c.a *= 2.0f;
|
||||
SV_Target0 = c;
|
||||
vec4 c = texture(TextureSampler, PSin_t);
|
||||
// Note: clamping will be done by fixed unit
|
||||
c.a *= 2.0f;
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
void ps_main1()
|
||||
{
|
||||
vec4 c = texture(TextureSampler, PSin_t);
|
||||
c.a = BGColor.a;
|
||||
SV_Target0 = c;
|
||||
vec4 c = texture(TextureSampler, PSin_t);
|
||||
c.a = BGColor.a;
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -119,10 +119,10 @@ void ps_filter_triangular() // triangular
|
||||
#ifdef ps_filter_complex
|
||||
void ps_filter_complex()
|
||||
{
|
||||
const float PI = 3.14159265359f;
|
||||
vec2 texdim = vec2(textureSize(TextureSampler, 0));
|
||||
float factor = (0.9f - 0.4f * cos(2.0f * PI * PSin_t.y * texdim.y));
|
||||
vec4 c = factor * texture(TextureSampler, vec2(PSin_t.x, (floor(PSin_t.y * texdim.y) + 0.5f) / texdim.y));
|
||||
const float PI = 3.14159265359f;
|
||||
vec2 texdim = vec2(textureSize(TextureSampler, 0));
|
||||
float factor = (0.9f - 0.4f * cos(2.0f * PI * PSin_t.y * texdim.y));
|
||||
vec4 c = factor * texture(TextureSampler, vec2(PSin_t.x, (floor(PSin_t.y * texdim.y) + 0.5f) / texdim.y));
|
||||
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
@@ -24,33 +24,33 @@ layout(location = 0) out vec4 SV_Target0;
|
||||
// For all settings: 1.0 = 100% 0.5=50% 1.5 = 150%
|
||||
vec4 ContrastSaturationBrightness(vec4 color)
|
||||
{
|
||||
float brt = params.x;
|
||||
float con = params.y;
|
||||
float sat = params.z;
|
||||
float brt = params.x;
|
||||
float con = params.y;
|
||||
float sat = params.z;
|
||||
|
||||
// Increase or decrease these values to adjust r, g and b color channels separately
|
||||
const float AvgLumR = 0.5;
|
||||
const float AvgLumG = 0.5;
|
||||
const float AvgLumB = 0.5;
|
||||
// Increase or decrease these values to adjust r, g and b color channels separately
|
||||
const float AvgLumR = 0.5;
|
||||
const float AvgLumG = 0.5;
|
||||
const float AvgLumB = 0.5;
|
||||
|
||||
const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
|
||||
const vec3 LumCoeff = vec3(0.2125, 0.7154, 0.0721);
|
||||
|
||||
vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
|
||||
vec3 brtColor = color.rgb * brt;
|
||||
float dot_intensity = dot(brtColor, LumCoeff);
|
||||
vec3 intensity = vec3(dot_intensity, dot_intensity, dot_intensity);
|
||||
vec3 satColor = mix(intensity, brtColor, sat);
|
||||
vec3 conColor = mix(AvgLumin, satColor, con);
|
||||
vec3 AvgLumin = vec3(AvgLumR, AvgLumG, AvgLumB);
|
||||
vec3 brtColor = color.rgb * brt;
|
||||
float dot_intensity = dot(brtColor, LumCoeff);
|
||||
vec3 intensity = vec3(dot_intensity, dot_intensity, dot_intensity);
|
||||
vec3 satColor = mix(intensity, brtColor, sat);
|
||||
vec3 conColor = mix(AvgLumin, satColor, con);
|
||||
|
||||
color.rgb = conColor;
|
||||
return color;
|
||||
color.rgb = conColor;
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
void ps_main()
|
||||
{
|
||||
vec4 c = texture(TextureSampler, PSin_t);
|
||||
SV_Target0 = ContrastSaturationBrightness(c);
|
||||
vec4 c = texture(TextureSampler, PSin_t);
|
||||
SV_Target0 = ContrastSaturationBrightness(c);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,18 +2,34 @@
|
||||
|
||||
layout(std140, binding = 1) uniform cb20
|
||||
{
|
||||
vec2 VertexScale;
|
||||
vec2 VertexOffset;
|
||||
vec2 VertexScale;
|
||||
vec2 VertexOffset;
|
||||
|
||||
vec2 TextureScale;
|
||||
vec2 TextureOffset;
|
||||
vec2 TextureScale;
|
||||
vec2 TextureOffset;
|
||||
|
||||
vec2 PointSize;
|
||||
uint MaxDepth;
|
||||
uint pad_cb20;
|
||||
vec2 PointSize;
|
||||
uint MaxDepth;
|
||||
uint pad_cb20;
|
||||
};
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
|
||||
out SHADER
|
||||
{
|
||||
vec4 t_float;
|
||||
vec4 t_int;
|
||||
#if VS_IIP != 0
|
||||
vec4 c;
|
||||
#else
|
||||
flat vec4 c;
|
||||
#endif
|
||||
} VSout;
|
||||
|
||||
const float exp_min32 = exp2(-32.0f);
|
||||
|
||||
#if VS_EXPAND == 0
|
||||
|
||||
layout(location = 0) in vec2 i_st;
|
||||
layout(location = 2) in vec4 i_c;
|
||||
layout(location = 3) in float i_q;
|
||||
@@ -22,232 +38,202 @@ layout(location = 5) in uint i_z;
|
||||
layout(location = 6) in uvec2 i_uv;
|
||||
layout(location = 7) in vec4 i_f;
|
||||
|
||||
out SHADER
|
||||
{
|
||||
vec4 t_float;
|
||||
vec4 t_int;
|
||||
#if VS_IIP != 0
|
||||
vec4 c;
|
||||
#else
|
||||
flat vec4 c;
|
||||
#endif
|
||||
} VSout;
|
||||
|
||||
const float exp_min32 = exp2(-32.0f);
|
||||
|
||||
void texture_coord()
|
||||
{
|
||||
vec2 uv = vec2(i_uv) - TextureOffset;
|
||||
vec2 st = i_st - TextureOffset;
|
||||
vec2 uv = vec2(i_uv) - TextureOffset;
|
||||
vec2 st = i_st - TextureOffset;
|
||||
|
||||
// Float coordinate
|
||||
VSout.t_float.xy = st;
|
||||
VSout.t_float.w = i_q;
|
||||
// Float coordinate
|
||||
VSout.t_float.xy = st;
|
||||
VSout.t_float.w = i_q;
|
||||
|
||||
// Integer coordinate => normalized
|
||||
VSout.t_int.xy = uv * TextureScale;
|
||||
#if VS_INT_FST == 1
|
||||
// Some games uses float coordinate for post-processing effect
|
||||
VSout.t_int.zw = st / TextureScale;
|
||||
// Integer coordinate => normalized
|
||||
VSout.t_int.xy = uv * TextureScale;
|
||||
#if VS_FST
|
||||
// Integer coordinate => integral
|
||||
VSout.t_int.zw = uv;
|
||||
#else
|
||||
// Integer coordinate => integral
|
||||
VSout.t_int.zw = uv;
|
||||
// Some games uses float coordinate for post-processing effect
|
||||
VSout.t_int.zw = st / TextureScale;
|
||||
#endif
|
||||
}
|
||||
|
||||
void vs_main()
|
||||
{
|
||||
// Clamp to max depth, gs doesn't wrap
|
||||
highp uint z = min(i_z, MaxDepth);
|
||||
// Clamp to max depth, gs doesn't wrap
|
||||
highp uint z = min(i_z, MaxDepth);
|
||||
|
||||
// pos -= 0.05 (1/320 pixel) helps avoiding rounding problems (integral part of pos is usually 5 digits, 0.05 is about as low as we can go)
|
||||
// example: ceil(afterseveralvertextransformations(y = 133)) => 134 => line 133 stays empty
|
||||
// input granularity is 1/16 pixel, anything smaller than that won't step drawing up/left by one pixel
|
||||
// example: 133.0625 (133 + 1/16) should start from line 134, ceil(133.0625 - 0.05) still above 133
|
||||
vec4 p;
|
||||
// pos -= 0.05 (1/320 pixel) helps avoiding rounding problems (integral part of pos is usually 5 digits, 0.05 is about as low as we can go)
|
||||
// example: ceil(afterseveralvertextransformations(y = 133)) => 134 => line 133 stays empty
|
||||
// input granularity is 1/16 pixel, anything smaller than that won't step drawing up/left by one pixel
|
||||
// example: 133.0625 (133 + 1/16) should start from line 134, ceil(133.0625 - 0.05) still above 133
|
||||
vec4 p;
|
||||
|
||||
p.xy = vec2(i_p) - vec2(0.05f, 0.05f);
|
||||
p.xy = p.xy * VertexScale - VertexOffset;
|
||||
p.w = 1.0f;
|
||||
p.xy = vec2(i_p) - vec2(0.05f, 0.05f);
|
||||
p.xy = p.xy * VertexScale - VertexOffset;
|
||||
p.w = 1.0f;
|
||||
|
||||
#if HAS_CLIP_CONTROL
|
||||
p.z = float(z) * exp_min32;
|
||||
p.z = float(z) * exp_min32;
|
||||
#else
|
||||
// GLES doesn't support ARB_clip_control, so remap it to -1..1. We also reduce the range from 32 bits
|
||||
// to 24 bits, which means some games with very large depth ranges will not render correctly. But,
|
||||
// for most, it's okay, and really, the best we can do.
|
||||
p.z = min(float(z) * exp2(-23.0f), 2.0f) - 1.0f;
|
||||
// GLES doesn't support ARB_clip_control, so remap it to -1..1. We also reduce the range from 32 bits
|
||||
// to 24 bits, which means some games with very large depth ranges will not render correctly. But,
|
||||
// for most, it's okay, and really, the best we can do.
|
||||
p.z = min(float(z) * exp2(-23.0f), 2.0f) - 1.0f;
|
||||
#endif
|
||||
|
||||
gl_Position = p;
|
||||
gl_Position = p;
|
||||
|
||||
texture_coord();
|
||||
texture_coord();
|
||||
|
||||
VSout.c = i_c;
|
||||
VSout.t_float.z = i_f.x; // pack for with texture
|
||||
VSout.c = i_c;
|
||||
VSout.t_float.z = i_f.x; // pack for with texture
|
||||
|
||||
#if VS_POINT_SIZE
|
||||
gl_PointSize = PointSize.x;
|
||||
#endif
|
||||
#if VS_POINT_SIZE
|
||||
gl_PointSize = PointSize.x;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
#else // VS_EXPAND
|
||||
|
||||
#ifdef GEOMETRY_SHADER
|
||||
|
||||
in SHADER
|
||||
struct RawVertex
|
||||
{
|
||||
vec4 t_float;
|
||||
vec4 t_int;
|
||||
#if GS_IIP != 0
|
||||
vec4 c;
|
||||
#else
|
||||
flat vec4 c;
|
||||
#endif
|
||||
} GSin[];
|
||||
|
||||
out SHADER
|
||||
{
|
||||
vec4 t_float;
|
||||
vec4 t_int;
|
||||
#if GS_IIP != 0
|
||||
vec4 c;
|
||||
#else
|
||||
flat vec4 c;
|
||||
#endif
|
||||
} GSout;
|
||||
|
||||
struct vertex
|
||||
{
|
||||
vec4 t_float;
|
||||
vec4 t_int;
|
||||
vec4 c;
|
||||
vec2 ST;
|
||||
uint RGBA;
|
||||
float Q;
|
||||
uint XY;
|
||||
uint Z;
|
||||
uint UV;
|
||||
uint FOG;
|
||||
};
|
||||
|
||||
void out_vertex(in vec4 position, in vertex v)
|
||||
layout(std140, binding = 2) readonly buffer VertexBuffer {
|
||||
RawVertex vertex_buffer[];
|
||||
};
|
||||
|
||||
struct ProcessedVertex
|
||||
{
|
||||
GSout.t_float = v.t_float;
|
||||
GSout.t_int = v.t_int;
|
||||
// Flat output
|
||||
#if GS_POINT == 1
|
||||
GSout.c = GSin[0].c;
|
||||
vec4 p;
|
||||
vec4 t_float;
|
||||
vec4 t_int;
|
||||
vec4 c;
|
||||
};
|
||||
|
||||
ProcessedVertex load_vertex(uint index)
|
||||
{
|
||||
#if defined(GL_ARB_shader_draw_parameters) && GL_ARB_shader_draw_parameters
|
||||
RawVertex rvtx = vertex_buffer[index + gl_BaseVertexARB];
|
||||
#else
|
||||
GSout.c = GSin[1].c;
|
||||
RawVertex rvtx = vertex_buffer[index];
|
||||
#endif
|
||||
gl_Position = position;
|
||||
gl_PrimitiveID = gl_PrimitiveIDIn;
|
||||
EmitVertex();
|
||||
}
|
||||
|
||||
#if GS_POINT == 1
|
||||
layout(points) in;
|
||||
vec2 i_st = rvtx.ST;
|
||||
vec4 i_c = vec4(uvec4(bitfieldExtract(rvtx.RGBA, 0, 8), bitfieldExtract(rvtx.RGBA, 8, 8),
|
||||
bitfieldExtract(rvtx.RGBA, 16, 8), bitfieldExtract(rvtx.RGBA, 24, 8)));
|
||||
float i_q = rvtx.Q;
|
||||
uvec2 i_p = uvec2(bitfieldExtract(rvtx.XY, 0, 16), bitfieldExtract(rvtx.XY, 16, 16));
|
||||
uint i_z = rvtx.Z;
|
||||
uvec2 i_uv = uvec2(bitfieldExtract(rvtx.UV, 0, 16), bitfieldExtract(rvtx.UV, 16, 16));
|
||||
vec4 i_f = unpackUnorm4x8(rvtx.FOG);
|
||||
|
||||
ProcessedVertex vtx;
|
||||
|
||||
uint z = min(i_z, MaxDepth);
|
||||
vtx.p.xy = vec2(i_p) - vec2(0.05f, 0.05f);
|
||||
vtx.p.xy = vtx.p.xy * VertexScale - VertexOffset;
|
||||
vtx.p.w = 1.0f;
|
||||
|
||||
#if HAS_CLIP_CONTROL
|
||||
vtx.p.z = float(z) * exp_min32;
|
||||
#else
|
||||
layout(lines) in;
|
||||
vtx.p.z = min(float(z) * exp2(-23.0f), 2.0f) - 1.0f;
|
||||
#endif
|
||||
layout(triangle_strip, max_vertices = 4) out;
|
||||
|
||||
#if GS_POINT == 1
|
||||
vec2 uv = vec2(i_uv) - TextureOffset;
|
||||
vec2 st = i_st - TextureOffset;
|
||||
|
||||
void gs_main()
|
||||
{
|
||||
// Transform a point to a NxN sprite
|
||||
vertex point = vertex(GSin[0].t_float, GSin[0].t_int, GSin[0].c);
|
||||
|
||||
// Get new position
|
||||
vec4 lt_p = gl_in[0].gl_Position;
|
||||
vec4 rb_p = gl_in[0].gl_Position + vec4(PointSize.x, PointSize.y, 0.0f, 0.0f);
|
||||
vec4 lb_p = rb_p;
|
||||
vec4 rt_p = rb_p;
|
||||
lb_p.x = lt_p.x;
|
||||
rt_p.y = lt_p.y;
|
||||
|
||||
out_vertex(lt_p, point);
|
||||
|
||||
out_vertex(lb_p, point);
|
||||
|
||||
out_vertex(rt_p, point);
|
||||
|
||||
out_vertex(rb_p, point);
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
#elif GS_LINE == 1
|
||||
|
||||
void gs_main()
|
||||
{
|
||||
// Transform a line to a thick line-sprite
|
||||
vertex left = vertex(GSin[0].t_float, GSin[0].t_int, GSin[0].c);
|
||||
vertex right = vertex(GSin[1].t_float, GSin[1].t_int, GSin[1].c);
|
||||
vec4 lt_p = gl_in[0].gl_Position;
|
||||
vec4 rt_p = gl_in[1].gl_Position;
|
||||
|
||||
// Potentially there is faster math
|
||||
vec2 line_vector = normalize(rt_p.xy - lt_p.xy);
|
||||
vec2 line_normal = vec2(line_vector.y, -line_vector.x);
|
||||
vec2 line_width = (line_normal * PointSize) / 2.0f;
|
||||
|
||||
lt_p.xy -= line_width;
|
||||
rt_p.xy -= line_width;
|
||||
vec4 lb_p = gl_in[0].gl_Position + vec4(line_width, 0.0f, 0.0f);
|
||||
vec4 rb_p = gl_in[1].gl_Position + vec4(line_width, 0.0f, 0.0f);
|
||||
|
||||
out_vertex(lt_p, left);
|
||||
|
||||
out_vertex(lb_p, left);
|
||||
|
||||
out_vertex(rt_p, right);
|
||||
|
||||
out_vertex(rb_p, right);
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
vtx.t_float.xy = st;
|
||||
vtx.t_float.w = i_q;
|
||||
|
||||
vtx.t_int.xy = uv * TextureScale;
|
||||
#if VS_FST
|
||||
vtx.t_int.zw = uv;
|
||||
#else
|
||||
vtx.t_int.zw = st / TextureScale;
|
||||
#endif
|
||||
|
||||
void gs_main()
|
||||
{
|
||||
// left top => GSin[0];
|
||||
// right bottom => GSin[1];
|
||||
vertex rb = vertex(GSin[1].t_float, GSin[1].t_int, GSin[1].c);
|
||||
vertex lt = vertex(GSin[0].t_float, GSin[0].t_int, GSin[0].c);
|
||||
vtx.c = i_c;
|
||||
vtx.t_float.z = i_f.x;
|
||||
|
||||
vec4 rb_p = gl_in[1].gl_Position;
|
||||
vec4 lb_p = rb_p;
|
||||
vec4 rt_p = rb_p;
|
||||
vec4 lt_p = gl_in[0].gl_Position;
|
||||
|
||||
// flat depth
|
||||
lt_p.z = rb_p.z;
|
||||
// flat fog and texture perspective
|
||||
lt.t_float.zw = rb.t_float.zw;
|
||||
// flat color
|
||||
lt.c = rb.c;
|
||||
|
||||
// Swap texture and position coordinate
|
||||
vertex lb = rb;
|
||||
lb.t_float.x = lt.t_float.x;
|
||||
lb.t_int.x = lt.t_int.x;
|
||||
lb.t_int.z = lt.t_int.z;
|
||||
lb_p.x = lt_p.x;
|
||||
|
||||
vertex rt = rb;
|
||||
rt_p.y = lt_p.y;
|
||||
rt.t_float.y = lt.t_float.y;
|
||||
rt.t_int.y = lt.t_int.y;
|
||||
rt.t_int.w = lt.t_int.w;
|
||||
|
||||
out_vertex(lt_p, lt);
|
||||
|
||||
out_vertex(lb_p, lb);
|
||||
|
||||
out_vertex(rt_p, rt);
|
||||
|
||||
out_vertex(rb_p, rb);
|
||||
|
||||
EndPrimitive();
|
||||
return vtx;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
ProcessedVertex vtx;
|
||||
|
||||
#if defined(GL_ARB_shader_draw_parameters) && GL_ARB_shader_draw_parameters
|
||||
uint vid = uint(gl_VertexID - gl_BaseVertexARB);
|
||||
#else
|
||||
uint vid = uint(gl_VertexID);
|
||||
#endif
|
||||
|
||||
#if VS_EXPAND == 1 // Point
|
||||
|
||||
vtx = load_vertex(vid >> 2);
|
||||
|
||||
vtx.p.x += ((vid & 1u) != 0u) ? PointSize.x : 0.0f;
|
||||
vtx.p.y += ((vid & 2u) != 0u) ? PointSize.y : 0.0f;
|
||||
|
||||
#elif VS_EXPAND == 2 // Line
|
||||
|
||||
uint vid_base = vid >> 2;
|
||||
bool is_bottom = (vid & 2u) != 0u;
|
||||
bool is_right = (vid & 1u) != 0u;
|
||||
uint vid_other = is_bottom ? vid_base - 1 : vid_base + 1;
|
||||
vtx = load_vertex(vid_base);
|
||||
ProcessedVertex other = load_vertex(vid_other);
|
||||
|
||||
vec2 line_vector = normalize(vtx.p.xy - other.p.xy);
|
||||
vec2 line_normal = vec2(line_vector.y, -line_vector.x);
|
||||
vec2 line_width = (line_normal * PointSize) / 2;
|
||||
// line_normal is inverted for bottom point
|
||||
vec2 offset = ((uint(is_bottom) ^ uint(is_right)) != 0u) ? line_width : -line_width;
|
||||
vtx.p.xy += offset;
|
||||
|
||||
// Lines will be run as (0 1 2) (1 2 3)
|
||||
// This means that both triangles will have a point based off the top line point as their first point
|
||||
// So we don't have to do anything for !IIP
|
||||
|
||||
#elif VS_EXPAND == 3 // Sprite
|
||||
|
||||
// Sprite points are always in pairs
|
||||
uint vid_base = vid >> 1;
|
||||
uint vid_lt = vid_base & ~1u;
|
||||
uint vid_rb = vid_base | 1u;
|
||||
|
||||
ProcessedVertex lt = load_vertex(vid_lt);
|
||||
ProcessedVertex rb = load_vertex(vid_rb);
|
||||
vtx = rb;
|
||||
|
||||
bool is_right = ((vid & 1u) != 0u);
|
||||
vtx.p.x = is_right ? lt.p.x : vtx.p.x;
|
||||
vtx.t_float.x = is_right ? lt.t_float.x : vtx.t_float.x;
|
||||
vtx.t_int.xz = is_right ? lt.t_int.xz : vtx.t_int.xz;
|
||||
|
||||
bool is_bottom = ((vid & 2u) != 0u);
|
||||
vtx.p.y = is_bottom ? lt.p.y : vtx.p.y;
|
||||
vtx.t_float.y = is_bottom ? lt.t_float.y : vtx.t_float.y;
|
||||
vtx.t_int.yw = is_bottom ? lt.t_int.yw : vtx.t_int.yw;
|
||||
|
||||
#endif
|
||||
|
||||
gl_Position = vtx.p;
|
||||
VSout.t_float = vtx.t_float;
|
||||
VSout.t_int = vtx.t_int;
|
||||
VSout.c = vtx.c;
|
||||
}
|
||||
|
||||
#endif // VS_EXPAND
|
||||
|
||||
#endif // VERTEX_SHADER
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifdef VERTEX_SHADER
|
||||
|
||||
layout(location = 0) in vec2 Position;
|
||||
layout(location = 1) in vec2 UV;
|
||||
layout(location = 2) in vec4 Color;
|
||||
|
||||
layout(push_constant) uniform PushConstants
|
||||
{
|
||||
vec2 uScale;
|
||||
vec2 uTranslate;
|
||||
};
|
||||
|
||||
layout(location = 0) out vec2 Frag_UV;
|
||||
layout(location = 1) out vec4 Frag_Color;
|
||||
|
||||
void vs_main()
|
||||
{
|
||||
Frag_UV = UV;
|
||||
Frag_Color = Color;
|
||||
gl_Position = vec4(Position * uScale + uTranslate, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef FRAGMENT_SHADER
|
||||
|
||||
layout(binding = 0) uniform sampler2D Texture;
|
||||
|
||||
layout(location = 0) in vec2 Frag_UV;
|
||||
layout(location = 1) in vec4 Frag_Color;
|
||||
|
||||
layout(location = 0) out vec4 Out_Color;
|
||||
|
||||
void ps_main()
|
||||
{
|
||||
Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,7 @@
|
||||
// Vertex Shader
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(VERTEX_SHADER) || defined(GEOMETRY_SHADER)
|
||||
#if defined(VERTEX_SHADER)
|
||||
|
||||
layout(std140, set = 0, binding = 0) uniform cb0
|
||||
{
|
||||
@@ -15,18 +15,6 @@ layout(std140, set = 0, binding = 0) uniform cb0
|
||||
uint pad_cb0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
|
||||
layout(location = 0) in vec2 a_st;
|
||||
layout(location = 1) in uvec4 a_c;
|
||||
layout(location = 2) in float a_q;
|
||||
layout(location = 3) in uvec2 a_p;
|
||||
layout(location = 4) in uint a_z;
|
||||
layout(location = 5) in uvec2 a_uv;
|
||||
layout(location = 6) in vec4 a_f;
|
||||
|
||||
layout(location = 0) out VSOutput
|
||||
{
|
||||
vec4 t;
|
||||
@@ -39,17 +27,27 @@ layout(location = 0) out VSOutput
|
||||
#endif
|
||||
} vsOut;
|
||||
|
||||
#if VS_EXPAND == 0
|
||||
|
||||
layout(location = 0) in vec2 a_st;
|
||||
layout(location = 1) in uvec4 a_c;
|
||||
layout(location = 2) in float a_q;
|
||||
layout(location = 3) in uvec2 a_p;
|
||||
layout(location = 4) in uint a_z;
|
||||
layout(location = 5) in uvec2 a_uv;
|
||||
layout(location = 6) in vec4 a_f;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Clamp to max depth, gs doesn't wrap
|
||||
float z = min(a_z, MaxDepth);
|
||||
uint z = min(a_z, MaxDepth);
|
||||
|
||||
// pos -= 0.05 (1/320 pixel) helps avoiding rounding problems (integral part of pos is usually 5 digits, 0.05 is about as low as we can go)
|
||||
// example: ceil(afterseveralvertextransformations(y = 133)) => 134 => line 133 stays empty
|
||||
// input granularity is 1/16 pixel, anything smaller than that won't step drawing up/left by one pixel
|
||||
// example: 133.0625 (133 + 1/16) should start from line 134, ceil(133.0625 - 0.05) still above 133
|
||||
|
||||
gl_Position = vec4(a_p, z, 1.0f) - vec4(0.05f, 0.05f, 0, 0);
|
||||
gl_Position = vec4(a_p, float(z), 1.0f) - vec4(0.05f, 0.05f, 0, 0);
|
||||
gl_Position.xy = gl_Position.xy * vec2(VertexScale.x, -VertexScale.y) - vec2(VertexOffset.x, -VertexOffset.y);
|
||||
gl_Position.z *= exp2(-32.0f); // integer->float depth
|
||||
gl_Position.y = -gl_Position.y;
|
||||
@@ -81,214 +79,150 @@ void main()
|
||||
gl_PointSize = PointSize.x;
|
||||
#endif
|
||||
|
||||
vsOut.c = a_c;
|
||||
vsOut.c = vec4(a_c);
|
||||
vsOut.t.z = a_f.r;
|
||||
}
|
||||
|
||||
#endif
|
||||
#else // VS_EXPAND
|
||||
|
||||
#ifdef GEOMETRY_SHADER
|
||||
|
||||
layout(location = 0) in VSOutput
|
||||
struct RawVertex
|
||||
{
|
||||
vec2 ST;
|
||||
uint RGBA;
|
||||
float Q;
|
||||
uint XY;
|
||||
uint Z;
|
||||
uint UV;
|
||||
uint FOG;
|
||||
};
|
||||
|
||||
layout(std140, set = 0, binding = 2) readonly buffer VertexBuffer {
|
||||
RawVertex vertex_buffer[];
|
||||
};
|
||||
|
||||
struct ProcessedVertex
|
||||
{
|
||||
vec4 p;
|
||||
vec4 t;
|
||||
vec4 ti;
|
||||
#if GS_IIP != 0
|
||||
vec4 c;
|
||||
vec4 c;
|
||||
};
|
||||
|
||||
ProcessedVertex load_vertex(uint index)
|
||||
{
|
||||
RawVertex rvtx = vertex_buffer[gl_BaseVertexARB + index];
|
||||
|
||||
vec2 a_st = rvtx.ST;
|
||||
uvec4 a_c = uvec4(bitfieldExtract(rvtx.RGBA, 0, 8), bitfieldExtract(rvtx.RGBA, 8, 8),
|
||||
bitfieldExtract(rvtx.RGBA, 16, 8), bitfieldExtract(rvtx.RGBA, 24, 8));
|
||||
float a_q = rvtx.Q;
|
||||
uvec2 a_p = uvec2(bitfieldExtract(rvtx.XY, 0, 16), bitfieldExtract(rvtx.XY, 16, 16));
|
||||
uint a_z = rvtx.Z;
|
||||
uvec2 a_uv = uvec2(bitfieldExtract(rvtx.UV, 0, 16), bitfieldExtract(rvtx.UV, 16, 16));
|
||||
vec4 a_f = unpackUnorm4x8(rvtx.FOG);
|
||||
|
||||
ProcessedVertex vtx;
|
||||
|
||||
uint z = min(a_z, MaxDepth);
|
||||
vtx.p = vec4(a_p, float(z), 1.0f) - vec4(0.05f, 0.05f, 0, 0);
|
||||
vtx.p.xy = vtx.p.xy * vec2(VertexScale.x, -VertexScale.y) - vec2(VertexOffset.x, -VertexOffset.y);
|
||||
vtx.p.z *= exp2(-32.0f); // integer->float depth
|
||||
vtx.p.y = -vtx.p.y;
|
||||
|
||||
#if VS_TME
|
||||
vec2 uv = a_uv - TextureOffset;
|
||||
vec2 st = a_st - TextureOffset;
|
||||
vtx.ti.xy = uv * TextureScale;
|
||||
|
||||
#if VS_FST
|
||||
vtx.ti.zw = uv;
|
||||
#else
|
||||
vtx.ti.zw = st / TextureScale;
|
||||
#endif
|
||||
|
||||
vtx.t.xy = st;
|
||||
vtx.t.w = a_q;
|
||||
#else
|
||||
flat vec4 c;
|
||||
vtx.t = vec4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
vtx.ti = vec4(0.0f);
|
||||
#endif
|
||||
} gsIn[];
|
||||
|
||||
layout(location = 0) out GSOutput
|
||||
{
|
||||
vec4 t;
|
||||
vec4 ti;
|
||||
#if GS_IIP != 0
|
||||
vec4 c;
|
||||
#else
|
||||
flat vec4 c;
|
||||
#endif
|
||||
} gsOut;
|
||||
vtx.c = a_c;
|
||||
vtx.t.z = a_f.r;
|
||||
|
||||
void WriteVertex(vec4 pos, vec4 t, vec4 ti, vec4 c)
|
||||
{
|
||||
#if GS_FORWARD_PRIMID
|
||||
gl_PrimitiveID = gl_PrimitiveIDIn;
|
||||
#endif
|
||||
gl_Position = pos;
|
||||
gsOut.t = t;
|
||||
gsOut.ti = ti;
|
||||
gsOut.c = c;
|
||||
EmitVertex();
|
||||
return vtx;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Geometry Shader
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if GS_PRIM == 0 && GS_POINT == 0
|
||||
|
||||
layout(points) in;
|
||||
layout(points, max_vertices = 1) out;
|
||||
void main()
|
||||
{
|
||||
WriteVertex(gl_in[0].gl_Position, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
#elif GS_PRIM == 0 && GS_POINT == 1
|
||||
|
||||
layout(points) in;
|
||||
layout(triangle_strip, max_vertices = 4) out;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Transform a point to a NxN sprite
|
||||
ProcessedVertex vtx;
|
||||
uint vid = uint(gl_VertexIndex - gl_BaseVertexARB);
|
||||
|
||||
// Get new position
|
||||
vec4 lt_p = gl_in[0].gl_Position;
|
||||
vec4 rb_p = gl_in[0].gl_Position + vec4(PointSize.x, PointSize.y, 0.0f, 0.0f);
|
||||
vec4 lb_p = rb_p;
|
||||
vec4 rt_p = rb_p;
|
||||
lb_p.x = lt_p.x;
|
||||
rt_p.y = lt_p.y;
|
||||
#if VS_EXPAND == 1 // Point
|
||||
|
||||
WriteVertex(lt_p, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
|
||||
WriteVertex(lb_p, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
|
||||
WriteVertex(rt_p, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
|
||||
WriteVertex(rb_p, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
|
||||
vtx = load_vertex(vid >> 2);
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
vtx.p.x += ((vid & 1u) != 0u) ? PointSize.x : 0.0f;
|
||||
vtx.p.y += ((vid & 2u) != 0u) ? PointSize.y : 0.0f;
|
||||
|
||||
#elif GS_PRIM == 1 && GS_LINE == 0
|
||||
#elif VS_EXPAND == 2 // Line
|
||||
|
||||
layout(lines) in;
|
||||
layout(line_strip, max_vertices = 2) out;
|
||||
uint vid_base = vid >> 2;
|
||||
|
||||
void main()
|
||||
{
|
||||
#if GS_IIP == 0
|
||||
WriteVertex(gl_in[0].gl_Position, gsIn[0].t, gsIn[0].ti, gsIn[1].c);
|
||||
WriteVertex(gl_in[1].gl_Position, gsIn[1].t, gsIn[1].ti, gsIn[1].c);
|
||||
bool is_bottom = (vid & 2u) != 0u;
|
||||
bool is_right = (vid & 1u) != 0u;
|
||||
#ifdef VS_PROVOKING_VERTEX_LAST
|
||||
uint vid_other = is_bottom ? vid_base - 1 : vid_base + 1;
|
||||
#else
|
||||
WriteVertex(gl_in[0].gl_Position, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
|
||||
WriteVertex(gl_in[1].gl_Position, gsIn[1].t, gsIn[1].ti, gsIn[1].c);
|
||||
uint vid_other = is_bottom ? vid_base + 1 : vid_base - 1;
|
||||
#endif
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
vtx = load_vertex(vid_base);
|
||||
ProcessedVertex other = load_vertex(vid_other);
|
||||
|
||||
#elif GS_PRIM == 1 && GS_LINE == 1
|
||||
|
||||
layout(lines) in;
|
||||
layout(triangle_strip, max_vertices = 4) out;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Transform a line to a thick line-sprite
|
||||
vec4 left_t = gsIn[0].t;
|
||||
vec4 left_ti = gsIn[0].ti;
|
||||
vec4 left_c = gsIn[0].c;
|
||||
vec4 right_t = gsIn[1].t;
|
||||
vec4 right_ti = gsIn[1].ti;
|
||||
vec4 right_c = gsIn[1].c;
|
||||
vec4 lt_p = gl_in[0].gl_Position;
|
||||
vec4 rt_p = gl_in[1].gl_Position;
|
||||
|
||||
// Potentially there is faster math
|
||||
vec2 line_vector = normalize(rt_p.xy - lt_p.xy);
|
||||
vec2 line_vector = normalize(vtx.p.xy - other.p.xy);
|
||||
vec2 line_normal = vec2(line_vector.y, -line_vector.x);
|
||||
vec2 line_width = (line_normal * PointSize) / 2.0;
|
||||
vec2 line_width = (line_normal * PointSize) / 2;
|
||||
// line_normal is inverted for bottom point
|
||||
vec2 offset = ((uint(is_bottom) ^ uint(is_right)) != 0u) ? line_width : -line_width;
|
||||
vtx.p.xy += offset;
|
||||
|
||||
lt_p.xy -= line_width;
|
||||
rt_p.xy -= line_width;
|
||||
vec4 lb_p = gl_in[0].gl_Position + vec4(line_width, 0.0, 0.0);
|
||||
vec4 rb_p = gl_in[1].gl_Position + vec4(line_width, 0.0, 0.0);
|
||||
// Lines will be run as (0 1 2) (1 2 3)
|
||||
// This means that both triangles will have a point based off the top line point as their first point
|
||||
// So we don't have to do anything for !IIP
|
||||
|
||||
#if GS_IIP == 0
|
||||
left_c = right_c;
|
||||
#endif
|
||||
#elif VS_EXPAND == 3 // Sprite
|
||||
|
||||
WriteVertex(lt_p, left_t, left_ti, left_c);
|
||||
WriteVertex(lb_p, left_t, left_ti, left_c);
|
||||
WriteVertex(rt_p, right_t, right_ti, right_c);
|
||||
WriteVertex(rb_p, right_t, right_ti, right_c);
|
||||
EndPrimitive();
|
||||
}
|
||||
// Sprite points are always in pairs
|
||||
uint vid_base = vid >> 1;
|
||||
uint vid_lt = vid_base & ~1u;
|
||||
uint vid_rb = vid_base | 1u;
|
||||
|
||||
#elif GS_PRIM == 2
|
||||
ProcessedVertex lt = load_vertex(vid_lt);
|
||||
ProcessedVertex rb = load_vertex(vid_rb);
|
||||
vtx = rb;
|
||||
|
||||
layout(triangles) in;
|
||||
layout(triangle_strip, max_vertices = 3) out;
|
||||
bool is_right = ((vid & 1u) != 0u);
|
||||
vtx.p.x = is_right ? lt.p.x : vtx.p.x;
|
||||
vtx.t.x = is_right ? lt.t.x : vtx.t.x;
|
||||
vtx.ti.xz = is_right ? lt.ti.xz : vtx.ti.xz;
|
||||
|
||||
void main()
|
||||
{
|
||||
#if GS_IIP == 0
|
||||
WriteVertex(gl_in[0].gl_Position, gsIn[0].t, gsIn[0].ti, gsIn[2].c);
|
||||
WriteVertex(gl_in[1].gl_Position, gsIn[1].t, gsIn[1].ti, gsIn[2].c);
|
||||
WriteVertex(gl_in[2].gl_Position, gsIn[2].t, gsIn[2].ti, gsIn[2].c);
|
||||
#else
|
||||
WriteVertex(gl_in[0].gl_Position, gsIn[0].t, gsIn[0].ti, gsIn[0].c);
|
||||
WriteVertex(gl_in[1].gl_Position, gsIn[1].t, gsIn[1].ti, gsIn[0].c);
|
||||
WriteVertex(gl_in[2].gl_Position, gsIn[2].t, gsIn[2].ti, gsIn[0].c);
|
||||
#endif
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
#elif GS_PRIM == 3
|
||||
|
||||
layout(lines) in;
|
||||
layout(triangle_strip, max_vertices = 4) out;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 lt_p = gl_in[0].gl_Position;
|
||||
vec4 lt_t = gsIn[0].t;
|
||||
vec4 lt_ti = gsIn[0].ti;
|
||||
vec4 lt_c = gsIn[0].c;
|
||||
vec4 rb_p = gl_in[1].gl_Position;
|
||||
vec4 rb_t = gsIn[1].t;
|
||||
vec4 rb_ti = gsIn[1].ti;
|
||||
vec4 rb_c = gsIn[1].c;
|
||||
|
||||
// flat depth
|
||||
lt_p.z = rb_p.z;
|
||||
// flat fog and texture perspective
|
||||
lt_t.zw = rb_t.zw;
|
||||
|
||||
// flat color
|
||||
lt_c = rb_c;
|
||||
|
||||
// Swap texture and position coordinate
|
||||
vec4 lb_p = rb_p;
|
||||
vec4 lb_t = rb_t;
|
||||
vec4 lb_ti = rb_ti;
|
||||
vec4 lb_c = rb_c;
|
||||
lb_p.x = lt_p.x;
|
||||
lb_t.x = lt_t.x;
|
||||
lb_ti.x = lt_ti.x;
|
||||
lb_ti.z = lt_ti.z;
|
||||
|
||||
vec4 rt_p = rb_p;
|
||||
vec4 rt_t = rb_t;
|
||||
vec4 rt_ti = rb_ti;
|
||||
vec4 rt_c = rb_c;
|
||||
rt_p.y = lt_p.y;
|
||||
rt_t.y = lt_t.y;
|
||||
rt_ti.y = lt_ti.y;
|
||||
rt_ti.w = lt_ti.w;
|
||||
|
||||
WriteVertex(lt_p, lt_t, lt_ti, lt_c);
|
||||
WriteVertex(lb_p, lb_t, lb_ti, lb_c);
|
||||
WriteVertex(rt_p, rt_t, rt_ti, rt_c);
|
||||
WriteVertex(rb_p, rb_t, rb_ti, rb_c);
|
||||
EndPrimitive();
|
||||
}
|
||||
bool is_bottom = ((vid & 2u) != 0u);
|
||||
vtx.p.y = is_bottom ? lt.p.y : vtx.p.y;
|
||||
vtx.t.y = is_bottom ? lt.t.y : vtx.t.y;
|
||||
vtx.ti.yw = is_bottom ? lt.ti.yw : vtx.ti.yw;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
gl_Position = vtx.p;
|
||||
vsOut.t = vtx.t;
|
||||
vsOut.ti = vtx.ti;
|
||||
vsOut.c = vtx.c;
|
||||
}
|
||||
|
||||
#endif // VS_EXPAND
|
||||
|
||||
#endif // VERTEX_SHADER
|
||||
|
||||
#ifdef FRAGMENT_SHADER
|
||||
|
||||
@@ -684,8 +618,12 @@ ivec2 clamp_wrap_uv_depth(ivec2 uv)
|
||||
vec4 sample_depth(vec2 st, ivec2 pos)
|
||||
{
|
||||
vec2 uv_f = vec2(clamp_wrap_uv_depth(ivec2(st))) * vec2(ScaledScaleFactor);
|
||||
ivec2 uv = ivec2(uv_f);
|
||||
|
||||
#if PS_REGION_RECT == 1
|
||||
uv_f = clamp(uv_f + STRange.xy, STRange.xy, STRange.zw);
|
||||
#endif
|
||||
|
||||
ivec2 uv = ivec2(uv_f);
|
||||
vec4 t = vec4(0.0f);
|
||||
|
||||
#if (PS_TALES_OF_ABYSS_HLE == 1)
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
set(wx_sdl_c_code "
|
||||
#include <wx/setup.h>
|
||||
|
||||
#if (wxUSE_LIBSDL == 0)
|
||||
#error cmake_WX_SDL
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
")
|
||||
|
||||
set(gcc7_mmx_code "
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
|
||||
class alignas(16) GSVector4i
|
||||
{
|
||||
public:
|
||||
__m128i m;
|
||||
|
||||
explicit GSVector4i(__m128i m)
|
||||
{
|
||||
this->m = m;
|
||||
}
|
||||
|
||||
static void storel(void* p, const GSVector4i& v)
|
||||
{
|
||||
_mm_storel_epi64((__m128i*)p, v.m);
|
||||
}
|
||||
|
||||
static GSVector4i loadl(const void* p)
|
||||
{
|
||||
return GSVector4i(_mm_loadl_epi64((__m128i*)p));
|
||||
}
|
||||
|
||||
bool eq(const GSVector4i& v) const
|
||||
{
|
||||
return _mm_movemask_epi8(_mm_cmpeq_epi32(m, v.m)) == 0xffff;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
union GIFRegTRXPOS
|
||||
{
|
||||
unsigned long long u64;
|
||||
void operator = (const GSVector4i& v) {GSVector4i::storel(this, v);}
|
||||
bool operator != (const union GIFRegTRXPOS& r) const {return !((GSVector4i)r).eq(*this);}
|
||||
operator GSVector4i() const {return GSVector4i::loadl(this);}
|
||||
};
|
||||
|
||||
extern GIFRegTRXPOS TRXPOS;
|
||||
GIFRegTRXPOS TRXPOS = {};
|
||||
|
||||
void GIFRegHandlerTRXPOS(const GIFRegTRXPOS& p)
|
||||
{
|
||||
if(p != TRXPOS)
|
||||
{
|
||||
printf(\"foo\");
|
||||
}
|
||||
|
||||
TRXPOS = (GSVector4i)p;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
GIFRegTRXPOS r = {};
|
||||
GIFRegHandlerTRXPOS(r);
|
||||
|
||||
uint16_t fpu[16] = {0};
|
||||
__asm__ __volatile__(\"fstenv %0\" : \"=m\"(fpu));
|
||||
|
||||
bool ok = fpu[4] == 0xFFFF;
|
||||
|
||||
if (!ok) {
|
||||
printf(\"Wrong MMX state !\");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
")
|
||||
|
||||
function(GCC7_BUG)
|
||||
# try_run doesn't work when cross-compiling is enabled. It is completely silly in our case
|
||||
# as i386 binaries are 100% fine on x64.
|
||||
set(OLD_CMAKE_CROSSCOMPILING ${CMAKE_CROSSCOMPILING})
|
||||
set(CMAKE_CROSSCOMPILING 0)
|
||||
|
||||
set(IN "${CMAKE_BINARY_DIR}/gcc7_mmx.cpp")
|
||||
file(WRITE "${IN}" "${gcc7_mmx_code}")
|
||||
|
||||
enable_language(CXX)
|
||||
|
||||
try_run(
|
||||
run_result
|
||||
compile_result_unused
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
"${IN}"
|
||||
CMAKE_FLAGS "-DCOMPILE_DEFINITIONS:STRING=-msse -msse2 -O2 -m32 -march=i686"
|
||||
)
|
||||
|
||||
if (${run_result})
|
||||
message(FATAL_ERROR "GCC 7.0/7.1 generates invalid code => https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80799\n"
|
||||
"You can either backport the fix or swith to another version of GCC.")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CROSSCOMPILING ${OLD_CMAKE_CROSSCOMPILING})
|
||||
|
||||
endfunction()
|
||||
@@ -34,6 +34,7 @@ if(UNIX AND NOT APPLE)
|
||||
option(USE_LEGACY_USER_DIRECTORY "Use legacy home/PCSX2 user directory instead of XDG standard" OFF)
|
||||
option(X11_API "Enable X11 support" ON)
|
||||
option(WAYLAND_API "Enable Wayland support" ON)
|
||||
option(DBUS_API "Enable DBus support for screensaver inhibiting" ON)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
@@ -52,9 +53,6 @@ if(MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
set(USE_CLANG TRUE)
|
||||
message(STATUS "Building with Clang/LLVM.")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
set(USE_ICC TRUE)
|
||||
message(STATUS "Building with Intel's ICC.")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(USE_GCC TRUE)
|
||||
message(STATUS "Building with GNU GCC")
|
||||
@@ -106,21 +104,13 @@ include(TargetArch)
|
||||
target_architecture(PCSX2_TARGET_ARCHITECTURES)
|
||||
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
message(STATUS "Compiling a ${PCSX2_TARGET_ARCHITECTURES} build on a ${CMAKE_HOST_SYSTEM_PROCESSOR} host.")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported architecture: ${PCSX2_TARGET_ARCHITECTURES}")
|
||||
endif()
|
||||
|
||||
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
# x86_64 requires -fPIC
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if(NOT DEFINED ARCH_FLAG AND NOT MSVC)
|
||||
if (DISABLE_ADVANCE_SIMD)
|
||||
if (USE_ICC)
|
||||
set(ARCH_FLAG "-msse2 -msse4.1")
|
||||
else()
|
||||
set(ARCH_FLAG "-msse -msse2 -msse4.1 -mfxsr")
|
||||
endif()
|
||||
set(ARCH_FLAG "-msse -msse2 -msse4.1 -mfxsr")
|
||||
else()
|
||||
#set(ARCH_FLAG "-march=native -fabi-version=6")
|
||||
set(ARCH_FLAG "-march=native")
|
||||
@@ -132,9 +122,6 @@ if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
set(_ARCH_64 1)
|
||||
set(_M_X86 1)
|
||||
else()
|
||||
# All but i386 requires -fPIC
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
message(FATAL_ERROR "Unsupported architecture: ${PCSX2_TARGET_ARCHITECTURES}")
|
||||
endif()
|
||||
string(REPLACE " " ";" ARCH_FLAG_LIST "${ARCH_FLAG}")
|
||||
@@ -220,24 +207,13 @@ endif()
|
||||
if (MSVC)
|
||||
set(DEFAULT_WARNINGS)
|
||||
else()
|
||||
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-attributes -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers -Wno-format -Wno-format-security)
|
||||
if (NOT USE_ICC)
|
||||
list(APPEND DEFAULT_WARNINGS -Wno-unused-value)
|
||||
endif()
|
||||
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-attributes -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers -Wno-format -Wno-format-security -Wno-unused-value)
|
||||
endif()
|
||||
|
||||
if (USE_GCC)
|
||||
list(APPEND DEFAULT_WARNINGS -Wno-stringop-truncation -Wno-stringop-overflow -Wno-maybe-uninitialized )
|
||||
endif()
|
||||
|
||||
|
||||
# -Wstrict-aliasing=n: to fix one day aliasing issue. n=1/2/3
|
||||
if (USE_ICC)
|
||||
set(AGGRESSIVE_WARNING -Wstrict-aliasing)
|
||||
elseif(NOT MSVC)
|
||||
set(AGGRESSIVE_WARNING -Wstrict-aliasing -Wstrict-overflow=1)
|
||||
endif()
|
||||
|
||||
if (USE_PGO_GENERATE OR USE_PGO_OPTIMIZE)
|
||||
add_compile_options("-fprofile-dir=${CMAKE_SOURCE_DIR}/profile")
|
||||
endif()
|
||||
@@ -264,7 +240,7 @@ if(USE_CLANG AND TIMETRACE)
|
||||
add_compile_options(-ftime-trace)
|
||||
endif()
|
||||
|
||||
set(PCSX2_WARNINGS ${DEFAULT_WARNINGS} ${AGGRESSIVE_WARNING})
|
||||
set(PCSX2_WARNINGS ${DEFAULT_WARNINGS})
|
||||
|
||||
if(DISABLE_BUILD_DATE)
|
||||
message(STATUS "Disabling the inclusion of the binary compile date.")
|
||||
|
||||
@@ -12,21 +12,12 @@ find_path(VTUNE_INCLUDE_DIRS NAMES jitprofiling.h PATHS
|
||||
/opt/intel/vtune_amplifier_xe_2016/include
|
||||
)
|
||||
|
||||
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "i386")
|
||||
find_library(VTUNE_LIBRARIES NAMES libjitprofiling.a PATHS
|
||||
/opt/intel/oneapi/vtune/latest/lib32
|
||||
/opt/intel/vtune_amplifier_xe_2018/lib32
|
||||
/opt/intel/vtune_amplifier_xe_2017/lib32
|
||||
/opt/intel/vtune_amplifier_xe_2016/lib32
|
||||
)
|
||||
else()
|
||||
find_library(VTUNE_LIBRARIES NAMES libjitprofiling.a PATHS
|
||||
/opt/intel/oneapi/vtune/latest/lib64
|
||||
/opt/intel/vtune_amplifier_xe_2018/lib64
|
||||
/opt/intel/vtune_amplifier_xe_2017/lib64
|
||||
/opt/intel/vtune_amplifier_xe_2016/lib64
|
||||
)
|
||||
endif()
|
||||
find_library(VTUNE_LIBRARIES NAMES libjitprofiling.a PATHS
|
||||
/opt/intel/oneapi/vtune/latest/lib64
|
||||
/opt/intel/vtune_amplifier_xe_2018/lib64
|
||||
/opt/intel/vtune_amplifier_xe_2017/lib64
|
||||
/opt/intel/vtune_amplifier_xe_2016/lib64
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set VTUNE_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
@@ -41,4 +32,3 @@ if(VTUNE_LIBRARIES AND NOT TARGET Vtune::Vtune)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(VTUNE_FOUND VTUNE_INCLUDE_DIRS VTUNE_LIBRARIES)
|
||||
|
||||
|
||||
@@ -102,18 +102,7 @@ if(ENABLE_TESTS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#----------------------------------------
|
||||
# Check correctness of the parameter
|
||||
# Note: wxWidgets_INCLUDE_DIRS must be defined
|
||||
#----------------------------------------
|
||||
include(ApiValidation)
|
||||
|
||||
# Blacklist bad GCC
|
||||
if(GCC_VERSION VERSION_EQUAL "7.0" OR GCC_VERSION VERSION_EQUAL "7.1")
|
||||
GCC7_BUG()
|
||||
endif()
|
||||
|
||||
if((GCC_VERSION VERSION_EQUAL "9.0" OR GCC_VERSION VERSION_GREATER "9.0") AND GCC_VERSION LESS "9.2")
|
||||
if(GCC_VERSION VERSION_GREATER_EQUAL "9.0" AND GCC_VERSION VERSION_LESS "9.2")
|
||||
message(WARNING "
|
||||
It looks like you are compiling with 9.0.x or 9.1.x. Using these versions is not recommended,
|
||||
as there is a bug known to cause the compiler to segfault while compiling. See patch
|
||||
@@ -134,7 +123,7 @@ find_optional_system_library(libzip 3rdparty/libzip 1.8.0)
|
||||
if(QT_BUILD)
|
||||
# Default to bundled Qt6 for Windows.
|
||||
if(WIN32 AND NOT DEFINED Qt6_DIR)
|
||||
set(Qt6_DIR ${CMAKE_SOURCE_DIR}/3rdparty/qt/6.4.0/msvc2022_64/lib/cmake/Qt6)
|
||||
set(Qt6_DIR ${CMAKE_SOURCE_DIR}/3rdparty/qt/6.5.0/msvc2022_64/lib/cmake/Qt6)
|
||||
endif()
|
||||
|
||||
# Find the Qt components that we need.
|
||||
|
||||
@@ -218,6 +218,14 @@ if(APPLE)
|
||||
target_link_options(common PRIVATE -fobjc-link-runtime)
|
||||
endif()
|
||||
|
||||
if(DBUS_API)
|
||||
target_compile_definitions(common PRIVATE DBUS_API)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(DBUS REQUIRED dbus-1)
|
||||
target_include_directories(common PRIVATE ${DBUS_INCLUDE_DIRS})
|
||||
target_link_libraries(common PRIVATE ${DBUS_LINK_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(USE_OPENGL)
|
||||
if(WIN32)
|
||||
target_sources(common PRIVATE
|
||||
|
||||
@@ -41,10 +41,7 @@ D3D11::ShaderCache::ShaderCache() = default;
|
||||
|
||||
D3D11::ShaderCache::~ShaderCache()
|
||||
{
|
||||
if (m_index_file)
|
||||
std::fclose(m_index_file);
|
||||
if (m_blob_file)
|
||||
std::fclose(m_blob_file);
|
||||
Close();
|
||||
}
|
||||
|
||||
bool D3D11::ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const
|
||||
@@ -82,6 +79,20 @@ bool D3D11::ShaderCache::Open(std::string_view base_path, D3D_FEATURE_LEVEL feat
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11::ShaderCache::Close()
|
||||
{
|
||||
if (m_index_file)
|
||||
{
|
||||
std::fclose(m_index_file);
|
||||
m_index_file = nullptr;
|
||||
}
|
||||
if (m_blob_file)
|
||||
{
|
||||
std::fclose(m_blob_file);
|
||||
m_blob_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool D3D11::ShaderCache::CreateNew(const std::string& index_filename, const std::string& blob_filename)
|
||||
{
|
||||
if (FileSystem::FileExists(index_filename.c_str()))
|
||||
@@ -326,16 +337,6 @@ bool D3D11::ShaderCache::GetVertexShaderAndInputLayout(ID3D11Device* device,
|
||||
return true;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11GeometryShader> D3D11::ShaderCache::GetGeometryShader(ID3D11Device* device,
|
||||
const std::string_view& shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */)
|
||||
{
|
||||
wil::com_ptr_nothrow<ID3DBlob> blob = GetShaderBlob(ShaderCompiler::Type::Geometry, shader_code, macros, entry_point);
|
||||
if (!blob)
|
||||
return {};
|
||||
|
||||
return D3D11::ShaderCompiler::CreateGeometryShader(device, blob.get());
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> D3D11::ShaderCache::GetPixelShader(ID3D11Device* device,
|
||||
const std::string_view& shader_code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace D3D11
|
||||
bool UsingDebugShaders() const { return m_debug; }
|
||||
|
||||
bool Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_level, u32 version, bool debug);
|
||||
void Close();
|
||||
|
||||
wil::com_ptr_nothrow<ID3DBlob> GetShaderBlob(ShaderCompiler::Type type, const std::string_view& shader_code,
|
||||
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
|
||||
@@ -50,9 +51,6 @@ namespace D3D11
|
||||
const D3D11_INPUT_ELEMENT_DESC* layout, size_t layout_size,
|
||||
const std::string_view& shader_code, const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11GeometryShader> GetGeometryShader(ID3D11Device* device, const std::string_view& shader_code,
|
||||
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> GetPixelShader(ID3D11Device* device, const std::string_view& shader_code,
|
||||
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
|
||||
|
||||
@@ -103,7 +101,6 @@ namespace D3D11
|
||||
|
||||
bool CreateNew(const std::string& index_filename, const std::string& blob_filename);
|
||||
bool ReadExisting(const std::string& index_filename, const std::string& blob_filename);
|
||||
void Close();
|
||||
|
||||
wil::com_ptr_nothrow<ID3DBlob> CompileAndAddShaderBlob(const CacheIndexKey& key, const std::string_view& shader_code,
|
||||
const D3D_SHADER_MACRO* macros, const char* entry_point);
|
||||
|
||||
@@ -31,21 +31,21 @@ wil::com_ptr_nothrow<ID3DBlob> D3D11::ShaderCompiler::CompileShader(Type type, D
|
||||
{
|
||||
case D3D_FEATURE_LEVEL_10_0:
|
||||
{
|
||||
static constexpr std::array<const char*, 4> targets = {{"vs_4_0", "gs_4_0", "ps_4_0", "cs_4_0"}};
|
||||
static constexpr std::array<const char*, 4> targets = {{"vs_4_0", "ps_4_0", "cs_4_0"}};
|
||||
target = targets[static_cast<int>(type)];
|
||||
}
|
||||
break;
|
||||
|
||||
case D3D_FEATURE_LEVEL_10_1:
|
||||
{
|
||||
static constexpr std::array<const char*, 4> targets = {{"vs_4_1", "gs_4_1", "ps_4_1", "cs_4_1"}};
|
||||
static constexpr std::array<const char*, 4> targets = {{"vs_4_1", "ps_4_1", "cs_4_1"}};
|
||||
target = targets[static_cast<int>(type)];
|
||||
}
|
||||
break;
|
||||
|
||||
case D3D_FEATURE_LEVEL_11_0:
|
||||
{
|
||||
static constexpr std::array<const char*, 4> targets = {{"vs_5_0", "gs_5_0", "ps_5_0", "cs_5_0"}};
|
||||
static constexpr std::array<const char*, 4> targets = {{"vs_5_0", "ps_5_0", "cs_5_0"}};
|
||||
target = targets[static_cast<int>(type)];
|
||||
}
|
||||
break;
|
||||
@@ -53,7 +53,7 @@ wil::com_ptr_nothrow<ID3DBlob> D3D11::ShaderCompiler::CompileShader(Type type, D
|
||||
case D3D_FEATURE_LEVEL_11_1:
|
||||
default:
|
||||
{
|
||||
static constexpr std::array<const char*, 4> targets = {{"vs_5_1", "gs_5_1", "ps_5_1", "cs_5_1"}};
|
||||
static constexpr std::array<const char*, 4> targets = {{"vs_5_1", "ps_5_1", "cs_5_1"}};
|
||||
target = targets[static_cast<int>(type)];
|
||||
}
|
||||
break;
|
||||
@@ -108,16 +108,6 @@ wil::com_ptr_nothrow<ID3D11VertexShader> D3D11::ShaderCompiler::CompileAndCreate
|
||||
return CreateVertexShader(device, blob.get());
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11GeometryShader> D3D11::ShaderCompiler::CompileAndCreateGeometryShader(ID3D11Device* device, bool debug,
|
||||
const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */)
|
||||
{
|
||||
wil::com_ptr_nothrow<ID3DBlob> blob = CompileShader(Type::Geometry, device->GetFeatureLevel(), debug, code, macros, entry_point);
|
||||
if (!blob)
|
||||
return {};
|
||||
|
||||
return CreateGeometryShader(device, blob.get());
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> D3D11::ShaderCompiler::CompileAndCreatePixelShader(ID3D11Device* device, bool debug,
|
||||
const std::string_view& code, const D3D_SHADER_MACRO* macros /* = nullptr */, const char* entry_point /* = "main" */)
|
||||
{
|
||||
@@ -157,25 +147,6 @@ wil::com_ptr_nothrow<ID3D11VertexShader> D3D11::ShaderCompiler::CreateVertexShad
|
||||
const_cast<ID3DBlob*>(blob)->GetBufferSize());
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11GeometryShader> D3D11::ShaderCompiler::CreateGeometryShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length)
|
||||
{
|
||||
wil::com_ptr_nothrow<ID3D11GeometryShader> shader;
|
||||
const HRESULT hr = device->CreateGeometryShader(bytecode, bytecode_length, nullptr, shader.put());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("Failed to create geometry shader: 0x%08X", hr);
|
||||
return {};
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11GeometryShader> D3D11::ShaderCompiler::CreateGeometryShader(ID3D11Device* device, const ID3DBlob* blob)
|
||||
{
|
||||
return CreateGeometryShader(device, const_cast<ID3DBlob*>(blob)->GetBufferPointer(),
|
||||
const_cast<ID3DBlob*>(blob)->GetBufferSize());
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> D3D11::ShaderCompiler::CreatePixelShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length)
|
||||
{
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> shader;
|
||||
|
||||
@@ -27,7 +27,6 @@ namespace D3D11::ShaderCompiler
|
||||
enum class Type
|
||||
{
|
||||
Vertex,
|
||||
Geometry,
|
||||
Pixel,
|
||||
Compute
|
||||
};
|
||||
@@ -37,8 +36,6 @@ namespace D3D11::ShaderCompiler
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11VertexShader> CompileAndCreateVertexShader(ID3D11Device* device, bool debug, const std::string_view& code,
|
||||
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
|
||||
wil::com_ptr_nothrow<ID3D11GeometryShader> CompileAndCreateGeometryShader(ID3D11Device* device, bool debug, const std::string_view& code,
|
||||
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> CompileAndCreatePixelShader(ID3D11Device* device, bool debug, const std::string_view& code,
|
||||
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main");
|
||||
wil::com_ptr_nothrow<ID3D11ComputeShader> CompileAndCreateComputeShader(ID3D11Device* device, bool debug, const std::string_view& code,
|
||||
@@ -46,8 +43,6 @@ namespace D3D11::ShaderCompiler
|
||||
|
||||
wil::com_ptr_nothrow<ID3D11VertexShader> CreateVertexShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length);
|
||||
wil::com_ptr_nothrow<ID3D11VertexShader> CreateVertexShader(ID3D11Device* device, const ID3DBlob* blob);
|
||||
wil::com_ptr_nothrow<ID3D11GeometryShader> CreateGeometryShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length);
|
||||
wil::com_ptr_nothrow<ID3D11GeometryShader> CreateGeometryShader(ID3D11Device* device, const ID3DBlob* blob);
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> CreatePixelShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length);
|
||||
wil::com_ptr_nothrow<ID3D11PixelShader> CreatePixelShader(ID3D11Device* device, const ID3DBlob* blob);
|
||||
wil::com_ptr_nothrow<ID3D11ComputeShader> CreateComputeShader(ID3D11Device* device, const void* bytecode, size_t bytecode_length);
|
||||
|
||||
@@ -130,7 +130,10 @@ bool Context::Create(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter, bool e
|
||||
pxAssertRel(!g_d3d12_context, "No context exists");
|
||||
|
||||
if (!LoadD3D12Library())
|
||||
{
|
||||
Console.Error("Failed to load D3D12 library");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_d3d12_context.reset(new Context());
|
||||
if (!g_d3d12_context->CreateDevice(dxgi_factory, adapter, enable_debug_layer) ||
|
||||
@@ -188,7 +191,10 @@ bool Context::CreateDevice(IDXGIFactory5* dxgi_factory, IDXGIAdapter1* adapter,
|
||||
// Create the actual device.
|
||||
hr = s_d3d12_create_device(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("Failed to create D3D12 device: %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
// get adapter
|
||||
const LUID luid(m_device->GetAdapterLuid());
|
||||
@@ -659,3 +665,57 @@ void Context::SetEnableGPUTiming(bool enabled)
|
||||
{
|
||||
m_gpu_timing_enabled = enabled;
|
||||
}
|
||||
|
||||
bool Context::AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer,
|
||||
D3D12MA::Allocation** gpu_allocation, const std::function<void(void*)>& fill_callback)
|
||||
{
|
||||
// Try to place the fixed index buffer in GPU local memory.
|
||||
// Use the staging buffer to copy into it.
|
||||
const D3D12_RESOURCE_DESC rd = {D3D12_RESOURCE_DIMENSION_BUFFER, 0, size, 1, 1, 1,
|
||||
DXGI_FORMAT_UNKNOWN, {1, 0}, D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
||||
D3D12_RESOURCE_FLAG_NONE};
|
||||
|
||||
const D3D12MA::ALLOCATION_DESC cpu_ad = {
|
||||
D3D12MA::ALLOCATION_FLAG_NONE,
|
||||
D3D12_HEAP_TYPE_UPLOAD};
|
||||
|
||||
ComPtr<ID3D12Resource> cpu_buffer;
|
||||
ComPtr<D3D12MA::Allocation> cpu_allocation;
|
||||
HRESULT hr = m_allocator->CreateResource(&cpu_ad, &rd, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr,
|
||||
cpu_allocation.put(), IID_PPV_ARGS(cpu_buffer.put()));
|
||||
pxAssertMsg(SUCCEEDED(hr), "Allocate CPU buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
static constexpr const D3D12_RANGE read_range = {};
|
||||
const D3D12_RANGE write_range = {0, size};
|
||||
void* mapped;
|
||||
hr = cpu_buffer->Map(0, &read_range, &mapped);
|
||||
pxAssertMsg(SUCCEEDED(hr), "Map CPU buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
fill_callback(mapped);
|
||||
cpu_buffer->Unmap(0, &write_range);
|
||||
|
||||
const D3D12MA::ALLOCATION_DESC gpu_ad = {
|
||||
D3D12MA::ALLOCATION_FLAG_COMMITTED,
|
||||
D3D12_HEAP_TYPE_DEFAULT};
|
||||
|
||||
hr = m_allocator->CreateResource(&gpu_ad, &rd, D3D12_RESOURCE_STATE_COPY_DEST, nullptr,
|
||||
gpu_allocation, IID_PPV_ARGS(gpu_buffer));
|
||||
pxAssertMsg(SUCCEEDED(hr), "Allocate GPU buffer");
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
GetInitCommandList()->CopyBufferRegion(*gpu_buffer, 0, cpu_buffer.get(), 0, size);
|
||||
|
||||
D3D12_RESOURCE_BARRIER rb = {D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_BARRIER_FLAG_NONE};
|
||||
rb.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
rb.Transition.pResource = *gpu_buffer;
|
||||
rb.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||
rb.Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;
|
||||
GetInitCommandList()->ResourceBarrier(1, &rb);
|
||||
|
||||
DeferResourceDestruction(cpu_allocation.get(), cpu_buffer.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -152,6 +152,10 @@ namespace D3D12
|
||||
float GetAndResetAccumulatedGPUTime();
|
||||
void SetEnableGPUTiming(bool enabled);
|
||||
|
||||
// Allocates a temporary CPU staging buffer, fires the callback with it to populate, then copies to a GPU buffer.
|
||||
bool AllocatePreinitializedGPUBuffer(u32 size, ID3D12Resource** gpu_buffer, D3D12MA::Allocation** gpu_allocation,
|
||||
const std::function<void(void*)>& fill_callback);
|
||||
|
||||
private:
|
||||
struct CommandListResources
|
||||
{
|
||||
|
||||
@@ -45,14 +45,7 @@ ShaderCache::ShaderCache() = default;
|
||||
|
||||
ShaderCache::~ShaderCache()
|
||||
{
|
||||
if (m_pipeline_index_file)
|
||||
std::fclose(m_pipeline_index_file);
|
||||
if (m_pipeline_blob_file)
|
||||
std::fclose(m_pipeline_blob_file);
|
||||
if (m_shader_index_file)
|
||||
std::fclose(m_shader_index_file);
|
||||
if (m_shader_blob_file)
|
||||
std::fclose(m_shader_blob_file);
|
||||
Close();
|
||||
}
|
||||
|
||||
bool ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const
|
||||
@@ -109,6 +102,32 @@ bool ShaderCache::Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_lev
|
||||
return result;
|
||||
}
|
||||
|
||||
void ShaderCache::Close()
|
||||
{
|
||||
if (m_pipeline_index_file)
|
||||
{
|
||||
std::fclose(m_pipeline_index_file);
|
||||
m_pipeline_index_file = nullptr;
|
||||
}
|
||||
if (m_pipeline_blob_file)
|
||||
{
|
||||
std::fclose(m_pipeline_blob_file);
|
||||
m_pipeline_blob_file = nullptr;
|
||||
}
|
||||
if (m_shader_index_file)
|
||||
{
|
||||
std::fclose(m_shader_index_file);
|
||||
m_shader_index_file = nullptr;
|
||||
}
|
||||
if (m_shader_blob_file)
|
||||
{
|
||||
std::fclose(m_shader_blob_file);
|
||||
m_shader_blob_file = nullptr;
|
||||
}
|
||||
|
||||
m_base_path = {};
|
||||
}
|
||||
|
||||
void ShaderCache::InvalidatePipelineCache()
|
||||
{
|
||||
m_pipeline_index.clear();
|
||||
@@ -502,9 +521,6 @@ ShaderCache::ComPtr<ID3DBlob> ShaderCache::CompileAndAddShaderBlob(const CacheIn
|
||||
case EntryType::VertexShader:
|
||||
blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Vertex, m_feature_level, m_debug, shader_code, macros, entry_point);
|
||||
break;
|
||||
case EntryType::GeometryShader:
|
||||
blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Geometry, m_feature_level, m_debug, shader_code, macros, entry_point);
|
||||
break;
|
||||
case EntryType::PixelShader:
|
||||
blob = D3D11::ShaderCompiler::CompileShader(D3D11::ShaderCompiler::Type::Pixel, m_feature_level, m_debug, shader_code, macros, entry_point);
|
||||
break;
|
||||
|
||||
@@ -37,7 +37,6 @@ namespace D3D12
|
||||
enum class EntryType
|
||||
{
|
||||
VertexShader,
|
||||
GeometryShader,
|
||||
PixelShader,
|
||||
ComputeShader,
|
||||
GraphicsPipeline,
|
||||
@@ -52,17 +51,13 @@ namespace D3D12
|
||||
__fi bool UsingDebugShaders() const { return m_debug; }
|
||||
|
||||
bool Open(std::string_view base_path, D3D_FEATURE_LEVEL feature_level, u32 version, bool debug);
|
||||
void Close();
|
||||
|
||||
__fi ComPtr<ID3DBlob> GetVertexShader(std::string_view shader_code,
|
||||
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main")
|
||||
{
|
||||
return GetShaderBlob(EntryType::VertexShader, shader_code, macros, entry_point);
|
||||
}
|
||||
__fi ComPtr<ID3DBlob> GetGeometryShader(std::string_view shader_code,
|
||||
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main")
|
||||
{
|
||||
return GetShaderBlob(EntryType::GeometryShader, shader_code, macros, entry_point);
|
||||
}
|
||||
__fi ComPtr<ID3DBlob> GetPixelShader(std::string_view shader_code,
|
||||
const D3D_SHADER_MACRO* macros = nullptr, const char* entry_point = "main")
|
||||
{
|
||||
@@ -129,7 +124,6 @@ namespace D3D12
|
||||
bool ReadExisting(const std::string& index_filename, const std::string& blob_filename, std::FILE*& index_file,
|
||||
std::FILE*& blob_file, CacheIndex& index);
|
||||
void InvalidatePipelineCache();
|
||||
void Close();
|
||||
|
||||
ComPtr<ID3DBlob> CompileAndAddShaderBlob(const CacheIndexKey& key, std::string_view shader_code,
|
||||
const D3D_SHADER_MACRO* macros, const char* entry_point);
|
||||
|
||||
@@ -100,43 +100,27 @@ namespace GL
|
||||
s_last_program_id = 0;
|
||||
}
|
||||
|
||||
bool Program::Compile(const std::string_view vertex_shader, const std::string_view geometry_shader,
|
||||
const std::string_view fragment_shader)
|
||||
bool Program::Compile(const std::string_view vertex_shader, const std::string_view fragment_shader)
|
||||
{
|
||||
GLuint vertex_shader_id = 0;
|
||||
if (!vertex_shader.empty())
|
||||
{
|
||||
vertex_shader_id = CompileShader(GL_VERTEX_SHADER, vertex_shader);
|
||||
if (vertex_shader_id == 0)
|
||||
m_vertex_shader_id = CompileShader(GL_VERTEX_SHADER, vertex_shader);
|
||||
if (m_vertex_shader_id == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint geometry_shader_id = 0;
|
||||
if (!geometry_shader.empty())
|
||||
{
|
||||
geometry_shader_id = CompileShader(GL_GEOMETRY_SHADER, geometry_shader);
|
||||
if (geometry_shader_id == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
GLuint fragment_shader_id = 0;
|
||||
if (!fragment_shader.empty())
|
||||
{
|
||||
fragment_shader_id = CompileShader(GL_FRAGMENT_SHADER, fragment_shader);
|
||||
if (fragment_shader_id == 0)
|
||||
{
|
||||
glDeleteShader(vertex_shader_id);
|
||||
m_fragment_shader_id = CompileShader(GL_FRAGMENT_SHADER, fragment_shader);
|
||||
if (m_fragment_shader_id == 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_program_id = glCreateProgram();
|
||||
if (vertex_shader_id != 0)
|
||||
glAttachShader(m_program_id, vertex_shader_id);
|
||||
if (geometry_shader_id != 0)
|
||||
glAttachShader(m_program_id, geometry_shader_id);
|
||||
if (fragment_shader_id != 0)
|
||||
glAttachShader(m_program_id, fragment_shader_id);
|
||||
if (m_vertex_shader_id != 0)
|
||||
glAttachShader(m_program_id, m_vertex_shader_id);
|
||||
if (m_fragment_shader_id != 0)
|
||||
glAttachShader(m_program_id, m_fragment_shader_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -485,151 +469,28 @@ namespace GL
|
||||
glUniform4fv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform1ui(const char* name, u32 x) const
|
||||
void Program::UniformMatrix2fv(int index, const float* v)
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
|
||||
const GLint location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform1ui(location, x);
|
||||
glUniformMatrix2fv(location, 1, GL_FALSE, v);
|
||||
}
|
||||
|
||||
void Program::Uniform2ui(const char* name, u32 x, u32 y) const
|
||||
void Program::UniformMatrix3fv(int index, const float* v)
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
|
||||
const GLint location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform2ui(location, x, y);
|
||||
glUniformMatrix3fv(location, 1, GL_FALSE, v);
|
||||
}
|
||||
|
||||
void Program::Uniform3ui(const char* name, u32 x, u32 y, u32 z) const
|
||||
void Program::UniformMatrix4fv(int index, const float* v)
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
pxAssert(static_cast<size_t>(index) < m_uniform_locations.size());
|
||||
const GLint location = m_uniform_locations[index];
|
||||
if (location >= 0)
|
||||
glUniform3ui(location, x, y, z);
|
||||
}
|
||||
|
||||
void Program::Uniform4ui(const char* name, u32 x, u32 y, u32 z, u32 w) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform4ui(location, x, y, z, w);
|
||||
}
|
||||
|
||||
void Program::Uniform1i(const char* name, s32 x) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform1i(location, x);
|
||||
}
|
||||
|
||||
void Program::Uniform2i(const char* name, s32 x, s32 y) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform2i(location, x, y);
|
||||
}
|
||||
|
||||
void Program::Uniform3i(const char* name, s32 x, s32 y, s32 z) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform3i(location, x, y, z);
|
||||
}
|
||||
|
||||
void Program::Uniform4i(const char* name, s32 x, s32 y, s32 z, s32 w) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform4i(location, x, y, z, w);
|
||||
}
|
||||
|
||||
void Program::Uniform1f(const char* name, float x) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform1f(location, x);
|
||||
}
|
||||
|
||||
void Program::Uniform2f(const char* name, float x, float y) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform2f(location, x, y);
|
||||
}
|
||||
|
||||
void Program::Uniform3f(const char* name, float x, float y, float z) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform3f(location, x, y, z);
|
||||
}
|
||||
|
||||
void Program::Uniform4f(const char* name, float x, float y, float z, float w) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform4f(location, x, y, z, w);
|
||||
}
|
||||
|
||||
void Program::Uniform2uiv(const char* name, const u32* v) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform2uiv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform3uiv(const char* name, const u32* v) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform3uiv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform4uiv(const char* name, const u32* v) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform4uiv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform2iv(const char* name, const s32* v) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform2iv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform3iv(const char* name, const s32* v) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform3iv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform4iv(const char* name, const s32* v) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform4iv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform2fv(const char* name, const float* v) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform2fv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform3fv(const char* name, const float* v) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform3fv(location, 1, v);
|
||||
}
|
||||
|
||||
void Program::Uniform4fv(const char* name, const float* v) const
|
||||
{
|
||||
const GLint location = glGetUniformLocation(m_program_id, name);
|
||||
if (location >= 0)
|
||||
glUniform4fv(location, 1, v);
|
||||
glUniformMatrix4fv(location, 1, GL_FALSE, v);
|
||||
}
|
||||
|
||||
void Program::BindUniformBlock(const char* name, u32 index)
|
||||
|
||||
@@ -34,8 +34,7 @@ namespace GL
|
||||
|
||||
bool IsValid() const { return m_program_id != 0; }
|
||||
|
||||
bool Compile(const std::string_view vertex_shader, const std::string_view geometry_shader,
|
||||
const std::string_view fragment_shader);
|
||||
bool Compile(const std::string_view vertex_shader, const std::string_view fragment_shader);
|
||||
|
||||
bool CompileCompute(const std::string_view glsl);
|
||||
|
||||
@@ -79,27 +78,9 @@ namespace GL
|
||||
void Uniform3fv(int index, const float* v) const;
|
||||
void Uniform4fv(int index, const float* v) const;
|
||||
|
||||
void Uniform1ui(const char* name, u32 x) const;
|
||||
void Uniform2ui(const char* name, u32 x, u32 y) const;
|
||||
void Uniform3ui(const char* name, u32 x, u32 y, u32 z) const;
|
||||
void Uniform4ui(const char* name, u32 x, u32 y, u32 z, u32 w) const;
|
||||
void Uniform1i(const char* name, s32 x) const;
|
||||
void Uniform2i(const char* name, s32 x, s32 y) const;
|
||||
void Uniform3i(const char* name, s32 x, s32 y, s32 z) const;
|
||||
void Uniform4i(const char* name, s32 x, s32 y, s32 z, s32 w) const;
|
||||
void Uniform1f(const char* name, float x) const;
|
||||
void Uniform2f(const char* name, float x, float y) const;
|
||||
void Uniform3f(const char* name, float x, float y, float z) const;
|
||||
void Uniform4f(const char* name, float x, float y, float z, float w) const;
|
||||
void Uniform2uiv(const char* name, const u32* v) const;
|
||||
void Uniform3uiv(const char* name, const u32* v) const;
|
||||
void Uniform4uiv(const char* name, const u32* v) const;
|
||||
void Uniform2iv(const char* name, const s32* v) const;
|
||||
void Uniform3iv(const char* name, const s32* v) const;
|
||||
void Uniform4iv(const char* name, const s32* v) const;
|
||||
void Uniform2fv(const char* name, const float* v) const;
|
||||
void Uniform3fv(const char* name, const float* v) const;
|
||||
void Uniform4fv(const char* name, const float* v) const;
|
||||
void UniformMatrix2fv(int index, const float* v);
|
||||
void UniformMatrix3fv(int index, const float* v);
|
||||
void UniformMatrix4fv(int index, const float* v);
|
||||
|
||||
void BindUniformBlock(const char* name, u32 index);
|
||||
|
||||
|
||||
@@ -28,9 +28,6 @@ namespace GL
|
||||
u64 vertex_source_hash_low;
|
||||
u64 vertex_source_hash_high;
|
||||
u32 vertex_source_length;
|
||||
u64 geometry_source_hash_low;
|
||||
u64 geometry_source_hash_high;
|
||||
u32 geometry_source_length;
|
||||
u64 fragment_source_hash_low;
|
||||
u64 fragment_source_hash_high;
|
||||
u32 fragment_source_length;
|
||||
@@ -51,9 +48,7 @@ namespace GL
|
||||
{
|
||||
return (
|
||||
vertex_source_hash_low == key.vertex_source_hash_low && vertex_source_hash_high == key.vertex_source_hash_high &&
|
||||
vertex_source_length == key.vertex_source_length && geometry_source_hash_low == key.geometry_source_hash_low &&
|
||||
geometry_source_hash_high == key.geometry_source_hash_high &&
|
||||
geometry_source_length == key.geometry_source_length && fragment_source_hash_low == key.fragment_source_hash_low &&
|
||||
vertex_source_length == key.vertex_source_length && fragment_source_hash_low == key.fragment_source_hash_low &&
|
||||
fragment_source_hash_high == key.fragment_source_hash_high && fragment_source_length == key.fragment_source_length);
|
||||
}
|
||||
|
||||
@@ -61,9 +56,7 @@ namespace GL
|
||||
{
|
||||
return (
|
||||
vertex_source_hash_low != key.vertex_source_hash_low || vertex_source_hash_high != key.vertex_source_hash_high ||
|
||||
vertex_source_length != key.vertex_source_length || geometry_source_hash_low != key.geometry_source_hash_low ||
|
||||
geometry_source_hash_high != key.geometry_source_hash_high ||
|
||||
geometry_source_length != key.geometry_source_length || fragment_source_hash_low != key.fragment_source_hash_low ||
|
||||
vertex_source_length != key.vertex_source_length || fragment_source_hash_low != key.fragment_source_hash_low ||
|
||||
fragment_source_hash_high != key.fragment_source_hash_high || fragment_source_length != key.fragment_source_length);
|
||||
}
|
||||
|
||||
@@ -204,7 +197,6 @@ namespace GL
|
||||
|
||||
const CacheIndexKey key{
|
||||
entry.vertex_source_hash_low, entry.vertex_source_hash_high, entry.vertex_source_length,
|
||||
entry.geometry_source_hash_low, entry.geometry_source_hash_high, entry.geometry_source_length,
|
||||
entry.fragment_source_hash_low, entry.fragment_source_hash_high, entry.fragment_source_length};
|
||||
const CacheIndexData data{entry.file_offset, entry.blob_size, entry.blob_format};
|
||||
m_index.emplace(key, data);
|
||||
@@ -218,9 +210,17 @@ namespace GL
|
||||
{
|
||||
m_index.clear();
|
||||
if (m_index_file)
|
||||
{
|
||||
std::fclose(m_index_file);
|
||||
m_index_file = nullptr;
|
||||
}
|
||||
if (m_blob_file)
|
||||
{
|
||||
std::fclose(m_blob_file);
|
||||
m_blob_file = nullptr;
|
||||
}
|
||||
|
||||
m_base_path = {};
|
||||
}
|
||||
|
||||
bool ShaderCache::Recreate()
|
||||
@@ -234,7 +234,6 @@ namespace GL
|
||||
}
|
||||
|
||||
ShaderCache::CacheIndexKey ShaderCache::GetCacheKey(const std::string_view& vertex_shader,
|
||||
const std::string_view& geometry_shader,
|
||||
const std::string_view& fragment_shader)
|
||||
{
|
||||
union ShaderHash
|
||||
@@ -248,7 +247,6 @@ namespace GL
|
||||
};
|
||||
|
||||
ShaderHash vertex_hash = {};
|
||||
ShaderHash geometry_hash = {};
|
||||
ShaderHash fragment_hash = {};
|
||||
|
||||
MD5Digest digest;
|
||||
@@ -258,13 +256,6 @@ namespace GL
|
||||
digest.Final(vertex_hash.bytes);
|
||||
}
|
||||
|
||||
if (!geometry_shader.empty())
|
||||
{
|
||||
digest.Reset();
|
||||
digest.Update(geometry_shader.data(), static_cast<u32>(geometry_shader.length()));
|
||||
digest.Final(geometry_hash.bytes);
|
||||
}
|
||||
|
||||
if (!fragment_shader.empty())
|
||||
{
|
||||
digest.Reset();
|
||||
@@ -273,7 +264,6 @@ namespace GL
|
||||
}
|
||||
|
||||
return CacheIndexKey{vertex_hash.low, vertex_hash.high, static_cast<u32>(vertex_shader.length()),
|
||||
geometry_hash.low, geometry_hash.high, static_cast<u32>(geometry_shader.length()),
|
||||
fragment_hash.low, fragment_hash.high, static_cast<u32>(fragment_shader.length())};
|
||||
}
|
||||
|
||||
@@ -288,7 +278,6 @@ namespace GL
|
||||
}
|
||||
|
||||
std::optional<Program> ShaderCache::GetProgram(const std::string_view vertex_shader,
|
||||
const std::string_view geometry_shader,
|
||||
const std::string_view fragment_shader, const PreLinkCallback& callback)
|
||||
{
|
||||
if (!m_program_binary_supported || !m_blob_file)
|
||||
@@ -297,7 +286,7 @@ namespace GL
|
||||
Common::Timer timer;
|
||||
#endif
|
||||
|
||||
std::optional<Program> res = CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, false);
|
||||
std::optional<Program> res = CompileProgram(vertex_shader, fragment_shader, callback, false);
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
Console.WriteLn("Time to compile shader without caching: %.2fms", timer.GetTimeMilliseconds());
|
||||
@@ -305,10 +294,10 @@ namespace GL
|
||||
return res;
|
||||
}
|
||||
|
||||
const auto key = GetCacheKey(vertex_shader, geometry_shader, fragment_shader);
|
||||
const auto key = GetCacheKey(vertex_shader, fragment_shader);
|
||||
auto iter = m_index.find(key);
|
||||
if (iter == m_index.end())
|
||||
return CompileAndAddProgram(key, vertex_shader, geometry_shader, fragment_shader, callback);
|
||||
return CompileAndAddProgram(key, vertex_shader, fragment_shader, callback);
|
||||
|
||||
std::vector<u8> data(iter->second.blob_size);
|
||||
if (std::fseek(m_blob_file, iter->second.file_offset, SEEK_SET) != 0 ||
|
||||
@@ -335,16 +324,15 @@ namespace GL
|
||||
Console.Warning(
|
||||
"Failed to create program from binary, this may be due to a driver or GPU Change. Recreating cache.");
|
||||
if (!Recreate())
|
||||
return CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, false);
|
||||
return CompileProgram(vertex_shader, fragment_shader, callback, false);
|
||||
else
|
||||
return CompileAndAddProgram(key, vertex_shader, geometry_shader, fragment_shader, callback);
|
||||
return CompileAndAddProgram(key, vertex_shader, fragment_shader, callback);
|
||||
}
|
||||
|
||||
bool ShaderCache::GetProgram(Program* out_program, const std::string_view vertex_shader,
|
||||
const std::string_view geometry_shader, const std::string_view fragment_shader,
|
||||
const PreLinkCallback& callback /* = */)
|
||||
const std::string_view fragment_shader, const PreLinkCallback& callback /* = */)
|
||||
{
|
||||
auto prog = GetProgram(vertex_shader, geometry_shader, fragment_shader, callback);
|
||||
auto prog = GetProgram(vertex_shader, fragment_shader, callback);
|
||||
if (!prog)
|
||||
return false;
|
||||
|
||||
@@ -366,9 +354,6 @@ namespace GL
|
||||
entry.vertex_source_hash_low = key.vertex_source_hash_low;
|
||||
entry.vertex_source_hash_high = key.vertex_source_hash_high;
|
||||
entry.vertex_source_length = key.vertex_source_length;
|
||||
entry.geometry_source_hash_low = key.geometry_source_hash_low;
|
||||
entry.geometry_source_hash_high = key.geometry_source_hash_high;
|
||||
entry.geometry_source_length = key.geometry_source_length;
|
||||
entry.fragment_source_hash_low = key.fragment_source_hash_low;
|
||||
entry.fragment_source_hash_high = key.fragment_source_hash_high;
|
||||
entry.fragment_source_length = key.fragment_source_length;
|
||||
@@ -389,12 +374,10 @@ namespace GL
|
||||
}
|
||||
|
||||
std::optional<Program> ShaderCache::CompileProgram(const std::string_view& vertex_shader,
|
||||
const std::string_view& geometry_shader,
|
||||
const std::string_view& fragment_shader,
|
||||
const PreLinkCallback& callback, bool set_retrievable)
|
||||
const std::string_view& fragment_shader, const PreLinkCallback& callback, bool set_retrievable)
|
||||
{
|
||||
Program prog;
|
||||
if (!prog.Compile(vertex_shader, geometry_shader, fragment_shader))
|
||||
if (!prog.Compile(vertex_shader, fragment_shader))
|
||||
return std::nullopt;
|
||||
|
||||
if (callback)
|
||||
@@ -429,16 +412,14 @@ namespace GL
|
||||
}
|
||||
|
||||
std::optional<Program> ShaderCache::CompileAndAddProgram(const CacheIndexKey& key,
|
||||
const std::string_view& vertex_shader,
|
||||
const std::string_view& geometry_shader,
|
||||
const std::string_view& fragment_shader,
|
||||
const std::string_view& vertex_shader, const std::string_view& fragment_shader,
|
||||
const PreLinkCallback& callback)
|
||||
{
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
Common::Timer timer;
|
||||
#endif
|
||||
|
||||
std::optional<Program> prog = CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, true);
|
||||
std::optional<Program> prog = CompileProgram(vertex_shader, fragment_shader, callback, true);
|
||||
if (!prog)
|
||||
return std::nullopt;
|
||||
|
||||
@@ -483,7 +464,7 @@ namespace GL
|
||||
return res;
|
||||
}
|
||||
|
||||
const auto key = GetCacheKey(glsl, std::string_view(), std::string_view());
|
||||
const auto key = GetCacheKey(glsl, std::string_view());
|
||||
auto iter = m_index.find(key);
|
||||
if (iter == m_index.end())
|
||||
return CompileAndAddComputeProgram(key, glsl, callback);
|
||||
|
||||
@@ -36,11 +36,10 @@ namespace GL
|
||||
~ShaderCache();
|
||||
|
||||
bool Open(bool is_gles, std::string_view base_path, u32 version);
|
||||
void Close();
|
||||
|
||||
std::optional<Program> GetProgram(const std::string_view vertex_shader, const std::string_view geometry_shader,
|
||||
const std::string_view fragment_shader, const PreLinkCallback& callback = {});
|
||||
bool GetProgram(Program* out_program, const std::string_view vertex_shader, const std::string_view geometry_shader,
|
||||
const std::string_view fragment_shader, const PreLinkCallback& callback = {});
|
||||
std::optional<Program> GetProgram(const std::string_view vertex_shader, const std::string_view fragment_shader, const PreLinkCallback& callback = {});
|
||||
bool GetProgram(Program* out_program, const std::string_view vertex_shader, const std::string_view fragment_shader, const PreLinkCallback& callback = {});
|
||||
|
||||
std::optional<Program> GetComputeProgram(const std::string_view glsl, const PreLinkCallback& callback = {});
|
||||
bool GetComputeProgram(Program* out_program, const std::string_view glsl, const PreLinkCallback& callback = {});
|
||||
@@ -53,9 +52,6 @@ namespace GL
|
||||
u64 vertex_source_hash_low;
|
||||
u64 vertex_source_hash_high;
|
||||
u32 vertex_source_length;
|
||||
u64 geometry_source_hash_low;
|
||||
u64 geometry_source_hash_high;
|
||||
u32 geometry_source_length;
|
||||
u64 fragment_source_hash_low;
|
||||
u64 fragment_source_hash_high;
|
||||
u32 fragment_source_length;
|
||||
@@ -71,7 +67,6 @@ namespace GL
|
||||
std::size_t h = 0;
|
||||
HashCombine(h,
|
||||
e.vertex_source_hash_low, e.vertex_source_hash_high, e.vertex_source_length,
|
||||
e.geometry_source_hash_low, e.geometry_source_hash_high, e.geometry_source_length,
|
||||
e.fragment_source_hash_low, e.fragment_source_hash_high, e.fragment_source_length);
|
||||
return h;
|
||||
}
|
||||
@@ -86,24 +81,21 @@ namespace GL
|
||||
|
||||
using CacheIndex = std::unordered_map<CacheIndexKey, CacheIndexData, CacheIndexEntryHasher>;
|
||||
|
||||
static CacheIndexKey GetCacheKey(const std::string_view& vertex_shader, const std::string_view& geometry_shader,
|
||||
const std::string_view& fragment_shader);
|
||||
static CacheIndexKey GetCacheKey(const std::string_view& vertex_shader, const std::string_view& fragment_shader);
|
||||
|
||||
std::string GetIndexFileName() const;
|
||||
std::string GetBlobFileName() const;
|
||||
|
||||
bool CreateNew(const std::string& index_filename, const std::string& blob_filename);
|
||||
bool ReadExisting(const std::string& index_filename, const std::string& blob_filename);
|
||||
void Close();
|
||||
bool Recreate();
|
||||
|
||||
bool WriteToBlobFile(const CacheIndexKey& key, const std::vector<u8>& prog_data, u32 prog_format);
|
||||
|
||||
std::optional<Program> CompileProgram(const std::string_view& vertex_shader, const std::string_view& geometry_shader,
|
||||
std::optional<Program> CompileProgram(const std::string_view& vertex_shader,
|
||||
const std::string_view& fragment_shader, const PreLinkCallback& callback,
|
||||
bool set_retrievable);
|
||||
std::optional<Program> CompileAndAddProgram(const CacheIndexKey& key, const std::string_view& vertex_shader,
|
||||
const std::string_view& geometry_shader,
|
||||
const std::string_view& fragment_shader, const PreLinkCallback& callback);
|
||||
|
||||
std::optional<Program> CompileComputeProgram(const std::string_view& glsl, const PreLinkCallback& callback, bool set_retrievable);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "StreamBuffer.h"
|
||||
#include "common/Align.h"
|
||||
#include "common/AlignedMalloc.h"
|
||||
#include "common/Assertions.h"
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
@@ -49,11 +50,14 @@ namespace GL
|
||||
class BufferSubDataStreamBuffer final : public StreamBuffer
|
||||
{
|
||||
public:
|
||||
~BufferSubDataStreamBuffer() override = default;
|
||||
~BufferSubDataStreamBuffer() override
|
||||
{
|
||||
_aligned_free(m_cpu_buffer);
|
||||
}
|
||||
|
||||
MappingResult Map(u32 alignment, u32 min_size) override
|
||||
{
|
||||
return MappingResult{static_cast<void*>(m_cpu_buffer.data()), 0, 0, m_size / alignment};
|
||||
return MappingResult{static_cast<void*>(m_cpu_buffer), 0, 0, m_size / alignment};
|
||||
}
|
||||
|
||||
void Unmap(u32 used_size) override
|
||||
@@ -62,7 +66,7 @@ namespace GL
|
||||
return;
|
||||
|
||||
glBindBuffer(m_target, m_buffer_id);
|
||||
glBufferSubData(m_target, 0, used_size, m_cpu_buffer.data());
|
||||
glBufferSubData(m_target, 0, used_size, m_cpu_buffer);
|
||||
}
|
||||
|
||||
u32 GetChunkSize() const override
|
||||
@@ -93,22 +97,27 @@ namespace GL
|
||||
private:
|
||||
BufferSubDataStreamBuffer(GLenum target, GLuint buffer_id, u32 size)
|
||||
: StreamBuffer(target, buffer_id, size)
|
||||
, m_cpu_buffer(size)
|
||||
{
|
||||
m_cpu_buffer = static_cast<u8*>(_aligned_malloc(size, 32));
|
||||
if (!m_cpu_buffer)
|
||||
pxFailRel("Failed to allocate CPU storage for GL buffer");
|
||||
}
|
||||
|
||||
std::vector<u8> m_cpu_buffer;
|
||||
u8* m_cpu_buffer;
|
||||
};
|
||||
|
||||
// Uses BufferData() to orphan the buffer after every update. Used on Mali where BufferSubData forces a sync.
|
||||
class BufferDataStreamBuffer final : public StreamBuffer
|
||||
{
|
||||
public:
|
||||
~BufferDataStreamBuffer() override = default;
|
||||
~BufferDataStreamBuffer() override
|
||||
{
|
||||
_aligned_free(m_cpu_buffer);
|
||||
}
|
||||
|
||||
MappingResult Map(u32 alignment, u32 min_size) override
|
||||
{
|
||||
return MappingResult{static_cast<void*>(m_cpu_buffer.data()), 0, 0, m_size / alignment};
|
||||
return MappingResult{static_cast<void*>(m_cpu_buffer), 0, 0, m_size / alignment};
|
||||
}
|
||||
|
||||
void Unmap(u32 used_size) override
|
||||
@@ -117,7 +126,7 @@ namespace GL
|
||||
return;
|
||||
|
||||
glBindBuffer(m_target, m_buffer_id);
|
||||
glBufferData(m_target, used_size, m_cpu_buffer.data(), GL_STREAM_DRAW);
|
||||
glBufferData(m_target, used_size, m_cpu_buffer, GL_STREAM_DRAW);
|
||||
}
|
||||
|
||||
u32 GetChunkSize() const override
|
||||
@@ -148,11 +157,13 @@ namespace GL
|
||||
private:
|
||||
BufferDataStreamBuffer(GLenum target, GLuint buffer_id, u32 size)
|
||||
: StreamBuffer(target, buffer_id, size)
|
||||
, m_cpu_buffer(size)
|
||||
{
|
||||
m_cpu_buffer = static_cast<u8*>(_aligned_malloc(size, 32));
|
||||
if (!m_cpu_buffer)
|
||||
pxFailRel("Failed to allocate CPU storage for GL buffer");
|
||||
}
|
||||
|
||||
std::vector<u8> m_cpu_buffer;
|
||||
u8* m_cpu_buffer;
|
||||
};
|
||||
|
||||
// Base class for implementations which require syncing.
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
#include "common/Threading.h"
|
||||
#include "common/WindowInfo.h"
|
||||
|
||||
#ifdef DBUS_API
|
||||
#include <dbus/dbus.h>
|
||||
#endif
|
||||
|
||||
// Returns 0 on failure (not supported by the operating system).
|
||||
u64 GetPhysicalMemory()
|
||||
{
|
||||
@@ -69,11 +73,77 @@ std::string GetOSVersionString()
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef X11_API
|
||||
#ifdef DBUS_API
|
||||
|
||||
bool ChangeScreenSaverStateDBus(const bool inhibit_requested, const char* program_name, const char* reason)
|
||||
{
|
||||
static dbus_uint32_t s_cookie;
|
||||
// "error_dbus" doesn't need to be cleared in the end with "dbus_message_unref" at least if there is
|
||||
// no error set, since calling "dbus_error_free" reinitializes it like "dbus_error_init" after freeing.
|
||||
DBusError error_dbus;
|
||||
dbus_error_init(&error_dbus);
|
||||
DBusConnection* connection = nullptr;
|
||||
DBusMessage* message = nullptr;
|
||||
DBusMessage* response = nullptr;
|
||||
// Initialized here because initializations should be before "goto" statements.
|
||||
const char* bus_method = (inhibit_requested) ? "Inhibit" : "UnInhibit";
|
||||
// "dbus_bus_get" gets a pointer to the same connection in libdbus, if exists, without creating a new connection.
|
||||
// this doesn't need to be deleted, except if there's an error then calling "dbus_connection_unref", to free it,
|
||||
// might be better so a new connection is established on the next try.
|
||||
if (!(connection = dbus_bus_get(DBUS_BUS_SESSION, &error_dbus)) || (dbus_error_is_set(&error_dbus)))
|
||||
goto cleanup;
|
||||
if (!(message = dbus_message_new_method_call("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", bus_method)))
|
||||
goto cleanup;
|
||||
// Initialize an append iterator for the message, gets freed with the message.
|
||||
DBusMessageIter message_itr;
|
||||
dbus_message_iter_init_append(message, &message_itr);
|
||||
if (inhibit_requested)
|
||||
{
|
||||
// Append process/window name.
|
||||
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_STRING, &program_name))
|
||||
goto cleanup;
|
||||
// Append reason for inhibiting the screensaver.
|
||||
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_STRING, &reason))
|
||||
goto cleanup;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only Append the cookie.
|
||||
if (!dbus_message_iter_append_basic(&message_itr, DBUS_TYPE_UINT32, &s_cookie))
|
||||
goto cleanup;
|
||||
}
|
||||
// Send message and get response.
|
||||
if (!(response = dbus_connection_send_with_reply_and_block(connection, message, DBUS_TIMEOUT_USE_DEFAULT, &error_dbus))
|
||||
|| dbus_error_is_set(&error_dbus))
|
||||
goto cleanup;
|
||||
if (inhibit_requested)
|
||||
{
|
||||
// Get the cookie from the response message.
|
||||
if (!dbus_message_get_args(response, &error_dbus, DBUS_TYPE_UINT32, &s_cookie, DBUS_TYPE_INVALID))
|
||||
goto cleanup;
|
||||
}
|
||||
dbus_message_unref(message);
|
||||
dbus_message_unref(response);
|
||||
return true;
|
||||
cleanup:
|
||||
if (dbus_error_is_set(&error_dbus))
|
||||
dbus_error_free(&error_dbus);
|
||||
if (connection)
|
||||
dbus_connection_unref(connection);
|
||||
if (message)
|
||||
dbus_message_unref(message);
|
||||
if (response)
|
||||
dbus_message_unref(response);
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(DBUS_API) && defined(X11_API)
|
||||
|
||||
static bool SetScreensaverInhibitX11(const WindowInfo& wi, bool inhibit)
|
||||
{
|
||||
extern char **environ;
|
||||
extern char** environ;
|
||||
|
||||
const char* command = "xdg-screensaver";
|
||||
const char* operation = inhibit ? "suspend" : "resume";
|
||||
@@ -88,8 +158,6 @@ static bool SetScreensaverInhibitX11(const WindowInfo& wi, bool inhibit)
|
||||
return (res == 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool SetScreensaverInhibit(const WindowInfo& wi, bool inhibit)
|
||||
{
|
||||
switch (wi.type)
|
||||
@@ -106,8 +174,18 @@ static bool SetScreensaverInhibit(const WindowInfo& wi, bool inhibit)
|
||||
|
||||
static std::optional<WindowInfo> s_inhibit_window_info;
|
||||
|
||||
#endif
|
||||
|
||||
bool WindowInfo::InhibitScreensaver(const WindowInfo& wi, bool inhibit)
|
||||
{
|
||||
|
||||
#ifdef DBUS_API
|
||||
|
||||
return ChangeScreenSaverStateDBus(inhibit, "PCSX2", "PCSX2 VM is running.");
|
||||
|
||||
#else
|
||||
|
||||
//ChangeScreenSaverStateDBus
|
||||
if (s_inhibit_window_info.has_value())
|
||||
{
|
||||
// Bit of extra logic here, because wx spams it and we don't want to
|
||||
@@ -132,6 +210,9 @@ bool WindowInfo::InhibitScreensaver(const WindowInfo& wi, bool inhibit)
|
||||
|
||||
s_inhibit_window_info = wi;
|
||||
return true;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool Common::PlaySoundAsync(const char* path)
|
||||
|
||||
@@ -15,197 +15,211 @@
|
||||
|
||||
#include "common/Perf.h"
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#ifdef __unix__
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "common/Assertions.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#ifdef ENABLE_VTUNE
|
||||
#include "jitprofiling.h"
|
||||
#endif
|
||||
|
||||
#include <string> // std::string
|
||||
#include <cstring> // strncpy
|
||||
#include <algorithm> // std::remove_if
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <atomic>
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <elf.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
//#define ProfileWithPerf
|
||||
#define MERGE_BLOCK_RESULT
|
||||
//#define ProfileWithPerfJitDump
|
||||
|
||||
#ifdef ENABLE_VTUNE
|
||||
#ifdef _WIN32
|
||||
#if defined(ENABLE_VTUNE) && defined(_WIN32)
|
||||
#pragma comment(lib, "jitprofiling.lib")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Perf
|
||||
{
|
||||
// Warning object aren't thread safe
|
||||
InfoVector any("");
|
||||
InfoVector ee("EE");
|
||||
InfoVector iop("IOP");
|
||||
InfoVector vu("VU");
|
||||
InfoVector vif("VIF");
|
||||
Group any("");
|
||||
Group ee("EE");
|
||||
Group iop("IOP");
|
||||
Group vu0("VU0");
|
||||
Group vu1("VU1");
|
||||
Group vif("VIF");
|
||||
|
||||
// Perf is only supported on linux
|
||||
#if defined(__linux__) && (defined(ProfileWithPerf) || defined(ENABLE_VTUNE))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of the Info object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Info::Info(uptr x86, u32 size, const char* symbol)
|
||||
: m_x86(x86)
|
||||
, m_size(size)
|
||||
, m_dynamic(false)
|
||||
#if defined(__linux__) && defined(ProfileWithPerf)
|
||||
static std::FILE* s_map_file = nullptr;
|
||||
static bool s_map_file_opened = false;
|
||||
static std::mutex s_mutex;
|
||||
static void RegisterMethod(const void* ptr, size_t size, const char* symbol)
|
||||
{
|
||||
strncpy(m_symbol, symbol, sizeof(m_symbol));
|
||||
}
|
||||
std::unique_lock lock(s_mutex);
|
||||
|
||||
Info::Info(uptr x86, u32 size, const char* symbol, u32 pc)
|
||||
: m_x86(x86)
|
||||
, m_size(size)
|
||||
, m_dynamic(true)
|
||||
{
|
||||
snprintf(m_symbol, sizeof(m_symbol), "%s_0x%08x", symbol, pc);
|
||||
}
|
||||
|
||||
void Info::Print(FILE* fp)
|
||||
{
|
||||
fprintf(fp, "%x %x %s\n", m_x86, m_size, m_symbol);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of the InfoVector object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
InfoVector::InfoVector(const char* prefix)
|
||||
{
|
||||
strncpy(m_prefix, prefix, sizeof(m_prefix));
|
||||
#ifdef ENABLE_VTUNE
|
||||
m_vtune_id = iJIT_GetNewMethodID();
|
||||
#else
|
||||
m_vtune_id = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void InfoVector::print(FILE* fp)
|
||||
{
|
||||
for (auto&& it : m_v)
|
||||
it.Print(fp);
|
||||
}
|
||||
|
||||
void InfoVector::map(uptr x86, u32 size, const char* symbol)
|
||||
{
|
||||
// This function is typically used for dispatcher and recompiler.
|
||||
// Dispatchers are on a page and must always be kept.
|
||||
// Recompilers are much bigger (TODO check VIF) and are only
|
||||
// useful when MERGE_BLOCK_RESULT is defined
|
||||
#if defined(ENABLE_VTUNE) || !defined(MERGE_BLOCK_RESULT)
|
||||
u32 max_code_size = 16 * _1kb;
|
||||
#else
|
||||
u32 max_code_size = _1gb;
|
||||
#endif
|
||||
|
||||
if (size < max_code_size)
|
||||
if (!s_map_file)
|
||||
{
|
||||
m_v.emplace_back(x86, size, symbol);
|
||||
if (s_map_file_opened)
|
||||
return;
|
||||
|
||||
#ifdef ENABLE_VTUNE
|
||||
std::string name = std::string(symbol);
|
||||
|
||||
iJIT_Method_Load ml;
|
||||
|
||||
memset(&ml, 0, sizeof(ml));
|
||||
|
||||
ml.method_id = iJIT_GetNewMethodID();
|
||||
ml.method_name = (char*)name.c_str();
|
||||
ml.method_load_address = (void*)x86;
|
||||
ml.method_size = size;
|
||||
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &ml);
|
||||
|
||||
//fprintf(stderr, "mapF %s: %p size %dKB\n", ml.method_name, ml.method_load_address, ml.method_size / 1024u);
|
||||
#endif
|
||||
char file[256];
|
||||
snprintf(file, std::size(file), "/tmp/perf-%d.map", getpid());
|
||||
s_map_file = std::fopen(file, "wb");
|
||||
s_map_file_opened = true;
|
||||
if (!s_map_file)
|
||||
return;
|
||||
}
|
||||
|
||||
std::fprintf(s_map_file, "%" PRIx64 " %zx %s\n", static_cast<u64>(reinterpret_cast<uintptr_t>(ptr)), size, symbol);
|
||||
std::fflush(s_map_file);
|
||||
}
|
||||
#elif defined(__linux__) && defined(ProfileWithPerfJitDump)
|
||||
enum : u32
|
||||
{
|
||||
JIT_CODE_LOAD = 0,
|
||||
JIT_CODE_MOVE = 1,
|
||||
JIT_CODE_DEBUG_INFO = 2,
|
||||
JIT_CODE_CLOSE = 3,
|
||||
JIT_CODE_UNWINDING_INFO = 4
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct JITDUMP_HEADER
|
||||
{
|
||||
u32 magic = 0x4A695444; // JiTD
|
||||
u32 version = 1;
|
||||
u32 header_size = sizeof(JITDUMP_HEADER);
|
||||
u32 elf_mach;
|
||||
u32 pad1 = 0;
|
||||
u32 pid;
|
||||
u64 timestamp;
|
||||
u64 flags = 0;
|
||||
};
|
||||
struct JITDUMP_RECORD_HEADER
|
||||
{
|
||||
u32 id;
|
||||
u32 total_size;
|
||||
u64 timestamp;
|
||||
};
|
||||
struct JITDUMP_CODE_LOAD
|
||||
{
|
||||
JITDUMP_RECORD_HEADER header;
|
||||
u32 pid;
|
||||
u32 tid;
|
||||
u64 vma;
|
||||
u64 code_addr;
|
||||
u64 code_size;
|
||||
u64 code_index;
|
||||
// name
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
static u64 JitDumpTimestamp()
|
||||
{
|
||||
struct timespec ts = {};
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (static_cast<u64>(ts.tv_sec) * 1000000000ULL) + static_cast<u64>(ts.tv_nsec);
|
||||
}
|
||||
|
||||
void InfoVector::map(uptr x86, u32 size, u32 pc)
|
||||
static FILE* s_jitdump_file = nullptr;
|
||||
static bool s_jitdump_file_opened = false;
|
||||
static std::mutex s_jitdump_mutex;
|
||||
static u32 s_jitdump_record_id;
|
||||
|
||||
static void RegisterMethod(const void* ptr, size_t size, const char* symbol)
|
||||
{
|
||||
#ifndef MERGE_BLOCK_RESULT
|
||||
m_v.emplace_back(x86, size, m_prefix, pc);
|
||||
#endif
|
||||
const u32 namelen = std::strlen(symbol) + 1;
|
||||
|
||||
#ifdef ENABLE_VTUNE
|
||||
iJIT_Method_Load_V2 ml;
|
||||
std::unique_lock lock(s_jitdump_mutex);
|
||||
if (!s_jitdump_file)
|
||||
{
|
||||
if (!s_jitdump_file_opened)
|
||||
{
|
||||
char file[256];
|
||||
snprintf(file, std::size(file), "jit-%d.dump", getpid());
|
||||
s_jitdump_file = fopen(file, "w+b");
|
||||
s_jitdump_file_opened = true;
|
||||
if (!s_jitdump_file)
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&ml, 0, sizeof(ml));
|
||||
void* perf_marker = mmap(nullptr, 4096, PROT_READ | PROT_EXEC, MAP_PRIVATE, fileno(s_jitdump_file), 0);
|
||||
pxAssertRel(perf_marker != MAP_FAILED, "Map perf marker");
|
||||
|
||||
#ifdef MERGE_BLOCK_RESULT
|
||||
ml.method_id = m_vtune_id;
|
||||
ml.method_name = m_prefix;
|
||||
#else
|
||||
std::string name = std::string(m_prefix) + "_" + std::to_string(pc);
|
||||
JITDUMP_HEADER jh = {};
|
||||
jh.elf_mach = EM_X86_64;
|
||||
jh.pid = getpid();
|
||||
jh.timestamp = JitDumpTimestamp();
|
||||
std::fwrite(&jh, sizeof(jh), 1, s_jitdump_file);
|
||||
}
|
||||
|
||||
JITDUMP_CODE_LOAD cl = {};
|
||||
cl.header.id = JIT_CODE_LOAD;
|
||||
cl.header.total_size = sizeof(cl) + namelen + static_cast<u32>(size);
|
||||
cl.header.timestamp = JitDumpTimestamp();
|
||||
cl.pid = getpid();
|
||||
cl.tid = syscall(SYS_gettid);
|
||||
cl.vma = 0;
|
||||
cl.code_addr = static_cast<u64>(reinterpret_cast<uintptr_t>(ptr));
|
||||
cl.code_size = static_cast<u64>(size);
|
||||
cl.code_index = s_jitdump_record_id++;
|
||||
std::fwrite(&cl, sizeof(cl), 1, s_jitdump_file);
|
||||
std::fwrite(symbol, namelen, 1, s_jitdump_file);
|
||||
std::fwrite(ptr, size, 1, s_jitdump_file);
|
||||
std::fflush(s_jitdump_file);
|
||||
}
|
||||
#elif defined(ENABLE_VTUNE)
|
||||
static void RegisterMethod(const void* ptr, size_t size, const char* symbol)
|
||||
{
|
||||
iJIT_Method_Load_V2 ml = {};
|
||||
ml.method_id = iJIT_GetNewMethodID();
|
||||
ml.method_name = (char*)name.c_str();
|
||||
#endif
|
||||
ml.method_load_address = (void*)x86;
|
||||
ml.method_size = size;
|
||||
|
||||
ml.method_name = const_cast<char*>(symbol);
|
||||
ml.method_load_address = const_cast<void*>(ptr);
|
||||
ml.method_size = static_cast<unsigned int>(size);
|
||||
iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2, &ml);
|
||||
|
||||
//fprintf(stderr, "mapB %s: %p size %d\n", ml.method_name, ml.method_load_address, ml.method_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void InfoVector::reset()
|
||||
{
|
||||
auto dynamic = std::remove_if(m_v.begin(), m_v.end(), [](Info i) { return i.m_dynamic; });
|
||||
m_v.erase(dynamic, m_v.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Global function
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void dump()
|
||||
{
|
||||
char file[256];
|
||||
snprintf(file, 250, "/tmp/perf-%d.map", getpid());
|
||||
FILE* fp = fopen(file, "w");
|
||||
|
||||
any.print(fp);
|
||||
ee.print(fp);
|
||||
iop.print(fp);
|
||||
vu.print(fp);
|
||||
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void dump_and_reset()
|
||||
{
|
||||
dump();
|
||||
|
||||
any.reset();
|
||||
ee.reset();
|
||||
iop.reset();
|
||||
vu.reset();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Dummy implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
InfoVector::InfoVector(const char* prefix)
|
||||
: m_vtune_id(0)
|
||||
static void RegisterMethod(const void* ptr, size_t size, const char* method)
|
||||
{
|
||||
}
|
||||
void InfoVector::map(uptr x86, u32 size, const char* symbol) {}
|
||||
void InfoVector::map(uptr x86, u32 size, u32 pc) {}
|
||||
void InfoVector::reset() {}
|
||||
#endif
|
||||
|
||||
void dump() {}
|
||||
void dump_and_reset() {}
|
||||
#if (defined(__linux__) && (defined(ProfileWithPerf) || defined(ProfileWithPerfJitDump))) || defined(ENABLE_VTUNE)
|
||||
void Group::Register(const void* ptr, size_t size, const char* symbol)
|
||||
{
|
||||
char full_symbol[128];
|
||||
if (HasPrefix())
|
||||
std::snprintf(full_symbol, std::size(full_symbol), "%s_%s", m_prefix, symbol);
|
||||
else
|
||||
StringUtil::Strlcpy(full_symbol, symbol, std::size(full_symbol));
|
||||
RegisterMethod(ptr, size, full_symbol);
|
||||
}
|
||||
|
||||
void Group::RegisterPC(const void* ptr, size_t size, u32 pc)
|
||||
{
|
||||
char full_symbol[128];
|
||||
if (HasPrefix())
|
||||
std::snprintf(full_symbol, std::size(full_symbol), "%s_%08X", m_prefix, pc);
|
||||
else
|
||||
std::snprintf(full_symbol, std::size(full_symbol), "%08X", pc);
|
||||
RegisterMethod(ptr, size, full_symbol);
|
||||
}
|
||||
|
||||
void Group::RegisterKey(const void* ptr, size_t size, const char* prefix, u64 key)
|
||||
{
|
||||
char full_symbol[128];
|
||||
if (HasPrefix())
|
||||
std::snprintf(full_symbol, std::size(full_symbol), "%s_%s%016" PRIX64, m_prefix, prefix, key);
|
||||
else
|
||||
std::snprintf(full_symbol, std::size(full_symbol), "%s%016" PRIX64, prefix, key);
|
||||
RegisterMethod(ptr, size, full_symbol);
|
||||
}
|
||||
#else
|
||||
void Group::Register(const void* ptr, size_t size, const char* symbol) {}
|
||||
void Group::RegisterPC(const void* ptr, size_t size, u32 pc) {}
|
||||
void Group::RegisterKey(const void* ptr, size_t size, const char* prefix, u64 key) {}
|
||||
#endif
|
||||
} // namespace Perf
|
||||
|
||||
@@ -21,42 +21,23 @@
|
||||
|
||||
namespace Perf
|
||||
{
|
||||
|
||||
struct Info
|
||||
class Group
|
||||
{
|
||||
uptr m_x86;
|
||||
u32 m_size;
|
||||
char m_symbol[20];
|
||||
// The idea is to keep static zones that are set only
|
||||
// once.
|
||||
bool m_dynamic;
|
||||
|
||||
Info(uptr x86, u32 size, const char* symbol);
|
||||
Info(uptr x86, u32 size, const char* symbol, u32 pc);
|
||||
void Print(FILE* fp);
|
||||
};
|
||||
|
||||
class InfoVector
|
||||
{
|
||||
std::vector<Info> m_v;
|
||||
char m_prefix[20];
|
||||
unsigned int m_vtune_id;
|
||||
const char* m_prefix;
|
||||
|
||||
public:
|
||||
InfoVector(const char* prefix);
|
||||
constexpr Group(const char* prefix) : m_prefix(prefix) {}
|
||||
bool HasPrefix() const { return (m_prefix && m_prefix[0]); }
|
||||
|
||||
void print(FILE* fp);
|
||||
void map(uptr x86, u32 size, const char* symbol);
|
||||
void map(uptr x86, u32 size, u32 pc);
|
||||
void reset();
|
||||
void Register(const void* ptr, size_t size, const char* symbol);
|
||||
void RegisterPC(const void* ptr, size_t size, u32 pc);
|
||||
void RegisterKey(const void* ptr, size_t size, const char* prefix, u64 key);
|
||||
};
|
||||
|
||||
void dump();
|
||||
void dump_and_reset();
|
||||
|
||||
extern InfoVector any;
|
||||
extern InfoVector ee;
|
||||
extern InfoVector iop;
|
||||
extern InfoVector vu;
|
||||
extern InfoVector vif;
|
||||
extern Group any;
|
||||
extern Group ee;
|
||||
extern Group iop;
|
||||
extern Group vu0;
|
||||
extern Group vu1;
|
||||
extern Group vif;
|
||||
} // namespace Perf
|
||||
|
||||
@@ -97,114 +97,3 @@ public:
|
||||
|
||||
virtual SafeArray<T>* Clone() const;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SafeList - Simple growable container without all the mess or hassle of std containers.
|
||||
//
|
||||
// This container is intended for reasonably simple class types only. Things which this
|
||||
// container does not handle with desired robustness:
|
||||
//
|
||||
// * Classes with non-trivial constructors (such that construction creates much overhead)
|
||||
// * Classes with copy constructors (copying is done using performance memcpy)
|
||||
// * Classes with destructors (they're not called, sorry!)
|
||||
//
|
||||
template <typename T>
|
||||
class SafeList
|
||||
{
|
||||
DeclareNoncopyableObject(SafeList);
|
||||
|
||||
public:
|
||||
static const int DefaultChunkSize = 0x80 * sizeof(T);
|
||||
|
||||
public:
|
||||
std::string Name; // user-assigned block name
|
||||
int ChunkSize; // assigned DefaultChunkSize on init, reconfigurable at any time.
|
||||
|
||||
protected:
|
||||
T* m_ptr;
|
||||
int m_allocsize; // size of the allocation of memory
|
||||
uint m_length; // length of the array (active items, not buffer allocation)
|
||||
|
||||
protected:
|
||||
virtual T* _virtual_realloc(int newsize);
|
||||
void _MakeRoomFor_threshold(int newsize);
|
||||
|
||||
T* _getPtr(uint i) const;
|
||||
|
||||
public:
|
||||
virtual ~SafeList();
|
||||
explicit SafeList(const char* name = "Unnamed");
|
||||
explicit SafeList(int initialSize, const char* name = "Unnamed");
|
||||
virtual SafeList<T>* Clone() const;
|
||||
|
||||
void Remove(int index);
|
||||
void MakeRoomFor(int blockSize);
|
||||
|
||||
T& New();
|
||||
int Add(const T& src);
|
||||
T& AddNew(const T& src);
|
||||
|
||||
// Returns the size of the list, as according to the array type. This includes
|
||||
// mapped items only. The actual size of the allocation may differ.
|
||||
int GetLength() const { return m_length; }
|
||||
|
||||
// Returns the size of the list, in bytes. This includes mapped items only.
|
||||
// The actual size of the allocation may differ.
|
||||
int GetSizeInBytes() const { return m_length * sizeof(T); }
|
||||
|
||||
void MatchLengthToAllocatedSize()
|
||||
{
|
||||
m_length = m_allocsize;
|
||||
}
|
||||
|
||||
void GrowBy(int items)
|
||||
{
|
||||
MakeRoomFor(m_length + ChunkSize + items + 1);
|
||||
}
|
||||
|
||||
// Sets the item length to zero. Does not free memory allocations.
|
||||
void Clear()
|
||||
{
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
// Gets an element of this memory allocation much as if it were an array.
|
||||
// DevBuilds : Generates assertion if the index is invalid.
|
||||
T& operator[](int idx) { return *_getPtr((uint)idx); }
|
||||
const T& operator[](int idx) const { return *_getPtr((uint)idx); }
|
||||
|
||||
T* GetPtr() { return m_ptr; }
|
||||
const T* GetPtr() const { return m_ptr; }
|
||||
|
||||
T& GetLast() { return m_ptr[m_length - 1]; }
|
||||
const T& GetLast() const { return m_ptr[m_length - 1]; }
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SafeAlignedArray<T>
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Handy little class for allocating a resizable memory block, complete with
|
||||
// exception-based error handling and automatic cleanup.
|
||||
// This one supports aligned data allocations too!
|
||||
|
||||
template <typename T, uint Alignment>
|
||||
class SafeAlignedArray : public SafeArray<T>
|
||||
{
|
||||
typedef SafeArray<T> _parent;
|
||||
|
||||
protected:
|
||||
T* _virtual_realloc(int newsize);
|
||||
|
||||
public:
|
||||
using _parent::operator[];
|
||||
|
||||
virtual ~SafeAlignedArray();
|
||||
|
||||
explicit SafeAlignedArray(std::string name = "Unnamed")
|
||||
: SafeArray<T>::SafeArray(name)
|
||||
{
|
||||
}
|
||||
|
||||
explicit SafeAlignedArray(int initialSize, std::string name = "Unnamed");
|
||||
virtual SafeAlignedArray<T, Alignment>* Clone() const;
|
||||
};
|
||||
|
||||
@@ -15,13 +15,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/AlignedMalloc.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/SafeArray.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
// Internal constructor for use by derived classes. This allows a derived class to
|
||||
// use its own memory allocation (with an aligned memory, for example).
|
||||
// Throws:
|
||||
@@ -123,165 +119,3 @@ SafeArray<T>* SafeArray<T>::Clone() const
|
||||
memcpy(retval->GetPtr(), m_ptr, sizeof(T) * m_size);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SafeAlignedArray<T> (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template <typename T, uint Alignment>
|
||||
T* SafeAlignedArray<T, Alignment>::_virtual_realloc(int newsize)
|
||||
{
|
||||
return (T*)((this->m_ptr == NULL) ?
|
||||
_aligned_malloc(newsize * sizeof(T), Alignment) :
|
||||
pcsx2_aligned_realloc(this->m_ptr, newsize * sizeof(T), Alignment, this->m_size * sizeof(T)));
|
||||
}
|
||||
|
||||
// Appends "(align: xx)" to the name of the allocation in devel builds.
|
||||
// Maybe useful,maybe not... no harm in attaching it. :D
|
||||
|
||||
template <typename T, uint Alignment>
|
||||
SafeAlignedArray<T, Alignment>::~SafeAlignedArray()
|
||||
{
|
||||
safe_aligned_free(this->m_ptr);
|
||||
// mptr is set to null, so the parent class's destructor won't re-free it.
|
||||
}
|
||||
|
||||
template <typename T, uint Alignment>
|
||||
SafeAlignedArray<T, Alignment>::SafeAlignedArray(int initialSize, std::string name)
|
||||
: SafeArray<T>::SafeArray(
|
||||
std::move(name),
|
||||
(T*)_aligned_malloc(initialSize * sizeof(T), Alignment),
|
||||
initialSize)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, uint Alignment>
|
||||
SafeAlignedArray<T, Alignment>* SafeAlignedArray<T, Alignment>::Clone() const
|
||||
{
|
||||
SafeAlignedArray<T, Alignment>* retval = new SafeAlignedArray<T, Alignment>(this->m_size);
|
||||
memcpy(retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SafeList<T> (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
T* SafeList<T>::_virtual_realloc(int newsize)
|
||||
{
|
||||
return (T*)realloc(m_ptr, newsize * sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeList<T>::~SafeList()
|
||||
{
|
||||
safe_free(m_ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeList<T>::SafeList(const char* name)
|
||||
: Name(name)
|
||||
{
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_ptr = NULL;
|
||||
m_allocsize = 0;
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeList<T>::SafeList(int initialSize, const char* name)
|
||||
: Name(name)
|
||||
{
|
||||
ChunkSize = DefaultChunkSize;
|
||||
m_allocsize = initialSize;
|
||||
m_length = 0;
|
||||
m_ptr = (T*)malloc(initialSize * sizeof(T));
|
||||
|
||||
if (m_ptr == NULL)
|
||||
pxFailRel("SafeList exact alloc failed");
|
||||
|
||||
for (int i = 0; i < m_allocsize; ++i)
|
||||
{
|
||||
new (&m_ptr[i]) T();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* SafeList<T>::_getPtr(uint i) const
|
||||
{
|
||||
pxAssumeDev(i < m_length, "Index in bounds");
|
||||
return &m_ptr[i];
|
||||
}
|
||||
|
||||
// Ensures that the allocation is large enough to fit data of the
|
||||
// amount requested. The memory allocation is not resized smaller.
|
||||
template <typename T>
|
||||
void SafeList<T>::MakeRoomFor(int blockSize)
|
||||
{
|
||||
if (blockSize > m_allocsize)
|
||||
{
|
||||
const int newalloc = blockSize + ChunkSize;
|
||||
m_ptr = _virtual_realloc(newalloc);
|
||||
if (m_ptr == NULL)
|
||||
pxFailRel("SafeList MakeRoomFor failed");
|
||||
|
||||
for (; m_allocsize < newalloc; ++m_allocsize)
|
||||
{
|
||||
new (&m_ptr[m_allocsize]) T();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Appends an item to the end of the list and returns a handle to it.
|
||||
template <typename T>
|
||||
T& SafeList<T>::New()
|
||||
{
|
||||
_MakeRoomFor_threshold(m_length + 1);
|
||||
return m_ptr[m_length++];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int SafeList<T>::Add(const T& src)
|
||||
{
|
||||
_MakeRoomFor_threshold(m_length + 1);
|
||||
m_ptr[m_length] = src;
|
||||
return m_length++;
|
||||
}
|
||||
|
||||
// Same as Add, but returns the handle of the new object instead of it's array index.
|
||||
template <typename T>
|
||||
T& SafeList<T>::AddNew(const T& src)
|
||||
{
|
||||
_MakeRoomFor_threshold(m_length + 1);
|
||||
m_ptr[m_length] = src;
|
||||
return m_ptr[m_length];
|
||||
}
|
||||
|
||||
// Performs a standard array-copy removal of the given item. All items past the
|
||||
// given item are copied over.
|
||||
// DevBuilds : Generates assertion if the index is invalid.
|
||||
template <typename T>
|
||||
void SafeList<T>::Remove(int index)
|
||||
{
|
||||
pxAssert(index < m_length);
|
||||
|
||||
int copylen = m_length - index;
|
||||
if (copylen > 0)
|
||||
memcpy(&m_ptr[index], &m_ptr[index + 1], copylen);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SafeList<T>* SafeList<T>::Clone() const
|
||||
{
|
||||
SafeList<T>* retval = new SafeList<T>(m_length);
|
||||
memcpy(retval->m_ptr, m_ptr, sizeof(T) * m_length);
|
||||
return retval;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void SafeList<T>::_MakeRoomFor_threshold(int newsize)
|
||||
{
|
||||
MakeRoomFor(newsize + ChunkSize);
|
||||
}
|
||||
|
||||
@@ -698,11 +698,6 @@ namespace Vulkan
|
||||
{
|
||||
pxAssert(m_num_writes < MAX_WRITES && (m_num_image_infos + num_views) < MAX_IMAGE_INFOS);
|
||||
|
||||
#if 1
|
||||
// NOTE: This is deliberately split up - updating multiple descriptors in one write is broken on Adreno.
|
||||
for (u32 i = 0; i < num_views; i++)
|
||||
AddCombinedImageSamplerDescriptorWrite(set, binding + i, views[i], samplers[i], layout);
|
||||
#else
|
||||
VkWriteDescriptorSet& dw = m_writes[m_num_writes++];
|
||||
dw.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
dw.dstSet = set;
|
||||
@@ -718,7 +713,6 @@ namespace Vulkan
|
||||
ii.sampler = samplers[i];
|
||||
ii.imageLayout = layout;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DescriptorSetUpdateBuilder::AddBufferDescriptorWrite(
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/RedtapeWindows.h"
|
||||
#else
|
||||
@@ -70,8 +72,7 @@ namespace Vulkan
|
||||
|
||||
Context::~Context() = default;
|
||||
|
||||
VkInstance Context::CreateVulkanInstance(
|
||||
const WindowInfo* wi, bool enable_debug_utils, bool enable_validation_layer)
|
||||
VkInstance Context::CreateVulkanInstance(const WindowInfo& wi, bool enable_debug_utils, bool enable_validation_layer)
|
||||
{
|
||||
ExtensionList enabled_extensions;
|
||||
if (!SelectInstanceExtensions(&enabled_extensions, wi, enable_debug_utils))
|
||||
@@ -118,7 +119,7 @@ namespace Vulkan
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool Context::SelectInstanceExtensions(ExtensionList* extension_list, const WindowInfo* wi, bool enable_debug_utils)
|
||||
bool Context::SelectInstanceExtensions(ExtensionList* extension_list, const WindowInfo& wi, bool enable_debug_utils)
|
||||
{
|
||||
u32 extension_count = 0;
|
||||
VkResult res = vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr);
|
||||
@@ -155,34 +156,32 @@ namespace Vulkan
|
||||
};
|
||||
|
||||
// Common extensions
|
||||
if (wi && wi->type != WindowInfo::Type::Surfaceless && !SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true))
|
||||
if (wi.type != WindowInfo::Type::Surfaceless && !SupportsExtension(VK_KHR_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||
if (wi && wi->type == WindowInfo::Type::Win32 && !SupportsExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true))
|
||||
if (wi.type == WindowInfo::Type::Win32 && !SupportsExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
#endif
|
||||
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||
if (wi && wi->type == WindowInfo::Type::X11 && !SupportsExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, true))
|
||||
if (wi.type == WindowInfo::Type::X11 && !SupportsExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
#endif
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
if (wi && wi->type == WindowInfo::Type::Wayland &&
|
||||
!SupportsExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true))
|
||||
if (wi.type == WindowInfo::Type::Wayland && !SupportsExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
#endif
|
||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
if (wi && wi->type == WindowInfo::Type::Android &&
|
||||
!SupportsExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true))
|
||||
if (wi.type == WindowInfo::Type::Android && !SupportsExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
#endif
|
||||
#if defined(VK_USE_PLATFORM_METAL_EXT)
|
||||
if (wi && wi->type == WindowInfo::Type::MacOS && !SupportsExtension(VK_EXT_METAL_SURFACE_EXTENSION_NAME, true))
|
||||
if (wi.type == WindowInfo::Type::MacOS && !SupportsExtension(VK_EXT_METAL_SURFACE_EXTENSION_NAME, true))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (wi && wi->type == WindowInfo::Type::Display && !SupportsExtension(VK_KHR_DISPLAY_EXTENSION_NAME, true))
|
||||
if (wi.type == WindowInfo::Type::Display && !SupportsExtension(VK_KHR_DISPLAY_EXTENSION_NAME, true))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
@@ -195,170 +194,67 @@ namespace Vulkan
|
||||
|
||||
Context::GPUList Context::EnumerateGPUs(VkInstance instance)
|
||||
{
|
||||
GPUList gpus;
|
||||
|
||||
u32 gpu_count = 0;
|
||||
VkResult res = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr);
|
||||
if ((res != VK_SUCCESS && res != VK_INCOMPLETE) || gpu_count == 0)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices (1) failed: ");
|
||||
return {};
|
||||
return gpus;
|
||||
}
|
||||
|
||||
GPUList gpus;
|
||||
gpus.resize(gpu_count);
|
||||
|
||||
res = vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.data());
|
||||
std::vector<VkPhysicalDevice> physical_devices(gpu_count);
|
||||
res = vkEnumeratePhysicalDevices(instance, &gpu_count, physical_devices.data());
|
||||
if (res == VK_INCOMPLETE)
|
||||
{
|
||||
Console.Warning("First vkEnumeratePhysicalDevices() call returned %zu devices, but second returned %u", gpus.size(), gpu_count);
|
||||
Console.Warning("First vkEnumeratePhysicalDevices() call returned %zu devices, but second returned %u",
|
||||
physical_devices.size(), gpu_count);
|
||||
}
|
||||
else if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices (2) failed: ");
|
||||
return {};
|
||||
return gpus;
|
||||
}
|
||||
|
||||
// Maybe we lost a GPU?
|
||||
if (gpu_count < gpus.size())
|
||||
gpus.resize(gpu_count);
|
||||
if (gpu_count < physical_devices.size())
|
||||
physical_devices.resize(gpu_count);
|
||||
|
||||
return gpus;
|
||||
}
|
||||
|
||||
Context::GPUNameList Context::EnumerateGPUNames(VkInstance instance)
|
||||
{
|
||||
u32 gpu_count = 0;
|
||||
VkResult res = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr);
|
||||
if (res != VK_SUCCESS || gpu_count == 0)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices failed: ");
|
||||
return {};
|
||||
}
|
||||
|
||||
GPUList gpus;
|
||||
gpus.resize(gpu_count);
|
||||
|
||||
res = vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.data());
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices failed: ");
|
||||
return {};
|
||||
}
|
||||
|
||||
GPUNameList gpu_names;
|
||||
gpu_names.reserve(gpu_count);
|
||||
for (u32 i = 0; i < gpu_count; i++)
|
||||
gpus.reserve(physical_devices.size());
|
||||
for (VkPhysicalDevice device : physical_devices)
|
||||
{
|
||||
VkPhysicalDeviceProperties props = {};
|
||||
vkGetPhysicalDeviceProperties(gpus[i], &props);
|
||||
vkGetPhysicalDeviceProperties(device, &props);
|
||||
|
||||
std::string gpu_name(props.deviceName);
|
||||
std::string gpu_name = props.deviceName;
|
||||
|
||||
// handle duplicate adapter names
|
||||
if (std::any_of(gpu_names.begin(), gpu_names.end(),
|
||||
[&gpu_name](const std::string& other) { return (gpu_name == other); }))
|
||||
if (std::any_of(gpus.begin(), gpus.end(),
|
||||
[&gpu_name](const auto& other) { return (gpu_name == other.second); }))
|
||||
{
|
||||
std::string original_adapter_name = std::move(gpu_name);
|
||||
|
||||
u32 current_extra = 2;
|
||||
do
|
||||
{
|
||||
gpu_name = StringUtil::StdStringFromFormat("%s (%u)", original_adapter_name.c_str(), current_extra);
|
||||
gpu_name = fmt::format("{} ({})", original_adapter_name, current_extra);
|
||||
current_extra++;
|
||||
} while (std::any_of(gpu_names.begin(), gpu_names.end(),
|
||||
[&gpu_name](const std::string& other) { return (gpu_name == other); }));
|
||||
} while (std::any_of(gpus.begin(), gpus.end(),
|
||||
[&gpu_name](const auto& other) { return (gpu_name == other.second); }));
|
||||
}
|
||||
|
||||
gpu_names.push_back(std::move(gpu_name));
|
||||
gpus.emplace_back(device, std::move(gpu_name));
|
||||
}
|
||||
|
||||
return gpu_names;
|
||||
return gpus;
|
||||
}
|
||||
|
||||
bool Context::Create(std::string_view gpu_name, const WindowInfo* wi, std::unique_ptr<SwapChain>* out_swap_chain,
|
||||
VkPresentModeKHR preferred_present_mode, bool threaded_presentation, bool enable_debug_utils,
|
||||
bool enable_validation_layer)
|
||||
bool Context::Create(VkInstance instance, VkSurfaceKHR surface, VkPhysicalDevice physical_device,
|
||||
bool threaded_presentation, bool enable_debug_utils, bool enable_validation_layer)
|
||||
{
|
||||
pxAssertMsg(!g_vulkan_context, "Has no current context");
|
||||
|
||||
if (!Vulkan::LoadVulkanLibrary())
|
||||
{
|
||||
Console.Error("Failed to load Vulkan library");
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool enable_surface = (wi && wi->type != WindowInfo::Type::Surfaceless);
|
||||
VkInstance instance = CreateVulkanInstance(wi, enable_debug_utils, enable_validation_layer);
|
||||
if (instance == VK_NULL_HANDLE)
|
||||
{
|
||||
if (enable_debug_utils || enable_validation_layer)
|
||||
{
|
||||
// Try again without the validation layer.
|
||||
enable_debug_utils = false;
|
||||
enable_validation_layer = false;
|
||||
instance = CreateVulkanInstance(wi, enable_debug_utils, enable_validation_layer);
|
||||
if (instance == VK_NULL_HANDLE)
|
||||
{
|
||||
Vulkan::UnloadVulkanLibrary();
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.Error("Vulkan validation/debug layers requested but are unavailable. Creating non-debug device.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!Vulkan::LoadVulkanInstanceFunctions(instance))
|
||||
{
|
||||
Console.Error("Failed to load Vulkan instance functions");
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
Vulkan::UnloadVulkanLibrary();
|
||||
return false;
|
||||
}
|
||||
|
||||
GPUList gpus = EnumerateGPUs(instance);
|
||||
if (gpus.empty())
|
||||
{
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
Vulkan::UnloadVulkanLibrary();
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 gpu_index = 0;
|
||||
GPUNameList gpu_names = EnumerateGPUNames(instance);
|
||||
if (!gpu_name.empty())
|
||||
{
|
||||
for (; gpu_index < static_cast<u32>(gpu_names.size()); gpu_index++)
|
||||
{
|
||||
Console.WriteLn("GPU %u: %s", static_cast<u32>(gpu_index), gpu_names[gpu_index].c_str());
|
||||
if (gpu_names[gpu_index] == gpu_name)
|
||||
break;
|
||||
}
|
||||
|
||||
if (gpu_index == static_cast<u32>(gpu_names.size()))
|
||||
{
|
||||
Console.Warning("Requested GPU '%s' not found, using first (%s)", std::string(gpu_name).c_str(),
|
||||
gpu_names[0].c_str());
|
||||
gpu_index = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLn("No GPU requested, using first (%s)", gpu_names[0].c_str());
|
||||
}
|
||||
|
||||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||
WindowInfo wi_copy;
|
||||
if (wi)
|
||||
wi_copy = *wi;
|
||||
|
||||
if (enable_surface &&
|
||||
(surface = SwapChain::CreateVulkanSurface(instance, gpus[gpu_index], &wi_copy)) == VK_NULL_HANDLE)
|
||||
{
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
Vulkan::UnloadVulkanLibrary();
|
||||
return false;
|
||||
}
|
||||
|
||||
g_vulkan_context.reset(new Context(instance, gpus[gpu_index]));
|
||||
g_vulkan_context.reset(new Context(instance, physical_device));
|
||||
|
||||
if (enable_debug_utils)
|
||||
g_vulkan_context->EnableDebugUtils();
|
||||
@@ -367,8 +263,7 @@ namespace Vulkan
|
||||
if (!g_vulkan_context->CreateDevice(surface, enable_validation_layer, nullptr, 0, nullptr, 0, nullptr) ||
|
||||
!g_vulkan_context->CreateAllocator() || !g_vulkan_context->CreateGlobalDescriptorPool() ||
|
||||
!g_vulkan_context->CreateCommandBuffers() || !g_vulkan_context->CreateTextureStreamBuffer() ||
|
||||
!g_vulkan_context->InitSpinResources() ||
|
||||
(enable_surface && (*out_swap_chain = SwapChain::Create(wi_copy, surface, preferred_present_mode)) == nullptr))
|
||||
!g_vulkan_context->InitSpinResources())
|
||||
{
|
||||
// Since we are destroying the instance, we're also responsible for destroying the surface.
|
||||
if (surface != VK_NULL_HANDLE)
|
||||
@@ -468,12 +363,20 @@ namespace Vulkan
|
||||
SupportsExtension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_line_rasterization =
|
||||
SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access =
|
||||
SupportsExtension(VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, false) ||
|
||||
SupportsExtension(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_driver_properties =
|
||||
SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_arm_rasterization_order_attachment_access =
|
||||
SupportsExtension(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_fragment_shader_barycentric =
|
||||
SupportsExtension(VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_shader_draw_parameters =
|
||||
SupportsExtension(VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, false);
|
||||
|
||||
#ifdef _WIN32
|
||||
m_optional_extensions.vk_ext_full_screen_exclusive =
|
||||
SupportsExtension(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME, false);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -488,7 +391,6 @@ namespace Vulkan
|
||||
|
||||
// Enable the features we use.
|
||||
m_device_features.dualSrcBlend = available_features.dualSrcBlend;
|
||||
m_device_features.geometryShader = available_features.geometryShader;
|
||||
m_device_features.largePoints = available_features.largePoints;
|
||||
m_device_features.wideLines = available_features.wideLines;
|
||||
m_device_features.fragmentStoresAndAtomics = available_features.fragmentStoresAndAtomics;
|
||||
@@ -662,8 +564,8 @@ namespace Vulkan
|
||||
// provoking vertex
|
||||
VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT};
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
|
||||
@@ -677,7 +579,7 @@ namespace Vulkan
|
||||
line_rasterization_feature.bresenhamLines = VK_TRUE;
|
||||
Util::AddPointerToChain(&device_info, &line_rasterization_feature);
|
||||
}
|
||||
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
|
||||
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
||||
{
|
||||
rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess = VK_TRUE;
|
||||
Util::AddPointerToChain(&device_info, &rasterization_order_access_feature);
|
||||
@@ -743,15 +645,15 @@ namespace Vulkan
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT};
|
||||
|
||||
// add in optional feature structs
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
Util::AddPointerToChain(&features2, &provoking_vertex_features);
|
||||
if (m_optional_extensions.vk_ext_line_rasterization)
|
||||
Util::AddPointerToChain(&features2, &line_rasterization_feature);
|
||||
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
|
||||
if (m_optional_extensions.vk_ext_rasterization_order_attachment_access)
|
||||
Util::AddPointerToChain(&features2, &rasterization_order_access_feature);
|
||||
|
||||
// query
|
||||
@@ -759,7 +661,7 @@ namespace Vulkan
|
||||
|
||||
// confirm we actually support it
|
||||
m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE);
|
||||
m_optional_extensions.vk_arm_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_line_rasterization &= (line_rasterization_feature.bresenhamLines == VK_TRUE);
|
||||
|
||||
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
@@ -815,8 +717,8 @@ namespace Vulkan
|
||||
m_optional_extensions.vk_ext_line_rasterization ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_calibrated_timestamps is %s",
|
||||
m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_ARM_rasterization_order_attachment_access is %s",
|
||||
m_optional_extensions.vk_arm_rasterization_order_attachment_access ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_rasterization_order_attachment_access is %s",
|
||||
m_optional_extensions.vk_ext_rasterization_order_attachment_access ? "supported" : "NOT supported");
|
||||
}
|
||||
|
||||
bool Context::CreateAllocator()
|
||||
@@ -956,11 +858,9 @@ namespace Vulkan
|
||||
|
||||
bool Context::CreateGlobalDescriptorPool()
|
||||
{
|
||||
// TODO: A better way to choose the number of descriptors.
|
||||
VkDescriptorPoolSize pool_sizes[] = {
|
||||
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1024},
|
||||
{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1024},
|
||||
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1},
|
||||
static constexpr const VkDescriptorPoolSize pool_sizes[] = {
|
||||
{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 2},
|
||||
{VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2},
|
||||
};
|
||||
|
||||
VkDescriptorPoolCreateInfo pool_create_info = {VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, nullptr,
|
||||
@@ -1666,7 +1566,7 @@ namespace Vulkan
|
||||
input_reference.layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
input_reference_ptr = &input_reference;
|
||||
|
||||
if (!g_vulkan_context->GetOptionalExtensions().vk_arm_rasterization_order_attachment_access)
|
||||
if (!g_vulkan_context->GetOptionalExtensions().vk_ext_rasterization_order_attachment_access)
|
||||
{
|
||||
// don't need the framebuffer-local dependency when we have rasterization order attachment access
|
||||
subpass_dependency.srcSubpass = 0;
|
||||
@@ -1699,7 +1599,9 @@ namespace Vulkan
|
||||
}
|
||||
|
||||
const VkSubpassDescriptionFlags subpass_flags =
|
||||
(key.color_feedback_loop && g_vulkan_context->GetOptionalExtensions().vk_arm_rasterization_order_attachment_access) ? VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM : 0;
|
||||
(key.color_feedback_loop && g_vulkan_context->GetOptionalExtensions().vk_ext_rasterization_order_attachment_access) ?
|
||||
VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT :
|
||||
0;
|
||||
const VkSubpassDescription subpass = {subpass_flags, VK_PIPELINE_BIND_POINT_GRAPHICS, input_reference_ptr ? 1u : 0u,
|
||||
input_reference_ptr ? input_reference_ptr : nullptr, color_reference_ptr ? 1u : 0u,
|
||||
color_reference_ptr ? color_reference_ptr : nullptr, nullptr, depth_reference_ptr, 0, nullptr};
|
||||
@@ -2077,4 +1979,52 @@ void main()
|
||||
return static_cast<u64>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Context::AllocatePreinitializedGPUBuffer(u32 size, VkBuffer* gpu_buffer, VmaAllocation* gpu_allocation,
|
||||
VkBufferUsageFlags gpu_usage, const std::function<void(void*)>& fill_callback)
|
||||
{
|
||||
// Try to place the fixed index buffer in GPU local memory.
|
||||
// Use the staging buffer to copy into it.
|
||||
|
||||
const VkBufferCreateInfo cpu_bci = {
|
||||
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
nullptr,
|
||||
0, size,
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_SHARING_MODE_EXCLUSIVE};
|
||||
const VmaAllocationCreateInfo cpu_aci = {
|
||||
VMA_ALLOCATION_CREATE_MAPPED_BIT, VMA_MEMORY_USAGE_CPU_ONLY, 0, 0};
|
||||
VkBuffer cpu_buffer;
|
||||
VmaAllocation cpu_allocation;
|
||||
VmaAllocationInfo cpu_ai;
|
||||
VkResult res = vmaCreateBuffer(m_allocator, &cpu_bci, &cpu_aci, &cpu_buffer,
|
||||
&cpu_allocation, &cpu_ai);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vmaCreateBuffer() for CPU expand buffer failed: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkBufferCreateInfo gpu_bci = {
|
||||
VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
||||
nullptr,
|
||||
0, size,
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE};
|
||||
const VmaAllocationCreateInfo gpu_aci = {
|
||||
0, VMA_MEMORY_USAGE_GPU_ONLY, 0, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT};
|
||||
VmaAllocationInfo ai;
|
||||
res = vmaCreateBuffer(m_allocator, &gpu_bci, &gpu_aci, gpu_buffer, gpu_allocation, &ai);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vmaCreateBuffer() for expand buffer failed: ");
|
||||
vmaDestroyBuffer(m_allocator, cpu_buffer, cpu_allocation);
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkBufferCopy buf_copy = {0u, 0u, size};
|
||||
fill_callback(cpu_ai.pMappedData);
|
||||
vmaFlushAllocation(m_allocator, cpu_allocation, 0, size);
|
||||
vkCmdCopyBuffer(GetCurrentInitCommandBuffer(), cpu_buffer, *gpu_buffer, 1, &buf_copy);
|
||||
DeferBufferDestruction(cpu_buffer, cpu_allocation);
|
||||
return true;
|
||||
}
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -53,27 +53,26 @@ namespace Vulkan
|
||||
bool vk_ext_memory_budget : 1;
|
||||
bool vk_ext_calibrated_timestamps : 1;
|
||||
bool vk_ext_line_rasterization : 1;
|
||||
bool vk_ext_rasterization_order_attachment_access : 1;
|
||||
bool vk_ext_full_screen_exclusive : 1;
|
||||
bool vk_khr_driver_properties : 1;
|
||||
bool vk_arm_rasterization_order_attachment_access : 1;
|
||||
bool vk_khr_fragment_shader_barycentric : 1;
|
||||
bool vk_khr_shader_draw_parameters : 1;
|
||||
};
|
||||
|
||||
~Context();
|
||||
|
||||
// Helper method to create a Vulkan instance.
|
||||
static VkInstance CreateVulkanInstance(
|
||||
const WindowInfo* wi, bool enable_debug_utils, bool enable_validation_layer);
|
||||
const WindowInfo& wi, bool enable_debug_utils, bool enable_validation_layer);
|
||||
|
||||
// Returns a list of Vulkan-compatible GPUs.
|
||||
using GPUList = std::vector<VkPhysicalDevice>;
|
||||
using GPUNameList = std::vector<std::string>;
|
||||
using GPUList = std::vector<std::pair<VkPhysicalDevice, std::string>>;
|
||||
static GPUList EnumerateGPUs(VkInstance instance);
|
||||
static GPUNameList EnumerateGPUNames(VkInstance instance);
|
||||
|
||||
// Creates a new context and sets it up as global.
|
||||
static bool Create(std::string_view gpu_name, const WindowInfo* wi, std::unique_ptr<SwapChain>* out_swap_chain,
|
||||
VkPresentModeKHR preferred_present_mode, bool threaded_presentation, bool enable_debug_utils,
|
||||
bool enable_validation_layer);
|
||||
static bool Create(VkInstance instance, VkSurfaceKHR surface, VkPhysicalDevice physical_device,
|
||||
bool threaded_presentation, bool enable_debug_utils, bool enable_validation_layer);
|
||||
|
||||
// Destroys context.
|
||||
static void Destroy();
|
||||
@@ -238,6 +237,10 @@ namespace Vulkan
|
||||
void CountRenderPass() { m_command_buffer_render_passes++; }
|
||||
void NotifyOfReadback();
|
||||
|
||||
// Allocates a temporary CPU staging buffer, fires the callback with it to populate, then copies to a GPU buffer.
|
||||
bool AllocatePreinitializedGPUBuffer(u32 size, VkBuffer* gpu_buffer, VmaAllocation* gpu_allocation,
|
||||
VkBufferUsageFlags gpu_usage, const std::function<void(void*)>& fill_callback);
|
||||
|
||||
private:
|
||||
Context(VkInstance instance, VkPhysicalDevice physical_device);
|
||||
|
||||
@@ -262,7 +265,7 @@ namespace Vulkan
|
||||
|
||||
using ExtensionList = std::vector<const char*>;
|
||||
static bool SelectInstanceExtensions(
|
||||
ExtensionList* extension_list, const WindowInfo* wi, bool enable_debug_utils);
|
||||
ExtensionList* extension_list, const WindowInfo& wi, bool enable_debug_utils);
|
||||
bool SelectDeviceExtensions(ExtensionList* extension_list, bool enable_surface);
|
||||
bool SelectDeviceFeatures(const VkPhysicalDeviceFeatures* required_features);
|
||||
bool CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer, const char** required_device_extensions,
|
||||
|
||||
@@ -493,11 +493,6 @@ namespace Vulkan
|
||||
return GetShaderModule(ShaderCompiler::Type::Vertex, std::move(shader_code));
|
||||
}
|
||||
|
||||
VkShaderModule ShaderCache::GetGeometryShader(std::string_view shader_code)
|
||||
{
|
||||
return GetShaderModule(ShaderCompiler::Type::Geometry, std::move(shader_code));
|
||||
}
|
||||
|
||||
VkShaderModule ShaderCache::GetFragmentShader(std::string_view shader_code)
|
||||
{
|
||||
return GetShaderModule(ShaderCompiler::Type::Fragment, std::move(shader_code));
|
||||
|
||||
@@ -47,7 +47,6 @@ namespace Vulkan
|
||||
VkShaderModule GetShaderModule(ShaderCompiler::Type type, std::string_view shader_code);
|
||||
|
||||
VkShaderModule GetVertexShader(std::string_view shader_code);
|
||||
VkShaderModule GetGeometryShader(std::string_view shader_code);
|
||||
VkShaderModule GetFragmentShader(std::string_view shader_code);
|
||||
VkShaderModule GetComputeShader(std::string_view shader_code);
|
||||
|
||||
|
||||
@@ -154,11 +154,6 @@ namespace Vulkan::ShaderCompiler
|
||||
return CompileShaderToSPV(EShLangVertex, "vs", source_code, debug);
|
||||
}
|
||||
|
||||
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code, bool debug)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangGeometry, "gs", source_code, debug);
|
||||
}
|
||||
|
||||
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code, bool debug)
|
||||
{
|
||||
return CompileShaderToSPV(EShLangFragment, "ps", source_code, debug);
|
||||
@@ -176,9 +171,6 @@ namespace Vulkan::ShaderCompiler
|
||||
case Type::Vertex:
|
||||
return CompileShaderToSPV(EShLangVertex, "vs", source_code, debug);
|
||||
|
||||
case Type::Geometry:
|
||||
return CompileShaderToSPV(EShLangGeometry, "gs", source_code, debug);
|
||||
|
||||
case Type::Fragment:
|
||||
return CompileShaderToSPV(EShLangFragment, "ps", source_code, debug);
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace Vulkan::ShaderCompiler
|
||||
enum class Type
|
||||
{
|
||||
Vertex,
|
||||
Geometry,
|
||||
Fragment,
|
||||
Compute
|
||||
};
|
||||
@@ -40,9 +39,6 @@ namespace Vulkan::ShaderCompiler
|
||||
// Compile a vertex shader to SPIR-V.
|
||||
std::optional<SPIRVCodeVector> CompileVertexShader(std::string_view source_code, bool debug);
|
||||
|
||||
// Compile a geometry shader to SPIR-V.
|
||||
std::optional<SPIRVCodeVector> CompileGeometryShader(std::string_view source_code, bool debug);
|
||||
|
||||
// Compile a fragment shader to SPIR-V.
|
||||
std::optional<SPIRVCodeVector> CompileFragmentShader(std::string_view source_code, bool debug);
|
||||
|
||||
|
||||
@@ -29,10 +29,12 @@
|
||||
|
||||
namespace Vulkan
|
||||
{
|
||||
SwapChain::SwapChain(const WindowInfo& wi, VkSurfaceKHR surface, VkPresentModeKHR preferred_present_mode)
|
||||
SwapChain::SwapChain(const WindowInfo& wi, VkSurfaceKHR surface, VkPresentModeKHR preferred_present_mode,
|
||||
std::optional<bool> exclusive_fullscreen_control)
|
||||
: m_window_info(wi)
|
||||
, m_surface(surface)
|
||||
, m_preferred_present_mode(preferred_present_mode)
|
||||
, m_exclusive_fullscreen_control(exclusive_fullscreen_control)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -412,9 +414,10 @@ namespace Vulkan
|
||||
}
|
||||
|
||||
std::unique_ptr<SwapChain> SwapChain::Create(const WindowInfo& wi, VkSurfaceKHR surface,
|
||||
VkPresentModeKHR preferred_present_mode)
|
||||
VkPresentModeKHR preferred_present_mode, std::optional<bool> exclusive_fullscreen_control)
|
||||
{
|
||||
std::unique_ptr<SwapChain> swap_chain = std::make_unique<SwapChain>(wi, surface, preferred_present_mode);
|
||||
std::unique_ptr<SwapChain> swap_chain = std::unique_ptr<SwapChain>(
|
||||
new SwapChain(wi, surface, preferred_present_mode, exclusive_fullscreen_control));
|
||||
if (!swap_chain->CreateSwapChain() || !swap_chain->SetupSwapChainImages())
|
||||
return nullptr;
|
||||
|
||||
@@ -545,9 +548,7 @@ namespace Vulkan
|
||||
// Determine the dimensions of the swap chain. Values of -1 indicate the size we specify here
|
||||
// determines window size?
|
||||
VkExtent2D size = surface_capabilities.currentExtent;
|
||||
#ifndef ANDROID
|
||||
if (size.width == UINT32_MAX)
|
||||
#endif
|
||||
{
|
||||
size.width = m_window_info.surface_width;
|
||||
size.height = m_window_info.surface_height;
|
||||
@@ -562,22 +563,31 @@ namespace Vulkan
|
||||
if (!(surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR))
|
||||
transform = surface_capabilities.currentTransform;
|
||||
|
||||
VkCompositeAlphaFlagBitsKHR alpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
if (!(surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR))
|
||||
{
|
||||
// If we only support pre-multiplied/post-multiplied... :/
|
||||
if (surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
|
||||
alpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
|
||||
}
|
||||
|
||||
// Select swap chain flags, we only need a colour attachment
|
||||
VkImageUsageFlags image_usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
if (!(surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT))
|
||||
VkImageUsageFlags image_usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||
if ((surface_capabilities.supportedUsageFlags & image_usage) != image_usage)
|
||||
{
|
||||
Console.Error("Vulkan: Swap chain does not support usage as color attachment");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the old/current swap chain when recreating for resize
|
||||
// Old swap chain is destroyed regardless of whether the create call succeeds
|
||||
VkSwapchainKHR old_swap_chain = m_swap_chain;
|
||||
m_swap_chain = VK_NULL_HANDLE;
|
||||
|
||||
// Now we can actually create the swap chain
|
||||
VkSwapchainCreateInfoKHR swap_chain_info = {VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, nullptr, 0, m_surface,
|
||||
image_count, m_surface_format.format, m_surface_format.colorSpace, size, 1u, image_usage,
|
||||
VK_SHARING_MODE_EXCLUSIVE, 0, nullptr, transform, VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, m_present_mode,
|
||||
VK_SHARING_MODE_EXCLUSIVE, 0, nullptr, transform, alpha, m_present_mode,
|
||||
VK_TRUE, old_swap_chain};
|
||||
std::array<uint32_t, 2> indices = {{
|
||||
g_vulkan_context->GetGraphicsQueueFamilyIndex(),
|
||||
@@ -590,10 +600,27 @@ namespace Vulkan
|
||||
swap_chain_info.pQueueFamilyIndices = indices.data();
|
||||
}
|
||||
|
||||
if (m_swap_chain == VK_NULL_HANDLE)
|
||||
#ifdef _WIN32
|
||||
VkSurfaceFullScreenExclusiveInfoEXT exclusive_info = {VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT};
|
||||
if (g_vulkan_context->GetOptionalExtensions().vk_ext_full_screen_exclusive)
|
||||
{
|
||||
res = vkCreateSwapchainKHR(g_vulkan_context->GetDevice(), &swap_chain_info, nullptr, &m_swap_chain);
|
||||
exclusive_info.fullScreenExclusive = m_exclusive_fullscreen_control.has_value() ?
|
||||
(m_exclusive_fullscreen_control.value() ?
|
||||
VK_FULL_SCREEN_EXCLUSIVE_ALLOWED_EXT :
|
||||
VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT) :
|
||||
VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT;
|
||||
Util::AddPointerToChain(&swap_chain_info, &exclusive_info);
|
||||
}
|
||||
else if (m_exclusive_fullscreen_control.has_value())
|
||||
{
|
||||
Console.Error("Exclusive fullscreen control requested, but VK_EXT_full_screen_exclusive is not supported.");
|
||||
}
|
||||
#else
|
||||
if (m_exclusive_fullscreen_control.has_value())
|
||||
Console.Error("Exclusive fullscreen control requested, but is not supported on this platform.");
|
||||
#endif
|
||||
|
||||
res = vkCreateSwapchainKHR(g_vulkan_context->GetDevice(), &swap_chain_info, nullptr, &m_swap_chain);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateSwapchainKHR failed: ");
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace Vulkan
|
||||
class SwapChain
|
||||
{
|
||||
public:
|
||||
SwapChain(const WindowInfo& wi, VkSurfaceKHR surface, VkPresentModeKHR preferred_present_mode);
|
||||
~SwapChain();
|
||||
|
||||
// Creates a vulkan-renderable surface for the specified window handle.
|
||||
@@ -49,7 +48,7 @@ namespace Vulkan
|
||||
|
||||
// Create a new swap chain from a pre-existing surface.
|
||||
static std::unique_ptr<SwapChain> Create(const WindowInfo& wi, VkSurfaceKHR surface,
|
||||
VkPresentModeKHR preferred_present_mode);
|
||||
VkPresentModeKHR preferred_present_mode, std::optional<bool> exclusive_fullscreen_control);
|
||||
|
||||
__fi VkSurfaceKHR GetSurface() const { return m_surface; }
|
||||
__fi VkSurfaceFormatKHR GetSurfaceFormat() const { return m_surface_format; }
|
||||
@@ -91,6 +90,9 @@ namespace Vulkan
|
||||
}
|
||||
|
||||
private:
|
||||
SwapChain(const WindowInfo& wi, VkSurfaceKHR surface, VkPresentModeKHR preferred_present_mode,
|
||||
std::optional<bool> exclusive_fullscreen_control);
|
||||
|
||||
bool SelectSurfaceFormat();
|
||||
bool SelectPresentMode();
|
||||
|
||||
@@ -131,5 +133,6 @@ namespace Vulkan
|
||||
u32 m_current_image = 0;
|
||||
u32 m_current_semaphore = 0;
|
||||
std::optional<VkResult> m_image_acquire_result;
|
||||
std::optional<bool> m_exclusive_fullscreen_control;
|
||||
};
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<BinaryOutputDir>$(SolutionDir)bin\</BinaryOutputDir>
|
||||
<PCSX2QTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)3rdparty\qt\6.4.0\msvc2022_64\</PCSX2QTDIRDefault>
|
||||
<PCSX2QTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)3rdparty\qt\6.4.0\msvc2022_arm64\</PCSX2QTDIRDefault>
|
||||
<PCSX2QTDIRDefault Condition="'$(Platform)'=='x64'">$(SolutionDir)3rdparty\qt\6.5.0\msvc2022_64\</PCSX2QTDIRDefault>
|
||||
<PCSX2QTDIRDefault Condition="'$(Platform)'=='ARM64'">$(SolutionDir)3rdparty\qt\6.5.0\msvc2022_arm64\</PCSX2QTDIRDefault>
|
||||
<PCSX2QTDIR Condition="Exists('$(PCSX2QTDIRDefault)') And ('$(PCSX2QTDIR)'=='' Or !Exists('$(PCSX2QTDIR)'))">$(PCSX2QTDIRDefault)</PCSX2QTDIR>
|
||||
<PCSX2QTDIR Condition="Exists('$(PCSX2QTDIR)') And !HasTrailingSlash('$(PCSX2QTDIR)')">$(PCSX2QTDIR)\</PCSX2QTDIR>
|
||||
<PCSX2QTDIRHost>$(SolutionDir)3rdparty\qt\6.4.0\msvc2022_64\</PCSX2QTDIRHost>
|
||||
<PCSX2QTDIRHost>$(SolutionDir)3rdparty\qt\6.5.0\msvc2022_64\</PCSX2QTDIRHost>
|
||||
<QtDirValid>false</QtDirValid>
|
||||
<QtDirValid Condition="Exists('$(PCSX2QTDIR)')">true</QtDirValid>
|
||||
<QtIncludeDir>$(PCSX2QTDIR)include\</QtIncludeDir>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#include "pcsx2/GS.h"
|
||||
#include "pcsx2/GS/GS.h"
|
||||
#include "pcsx2/GSDumpReplayer.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/Host.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
#include "pcsx2/INISettingsInterface.h"
|
||||
#include "pcsx2/PAD/Host/PAD.h"
|
||||
@@ -254,36 +254,16 @@ void Host::SetRelativeMouseMode(bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
bool Host::AcquireHostDisplay(RenderAPI api, bool clear_state_on_fail)
|
||||
std::optional<WindowInfo> Host::AcquireRenderWindow(bool recreate_window)
|
||||
{
|
||||
const std::optional<WindowInfo> wi(GSRunner::GetPlatformWindowInfo());
|
||||
if (!wi.has_value())
|
||||
return false;
|
||||
|
||||
g_host_display = HostDisplay::CreateForAPI(api);
|
||||
if (!g_host_display)
|
||||
return false;
|
||||
|
||||
if (!g_host_display->CreateDevice(wi.value(), Host::GetEffectiveVSyncMode()) ||
|
||||
!g_host_display->MakeCurrent() || !g_host_display->SetupDevice() || !ImGuiManager::Initialize())
|
||||
{
|
||||
ReleaseHostDisplay(clear_state_on_fail);
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLn(Color_StrongGreen, "%s Graphics Driver Info:", HostDisplay::RenderAPIToString(g_host_display->GetRenderAPI()));
|
||||
Console.Indent().WriteLn(g_host_display->GetDriverInfo());
|
||||
|
||||
return g_host_display.get();
|
||||
return GSRunner::GetPlatformWindowInfo();
|
||||
}
|
||||
|
||||
void Host::ReleaseHostDisplay(bool clear_state)
|
||||
void Host::ReleaseRenderWindow()
|
||||
{
|
||||
ImGuiManager::Shutdown(clear_state);
|
||||
g_host_display.reset();
|
||||
}
|
||||
|
||||
HostDisplay::PresentResult Host::BeginPresentFrame(bool frame_skip)
|
||||
void Host::BeginPresentFrame()
|
||||
{
|
||||
if (s_loop_number == 0 && !s_output_prefix.empty())
|
||||
{
|
||||
@@ -294,33 +274,6 @@ HostDisplay::PresentResult Host::BeginPresentFrame(bool frame_skip)
|
||||
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
|
||||
GSQueueSnapshot(dump_path);
|
||||
}
|
||||
|
||||
const HostDisplay::PresentResult result = g_host_display->BeginPresent(frame_skip);
|
||||
if (result != HostDisplay::PresentResult::OK)
|
||||
{
|
||||
// don't render imgui
|
||||
ImGuiManager::SkipFrame();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Host::EndPresentFrame()
|
||||
{
|
||||
if (GSDumpReplayer::IsReplayingDump())
|
||||
GSDumpReplayer::RenderUI();
|
||||
|
||||
ImGuiManager::RenderOSD();
|
||||
g_host_display->EndPresent();
|
||||
ImGuiManager::NewFrame();
|
||||
}
|
||||
|
||||
void Host::ResizeHostDisplay(u32 new_window_width, u32 new_window_height, float new_window_scale)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::UpdateHostDisplay()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RequestResizeHostDisplay(s32 width, s32 height)
|
||||
|
||||
@@ -7,20 +7,19 @@ import multiprocessing
|
||||
from pathlib import Path
|
||||
from functools import partial
|
||||
|
||||
def is_gs_path(path):
|
||||
ppath = Path(path)
|
||||
for extension in [[".gs"], [".gs", ".xz"], [".gs", ".zst"]]:
|
||||
if ppath.suffixes == extension:
|
||||
return True
|
||||
def get_gs_name(path):
|
||||
lpath = path.lower()
|
||||
|
||||
return False
|
||||
for extension in [".gs", ".gs.xz", ".gs.zst"]:
|
||||
if lpath.endswith(extension):
|
||||
return os.path.basename(path)[:-len(extension)]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def run_regression_test(runner, dumpdir, renderer, upscale, renderhacks, parallel, gspath):
|
||||
args = [runner]
|
||||
gsname = Path(gspath).name
|
||||
while gsname.rfind('.') >= 0:
|
||||
gsname = gsname[:gsname.rfind('.')]
|
||||
gsname = get_gs_name(gspath)
|
||||
|
||||
real_dumpdir = os.path.join(dumpdir, gsname).strip()
|
||||
if not os.path.exists(real_dumpdir):
|
||||
@@ -62,7 +61,7 @@ def run_regression_test(runner, dumpdir, renderer, upscale, renderhacks, paralle
|
||||
|
||||
def run_regression_tests(runner, gsdir, dumpdir, renderer, upscale, renderhacks, parallel=1):
|
||||
paths = glob.glob(gsdir + "/*.*", recursive=True)
|
||||
gamepaths = list(filter(is_gs_path, paths))
|
||||
gamepaths = list(filter(lambda x: get_gs_name(x) is not None, paths))
|
||||
|
||||
if not os.path.isdir(dumpdir):
|
||||
os.mkdir(dumpdir)
|
||||
|
||||
@@ -24,6 +24,8 @@ target_sources(pcsx2-qt PRIVATE
|
||||
MainWindow.ui
|
||||
PrecompiledHeader.cpp
|
||||
PrecompiledHeader.h
|
||||
SettingWidgetBinder.h
|
||||
Themes.cpp
|
||||
QtHost.cpp
|
||||
QtHost.h
|
||||
QtKeyCodes.cpp
|
||||
@@ -31,7 +33,6 @@ target_sources(pcsx2-qt PRIVATE
|
||||
QtProgressCallback.h
|
||||
QtUtils.cpp
|
||||
QtUtils.h
|
||||
SettingWidgetBinder.h
|
||||
GameList/EmptyGameListWidget.ui
|
||||
GameList/GameListModel.cpp
|
||||
GameList/GameListModel.h
|
||||
|
||||
@@ -319,8 +319,12 @@ bool BreakpointModel::insertBreakpointRows(int row, int count, std::vector<Break
|
||||
if (breakpoints.size() != static_cast<size_t>(count))
|
||||
return false;
|
||||
|
||||
beginInsertRows(index, row, row + count);
|
||||
beginInsertRows(index, row, row + (count - 1));
|
||||
|
||||
// After endInsertRows, Qt will try and validate our new rows
|
||||
// Because we add the breakpoints off of the UI thread, our new rows may not be visible yet
|
||||
// To prevent the (seemingly harmless?) warning emitted by enderInsertRows, add the breakpoints manually here as well
|
||||
m_breakpoints.insert(m_breakpoints.begin(), breakpoints.begin(), breakpoints.end());
|
||||
for (const auto& bp_mc : breakpoints)
|
||||
{
|
||||
if (const auto* bp = std::get_if<BreakPoint>(&bp_mc))
|
||||
|
||||
@@ -181,7 +181,7 @@ void GameListWidget::initialize()
|
||||
m_list_view = new GameListGridListView(m_ui.stack);
|
||||
m_list_view->setModel(m_sort_model);
|
||||
m_list_view->setModelColumn(GameListModel::Column_Cover);
|
||||
m_list_view->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
m_list_view->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_list_view->setViewMode(QListView::IconMode);
|
||||
m_list_view->setResizeMode(QListView::Adjust);
|
||||
m_list_view->setUniformItemSizes(true);
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
#include "pcsx2/CDVD/CDVDdiscReader.h"
|
||||
#include "pcsx2/Frontend/GameList.h"
|
||||
#include "pcsx2/Frontend/LogSink.h"
|
||||
#include "pcsx2/GS.h"
|
||||
#include "pcsx2/GS/GS.h"
|
||||
#include "pcsx2/GSDumpReplayer.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
#include "pcsx2/PerformanceMetrics.h"
|
||||
#include "pcsx2/Recording/InputRecording.h"
|
||||
@@ -66,7 +66,6 @@
|
||||
#include "pcsx2/Frontend/Achievements.h"
|
||||
#endif
|
||||
|
||||
|
||||
const char* MainWindow::OPEN_FILE_FILTER =
|
||||
QT_TRANSLATE_NOOP("MainWindow", "All File Types (*.bin *.iso *.cue *.chd *.cso *.gz *.elf *.irx *.gs *.gs.xz *.gs.zst *.dump);;"
|
||||
"Single-Track Raw Images (*.bin *.iso);;"
|
||||
@@ -87,16 +86,7 @@ const char* MainWindow::DISC_IMAGE_FILTER = QT_TRANSLATE_NOOP("MainWindow", "All
|
||||
"GZ Images (*.gz);;"
|
||||
"Block Dumps (*.dump)");
|
||||
|
||||
#ifdef __APPLE__
|
||||
const char* MainWindow::DEFAULT_THEME_NAME = "";
|
||||
#else
|
||||
const char* MainWindow::DEFAULT_THEME_NAME = "darkfusion";
|
||||
#endif
|
||||
|
||||
MainWindow* g_main_window = nullptr;
|
||||
static QString s_unthemed_style_name;
|
||||
static QPalette s_unthemed_palette;
|
||||
static bool s_unthemed_style_name_set;
|
||||
|
||||
#if defined(_WIN32) || defined(__APPLE__)
|
||||
static const bool s_use_central_widget = false;
|
||||
@@ -415,10 +405,9 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
|
||||
connect(m_ui.actionStartFullscreenUI, &QAction::triggered, thread, &EmuThread::startFullscreenUI);
|
||||
connect(m_ui.actionStartFullscreenUI2, &QAction::triggered, thread, &EmuThread::startFullscreenUI);
|
||||
connect(thread, &EmuThread::messageConfirmed, this, &MainWindow::confirmMessage, Qt::BlockingQueuedConnection);
|
||||
connect(thread, &EmuThread::onCreateDisplayRequested, this, &MainWindow::createDisplay, Qt::BlockingQueuedConnection);
|
||||
connect(thread, &EmuThread::onUpdateDisplayRequested, this, &MainWindow::updateDisplay, Qt::BlockingQueuedConnection);
|
||||
connect(thread, &EmuThread::onDestroyDisplayRequested, this, &MainWindow::destroyDisplay, Qt::BlockingQueuedConnection);
|
||||
connect(thread, &EmuThread::onResizeDisplayRequested, this, &MainWindow::displayResizeRequested);
|
||||
connect(thread, &EmuThread::onAcquireRenderWindowRequested, this, &MainWindow::acquireRenderWindow, Qt::BlockingQueuedConnection);
|
||||
connect(thread, &EmuThread::onReleaseRenderWindowRequested, this, &MainWindow::releaseRenderWindow, Qt::BlockingQueuedConnection);
|
||||
connect(thread, &EmuThread::onResizeRenderWindowRequested, this, &MainWindow::displayResizeRequested);
|
||||
connect(thread, &EmuThread::onRelativeMouseModeRequested, this, &MainWindow::relativeMouseModeRequested);
|
||||
connect(thread, &EmuThread::onVMStarting, this, &MainWindow::onVMStarting);
|
||||
connect(thread, &EmuThread::onVMStarted, this, &MainWindow::onVMStarted);
|
||||
@@ -503,453 +492,7 @@ void MainWindow::resetSettings(bool ui)
|
||||
g_main_window->recreateSettings();
|
||||
}
|
||||
|
||||
void MainWindow::updateApplicationTheme()
|
||||
{
|
||||
if (!s_unthemed_style_name_set)
|
||||
{
|
||||
s_unthemed_style_name_set = true;
|
||||
s_unthemed_style_name = QApplication::style()->objectName();
|
||||
s_unthemed_palette = QApplication::style()->standardPalette();
|
||||
}
|
||||
|
||||
setStyleFromSettings();
|
||||
setIconThemeFromStyle();
|
||||
}
|
||||
|
||||
void MainWindow::setStyleFromSettings()
|
||||
{
|
||||
const std::string theme(Host::GetBaseStringSettingValue("UI", "Theme", DEFAULT_THEME_NAME));
|
||||
|
||||
if (theme == "fusion")
|
||||
{
|
||||
qApp->setPalette(s_unthemed_palette);
|
||||
qApp->setStyleSheet(QString());
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
}
|
||||
else if (theme == "darkfusion")
|
||||
{
|
||||
// adapted from https://gist.github.com/QuantumCD/6245215
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor lighterGray(75, 75, 75);
|
||||
const QColor darkGray(53, 53, 53);
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor blue(198, 238, 255);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkGray);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, black);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, blue);
|
||||
darkPalette.setColor(QPalette::Highlight, lighterGray);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "darkfusionblue")
|
||||
{
|
||||
// adapted from https://gist.github.com/QuantumCD/6245215
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor darkGray(53, 53, 53);
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor blue(198, 238, 255);
|
||||
const QColor blue2(0, 88, 208);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkGray);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, black);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, blue2);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, blue);
|
||||
darkPalette.setColor(QPalette::Highlight, blue2);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "UntouchedLagoon")
|
||||
{
|
||||
// Custom palette by RedDevilus, Tame (Light/Washed out) Green as main color and Grayish Blue as complimentary.
|
||||
// Alternative white theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor darkteal(0, 77, 77);
|
||||
const QColor teal(0, 128, 128);
|
||||
const QColor tameTeal(160, 190, 185);
|
||||
const QColor grayBlue(160, 180, 190);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, tameTeal);
|
||||
standardPalette.setColor(QPalette::WindowText, black.lighter());
|
||||
standardPalette.setColor(QPalette::Base, grayBlue);
|
||||
standardPalette.setColor(QPalette::AlternateBase, tameTeal);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, tameTeal);
|
||||
standardPalette.setColor(QPalette::ToolTipText, grayBlue);
|
||||
standardPalette.setColor(QPalette::Text, black);
|
||||
standardPalette.setColor(QPalette::Button, tameTeal);
|
||||
standardPalette.setColor(QPalette::ButtonText, black);
|
||||
standardPalette.setColor(QPalette::Link, black.lighter());
|
||||
standardPalette.setColor(QPalette::Highlight, teal);
|
||||
standardPalette.setColor(QPalette::HighlightedText, grayBlue.lighter());
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, tameTeal);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkteal);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkteal.lighter());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkteal.lighter());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, tameTeal);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "BabyPastel")
|
||||
{
|
||||
// Custom palette by RedDevilus, Blue as main color and blue as complimentary.
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(150, 150, 150);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor redpinkish(200, 75, 132);
|
||||
const QColor pink(255, 174, 201);
|
||||
const QColor brightPink(255, 230, 255);
|
||||
const QColor congoPink(255, 127, 121);
|
||||
const QColor blue(221, 225, 239);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, pink);
|
||||
standardPalette.setColor(QPalette::WindowText, black);
|
||||
standardPalette.setColor(QPalette::Base, brightPink);
|
||||
standardPalette.setColor(QPalette::AlternateBase, blue);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, pink);
|
||||
standardPalette.setColor(QPalette::ToolTipText, brightPink);
|
||||
standardPalette.setColor(QPalette::Text, black);
|
||||
standardPalette.setColor(QPalette::Button, pink);
|
||||
standardPalette.setColor(QPalette::ButtonText, black);
|
||||
standardPalette.setColor(QPalette::Link, black);
|
||||
standardPalette.setColor(QPalette::Highlight, congoPink);
|
||||
standardPalette.setColor(QPalette::HighlightedText, black);
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, pink);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "PizzaBrown")
|
||||
{
|
||||
// Custom palette by KamFretoZ, a Pizza Tower Reference!
|
||||
// With a mixtures of Light Brown, Peachy/Creamy White, Latte-like Color.
|
||||
// Thanks to Jordan for the idea :P
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor extr(248, 192, 88);
|
||||
const QColor main(233, 187, 147);
|
||||
const QColor comp(248, 230, 213);
|
||||
const QColor highlight(188, 100, 60);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, main);
|
||||
standardPalette.setColor(QPalette::WindowText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Base, comp);
|
||||
standardPalette.setColor(QPalette::AlternateBase, extr);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, comp);
|
||||
standardPalette.setColor(QPalette::ToolTipText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Text, Qt::black);
|
||||
standardPalette.setColor(QPalette::Button, extr);
|
||||
standardPalette.setColor(QPalette::ButtonText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Link, Qt::black);
|
||||
standardPalette.setColor(QPalette::Highlight, highlight);
|
||||
standardPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, extr);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.darker());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.darker());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, Qt::gray);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray.lighter());
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #cc3f18; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "PCSX2Blue")
|
||||
{
|
||||
// Custom palette by RedDevilus, White as main color and Blue as complimentary.
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor blackish(35, 35, 35);
|
||||
const QColor darkBlue(73, 97, 177);
|
||||
const QColor blue2(80, 120, 200);
|
||||
const QColor blue(106, 156, 255);
|
||||
const QColor lightBlue(130, 155, 241);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, blue2.lighter());
|
||||
standardPalette.setColor(QPalette::WindowText, blackish);
|
||||
standardPalette.setColor(QPalette::Base, lightBlue);
|
||||
standardPalette.setColor(QPalette::AlternateBase, blue2.lighter());
|
||||
standardPalette.setColor(QPalette::ToolTipBase, blue2);
|
||||
standardPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
standardPalette.setColor(QPalette::Text, blackish);
|
||||
standardPalette.setColor(QPalette::Button, blue);
|
||||
standardPalette.setColor(QPalette::ButtonText, blackish);
|
||||
standardPalette.setColor(QPalette::Link, darkBlue);
|
||||
standardPalette.setColor(QPalette::Highlight, Qt::white);
|
||||
standardPalette.setColor(QPalette::HighlightedText, blackish);
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, blue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, darkBlue);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "ScarletDevilRed")
|
||||
{
|
||||
// Custom palette by RedDevilus, Red as main color and Purple as complimentary.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor darkRed(80, 45, 69);
|
||||
const QColor purplishRed(120, 45, 69);
|
||||
const QColor brightRed(200, 45, 69);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkRed);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, purplishRed);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkRed);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkRed);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, purplishRed.darker());
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, brightRed);
|
||||
darkPalette.setColor(QPalette::Highlight, brightRed);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, purplishRed.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkRed);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "CobaltSky")
|
||||
{
|
||||
// Custom palette by KamFretoZ, A soothing deep royal blue
|
||||
// that are meant to be easy on the eyes as the main color.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(192, 192, 192);
|
||||
const QColor royalBlue(29, 41, 81);
|
||||
const QColor darkishBlue(17, 30, 108);
|
||||
const QColor highlight(36, 93, 218);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, royalBlue);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, royalBlue.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, highlight);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkishBlue);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "VioletAngelPurple")
|
||||
{
|
||||
// Custom palette by RedDevilus, Blue as main color and Purple as complimentary.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor blackishblue(50, 25, 70);
|
||||
const QColor darkerPurple(90, 30, 105);
|
||||
const QColor nauticalPurple(110, 30, 125);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, blackishblue);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, nauticalPurple);
|
||||
darkPalette.setColor(QPalette::AlternateBase, blackishblue);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, nauticalPurple);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, nauticalPurple.darker());
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Highlight, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, nauticalPurple.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, darkerPurple.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, nauticalPurple);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Ruby")
|
||||
{
|
||||
// Custom palette by Daisouji, Black as main color and Red as complimentary.
|
||||
// Alternative dark (black) theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor slate(18, 18, 18);
|
||||
const QColor rubyish(172, 21, 31);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, slate);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, slate.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
|
||||
darkPalette.setColor(QPalette::ToolTipBase, slate);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, rubyish);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Sapphire")
|
||||
{
|
||||
// Custom palette by RedDevilus, Black as main color and Blue as complimentary.
|
||||
// Alternative dark (black) theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor slate(18, 18, 18);
|
||||
const QColor persianBlue(32, 35, 204);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, slate);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, slate.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
|
||||
darkPalette.setColor(QPalette::ToolTipBase, slate);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, persianBlue);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Custom")
|
||||
{
|
||||
|
||||
//Additional Theme option than loads .qss from main PCSX2 Directory
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
QString sheet_content;
|
||||
QFile sheets(QString::fromStdString(Path::Combine(EmuFolders::DataRoot, "custom.qss")));
|
||||
|
||||
if (sheets.open(QFile::ReadOnly))
|
||||
{
|
||||
QString sheet_content = QString::fromUtf8(sheets.readAll().data());
|
||||
qApp->setStyleSheet(sheet_content);
|
||||
}
|
||||
else
|
||||
{
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qApp->setPalette(s_unthemed_palette);
|
||||
qApp->setStyleSheet(QString());
|
||||
qApp->setStyle(s_unthemed_style_name);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setIconThemeFromStyle()
|
||||
{
|
||||
QPalette palette = qApp->palette();
|
||||
bool dark = palette.windowText().color().value() > palette.window().color().value();
|
||||
QIcon::setThemeName(dark ? QStringLiteral("white") : QStringLiteral("black"));
|
||||
}
|
||||
|
||||
void MainWindow::onScreenshotActionTriggered()
|
||||
{
|
||||
@@ -1167,7 +710,7 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool stoppi
|
||||
void MainWindow::updateDisplayRelatedActions(bool has_surface, bool render_to_main, bool fullscreen)
|
||||
{
|
||||
// rendering to main, or switched to gamelist/grid
|
||||
m_ui.actionViewSystemDisplay->setEnabled((has_surface && render_to_main) || (!has_surface && g_host_display));
|
||||
m_ui.actionViewSystemDisplay->setEnabled((has_surface && render_to_main) || (!has_surface && GetMTGS().IsOpen()));
|
||||
m_ui.menuWindowSize->setEnabled(has_surface && !fullscreen);
|
||||
m_ui.actionFullscreen->setEnabled(has_surface);
|
||||
|
||||
@@ -1279,10 +822,10 @@ bool MainWindow::isShowingGameList() const
|
||||
|
||||
bool MainWindow::isRenderingFullscreen() const
|
||||
{
|
||||
if (!g_host_display || !m_display_widget)
|
||||
if (!GetMTGS().IsOpen() || !m_display_widget)
|
||||
return false;
|
||||
|
||||
return getDisplayContainer()->isFullScreen() || g_host_display->IsFullscreen();
|
||||
return getDisplayContainer()->isFullScreen();
|
||||
}
|
||||
|
||||
bool MainWindow::isRenderingToMain() const
|
||||
@@ -1430,13 +973,16 @@ bool MainWindow::requestShutdown(bool allow_confirm, bool allow_save_to_state, b
|
||||
|
||||
void MainWindow::requestExit(bool allow_confirm)
|
||||
{
|
||||
// requestShutdown() clears this flag.
|
||||
const bool vm_was_valid = QtHost::IsVMValid();
|
||||
|
||||
// this is block, because otherwise closeEvent() will also prompt
|
||||
if (!requestShutdown(allow_confirm, true, EmuConfig.SaveStateOnShutdown))
|
||||
return;
|
||||
|
||||
// VM stopped signal won't have fired yet, so queue an exit if we still have one.
|
||||
// Otherwise, immediately exit, because there's no VM to exit us later.
|
||||
if (QtHost::IsVMValid())
|
||||
if (vm_was_valid)
|
||||
m_is_closing = true;
|
||||
else
|
||||
QGuiApplication::quit();
|
||||
@@ -1571,7 +1117,11 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
||||
if (m_ui.menuDebug->menuAction()->isVisible())
|
||||
{
|
||||
action = menu.addAction(tr("Boot and Debug"));
|
||||
connect(action, &QAction::triggered, [this, entry]() { DebugInterface::setPauseOnEntry(true); startGameListEntry(entry); getDebuggerWindow()->show(); });
|
||||
connect(action, &QAction::triggered, [this, entry]() {
|
||||
DebugInterface::setPauseOnEntry(true);
|
||||
startGameListEntry(entry);
|
||||
getDebuggerWindow()->show();
|
||||
});
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
@@ -1835,7 +1385,7 @@ void MainWindow::onToolsCoverDownloaderTriggered()
|
||||
|
||||
void MainWindow::updateTheme()
|
||||
{
|
||||
updateApplicationTheme();
|
||||
QtHost::UpdateApplicationTheme();
|
||||
m_game_list_widget->refreshImages();
|
||||
}
|
||||
|
||||
@@ -2197,83 +1747,29 @@ bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, qintptr
|
||||
|
||||
#endif
|
||||
|
||||
DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
|
||||
std::optional<WindowInfo> MainWindow::acquireRenderWindow(bool recreate_window, bool fullscreen, bool render_to_main, bool surfaceless)
|
||||
{
|
||||
DevCon.WriteLn("createDisplay(%u, %u)", static_cast<u32>(fullscreen), static_cast<u32>(render_to_main));
|
||||
|
||||
if (!g_host_display)
|
||||
return nullptr;
|
||||
|
||||
const std::string fullscreen_mode(Host::GetBaseStringSettingValue("EmuCore/GS", "FullscreenMode", ""));
|
||||
const bool is_exclusive_fullscreen = (fullscreen && !fullscreen_mode.empty() && g_host_display->SupportsFullscreen());
|
||||
|
||||
createDisplayWidget(fullscreen, render_to_main, is_exclusive_fullscreen);
|
||||
|
||||
// we need the surface visible.. this might be able to be replaced with something else
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
|
||||
std::optional<WindowInfo> wi = m_display_widget->getWindowInfo();
|
||||
if (!wi.has_value())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to get window info from widget"));
|
||||
destroyDisplayWidget(true);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
g_emu_thread->connectDisplaySignals(m_display_widget);
|
||||
|
||||
if (!g_host_display->CreateDevice(wi.value(), Host::GetEffectiveVSyncMode()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Failed to create host display device. This may be due to your GPU not supporting the chosen renderer (%1), or because your "
|
||||
"graphics drivers need to be updated.")
|
||||
.arg(QString::fromUtf8(Pcsx2Config::GSOptions::GetRendererName(EmuConfig.GS.Renderer))));
|
||||
destroyDisplayWidget(true);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_display_created = true;
|
||||
|
||||
if (is_exclusive_fullscreen)
|
||||
setDisplayFullscreen(fullscreen_mode);
|
||||
|
||||
updateWindowTitle();
|
||||
updateWindowState();
|
||||
|
||||
m_ui.actionStartFullscreenUI->setEnabled(false);
|
||||
m_ui.actionStartFullscreenUI2->setEnabled(false);
|
||||
|
||||
updateDisplayWidgetCursor();
|
||||
m_display_widget->setFocus();
|
||||
|
||||
g_host_display->DoneCurrent();
|
||||
return m_display_widget;
|
||||
}
|
||||
|
||||
DisplayWidget* MainWindow::updateDisplay(bool fullscreen, bool render_to_main, bool surfaceless)
|
||||
{
|
||||
DevCon.WriteLn("updateDisplay() fullscreen=%s render_to_main=%s surfaceless=%s", fullscreen ? "true" : "false",
|
||||
render_to_main ? "true" : "false", surfaceless ? "true" : "false");
|
||||
DevCon.WriteLn("acquireRenderWindow() recreate=%s fullscreen=%s render_to_main=%s surfaceless=%s", recreate_window ? "true" : "false",
|
||||
fullscreen ? "true" : "false", render_to_main ? "true" : "false", surfaceless ? "true" : "false");
|
||||
|
||||
QWidget* container = m_display_container ? static_cast<QWidget*>(m_display_container) : static_cast<QWidget*>(m_display_widget);
|
||||
const bool is_fullscreen = isRenderingFullscreen();
|
||||
const bool is_rendering_to_main = isRenderingToMain();
|
||||
const std::string fullscreen_mode(Host::GetBaseStringSettingValue("EmuCore/GS", "FullscreenMode", ""));
|
||||
const bool is_exclusive_fullscreen = (fullscreen && !fullscreen_mode.empty() && g_host_display->SupportsFullscreen());
|
||||
const bool changing_surfaceless = (!m_display_widget != surfaceless);
|
||||
if (fullscreen == is_fullscreen && is_rendering_to_main == render_to_main && !changing_surfaceless)
|
||||
return m_display_widget;
|
||||
if (m_display_created && !recreate_window && fullscreen == is_fullscreen && is_rendering_to_main == render_to_main &&
|
||||
!changing_surfaceless)
|
||||
{
|
||||
return m_display_widget ? m_display_widget->getWindowInfo() : WindowInfo();
|
||||
}
|
||||
|
||||
// Skip recreating the surface if we're just transitioning between fullscreen and windowed with render-to-main off.
|
||||
// .. except on Wayland, where everything tends to break if you don't recreate.
|
||||
const bool has_container = (m_display_container != nullptr);
|
||||
const bool needs_container = DisplayContainer::isNeeded(fullscreen, render_to_main);
|
||||
if (!is_rendering_to_main && !render_to_main && !is_exclusive_fullscreen && has_container == needs_container && !needs_container &&
|
||||
!changing_surfaceless)
|
||||
if (m_display_created && !recreate_window && !is_rendering_to_main && !render_to_main && has_container == needs_container &&
|
||||
!needs_container && !changing_surfaceless)
|
||||
{
|
||||
DevCon.WriteLn("Toggling to %s without recreating surface", (fullscreen ? "fullscreen" : "windowed"));
|
||||
if (g_host_display->IsFullscreen())
|
||||
g_host_display->SetFullscreen(false, 0, 0, 0.0f);
|
||||
|
||||
// since we don't destroy the display widget, we need to save it here
|
||||
if (!is_fullscreen && !is_rendering_to_main)
|
||||
@@ -2294,45 +1790,44 @@ DisplayWidget* MainWindow::updateDisplay(bool fullscreen, bool render_to_main, b
|
||||
updateWindowState();
|
||||
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
return m_display_widget;
|
||||
return m_display_widget->getWindowInfo();
|
||||
}
|
||||
|
||||
g_host_display->DestroySurface();
|
||||
|
||||
destroyDisplayWidget(surfaceless);
|
||||
m_display_created = true;
|
||||
|
||||
// if we're going to surfaceless, we're done here
|
||||
if (surfaceless)
|
||||
return nullptr;
|
||||
return WindowInfo();
|
||||
|
||||
createDisplayWidget(fullscreen, render_to_main, is_exclusive_fullscreen);
|
||||
createDisplayWidget(fullscreen, render_to_main);
|
||||
|
||||
// we need the surface visible.. this might be able to be replaced with something else
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
|
||||
std::optional<WindowInfo> wi = m_display_widget->getWindowInfo();
|
||||
if (!wi.has_value())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to get new window info from widget"));
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to get window info from widget"));
|
||||
destroyDisplayWidget(true);
|
||||
return nullptr;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
g_emu_thread->connectDisplaySignals(m_display_widget);
|
||||
|
||||
if (!g_host_display->ChangeWindow(wi.value()))
|
||||
pxFailRel("Failed to recreate surface on new widget.");
|
||||
|
||||
if (is_exclusive_fullscreen)
|
||||
setDisplayFullscreen(fullscreen_mode);
|
||||
|
||||
updateWindowTitle();
|
||||
updateWindowState();
|
||||
|
||||
m_ui.actionStartFullscreenUI->setEnabled(false);
|
||||
m_ui.actionStartFullscreenUI2->setEnabled(false);
|
||||
|
||||
updateDisplayWidgetCursor();
|
||||
m_display_widget->setFocus();
|
||||
|
||||
return m_display_widget;
|
||||
return wi;
|
||||
}
|
||||
|
||||
void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main, bool is_exclusive_fullscreen)
|
||||
void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main)
|
||||
{
|
||||
// If we're rendering to main and were hidden (e.g. coming back from fullscreen),
|
||||
// make sure we're visible before trying to add ourselves. Otherwise Wayland breaks.
|
||||
@@ -2374,10 +1869,7 @@ void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main, bool
|
||||
restoreDisplayWindowGeometryFromConfig();
|
||||
}
|
||||
|
||||
if (!is_exclusive_fullscreen)
|
||||
container->showFullScreen();
|
||||
else
|
||||
container->showNormal();
|
||||
container->showFullScreen();
|
||||
}
|
||||
else if (!render_to_main)
|
||||
{
|
||||
@@ -2438,7 +1930,7 @@ void MainWindow::relativeMouseModeRequested(bool enabled)
|
||||
updateDisplayWidgetCursor();
|
||||
}
|
||||
|
||||
void MainWindow::destroyDisplay()
|
||||
void MainWindow::releaseRenderWindow()
|
||||
{
|
||||
// Now we can safely destroy the display window.
|
||||
destroyDisplayWidget(true);
|
||||
@@ -2558,23 +2050,6 @@ void MainWindow::restoreDisplayWindowGeometryFromConfig()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setDisplayFullscreen(const std::string& fullscreen_mode)
|
||||
{
|
||||
u32 width, height;
|
||||
float refresh_rate;
|
||||
if (HostDisplay::ParseFullscreenMode(fullscreen_mode, &width, &height, &refresh_rate))
|
||||
{
|
||||
if (g_host_display->SetFullscreen(true, width, height, refresh_rate))
|
||||
{
|
||||
Host::AddOSDMessage("Acquired exclusive fullscreen.", Host::OSD_INFO_DURATION);
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::AddOSDMessage("Failed to acquire exclusive fullscreen.", Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsDialog* MainWindow::getSettingsDialog()
|
||||
{
|
||||
if (!m_settings_dialog)
|
||||
@@ -3007,19 +2482,33 @@ void MainWindow::doDiscChange(CDVD_SourceType source, const QString& path)
|
||||
|
||||
MainWindow::VMLock MainWindow::pauseAndLockVM()
|
||||
{
|
||||
const bool was_fullscreen = isRenderingFullscreen();
|
||||
// To switch out of fullscreen when displaying a popup, or not to?
|
||||
// For Windows, with driver's direct scanout, what renders behind tends to be hit and miss.
|
||||
// We can't draw anything over exclusive fullscreen, so get out of it in that case.
|
||||
// Wayland's a pain as usual, we need to recreate the window, which means there'll be a brief
|
||||
// period when there's no window, and Qt might shut us down. So avoid it there.
|
||||
// On MacOS, it forces a workspace switch, which is kinda jarring.
|
||||
#ifndef __APPLE__
|
||||
const bool was_fullscreen = g_emu_thread->isFullscreen() && !s_use_central_widget;
|
||||
#else
|
||||
const bool was_fullscreen = false;
|
||||
#endif
|
||||
const bool was_paused = s_vm_paused;
|
||||
|
||||
// We use surfaceless rather than switching out of fullscreen, because
|
||||
// we're paused, so we're not going to be rendering anyway.
|
||||
if (was_fullscreen)
|
||||
g_emu_thread->setSurfaceless(true);
|
||||
if (!was_paused)
|
||||
g_emu_thread->setVMPaused(true);
|
||||
|
||||
// We want to parent dialogs to the display widget, except if we were fullscreen,
|
||||
// since it's going to get destroyed by the surfaceless call above.
|
||||
QWidget* dialog_parent = was_fullscreen ? static_cast<QWidget*>(this) : getDisplayContainer();
|
||||
// We need to switch out of exclusive fullscreen before we can display our popup.
|
||||
// However, we do not want to switch back to render-to-main, the window might have generated this event.
|
||||
if (was_fullscreen)
|
||||
{
|
||||
g_emu_thread->setFullscreen(false, false);
|
||||
while (QtHost::IsVMValid() && g_emu_thread->isFullscreen())
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||
}
|
||||
|
||||
// Now we'll either have a borderless window, or a regular window (if we were exclusive fullscreen).
|
||||
QWidget* dialog_parent = getDisplayContainer();
|
||||
|
||||
return VMLock(dialog_parent, was_paused, was_fullscreen);
|
||||
}
|
||||
@@ -3049,7 +2538,8 @@ MainWindow::VMLock::VMLock(VMLock&& lock)
|
||||
MainWindow::VMLock::~VMLock()
|
||||
{
|
||||
if (m_was_fullscreen)
|
||||
g_emu_thread->setSurfaceless(false);
|
||||
g_emu_thread->setFullscreen(true, true);
|
||||
|
||||
if (!m_was_paused)
|
||||
g_emu_thread->setVMPaused(false);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
void cancelResume();
|
||||
|
||||
private:
|
||||
VMLock(QWidget* dialog_parent, bool was_paused, bool was_fullscreen);
|
||||
VMLock(QWidget* dialog_parent, bool was_paused, bool was_exclusive_fullscreen);
|
||||
friend MainWindow;
|
||||
|
||||
QWidget* m_dialog_parent;
|
||||
@@ -77,9 +77,6 @@ public:
|
||||
bool m_was_fullscreen;
|
||||
};
|
||||
|
||||
/// Default theme name for the platform.
|
||||
static const char* DEFAULT_THEME_NAME;
|
||||
|
||||
/// Default filter for opening a file.
|
||||
static const char* OPEN_FILE_FILTER;
|
||||
|
||||
@@ -90,9 +87,6 @@ public:
|
||||
MainWindow();
|
||||
~MainWindow();
|
||||
|
||||
/// Sets application theme according to settings.
|
||||
static void updateApplicationTheme();
|
||||
|
||||
void initialize();
|
||||
void connectVMThreadSignals(EmuThread* thread);
|
||||
void startupUpdateCheck();
|
||||
@@ -128,11 +122,10 @@ public Q_SLOTS:
|
||||
private Q_SLOTS:
|
||||
void onUpdateCheckComplete();
|
||||
|
||||
DisplayWidget* createDisplay(bool fullscreen, bool render_to_main);
|
||||
DisplayWidget* updateDisplay(bool fullscreen, bool render_to_main, bool surfaceless);
|
||||
std::optional<WindowInfo> acquireRenderWindow(bool recreate_window, bool fullscreen, bool render_to_main, bool surfaceless);
|
||||
void displayResizeRequested(qint32 width, qint32 height);
|
||||
void relativeMouseModeRequested(bool enabled);
|
||||
void destroyDisplay();
|
||||
void releaseRenderWindow();
|
||||
void focusDisplayWidget();
|
||||
|
||||
void onGameListRefreshComplete();
|
||||
@@ -233,10 +226,9 @@ private:
|
||||
QWidget* getDisplayContainer() const;
|
||||
void saveDisplayWindowGeometryToConfig();
|
||||
void restoreDisplayWindowGeometryFromConfig();
|
||||
void createDisplayWidget(bool fullscreen, bool render_to_main, bool is_exclusive_fullscreen);
|
||||
void createDisplayWidget(bool fullscreen, bool render_to_main);
|
||||
void destroyDisplayWidget(bool show_game_list);
|
||||
void updateDisplayWidgetCursor();
|
||||
void setDisplayFullscreen(const std::string& fullscreen_mode);
|
||||
|
||||
SettingsDialog* getSettingsDialog();
|
||||
void doSettings(const char* category = nullptr);
|
||||
|
||||
@@ -438,16 +438,28 @@
|
||||
<property name="text">
|
||||
<string>&GitHub Repository...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="github">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSupportForums">
|
||||
<property name="text">
|
||||
<string>Support &Forums...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="at">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDiscordServer">
|
||||
<property name="text">
|
||||
<string>&Discord Server...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="discord">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCheckForUpdates">
|
||||
<property name="icon">
|
||||
@@ -471,6 +483,10 @@
|
||||
<property name="text">
|
||||
<string>&About PCSX2...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources/resources.qrc">
|
||||
<normaloff>:/icons/AppIcon.png</normaloff>:/icons/AppIcon.png</iconset>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionChangeDisc">
|
||||
<property name="icon">
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include "pcsx2/GS.h"
|
||||
#include "pcsx2/GS/GS.h"
|
||||
#include "pcsx2/GSDumpReplayer.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
#include "pcsx2/INISettingsInterface.h"
|
||||
#include "pcsx2/PAD/Host/PAD.h"
|
||||
@@ -191,12 +190,14 @@ void EmuThread::startFullscreenUI(bool fullscreen)
|
||||
return;
|
||||
}
|
||||
|
||||
if (VMManager::HasValidVM())
|
||||
if (VMManager::HasValidVM() || GetMTGS().IsOpen())
|
||||
return;
|
||||
|
||||
// this should just set the flag so it gets automatically started
|
||||
ImGuiManager::InitializeFullscreenUI();
|
||||
m_run_fullscreen_ui = true;
|
||||
if (fullscreen)
|
||||
m_is_fullscreen = true;
|
||||
m_is_rendering_to_main = shouldRenderToMain();
|
||||
m_is_fullscreen = fullscreen;
|
||||
|
||||
if (!GetMTGS().WaitForOpen())
|
||||
{
|
||||
@@ -216,13 +217,13 @@ void EmuThread::stopFullscreenUI()
|
||||
QMetaObject::invokeMethod(this, &EmuThread::stopFullscreenUI, Qt::QueuedConnection);
|
||||
|
||||
// wait until the host display is gone
|
||||
while (g_host_display)
|
||||
while (GetMTGS().IsOpen())
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_host_display)
|
||||
if (!GetMTGS().IsOpen())
|
||||
return;
|
||||
|
||||
pxAssertRel(!VMManager::HasValidVM(), "VM is not valid at FSUI shutdown time");
|
||||
@@ -241,6 +242,7 @@ void EmuThread::startVM(std::shared_ptr<VMBootParameters> boot_params)
|
||||
pxAssertRel(!VMManager::HasValidVM(), "VM is shut down");
|
||||
|
||||
// Determine whether to start fullscreen or not.
|
||||
m_is_rendering_to_main = shouldRenderToMain();
|
||||
if (boot_params->fullscreen.has_value())
|
||||
m_is_fullscreen = boot_params->fullscreen.value();
|
||||
else
|
||||
@@ -491,14 +493,14 @@ void EmuThread::toggleFullscreen()
|
||||
return;
|
||||
}
|
||||
|
||||
setFullscreen(!m_is_fullscreen);
|
||||
setFullscreen(!m_is_fullscreen, true);
|
||||
}
|
||||
|
||||
void EmuThread::setFullscreen(bool fullscreen)
|
||||
void EmuThread::setFullscreen(bool fullscreen, bool allow_render_to_main)
|
||||
{
|
||||
if (!isOnEmuThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "setFullscreen", Qt::QueuedConnection, Q_ARG(bool, fullscreen));
|
||||
QMetaObject::invokeMethod(this, "setFullscreen", Qt::QueuedConnection, Q_ARG(bool, fullscreen), Q_ARG(bool, allow_render_to_main));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -507,11 +509,12 @@ void EmuThread::setFullscreen(bool fullscreen)
|
||||
|
||||
// This will call back to us on the MTGS thread.
|
||||
m_is_fullscreen = fullscreen;
|
||||
m_is_rendering_to_main = allow_render_to_main && shouldRenderToMain();
|
||||
GetMTGS().UpdateDisplayWindow();
|
||||
GetMTGS().WaitGS();
|
||||
|
||||
// If we're using exclusive fullscreen, the refresh rate may have changed.
|
||||
UpdateVSyncRate();
|
||||
UpdateVSyncRate(true);
|
||||
}
|
||||
|
||||
void EmuThread::setSurfaceless(bool surfaceless)
|
||||
@@ -590,7 +593,7 @@ void EmuThread::checkForSettingChanges(const Pcsx2Config& old_config)
|
||||
{
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::checkForSettingChanges, Qt::QueuedConnection);
|
||||
|
||||
if (g_host_display)
|
||||
if (GetMTGS().IsOpen())
|
||||
{
|
||||
const bool render_to_main = shouldRenderToMain();
|
||||
if (!m_is_fullscreen && m_is_rendering_to_main != render_to_main)
|
||||
@@ -787,7 +790,7 @@ void EmuThread::connectDisplaySignals(DisplayWidget* widget)
|
||||
|
||||
void EmuThread::onDisplayWindowResized(int width, int height, float scale)
|
||||
{
|
||||
if (!g_host_display)
|
||||
if (!GetMTGS().IsOpen())
|
||||
return;
|
||||
|
||||
GetMTGS().ResizeDisplayWindow(width, height, scale);
|
||||
@@ -892,126 +895,38 @@ void EmuThread::endCapture()
|
||||
GetMTGS().RunOnGSThread(&GSEndCapture);
|
||||
}
|
||||
|
||||
void EmuThread::updateDisplay()
|
||||
std::optional<WindowInfo> EmuThread::acquireRenderWindow(bool recreate_window)
|
||||
{
|
||||
pxAssertRel(!isOnEmuThread(), "Not on emu thread");
|
||||
// Check if we're wanting to get exclusive fullscreen. This should be safe to read, since we're going to be calling from the GS thread.
|
||||
m_is_exclusive_fullscreen = m_is_fullscreen && GSWantsExclusiveFullscreen();
|
||||
const bool window_fullscreen = m_is_fullscreen && !m_is_exclusive_fullscreen;
|
||||
const bool render_to_main = !m_is_exclusive_fullscreen && !window_fullscreen && m_is_rendering_to_main;
|
||||
|
||||
// finished with the display for now
|
||||
g_host_display->DoneCurrent();
|
||||
|
||||
// but we should get it back after this call
|
||||
onUpdateDisplayRequested(m_is_fullscreen, !m_is_fullscreen && m_is_rendering_to_main, m_is_surfaceless);
|
||||
if (!g_host_display->MakeCurrent())
|
||||
{
|
||||
pxFailRel("Failed to recreate context after updating");
|
||||
return;
|
||||
}
|
||||
return emit onAcquireRenderWindowRequested(recreate_window, window_fullscreen, render_to_main, m_is_surfaceless);
|
||||
}
|
||||
|
||||
bool EmuThread::acquireHostDisplay(RenderAPI api, bool clear_state_on_fail)
|
||||
void EmuThread::releaseRenderWindow()
|
||||
{
|
||||
pxAssertRel(!g_host_display, "Host display does not exist on create");
|
||||
m_is_rendering_to_main = shouldRenderToMain();
|
||||
m_is_surfaceless = false;
|
||||
|
||||
g_host_display = HostDisplay::CreateForAPI(api);
|
||||
if (!g_host_display)
|
||||
return false;
|
||||
|
||||
DisplayWidget* widget = emit onCreateDisplayRequested(m_is_fullscreen, m_is_rendering_to_main);
|
||||
if (!widget)
|
||||
{
|
||||
g_host_display.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
connectDisplaySignals(widget);
|
||||
|
||||
if (!g_host_display->MakeCurrent())
|
||||
{
|
||||
Console.Error("Failed to make render context current");
|
||||
releaseHostDisplay(clear_state_on_fail);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!g_host_display->SetupDevice() || !ImGuiManager::Initialize())
|
||||
{
|
||||
Console.Error("Failed to initialize device/imgui");
|
||||
releaseHostDisplay(clear_state_on_fail);
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLn(Color_StrongGreen, "%s Graphics Driver Info:", HostDisplay::RenderAPIToString(g_host_display->GetRenderAPI()));
|
||||
Console.Indent().WriteLn(g_host_display->GetDriverInfo());
|
||||
|
||||
if (m_run_fullscreen_ui && !ImGuiManager::InitializeFullscreenUI())
|
||||
{
|
||||
Console.Error("Failed to initialize fullscreen UI");
|
||||
releaseHostDisplay(clear_state_on_fail);
|
||||
m_run_fullscreen_ui = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
emit onReleaseRenderWindowRequested();
|
||||
}
|
||||
|
||||
void EmuThread::releaseHostDisplay(bool clear_state)
|
||||
std::optional<WindowInfo> Host::AcquireRenderWindow(bool recreate_window)
|
||||
{
|
||||
ImGuiManager::Shutdown(clear_state);
|
||||
|
||||
g_host_display.reset();
|
||||
emit onDestroyDisplayRequested();
|
||||
return g_emu_thread->acquireRenderWindow(recreate_window);
|
||||
}
|
||||
|
||||
bool Host::AcquireHostDisplay(RenderAPI api, bool clear_state_on_fail)
|
||||
void Host::ReleaseRenderWindow()
|
||||
{
|
||||
return g_emu_thread->acquireHostDisplay(api, clear_state_on_fail);
|
||||
return g_emu_thread->releaseRenderWindow();
|
||||
}
|
||||
|
||||
void Host::ReleaseHostDisplay(bool clear_state)
|
||||
void Host::BeginPresentFrame()
|
||||
{
|
||||
g_emu_thread->releaseHostDisplay(clear_state);
|
||||
}
|
||||
|
||||
HostDisplay::PresentResult Host::BeginPresentFrame(bool frame_skip)
|
||||
{
|
||||
const HostDisplay::PresentResult result = g_host_display->BeginPresent(frame_skip);
|
||||
if (result != HostDisplay::PresentResult::OK)
|
||||
{
|
||||
// if we're skipping a frame, we need to reset imgui's state, since
|
||||
// we won't be calling EndPresentFrame().
|
||||
ImGuiManager::SkipFrame();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Host::EndPresentFrame()
|
||||
{
|
||||
if (GSDumpReplayer::IsReplayingDump())
|
||||
GSDumpReplayer::RenderUI();
|
||||
|
||||
FullscreenUI::Render();
|
||||
ImGuiManager::RenderOSD();
|
||||
g_host_display->EndPresent();
|
||||
ImGuiManager::NewFrame();
|
||||
}
|
||||
|
||||
void Host::ResizeHostDisplay(u32 new_window_width, u32 new_window_height, float new_window_scale)
|
||||
{
|
||||
g_host_display->ResizeWindow(new_window_width, new_window_height, new_window_scale);
|
||||
ImGuiManager::WindowResized();
|
||||
}
|
||||
|
||||
void Host::RequestResizeHostDisplay(s32 width, s32 height)
|
||||
{
|
||||
g_emu_thread->onResizeDisplayRequested(width, height);
|
||||
}
|
||||
|
||||
void Host::UpdateHostDisplay()
|
||||
{
|
||||
g_emu_thread->updateDisplay();
|
||||
ImGuiManager::WindowResized();
|
||||
g_emu_thread->onResizeRenderWindowRequested(width, height);
|
||||
}
|
||||
|
||||
void Host::OnVMStarting()
|
||||
@@ -1273,7 +1188,7 @@ bool Host::IsFullscreen()
|
||||
|
||||
void Host::SetFullscreen(bool enabled)
|
||||
{
|
||||
g_emu_thread->setFullscreen(enabled);
|
||||
g_emu_thread->setFullscreen(enabled, true);
|
||||
}
|
||||
|
||||
alignas(16) static SysMtgsThread s_mtgs_thread;
|
||||
@@ -1329,7 +1244,7 @@ void Host::SetDefaultUISettings(SettingsInterface& si)
|
||||
si.SetBoolValue("UI", "RenderToSeparateWindow", false);
|
||||
si.SetBoolValue("UI", "HideMainWindowWhenRunning", false);
|
||||
si.SetBoolValue("UI", "DisableWindowResize", false);
|
||||
si.SetStringValue("UI", "Theme", MainWindow::DEFAULT_THEME_NAME);
|
||||
si.SetStringValue("UI", "Theme", QtHost::GetDefaultThemeName());
|
||||
}
|
||||
|
||||
void QtHost::SaveSettings()
|
||||
@@ -1876,7 +1791,7 @@ int main(int argc, char* argv[])
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
// Set theme before creating any windows.
|
||||
MainWindow::updateApplicationTheme();
|
||||
QtHost::UpdateApplicationTheme();
|
||||
MainWindow* main_window = new MainWindow();
|
||||
|
||||
// Start up the CPU thread.
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <optional>
|
||||
|
||||
#include "pcsx2/Host.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
#include "pcsx2/Frontend/InputManager.h"
|
||||
#include "pcsx2/VMManager.h"
|
||||
@@ -62,6 +61,7 @@ public:
|
||||
|
||||
__fi QEventLoop* getEventLoop() const { return m_event_loop; }
|
||||
__fi bool isFullscreen() const { return m_is_fullscreen; }
|
||||
__fi bool isExclusiveFullscreen() const { return m_is_exclusive_fullscreen; }
|
||||
__fi bool isRenderingToMain() const { return m_is_rendering_to_main; }
|
||||
__fi bool isSurfaceless() const { return m_is_surfaceless; }
|
||||
__fi bool isRunningFullscreenUI() const { return m_run_fullscreen_ui; }
|
||||
@@ -70,10 +70,9 @@ public:
|
||||
bool shouldRenderToMain() const;
|
||||
|
||||
/// Called back from the GS thread when the display state changes (e.g. fullscreen, render to main).
|
||||
bool acquireHostDisplay(RenderAPI api, bool clear_state_on_fail);
|
||||
std::optional<WindowInfo> acquireRenderWindow(bool recreate_window);
|
||||
void connectDisplaySignals(DisplayWidget* widget);
|
||||
void releaseHostDisplay(bool clear_state);
|
||||
void updateDisplay();
|
||||
void releaseRenderWindow();
|
||||
|
||||
void startBackgroundControllerPollTimer();
|
||||
void stopBackgroundControllerPollTimer();
|
||||
@@ -94,7 +93,7 @@ public Q_SLOTS:
|
||||
void saveState(const QString& filename);
|
||||
void saveStateToSlot(qint32 slot);
|
||||
void toggleFullscreen();
|
||||
void setFullscreen(bool fullscreen);
|
||||
void setFullscreen(bool fullscreen, bool allow_render_to_main);
|
||||
void setSurfaceless(bool surfaceless);
|
||||
void applySettings();
|
||||
void reloadGameSettings();
|
||||
@@ -118,10 +117,9 @@ public Q_SLOTS:
|
||||
Q_SIGNALS:
|
||||
bool messageConfirmed(const QString& title, const QString& message);
|
||||
|
||||
DisplayWidget* onCreateDisplayRequested(bool fullscreen, bool render_to_main);
|
||||
DisplayWidget* onUpdateDisplayRequested(bool fullscreen, bool render_to_main, bool surfaceless);
|
||||
void onResizeDisplayRequested(qint32 width, qint32 height);
|
||||
void onDestroyDisplayRequested();
|
||||
std::optional<WindowInfo> onAcquireRenderWindowRequested(bool recreate_window, bool fullscreen, bool render_to_main, bool surfaceless);
|
||||
void onResizeRenderWindowRequested(qint32 width, qint32 height);
|
||||
void onReleaseRenderWindowRequested();
|
||||
void onRelativeMouseModeRequested(bool enabled);
|
||||
|
||||
/// Called when the VM is starting initialization, but has not been completed yet.
|
||||
@@ -196,6 +194,7 @@ private:
|
||||
bool m_run_fullscreen_ui = false;
|
||||
bool m_is_rendering_to_main = false;
|
||||
bool m_is_fullscreen = false;
|
||||
bool m_is_exclusive_fullscreen = false;
|
||||
bool m_is_surfaceless = false;
|
||||
bool m_save_state_on_shutdown = false;
|
||||
bool m_pause_on_focus_loss = false;
|
||||
@@ -214,6 +213,12 @@ extern EmuThread* g_emu_thread;
|
||||
|
||||
namespace QtHost
|
||||
{
|
||||
/// Default theme name for the platform.
|
||||
const char* GetDefaultThemeName();
|
||||
|
||||
/// Sets application theme according to settings.
|
||||
void UpdateApplicationTheme();
|
||||
|
||||
/// Sets batch mode (exit after game shutdown).
|
||||
bool InBatchMode();
|
||||
|
||||
|
||||
@@ -114,12 +114,18 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
|
||||
dialog->registerWidgetHelp(m_ui.syncMode, tr("Synchronization"), tr("TimeStretch (Recommended)"),
|
||||
tr("When running outside of 100% speed, adjusts the tempo on audio instead of dropping frames. Produces much nicer fast-forward/slowdown audio."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.expansionMode, tr("Expansion"), tr("Stereo (None, Default)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.expansionMode, tr("Expansion"), tr("Stereo (None, Default)"),
|
||||
tr("Determines how the stereo output from the emulated system is upmixed into a greater number of the output speakers."));
|
||||
|
||||
//: Cubeb is an audio engine name. Leave as-is.
|
||||
dialog->registerWidgetHelp(m_ui.outputModule, tr("Output Module"), tr("Cubeb (Cross-platform)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.outputModule, tr("Output Module"), tr("Cubeb (Cross-platform)"),
|
||||
tr("Selects the library to be used for audio output."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.backend, tr("Output Backend"), tr("Default"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.backend, tr("Output Backend"), tr("Default"),
|
||||
tr("When the sound output module supports multiple audio backends, determines the API to be used for audio output to the system."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.outputDevice, tr("Output Device"), tr("Default"),
|
||||
tr("Determines which audio device to output the sound to."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.targetLatency, tr("Target Latency"), tr("60 ms"),
|
||||
tr("Determines the buffer size which the time stretcher will try to keep filled. It effectively selects the average latency, as "
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset Defaults</string>
|
||||
<string>Restore Defaults</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -37,13 +37,19 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||
#ifdef SDL_BUILD
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLRawInput, "InputSources", "SDLRawInput", false);
|
||||
connect(m_ui.enableSDLSource, &QCheckBox::stateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
|
||||
connect(m_ui.ledSettings, &QToolButton::clicked, this, &ControllerGlobalSettingsWidget::ledSettingsClicked);
|
||||
#else
|
||||
m_ui.enableSDLSource->setEnabled(false);
|
||||
m_ui.ledSettings->setEnabled(false);
|
||||
m_ui.enableSDLRawInput->setEnabled(false);
|
||||
#endif
|
||||
|
||||
#if defined(SDL_BUILD) && defined(_WIN32)
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLRawInput, "InputSources", "SDLRawInput", false);
|
||||
#else
|
||||
m_ui.gridLayout_2->removeWidget(m_ui.enableSDLRawInput);
|
||||
m_ui.enableSDLRawInput->deleteLater();
|
||||
m_ui.enableSDLRawInput = nullptr;
|
||||
#endif
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableMouseMapping, "UI", "EnableMouseMapping", false);
|
||||
@@ -115,7 +121,9 @@ void ControllerGlobalSettingsWidget::updateSDLOptionsEnabled()
|
||||
const bool enabled = m_ui.enableSDLSource->isChecked();
|
||||
m_ui.enableSDLEnhancedMode->setEnabled(enabled);
|
||||
m_ui.ledSettings->setEnabled(enabled);
|
||||
#ifdef _WIN32
|
||||
m_ui.enableSDLRawInput->setEnabled(enabled);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ControllerGlobalSettingsWidget::ledSettingsClicked()
|
||||
|
||||
@@ -111,7 +111,7 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
//: P-Core = Performance Core, E-Core = Efficiency Core. See if Intel has official translations for these terms.
|
||||
"May help CPUs with big (P) and little (E) cores (e.g. Intel 12th or newer generation CPUs from Intel or other vendors such as AMD)."));
|
||||
dialog->registerWidgetHelp(m_ui.MTVU, tr("Enable Multithreaded VU1 (MTVU1)"), tr("Checked"),
|
||||
tr("Generally a speedup on CPUs with 3 or more threads. "
|
||||
tr("Generally a speedup on CPUs with 4 or more cores. "
|
||||
"Safe for most games, but a few are incompatible and may hang."));
|
||||
dialog->registerWidgetHelp(m_ui.instantVU1, tr("Enable Instant VU1"), tr("Checked"),
|
||||
tr("Runs VU1 instantly. Provides a modest speed improvement in most games. "
|
||||
|
||||
@@ -26,18 +26,6 @@
|
||||
#include "pcsx2/GS/GSCapture.h"
|
||||
#include "pcsx2/GS/GSUtil.h"
|
||||
|
||||
#ifdef ENABLE_VULKAN
|
||||
#include "Frontend/VulkanHostDisplay.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Frontend/D3D11HostDisplay.h"
|
||||
#include "Frontend/D3D12HostDisplay.h"
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#include "GS/Renderers/Metal/GSMetalCPPAccessible.h"
|
||||
#endif
|
||||
|
||||
struct RendererInfo
|
||||
{
|
||||
const char* name;
|
||||
@@ -193,7 +181,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// HW Renderer Fixes
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.halfScreenFix, "EmuCore/GS", "UserHacks_Half_Bottom_Override", -1, -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuSpriteRenderBW, "EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuSpriteRenderLevel, "EmuCore/GS", "UserHacks_CPUSpriteRenderLevel", 0);
|
||||
@@ -201,7 +190,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gpuTargetCLUTMode, "EmuCore/GS", "UserHacks_GPUTargetCLUTMode", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawStart, "EmuCore/GS", "UserHacks_SkipDraw_Start", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawEnd, "EmuCore/GS", "UserHacks_SkipDraw_End", 0);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hwAutoFlush, "EmuCore/GS", "UserHacks_AutoFlush", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.hwAutoFlush, "EmuCore/GS", "UserHacks_AutoFlushLevel", 0);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.frameBufferConversion, "EmuCore/GS", "UserHacks_CPU_FB_Conversion", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDepthEmulation, "EmuCore/GS", "UserHacks_DisableDepthSupport", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableSafeFeatures, "EmuCore/GS", "UserHacks_Disable_Safe_Features", false);
|
||||
@@ -211,13 +200,14 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.textureInsideRt, "EmuCore/GS", "UserHacks_TextureInsideRt", static_cast<int>(GSTextureInRtMode::Disabled));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.readTCOnClose, "EmuCore/GS", "UserHacks_ReadTCOnClose", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.targetPartialInvalidation, "EmuCore/GS", "UserHacks_TargetPartialInvalidation", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.targetPartialInvalidation, "EmuCore/GS", "UserHacks_TargetPartialInvalidation", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.estimateTextureRegion, "EmuCore/GS", "UserHacks_EstimateTextureRegion", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
|
||||
connect(m_ui.cpuSpriteRenderBW, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&GraphicsSettingsWidget::onCPUSpriteRenderBWChanged);
|
||||
connect(m_ui.textureInsideRt, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&GraphicsSettingsWidget::onTextureInsideRtChanged);
|
||||
connect(
|
||||
m_ui.textureInsideRt, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onTextureInsideRtChanged);
|
||||
connect(m_ui.gpuPaletteConversion, QOverload<int>::of(&QCheckBox::stateChanged), this,
|
||||
&GraphicsSettingsWidget::onGpuPaletteConversionChanged);
|
||||
onCPUSpriteRenderBWChanged();
|
||||
@@ -256,8 +246,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useDebugDevice, "EmuCore/GS", "UseDebugDevice", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.skipPresentingDuplicateFrames, "EmuCore/GS", "SkipDuplicateFrames", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.threadedPresentation, "EmuCore/GS", "DisableThreadedPresentation", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.exclusiveFullscreenControl, "EmuCore/GS", "ExclusiveFullscreenControl", -1, -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.overrideTextureBarriers, "EmuCore/GS", "OverrideTextureBarriers", -1, -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.overrideGeometryShader, "EmuCore/GS", "OverrideGeometryShaders", -1, -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.gsDumpCompression, "EmuCore/GS", "GSDumpCompression", static_cast<int>(GSDumpCompressionMethod::Zstandard));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableFramebufferFetch, "EmuCore/GS", "DisableFramebufferFetch", false);
|
||||
@@ -308,6 +298,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
connect(m_ui.swTextureFiltering, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onSWTextureFilteringChange);
|
||||
updateRendererDependentOptions();
|
||||
|
||||
#ifndef _WIN32
|
||||
// Exclusive fullscreen control is Windows-only.
|
||||
m_ui.advancedOptionsFormLayout->removeRow(2);
|
||||
m_ui.exclusiveFullscreenControl = nullptr;
|
||||
#endif
|
||||
|
||||
#ifndef PCSX2_DEVBUILD
|
||||
if (!m_dialog->isPerGameSettings())
|
||||
{
|
||||
@@ -397,8 +393,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.PCRTCOverscan, tr("Show Overscan"), tr("Unchecked"),
|
||||
tr("Enables the option to show the overscan area on games which draw more than the safe area of the screen."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.fmvAspectRatio, tr("FMV Aspect Ratio"), tr("Off (Default)"),
|
||||
tr("Overrides the full-motion video (FMV) aspect ratio."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.fmvAspectRatio, tr("FMV Aspect Ratio"), tr("Off (Default)"), tr("Overrides the full-motion video (FMV) aspect ratio."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.PCRTCAntiBlur, tr("Anti-Blur"), tr("Checked"),
|
||||
tr("Enables internal Anti-Blur hacks. Less accurate to PS2 rendering but will make a lot of games look less blurry."));
|
||||
@@ -435,17 +431,17 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.fullscreenModes, tr("Fullscreen Mode"), tr("Borderless Fullscreen"),
|
||||
tr("Chooses the fullscreen resolution and frequency."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.cropLeft, tr("Left"), tr("0px"),
|
||||
tr("Changes the number of pixels cropped from the left side of the display."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.cropLeft, tr("Left"), tr("0px"), tr("Changes the number of pixels cropped from the left side of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.cropTop, tr("Top"), tr("0px"),
|
||||
tr("Changes the number of pixels cropped from the top of the display."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.cropTop, tr("Top"), tr("0px"), tr("Changes the number of pixels cropped from the top of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.cropRight, tr("Right"), tr("0px"),
|
||||
tr("Changes the number of pixels cropped from the right side of the display."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.cropRight, tr("Right"), tr("0px"), tr("Changes the number of pixels cropped from the right side of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.cropBottom, tr("Bottom"), tr("0px"),
|
||||
tr("Changes the number of pixels cropped from the bottom of the display."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.cropBottom, tr("Bottom"), tr("0px"), tr("Changes the number of pixels cropped from the bottom of the display."));
|
||||
}
|
||||
|
||||
// Rendering tab
|
||||
@@ -652,8 +648,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
// OSD tab
|
||||
{
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.osdScale, tr("OSD Scale"), tr("100%"), tr("Scales the size of the onscreen OSD from 50% to 500%."));
|
||||
dialog->registerWidgetHelp(m_ui.osdScale, tr("OSD Scale"), tr("100%"), tr("Scales the size of the onscreen OSD from 50% to 500%."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowMessages, tr("Show OSD Messages"), tr("Checked"),
|
||||
tr("Shows on-screen-display messages when events occur such as save states being "
|
||||
@@ -675,7 +670,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.osdShowGSStats, tr("Show Statistics"), tr("Unchecked"),
|
||||
tr("Shows counters for internal graphical utilization, useful for debugging."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowIndicators, tr("Show Indicators"), tr("Unchecked"),
|
||||
dialog->registerWidgetHelp(m_ui.osdShowIndicators, tr("Show Indicators"), tr("Checked"),
|
||||
tr("Shows OSD icon indicators for emulation states such as Pausing, Turbo, Fast-Forward, and Slow-Motion."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowSettings, tr("Show Settings"), tr("Unchecked"),
|
||||
@@ -705,10 +700,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
{
|
||||
dialog->registerWidgetHelp(m_ui.overrideTextureBarriers, tr("Override Texture Barriers"), tr("Automatic (Default)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.overrideGeometryShader, tr("Override Geometry Shader"), tr("Automatic (Default)"),
|
||||
tr("Allows the GPU instead of just the CPU to transform lines into sprites. "
|
||||
"This reduces CPU load and bandwidth requirement, but it is heavier on the GPU."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.gsDumpCompression, tr("GS Dump Compression"), tr("Zstandard (zst)"),
|
||||
tr("Change the compression algorithm used when creating a GS dump."));
|
||||
|
||||
@@ -719,6 +710,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
"renderer. This usually results in slower performance, but may be required for some "
|
||||
"streaming applications, or to uncap framerates on some systems."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.exclusiveFullscreenControl, tr("Allow Exclusive Fullscreen"), tr("Automatic (Default)"),
|
||||
tr("Overrides the driver's heuristics for enabling exclusive fullscreen, or direct flip/scanout.<br>"
|
||||
"Disallowing exclusive fullscreen may enable smoother task switching and overlays, but increase input latency."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.useDebugDevice, tr("Use Debug Device"), tr("Unchecked"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.disableDualSource, tr("Disable Dual Source Blending"), tr("Unchecked"), tr(""));
|
||||
@@ -727,10 +722,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.skipPresentingDuplicateFrames, tr("Skip Presenting Duplicate Frames"), tr("Unchecked"),
|
||||
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still "
|
||||
"rendered, it just means "
|
||||
"the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time fluctuations when the CPU/GPU "
|
||||
"are near maximum "
|
||||
"utilization, but makes frame pacing more inconsistent and can increase input lag."));
|
||||
"rendered, it just means the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time "
|
||||
"fluctuations when the CPU/GPU are near maximum utilization, but makes frame pacing more inconsistent and can increase "
|
||||
"input lag."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.threadedPresentation, tr("Disable Threaded Presentation"), tr("Unchecked"),
|
||||
tr("Presents frames on the main GS thread instead of a worker thread. Used for debugging frametime issues. "
|
||||
@@ -928,6 +922,8 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::DX12 || type == GSRendererType::OGL ||
|
||||
type == GSRendererType::VK || type == GSRendererType::Metal);
|
||||
const bool is_software = (type == GSRendererType::SW);
|
||||
const bool is_auto = (type == GSRendererType::Auto);
|
||||
const bool is_vk = (type == GSRendererType::VK);
|
||||
const bool hw_fixes = (is_hardware && m_ui.enableHWFixes && m_ui.enableHWFixes->checkState() == Qt::Checked);
|
||||
const int prev_tab = m_ui.tabs->currentIndex();
|
||||
|
||||
@@ -960,42 +956,16 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
m_ui.useBlitSwapChain->setEnabled(is_dx11);
|
||||
|
||||
m_ui.overrideTextureBarriers->setDisabled(is_sw_dx);
|
||||
m_ui.overrideGeometryShader->setDisabled(is_sw_dx);
|
||||
|
||||
m_ui.disableFramebufferFetch->setDisabled(is_sw_dx);
|
||||
|
||||
if (m_ui.exclusiveFullscreenControl)
|
||||
m_ui.exclusiveFullscreenControl->setEnabled(is_auto || is_vk);
|
||||
|
||||
// populate adapters
|
||||
HostDisplay::AdapterAndModeList modes;
|
||||
switch (type)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
case GSRendererType::DX11:
|
||||
modes = D3D11HostDisplay::StaticGetAdapterAndModeList();
|
||||
break;
|
||||
case GSRendererType::DX12:
|
||||
modes = D3D12HostDisplay::StaticGetAdapterAndModeList();
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_VULKAN
|
||||
case GSRendererType::VK:
|
||||
modes = VulkanHostDisplay::StaticGetAdapterAndModeList(nullptr);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
case GSRendererType::Metal:
|
||||
modes = GetMetalAdapterAndModeList();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case GSRendererType::OGL:
|
||||
case GSRendererType::SW:
|
||||
case GSRendererType::Null:
|
||||
case GSRendererType::Auto:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
std::vector<std::string> adapters;
|
||||
std::vector<std::string> fullscreen_modes;
|
||||
GSGetAdaptersAndFullscreenModes(type, &adapters, &fullscreen_modes);
|
||||
|
||||
// fill+select adapters
|
||||
{
|
||||
@@ -1003,7 +973,7 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
|
||||
std::string current_adapter = Host::GetBaseStringSettingValue("EmuCore/GS", "Adapter", "");
|
||||
m_ui.adapter->clear();
|
||||
m_ui.adapter->setEnabled(!modes.adapter_names.empty());
|
||||
m_ui.adapter->setEnabled(!adapters.empty());
|
||||
m_ui.adapter->addItem(tr("(Default)"));
|
||||
m_ui.adapter->setCurrentIndex(0);
|
||||
|
||||
@@ -1019,7 +989,7 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::string& adapter : modes.adapter_names)
|
||||
for (const std::string& adapter : adapters)
|
||||
{
|
||||
m_ui.adapter->addItem(QString::fromStdString(adapter));
|
||||
if (current_adapter == adapter)
|
||||
@@ -1047,7 +1017,7 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::string& fs_mode : modes.fullscreen_modes)
|
||||
for (const std::string& fs_mode : fullscreen_modes)
|
||||
{
|
||||
m_ui.fullscreenModes->addItem(QString::fromStdString(fs_mode));
|
||||
if (current_mode == fs_mode)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>720</width>
|
||||
<height>476</height>
|
||||
<height>498</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -780,222 +780,6 @@
|
||||
<string>Hardware Fixes</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="hardwareFixesLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Half Screen Fix:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="halfScreenFix">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Automatic (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Force Disabled</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Force Enabled</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_36">
|
||||
<property name="text">
|
||||
<string>CPU Sprite Render Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Software CLUT Render:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="cpuCLUTRender">
|
||||
<property name="currentText">
|
||||
<string extracomment="0 (Disabled)">0 (Disabled)</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>0 (Disabled)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1 (Normal)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2 (Aggressive)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_47">
|
||||
<property name="text">
|
||||
<string extracomment="CLUT: Color Look Up Table, often referred to as a palette in non-PS2 things. GPU Target CLUT: GPU handling of when a game uses data from a render target as a CLUT.">GPU Target CLUT:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="gpuTargetCLUTMode">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enabled (Exact Match)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enabled (Check Inside Target)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_45">
|
||||
<property name="text">
|
||||
<string>Texture Inside RT:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="textureInsideRt">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Inside Target</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Merge Targets</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Skipdraw Range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawStart">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawEnd">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="hwAutoFlush">
|
||||
<property name="text">
|
||||
<string>Auto Flush</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="disableSafeFeatures">
|
||||
<property name="text">
|
||||
<string>Disable Safe Features</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="disableDepthEmulation">
|
||||
<property name="text">
|
||||
<string>Disable Depth Emulation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="frameBufferConversion">
|
||||
<property name="text">
|
||||
<string>Frame Buffer Conversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="readTCOnClose">
|
||||
<property name="text">
|
||||
<string>Read Targets When Closing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="disablePartialInvalidation">
|
||||
<property name="text">
|
||||
<string>Disable Partial Source Invalidation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="targetPartialInvalidation">
|
||||
<property name="text">
|
||||
<string>Target Partial Invalidation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="preloadFrameData">
|
||||
<property name="text">
|
||||
<string>Preload Frame Data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="estimateTextureRegion">
|
||||
<property name="text">
|
||||
<string>Estimate Texture Region</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="gpuPaletteConversion">
|
||||
<property name="text">
|
||||
<string>GPU Palette Conversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
@@ -1037,6 +821,39 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Half Screen Fix:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="halfScreenFix">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Automatic (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Force Disabled</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Force Enabled</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_36">
|
||||
<property name="text">
|
||||
<string>CPU Sprite Render Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0">
|
||||
<item>
|
||||
@@ -1119,6 +936,208 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Software CLUT Render:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="cpuCLUTRender">
|
||||
<property name="currentText">
|
||||
<string extracomment="0 (Disabled)">0 (Disabled)</string>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>0 (Disabled)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1 (Normal)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2 (Aggressive)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_47">
|
||||
<property name="text">
|
||||
<string extracomment="CLUT: Color Look Up Table, often referred to as a palette in non-PS2 things. GPU Target CLUT: GPU handling of when a game uses data from a render target as a CLUT.">GPU Target CLUT:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="gpuTargetCLUTMode">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enabled (Exact Match)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enabled (Check Inside Target)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_45">
|
||||
<property name="text">
|
||||
<string>Texture Inside RT:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="textureInsideRt">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Inside Target</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Merge Targets</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_30">
|
||||
<property name="text">
|
||||
<string>Auto Flush:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="hwAutoFlush">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enabled (Sprites Only)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enabled (All Primitives)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Skipdraw Range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawStart">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawEnd">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="8" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="disableDepthEmulation">
|
||||
<property name="text">
|
||||
<string>Disable Depth Emulation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="disablePartialInvalidation">
|
||||
<property name="text">
|
||||
<string>Disable Partial Source Invalidation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="disableSafeFeatures">
|
||||
<property name="text">
|
||||
<string>Disable Safe Features</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="estimateTextureRegion">
|
||||
<property name="text">
|
||||
<string>Estimate Texture Region</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="frameBufferConversion">
|
||||
<property name="text">
|
||||
<string>Frame Buffer Conversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="gpuPaletteConversion">
|
||||
<property name="text">
|
||||
<string>GPU Palette Conversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="preloadFrameData">
|
||||
<property name="text">
|
||||
<string>Preload Frame Data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="readTCOnClose">
|
||||
<property name="text">
|
||||
<string>Read Targets When Closing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="targetPartialInvalidation">
|
||||
<property name="text">
|
||||
<string>Target Partial Invalidation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="upscalingFixesTab">
|
||||
@@ -1232,33 +1251,33 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="wildHack">
|
||||
<property name="text">
|
||||
<string extracomment="Wild Arms: name of a game series. Leave as-is or use an official translation.">Wild Arms Hack</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="bilinearHack">
|
||||
<property name="text">
|
||||
<string>Bilinear Dirty Upscale</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="mergeSprite">
|
||||
<property name="text">
|
||||
<string>Merge Sprite</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="nativePaletteDraw">
|
||||
<property name="text">
|
||||
<string>Unscaled Palette Texture Draws</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="wildHack">
|
||||
<property name="text">
|
||||
<string extracomment="Wild Arms: name of a game series. Leave as-is or use an official translation.">Wild Arms Hack</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -2098,6 +2117,32 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_48">
|
||||
<property name="text">
|
||||
<string>Allow Exclusive Fullscreen:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="exclusiveFullscreenControl">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Automatic (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disallowed</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Allowed</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -2133,33 +2178,7 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_30">
|
||||
<property name="text">
|
||||
<string>Override Geometry Shader:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="overrideGeometryShader">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Automatic (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Force Disabled</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Force Enabled</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<item row="2" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_7">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="useDebugDevice">
|
||||
|
||||
@@ -20,11 +20,12 @@
|
||||
#include "MainWindow.h"
|
||||
#include "SettingWidgetBinder.h"
|
||||
#include "SettingsDialog.h"
|
||||
#include "QtHost.h"
|
||||
|
||||
static const char* THEME_NAMES[] = {
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Native"),
|
||||
//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated.
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Fusion [Light]"),
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Fusion [Light/Dark]"),
|
||||
//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated.
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Dark Fusion (Gray) [Dark]"),
|
||||
//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated.
|
||||
@@ -91,7 +92,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
connect(m_ui.renderToSeparateWindow, &QCheckBox::stateChanged, this, &InterfaceSettingsWidget::onRenderToSeparateWindowChanged);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.theme, "UI", "Theme", THEME_NAMES, THEME_VALUES,
|
||||
MainWindow::DEFAULT_THEME_NAME);
|
||||
QtHost::GetDefaultThemeName());
|
||||
connect(m_ui.theme, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() { emit themeChanged(); });
|
||||
|
||||
// Per-game settings is special, we don't want to bind it if we're editing per-game settings.
|
||||
@@ -173,8 +174,12 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.discordPresence, tr("Enable Discord Presence"), tr("Unchecked"),
|
||||
tr("Shows the game you are currently playing as part of your profile in Discord."));
|
||||
dialog->registerWidgetHelp(m_ui.doubleClickTogglesFullscreen, tr("Double-Click Toggles Fullscreen"), tr("Checked"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.disableWindowResizing, tr("Disable Window Resizing"), tr("Unchecked"), tr(""));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.doubleClickTogglesFullscreen, tr("Double-Click Toggles Fullscreen"), tr("Checked"),
|
||||
tr("Allows switching in and out of fullscreen mode by double-clicking the game window."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.disableWindowResizing, tr("Disable Window Resizing"), tr("Unchecked"),
|
||||
tr("Prevents the main window from being resized."));
|
||||
|
||||
// Not yet used, disable the options
|
||||
m_ui.language->setDisabled(true);
|
||||
|
||||
@@ -0,0 +1,495 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "QtHost.h"
|
||||
|
||||
#include "pcsx2/Config.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
|
||||
#include "common/Path.h"
|
||||
|
||||
#include <QtGui/QPalette>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QStyle>
|
||||
#include <QtWidgets/QStyleFactory>
|
||||
|
||||
namespace QtHost
|
||||
{
|
||||
static void SetStyleFromSettings();
|
||||
static void SetIconThemeFromStyle();
|
||||
} // namespace QtHost
|
||||
|
||||
static QString s_unthemed_style_name;
|
||||
static bool s_unthemed_style_name_set;
|
||||
|
||||
const char* QtHost::GetDefaultThemeName()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
return "";
|
||||
#else
|
||||
return "darkfusion";
|
||||
#endif
|
||||
}
|
||||
|
||||
void QtHost::UpdateApplicationTheme()
|
||||
{
|
||||
if (!s_unthemed_style_name_set)
|
||||
{
|
||||
s_unthemed_style_name_set = true;
|
||||
s_unthemed_style_name = QApplication::style()->objectName();
|
||||
}
|
||||
|
||||
SetStyleFromSettings();
|
||||
SetIconThemeFromStyle();
|
||||
}
|
||||
|
||||
void QtHost::SetStyleFromSettings()
|
||||
{
|
||||
const std::string theme(Host::GetBaseStringSettingValue("UI", "Theme", GetDefaultThemeName()));
|
||||
|
||||
if (theme == "fusion")
|
||||
{
|
||||
// setPalette() shouldn't be necessary, as the documentation claims that setStyle() resets the palette, but it
|
||||
// is here, to work around a bug in 6.4.x and 6.5.x where the palette doesn't restore after changing themes.
|
||||
qApp->setPalette(QPalette());
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
else if (theme == "darkfusion")
|
||||
{
|
||||
// adapted from https://gist.github.com/QuantumCD/6245215
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor lighterGray(75, 75, 75);
|
||||
const QColor darkGray(53, 53, 53);
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor blue(198, 238, 255);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkGray);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, black);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, blue);
|
||||
darkPalette.setColor(QPalette::Highlight, lighterGray);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "darkfusionblue")
|
||||
{
|
||||
// adapted from https://gist.github.com/QuantumCD/6245215
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor darkGray(53, 53, 53);
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor blue(198, 238, 255);
|
||||
const QColor blue2(0, 88, 208);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkGray);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, black);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkGray);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, blue2);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, blue);
|
||||
darkPalette.setColor(QPalette::Highlight, blue2);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "UntouchedLagoon")
|
||||
{
|
||||
// Custom palette by RedDevilus, Tame (Light/Washed out) Green as main color and Grayish Blue as complimentary.
|
||||
// Alternative white theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor darkteal(0, 77, 77);
|
||||
const QColor teal(0, 128, 128);
|
||||
const QColor tameTeal(160, 190, 185);
|
||||
const QColor grayBlue(160, 180, 190);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, tameTeal);
|
||||
standardPalette.setColor(QPalette::WindowText, black.lighter());
|
||||
standardPalette.setColor(QPalette::Base, grayBlue);
|
||||
standardPalette.setColor(QPalette::AlternateBase, tameTeal);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, tameTeal);
|
||||
standardPalette.setColor(QPalette::ToolTipText, grayBlue);
|
||||
standardPalette.setColor(QPalette::Text, black);
|
||||
standardPalette.setColor(QPalette::Button, tameTeal);
|
||||
standardPalette.setColor(QPalette::ButtonText, black);
|
||||
standardPalette.setColor(QPalette::Link, black.lighter());
|
||||
standardPalette.setColor(QPalette::Highlight, teal);
|
||||
standardPalette.setColor(QPalette::HighlightedText, grayBlue.lighter());
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, tameTeal);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkteal);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkteal.lighter());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkteal.lighter());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, tameTeal);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "BabyPastel")
|
||||
{
|
||||
// Custom palette by RedDevilus, Blue as main color and blue as complimentary.
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(150, 150, 150);
|
||||
const QColor black(25, 25, 25);
|
||||
const QColor redpinkish(200, 75, 132);
|
||||
const QColor pink(255, 174, 201);
|
||||
const QColor brightPink(255, 230, 255);
|
||||
const QColor congoPink(255, 127, 121);
|
||||
const QColor blue(221, 225, 239);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, pink);
|
||||
standardPalette.setColor(QPalette::WindowText, black);
|
||||
standardPalette.setColor(QPalette::Base, brightPink);
|
||||
standardPalette.setColor(QPalette::AlternateBase, blue);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, pink);
|
||||
standardPalette.setColor(QPalette::ToolTipText, brightPink);
|
||||
standardPalette.setColor(QPalette::Text, black);
|
||||
standardPalette.setColor(QPalette::Button, pink);
|
||||
standardPalette.setColor(QPalette::ButtonText, black);
|
||||
standardPalette.setColor(QPalette::Link, black);
|
||||
standardPalette.setColor(QPalette::Highlight, congoPink);
|
||||
standardPalette.setColor(QPalette::HighlightedText, black);
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, pink);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, redpinkish);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "PizzaBrown")
|
||||
{
|
||||
// Custom palette by KamFretoZ, a Pizza Tower Reference!
|
||||
// With a mixtures of Light Brown, Peachy/Creamy White, Latte-like Color.
|
||||
// Thanks to Jordan for the idea :P
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor extr(248, 192, 88);
|
||||
const QColor main(233, 187, 147);
|
||||
const QColor comp(248, 230, 213);
|
||||
const QColor highlight(188, 100, 60);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, main);
|
||||
standardPalette.setColor(QPalette::WindowText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Base, comp);
|
||||
standardPalette.setColor(QPalette::AlternateBase, extr);
|
||||
standardPalette.setColor(QPalette::ToolTipBase, comp);
|
||||
standardPalette.setColor(QPalette::ToolTipText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Text, Qt::black);
|
||||
standardPalette.setColor(QPalette::Button, extr);
|
||||
standardPalette.setColor(QPalette::ButtonText, Qt::black);
|
||||
standardPalette.setColor(QPalette::Link, Qt::black);
|
||||
standardPalette.setColor(QPalette::Highlight, highlight);
|
||||
standardPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, extr);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.darker());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.darker());
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, Qt::gray);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray.lighter());
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #cc3f18; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "PCSX2Blue")
|
||||
{
|
||||
// Custom palette by RedDevilus, White as main color and Blue as complimentary.
|
||||
// Alternative light theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor blackish(35, 35, 35);
|
||||
const QColor darkBlue(73, 97, 177);
|
||||
const QColor blue2(80, 120, 200);
|
||||
const QColor blue(106, 156, 255);
|
||||
const QColor lightBlue(130, 155, 241);
|
||||
|
||||
QPalette standardPalette;
|
||||
standardPalette.setColor(QPalette::Window, blue2.lighter());
|
||||
standardPalette.setColor(QPalette::WindowText, blackish);
|
||||
standardPalette.setColor(QPalette::Base, lightBlue);
|
||||
standardPalette.setColor(QPalette::AlternateBase, blue2.lighter());
|
||||
standardPalette.setColor(QPalette::ToolTipBase, blue2);
|
||||
standardPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
standardPalette.setColor(QPalette::Text, blackish);
|
||||
standardPalette.setColor(QPalette::Button, blue);
|
||||
standardPalette.setColor(QPalette::ButtonText, blackish);
|
||||
standardPalette.setColor(QPalette::Link, darkBlue);
|
||||
standardPalette.setColor(QPalette::Highlight, Qt::white);
|
||||
standardPalette.setColor(QPalette::HighlightedText, blackish);
|
||||
|
||||
standardPalette.setColor(QPalette::Active, QPalette::Button, blue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkBlue);
|
||||
standardPalette.setColor(QPalette::Disabled, QPalette::Light, darkBlue);
|
||||
|
||||
qApp->setPalette(standardPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "ScarletDevilRed")
|
||||
{
|
||||
// Custom palette by RedDevilus, Red as main color and Purple as complimentary.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor darkRed(80, 45, 69);
|
||||
const QColor purplishRed(120, 45, 69);
|
||||
const QColor brightRed(200, 45, 69);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, darkRed);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, purplishRed);
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkRed);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkRed);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, purplishRed.darker());
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, brightRed);
|
||||
darkPalette.setColor(QPalette::Highlight, brightRed);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, purplishRed.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, brightRed);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkRed);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "CobaltSky")
|
||||
{
|
||||
// Custom palette by KamFretoZ, A soothing deep royal blue
|
||||
// that are meant to be easy on the eyes as the main color.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(150, 150, 150);
|
||||
const QColor royalBlue(29, 41, 81);
|
||||
const QColor darkishBlue(17, 30, 108);
|
||||
const QColor highlight(36, 93, 218);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, royalBlue);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, royalBlue.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, highlight);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkishBlue);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "VioletAngelPurple")
|
||||
{
|
||||
// Custom palette by RedDevilus, Blue as main color and Purple as complimentary.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor blackishblue(50, 25, 70);
|
||||
const QColor darkerPurple(90, 30, 105);
|
||||
const QColor nauticalPurple(110, 30, 125);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, blackishblue);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, nauticalPurple);
|
||||
darkPalette.setColor(QPalette::AlternateBase, blackishblue);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, nauticalPurple);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, nauticalPurple.darker());
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Highlight, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, nauticalPurple.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkerPurple.lighter());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, darkerPurple.darker());
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, nauticalPurple);
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Ruby")
|
||||
{
|
||||
// Custom palette by Daisouji, Black as main color and Red as complimentary.
|
||||
// Alternative dark (black) theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor slate(18, 18, 18);
|
||||
const QColor rubyish(172, 21, 31);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, slate);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, slate.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
|
||||
darkPalette.setColor(QPalette::ToolTipBase, slate);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, rubyish);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Sapphire")
|
||||
{
|
||||
// Custom palette by RedDevilus, Black as main color and Blue as complimentary.
|
||||
// Alternative dark (black) theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(128, 128, 128);
|
||||
const QColor slate(18, 18, 18);
|
||||
const QColor persianBlue(32, 35, 204);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, slate);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, slate.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
|
||||
darkPalette.setColor(QPalette::ToolTipBase, slate);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, persianBlue);
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "Custom")
|
||||
{
|
||||
//Additional Theme option than loads .qss from main PCSX2 Directory
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
QString sheet_content;
|
||||
QFile sheets(QString::fromStdString(Path::Combine(EmuFolders::DataRoot, "custom.qss")));
|
||||
|
||||
if (sheets.open(QFile::ReadOnly))
|
||||
{
|
||||
QString sheet_content = QString::fromUtf8(sheets.readAll().data());
|
||||
qApp->setStyleSheet(sheet_content);
|
||||
}
|
||||
else
|
||||
{
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// setPalette() shouldn't be necessary, as the documentation claims that setStyle() resets the palette, but it
|
||||
// is here, to work around a bug in 6.4.x and 6.5.x where the palette doesn't restore after changing themes.
|
||||
qApp->setPalette(QPalette());
|
||||
qApp->setStyle(s_unthemed_style_name);
|
||||
qApp->setStyleSheet(QString());
|
||||
}
|
||||
}
|
||||
|
||||
void QtHost::SetIconThemeFromStyle()
|
||||
{
|
||||
QPalette palette = qApp->palette();
|
||||
bool dark = palette.windowText().color().value() > palette.window().color().value();
|
||||
QIcon::setThemeName(dark ? QStringLiteral("white") : QStringLiteral("black"));
|
||||
}
|
||||
@@ -692,7 +692,7 @@ Login token generated on %2.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AudioSettingsWidget.ui" line="179"/>
|
||||
<source>Reset Defaults</source>
|
||||
<source>Restore Defaults</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
|
||||
@@ -144,6 +144,7 @@
|
||||
<ClCompile Include="Settings\DebugSettingsWidget.cpp" />
|
||||
<ClCompile Include="Settings\FolderSettingsWidget.cpp" />
|
||||
<ClCompile Include="Settings\MemoryCardConvertWorker.cpp" />
|
||||
<ClCompile Include="Themes.cpp" />
|
||||
<ClCompile Include="Tools\InputRecording\InputRecordingViewer.cpp" />
|
||||
<ClCompile Include="Tools\InputRecording\NewInputRecordingDlg.cpp" />
|
||||
<ClCompile Include="Debugger\CpuWidget.cpp" />
|
||||
|
||||
@@ -315,6 +315,7 @@
|
||||
<ClCompile Include="$(IntDir)moc_ColorPickerButton.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Themes.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
|
||||
|
||||
@@ -5,7 +5,7 @@ IFS="
|
||||
|
||||
printf "<RCC>\n"
|
||||
printf "\t<qresource>\n"
|
||||
for i in $(find . -not -iname '*.sh' -not -iname '*.qrc' -type f | cut -d'/' -f2-99); do
|
||||
for i in $(find . -not -iname '.*' -not -iname '*.sh' -not -iname '*.qrc' -type f | cut -d'/' -f2-99 | sort -f); do
|
||||
printf "\t\t<file>%s</file>\n" "$i"
|
||||
done
|
||||
printf "\t</qresource>\n"
|
||||
|
||||
|
After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 700 B |
|
After Width: | Height: | Size: 1.2 KiB |
@@ -2,6 +2,10 @@
|
||||
Name=Black Icon Theme
|
||||
Comment=Black Icon Theme
|
||||
|
||||
[32]
|
||||
Size=32
|
||||
Type=Fixed
|
||||
|
||||
[svg]
|
||||
Size=64
|
||||
Type=Scalable
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-at" viewBox="0 0 16 16"> <path d="M13.106 7.222c0-2.967-2.249-5.032-5.482-5.032-3.35 0-5.646 2.318-5.646 5.702 0 3.493 2.235 5.708 5.762 5.708.862 0 1.689-.123 2.304-.335v-.862c-.43.199-1.354.328-2.29.328-2.926 0-4.813-1.88-4.813-4.798 0-2.844 1.921-4.881 4.594-4.881 2.735 0 4.608 1.688 4.608 4.156 0 1.682-.554 2.769-1.416 2.769-.492 0-.772-.28-.772-.76V5.206H8.923v.834h-.11c-.266-.595-.881-.964-1.6-.964-1.4 0-2.378 1.162-2.378 2.823 0 1.737.957 2.906 2.379 2.906.8 0 1.415-.39 1.709-1.087h.11c.081.67.703 1.148 1.503 1.148 1.572 0 2.57-1.415 2.57-3.643zm-7.177.704c0-1.197.54-1.907 1.456-1.907.93 0 1.524.738 1.524 1.907S8.308 9.84 7.371 9.84c-.895 0-1.442-.725-1.442-1.914z"/> </svg>
|
||||
|
After Width: | Height: | Size: 939 B |
|
Before Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 1.3 KiB |
@@ -2,6 +2,10 @@
|
||||
Name=White Icon Theme
|
||||
Comment=White Icon Theme
|
||||
|
||||
[32]
|
||||
Size=32
|
||||
Type=Fixed
|
||||
|
||||
[svg]
|
||||
Size=64
|
||||
Type=Scalable
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg style="color: white" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-at" viewBox="0 0 16 16"> <path d="M13.106 7.222c0-2.967-2.249-5.032-5.482-5.032-3.35 0-5.646 2.318-5.646 5.702 0 3.493 2.235 5.708 5.762 5.708.862 0 1.689-.123 2.304-.335v-.862c-.43.199-1.354.328-2.29.328-2.926 0-4.813-1.88-4.813-4.798 0-2.844 1.921-4.881 4.594-4.881 2.735 0 4.608 1.688 4.608 4.156 0 1.682-.554 2.769-1.416 2.769-.492 0-.772-.28-.772-.76V5.206H8.923v.834h-.11c-.266-.595-.881-.964-1.6-.964-1.4 0-2.378 1.162-2.378 2.823 0 1.737.957 2.906 2.379 2.906.8 0 1.415-.39 1.709-1.087h.11c.081.67.703 1.148 1.503 1.148 1.572 0 2.57-1.415 2.57-3.643zm-7.177.704c0-1.197.54-1.907 1.456-1.907.93 0 1.524.738 1.524 1.907S8.308 9.84 7.371 9.84c-.895 0-1.442-.725-1.442-1.914z" fill="white"></path> </svg>
|
||||
|
After Width: | Height: | Size: 978 B |
@@ -1,10 +1,13 @@
|
||||
<RCC>
|
||||
<qresource>
|
||||
<file>icons/address-book-new-22.png</file>
|
||||
<file>icons/AppIcon.png</file>
|
||||
<file>icons/applications-system-24.png</file>
|
||||
<file>icons/black/32/discord.png</file>
|
||||
<file>icons/black/32/github.png</file>
|
||||
<file>icons/black/index.theme</file>
|
||||
<file>icons/black/svg/arrow-left-right-line.svg</file>
|
||||
<file>icons/black/svg/artboard-2-line.svg</file>
|
||||
<file>icons/black/svg/at.svg</file>
|
||||
<file>icons/black/svg/book-open-line.svg</file>
|
||||
<file>icons/black/svg/brush-line.svg</file>
|
||||
<file>icons/black/svg/checkbox-multiple-blank-line.svg</file>
|
||||
@@ -56,16 +59,18 @@
|
||||
<file>icons/black/svg/usb-fill.svg</file>
|
||||
<file>icons/black/svg/volume-up-line.svg</file>
|
||||
<file>icons/black/svg/window-2-line.svg</file>
|
||||
<file>icons/discord.png</file>
|
||||
<file>icons/logo.png</file>
|
||||
<file>icons/media-optical-24.png</file>
|
||||
<file>icons/media-optical-gear-24.png</file>
|
||||
<file>icons/media-optical.png</file>
|
||||
<file>icons/QT.png</file>
|
||||
<file>icons/update.png</file>
|
||||
<file>icons/white/32/discord.png</file>
|
||||
<file>icons/white/32/github.png</file>
|
||||
<file>icons/white/index.theme</file>
|
||||
<file>icons/white/svg/arrow-left-right-line.svg</file>
|
||||
<file>icons/white/svg/artboard-2-line.svg</file>
|
||||
<file>icons/white/svg/at.svg</file>
|
||||
<file>icons/white/svg/book-open-line.svg</file>
|
||||
<file>icons/white/svg/brush-line.svg</file>
|
||||
<file>icons/white/svg/checkbox-multiple-blank-line.svg</file>
|
||||
|
||||
@@ -907,14 +907,6 @@ void cdvdReset()
|
||||
cdvdCtrlTrayClose();
|
||||
}
|
||||
|
||||
struct Freeze_v10Compat
|
||||
{
|
||||
u8 Action;
|
||||
u32 SeekToSector;
|
||||
u32 ReadTime;
|
||||
bool Spinning;
|
||||
};
|
||||
|
||||
void SaveStateBase::cdvdFreeze()
|
||||
{
|
||||
FreezeTag("cdvd");
|
||||
|
||||
@@ -253,7 +253,7 @@ bool InputIsoFile::Open(std::string srcfile, bool testOnly)
|
||||
|
||||
if (!detected)
|
||||
{
|
||||
Console.Error(fmt::format("Unable to identify the ISO image type for '{}'", srcfile));
|
||||
Console.Error(fmt::format("Unable to identify the ISO image type for '{}'", m_filename));
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,6 @@ set(pcsx2Sources
|
||||
Gif_Unit.cpp
|
||||
GS.cpp
|
||||
Host.cpp
|
||||
HostDisplay.cpp
|
||||
Hw.cpp
|
||||
HwRead.cpp
|
||||
HwWrite.cpp
|
||||
@@ -180,7 +179,6 @@ set(pcsx2Headers
|
||||
GS.h
|
||||
Hardware.h
|
||||
Host.h
|
||||
HostDisplay.h
|
||||
Hw.h
|
||||
IopBios.h
|
||||
IopCounters.h
|
||||
@@ -568,7 +566,6 @@ set(pcsx2GSHeaders
|
||||
GS/Renderers/Common/GSRenderer.h
|
||||
GS/Renderers/Common/GSTexture.h
|
||||
GS/Renderers/Common/GSVertex.h
|
||||
GS/Renderers/Common/GSVertexList.h
|
||||
GS/Renderers/Common/GSVertexTrace.h
|
||||
GS/Renderers/Null/GSRendererNull.h
|
||||
GS/Renderers/HW/GSHwHack.h
|
||||
@@ -785,42 +782,7 @@ set(pcsx2FrontendHeaders
|
||||
Frontend/ImGuiOverlays.h
|
||||
)
|
||||
|
||||
if(USE_OPENGL)
|
||||
list(APPEND pcsx2FrontendSources
|
||||
Frontend/OpenGLHostDisplay.cpp
|
||||
Frontend/imgui_impl_opengl3.cpp
|
||||
)
|
||||
list(APPEND pcsx2FrontendHeaders
|
||||
Frontend/OpenGLHostDisplay.h
|
||||
Frontend/imgui_impl_opengl3.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(USE_VULKAN)
|
||||
list(APPEND pcsx2FrontendSources
|
||||
Frontend/VulkanHostDisplay.cpp
|
||||
Frontend/imgui_impl_vulkan.cpp
|
||||
)
|
||||
list(APPEND pcsx2FrontendHeaders
|
||||
Frontend/imgui_impl_vulkan.h
|
||||
Frontend/VulkanHostDisplay.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND pcsx2FrontendSources
|
||||
Frontend/D3D11HostDisplay.cpp
|
||||
Frontend/D3D12HostDisplay.cpp
|
||||
Frontend/imgui_impl_dx11.cpp
|
||||
Frontend/imgui_impl_dx12.cpp
|
||||
)
|
||||
list(APPEND pcsx2FrontendHeaders
|
||||
Frontend/D3D11HostDisplay.h
|
||||
Frontend/D3D12HostDisplay.h
|
||||
Frontend/imgui_impl_dx11.h
|
||||
Frontend/imgui_impl_dx12.h
|
||||
)
|
||||
elseif(APPLE)
|
||||
if(APPLE)
|
||||
list(APPEND pcsx2GSSources
|
||||
GS/Renderers/Metal/GSDeviceMTL.mm
|
||||
GS/Renderers/Metal/GSMTLDeviceInfo.mm
|
||||
@@ -834,12 +796,6 @@ elseif(APPLE)
|
||||
GS/Renderers/Metal/GSMTLShaderCommon.h
|
||||
GS/Renderers/Metal/GSTextureMTL.h
|
||||
)
|
||||
list(APPEND pcsx2FrontendSources
|
||||
Frontend/MetalHostDisplay.mm
|
||||
)
|
||||
list(APPEND pcsx2FrontendHeaders
|
||||
Frontend/MetalHostDisplay.h
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND pcsx2FrontendSources
|
||||
@@ -1293,7 +1249,7 @@ function(setup_main_executable target)
|
||||
install(FILES $<TARGET_PDB_FILE:${target}> DESTINATION ${CMAKE_SOURCE_DIR}/bin)
|
||||
endif()
|
||||
find_program(WINDEPLOYQT_EXE windeployqt HINTS "${QT_BINARY_DIRECTORY}")
|
||||
install(CODE "execute_process(COMMAND \"${WINDEPLOYQT_EXE}\" \"${CMAKE_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${target}>\" --plugindir ${CMAKE_SOURCE_DIR}/bin/QtPlugins --no-compiler-runtime --no-system-d3d-compiler)")
|
||||
install(CODE "execute_process(COMMAND \"${WINDEPLOYQT_EXE}\" \"${CMAKE_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${target}>\" --plugindir \"${CMAKE_SOURCE_DIR}/bin/QtPlugins\" --no-compiler-runtime --no-system-d3d-compiler COMMAND_ERROR_IS_FATAL ANY)")
|
||||
install(CODE "file(WRITE \"${CMAKE_SOURCE_DIR}/bin/qt.conf\" \"[Paths]\\nPlugins = ./QtPlugins\")")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "common/General.h"
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
class SettingsInterface;
|
||||
@@ -350,6 +351,13 @@ enum class GSCASMode : u8
|
||||
SharpenAndResize,
|
||||
};
|
||||
|
||||
enum class GSHWAutoFlushLevel : u8
|
||||
{
|
||||
Disabled,
|
||||
SpritesOnly,
|
||||
Enabled,
|
||||
};
|
||||
|
||||
enum class GSGPUTargetCLUTMode : u8
|
||||
{
|
||||
Disabled,
|
||||
@@ -619,6 +627,9 @@ struct Pcsx2Config
|
||||
|
||||
static const char* GetRendererName(GSRendererType type);
|
||||
|
||||
/// Converts a tri-state option to an optional boolean value.
|
||||
static std::optional<bool> TriStateToOptionalBoolean(int value);
|
||||
|
||||
static constexpr float DEFAULT_FRAME_RATE_NTSC = 59.94f;
|
||||
static constexpr float DEFAULT_FRAME_RATE_PAL = 50.00f;
|
||||
|
||||
@@ -669,7 +680,6 @@ struct Pcsx2Config
|
||||
Mipmap : 1,
|
||||
ManualUserHacks : 1,
|
||||
UserHacks_AlignSpriteX : 1,
|
||||
UserHacks_AutoFlush : 1,
|
||||
UserHacks_CPUFBConversion : 1,
|
||||
UserHacks_ReadTCOnClose : 1,
|
||||
UserHacks_DisableDepthSupport : 1,
|
||||
@@ -704,86 +714,88 @@ struct Pcsx2Config
|
||||
};
|
||||
};
|
||||
|
||||
int VsyncQueueSize{2};
|
||||
int VsyncQueueSize = 2;
|
||||
|
||||
// forces the MTGS to execute tags/tasks in fully blocking/synchronous
|
||||
// style. Useful for debugging potential bugs in the MTGS pipeline.
|
||||
bool SynchronousMTGS{false};
|
||||
bool FrameLimitEnable{true};
|
||||
bool SynchronousMTGS = false;
|
||||
bool FrameLimitEnable = true;
|
||||
|
||||
VsyncMode VsyncEnable{VsyncMode::Off};
|
||||
VsyncMode VsyncEnable = VsyncMode::Off;
|
||||
|
||||
float LimitScalar{1.0f};
|
||||
float FramerateNTSC{DEFAULT_FRAME_RATE_NTSC};
|
||||
float FrameratePAL{DEFAULT_FRAME_RATE_PAL};
|
||||
float LimitScalar = 1.0f;
|
||||
float FramerateNTSC = DEFAULT_FRAME_RATE_NTSC;
|
||||
float FrameratePAL = DEFAULT_FRAME_RATE_PAL;
|
||||
|
||||
AspectRatioType AspectRatio{AspectRatioType::RAuto4_3_3_2};
|
||||
FMVAspectRatioSwitchType FMVAspectRatioSwitch{FMVAspectRatioSwitchType::Off};
|
||||
GSInterlaceMode InterlaceMode{GSInterlaceMode::Automatic};
|
||||
GSPostBilinearMode LinearPresent{ GSPostBilinearMode::BilinearSmooth };
|
||||
AspectRatioType AspectRatio = AspectRatioType::RAuto4_3_3_2;
|
||||
FMVAspectRatioSwitchType FMVAspectRatioSwitch = FMVAspectRatioSwitchType::Off;
|
||||
GSInterlaceMode InterlaceMode = GSInterlaceMode::Automatic;
|
||||
GSPostBilinearMode LinearPresent = GSPostBilinearMode::BilinearSmooth;
|
||||
|
||||
float StretchY{100.0f};
|
||||
int Crop[4]{};
|
||||
float StretchY = 100.0f;
|
||||
int Crop[4] = {};
|
||||
|
||||
float OsdScale{100.0};
|
||||
float OsdScale = 100.0;
|
||||
|
||||
GSRendererType Renderer{GSRendererType::Auto};
|
||||
float UpscaleMultiplier{1.0f};
|
||||
GSRendererType Renderer = GSRendererType::Auto;
|
||||
float UpscaleMultiplier = 1.0f;
|
||||
|
||||
HWMipmapLevel HWMipmap{HWMipmapLevel::Automatic};
|
||||
AccBlendLevel AccurateBlendingUnit{AccBlendLevel::Basic};
|
||||
CRCHackLevel CRCHack{CRCHackLevel::Automatic};
|
||||
BiFiltering TextureFiltering{BiFiltering::PS2};
|
||||
TexturePreloadingLevel TexturePreloading{TexturePreloadingLevel::Full};
|
||||
GSDumpCompressionMethod GSDumpCompression{GSDumpCompressionMethod::Zstandard};
|
||||
GSHardwareDownloadMode HWDownloadMode{GSHardwareDownloadMode::Enabled};
|
||||
GSCASMode CASMode{GSCASMode::Disabled};
|
||||
int Dithering{2};
|
||||
int MaxAnisotropy{0};
|
||||
int SWExtraThreads{2};
|
||||
int SWExtraThreadsHeight{4};
|
||||
int TVShader{0};
|
||||
s16 GetSkipCountFunctionId{-1};
|
||||
s16 BeforeDrawFunctionId{-1};
|
||||
int SkipDrawStart{0};
|
||||
int SkipDrawEnd{0};
|
||||
HWMipmapLevel HWMipmap = HWMipmapLevel::Automatic;
|
||||
AccBlendLevel AccurateBlendingUnit = AccBlendLevel::Basic;
|
||||
CRCHackLevel CRCHack = CRCHackLevel::Automatic;
|
||||
BiFiltering TextureFiltering = BiFiltering::PS2;
|
||||
TexturePreloadingLevel TexturePreloading = TexturePreloadingLevel::Full;
|
||||
GSDumpCompressionMethod GSDumpCompression = GSDumpCompressionMethod::Zstandard;
|
||||
GSHardwareDownloadMode HWDownloadMode = GSHardwareDownloadMode::Enabled;
|
||||
GSCASMode CASMode = GSCASMode::Disabled;
|
||||
u8 Dithering = 2;
|
||||
u8 MaxAnisotropy = 0;
|
||||
u8 TVShader = 0;
|
||||
s16 GetSkipCountFunctionId = -1;
|
||||
s16 BeforeDrawFunctionId = -1;
|
||||
int SkipDrawStart = 0;
|
||||
int SkipDrawEnd = 0;
|
||||
|
||||
int UserHacks_HalfBottomOverride{-1};
|
||||
int UserHacks_HalfPixelOffset{0};
|
||||
int UserHacks_RoundSprite{0};
|
||||
int UserHacks_TCOffsetX{0};
|
||||
int UserHacks_TCOffsetY{0};
|
||||
int UserHacks_CPUSpriteRenderBW{0};
|
||||
int UserHacks_CPUSpriteRenderLevel{0};
|
||||
int UserHacks_CPUCLUTRender{0};
|
||||
GSGPUTargetCLUTMode UserHacks_GPUTargetCLUTMode{GSGPUTargetCLUTMode::Disabled};
|
||||
GSTextureInRtMode UserHacks_TextureInsideRt{GSTextureInRtMode::Disabled};
|
||||
TriFiltering TriFilter{TriFiltering::Automatic};
|
||||
int OverrideTextureBarriers{-1};
|
||||
int OverrideGeometryShaders{-1};
|
||||
GSHWAutoFlushLevel UserHacks_AutoFlush = GSHWAutoFlushLevel::Disabled;
|
||||
s8 UserHacks_HalfBottomOverride = -1;
|
||||
s8 UserHacks_HalfPixelOffset = 0;
|
||||
s8 UserHacks_RoundSprite = 0;
|
||||
s32 UserHacks_TCOffsetX = 0;
|
||||
s32 UserHacks_TCOffsetY = 0;
|
||||
u8 UserHacks_CPUSpriteRenderBW = 0;
|
||||
u8 UserHacks_CPUSpriteRenderLevel = 0;
|
||||
u8 UserHacks_CPUCLUTRender = 0;
|
||||
GSGPUTargetCLUTMode UserHacks_GPUTargetCLUTMode = GSGPUTargetCLUTMode::Disabled;
|
||||
GSTextureInRtMode UserHacks_TextureInsideRt = GSTextureInRtMode::Disabled;
|
||||
TriFiltering TriFilter = TriFiltering::Automatic;
|
||||
s8 OverrideTextureBarriers = -1;
|
||||
|
||||
int CAS_Sharpness{50};
|
||||
int ShadeBoost_Brightness{50};
|
||||
int ShadeBoost_Contrast{50};
|
||||
int ShadeBoost_Saturation{50};
|
||||
int PNGCompressionLevel{1};
|
||||
u8 CAS_Sharpness = 50;
|
||||
u8 ShadeBoost_Brightness = 50;
|
||||
u8 ShadeBoost_Contrast = 50;
|
||||
u8 ShadeBoost_Saturation = 50;
|
||||
u8 PNGCompressionLevel = 1;
|
||||
|
||||
int SaveN{0};
|
||||
int SaveL{5000};
|
||||
u16 SWExtraThreads = 2;
|
||||
u16 SWExtraThreadsHeight = 4;
|
||||
|
||||
GSScreenshotSize ScreenshotSize{GSScreenshotSize::WindowResolution};
|
||||
GSScreenshotFormat ScreenshotFormat{GSScreenshotFormat::PNG};
|
||||
int ScreenshotQuality{50};
|
||||
int SaveN = 0;
|
||||
int SaveL = 5000;
|
||||
|
||||
std::string CaptureContainer{DEFAULT_CAPTURE_CONTAINER};
|
||||
s8 ExclusiveFullscreenControl = -1;
|
||||
GSScreenshotSize ScreenshotSize = GSScreenshotSize::WindowResolution;
|
||||
GSScreenshotFormat ScreenshotFormat = GSScreenshotFormat::PNG;
|
||||
int ScreenshotQuality = 50;
|
||||
|
||||
std::string CaptureContainer = DEFAULT_CAPTURE_CONTAINER;
|
||||
std::string VideoCaptureCodec;
|
||||
std::string VideoCaptureParameters;
|
||||
std::string AudioCaptureCodec;
|
||||
std::string AudioCaptureParameters;
|
||||
int VideoCaptureBitrate{DEFAULT_VIDEO_CAPTURE_BITRATE};
|
||||
int VideoCaptureWidth{DEFAULT_VIDEO_CAPTURE_WIDTH};
|
||||
int VideoCaptureHeight{DEFAULT_VIDEO_CAPTURE_HEIGHT};
|
||||
int AudioCaptureBitrate{DEFAULT_AUDIO_CAPTURE_BITRATE};
|
||||
int VideoCaptureBitrate = DEFAULT_VIDEO_CAPTURE_BITRATE;
|
||||
int VideoCaptureWidth = DEFAULT_VIDEO_CAPTURE_WIDTH;
|
||||
int VideoCaptureHeight = DEFAULT_VIDEO_CAPTURE_HEIGHT;
|
||||
int AudioCaptureBitrate = DEFAULT_AUDIO_CAPTURE_BITRATE;
|
||||
|
||||
std::string Adapter;
|
||||
std::string HWDumpDirectory;
|
||||
|
||||
@@ -25,13 +25,13 @@
|
||||
#include "IopCounters.h"
|
||||
|
||||
#include "GS.h"
|
||||
#include "GS/GS.h"
|
||||
#include "VUmicro.h"
|
||||
#include "PerformanceMetrics.h"
|
||||
#include "Patch.h"
|
||||
|
||||
#include "ps2/HwInternal.h"
|
||||
#include "Sio.h"
|
||||
#include "HostDisplay.h"
|
||||
#include "SPU2/spu2.h"
|
||||
#include "PAD/Host/PAD.h"
|
||||
#include "Recording/InputRecording.h"
|
||||
@@ -226,10 +226,11 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca
|
||||
// Dynasty Warriors 3 Xtreme Legends - fake save corruption when loading save
|
||||
// Jak II - random speedups
|
||||
// Shadow of Rome - FMV audio issues
|
||||
const bool ntsc_hblank = gsVideoMode != GS_VideoMode::PAL && gsVideoMode == GS_VideoMode::DVD_PAL;
|
||||
const u64 HalfFrame = Frame / 2;
|
||||
const u64 Blank = Scanline * ((gsVideoMode == GS_VideoMode::NTSC ? 22 : 25) + static_cast<int>(gsIsInterlaced));
|
||||
const u64 Blank = Scanline * ((ntsc_hblank ? 22 : 25) + static_cast<int>(!IsProgressiveVideoMode()));
|
||||
const u64 Render = HalfFrame - Blank;
|
||||
const u64 GSBlank = Scanline * (gsVideoMode == GS_VideoMode::NTSC ? 3.5 : 3); // GS VBlank/CSR Swap happens roughly 3.5(NTSC) and 3(PAL) Scanlines after VBlank Start
|
||||
const u64 GSBlank = Scanline * (ntsc_hblank ? 3.5 : 3); // GS VBlank/CSR Swap happens roughly 3.5(NTSC) and 3(PAL) Scanlines after VBlank Start
|
||||
|
||||
// Important! The hRender/hBlank timers should be 50/50 for best results.
|
||||
// (this appears to be what the real EE's timing crystal does anyway)
|
||||
@@ -321,6 +322,7 @@ double GetVerticalFrequency()
|
||||
// https://web.archive.org/web/20201102100937/http://forums.nesdev.com/viewtopic.php?t=7909
|
||||
// https://web.archive.org/web/20120629231826fw_/http://ntsc-tv.com/index.html
|
||||
// https://web.archive.org/web/20200831051302/https://www.hdretrovision.com/240p/
|
||||
|
||||
switch (gsVideoMode)
|
||||
{
|
||||
case GS_VideoMode::Uninitialized: // SetGsCrt hasn't executed yet, give some temporary values.
|
||||
@@ -355,7 +357,7 @@ static double AdjustToHostRefreshRate(double vertical_frequency, double frame_li
|
||||
}
|
||||
|
||||
float host_refresh_rate;
|
||||
if (!g_host_display->GetHostRefreshRate(&host_refresh_rate))
|
||||
if (!GSGetHostRefreshRate(&host_refresh_rate))
|
||||
{
|
||||
Console.Warning("Cannot sync to host refresh since the query failed.");
|
||||
SPU2::SetDeviceSampleRateMultiplier(1.0);
|
||||
@@ -378,7 +380,7 @@ static double AdjustToHostRefreshRate(double vertical_frequency, double frame_li
|
||||
return frame_limit;
|
||||
}
|
||||
|
||||
u32 UpdateVSyncRate()
|
||||
void UpdateVSyncRate(bool force)
|
||||
{
|
||||
// Notice: (and I probably repeat this elsewhere, but it's worth repeating)
|
||||
// The PS2's vsync timer is an *independent* crystal that is fixed to either 59.94 (NTSC)
|
||||
@@ -389,62 +391,63 @@ u32 UpdateVSyncRate()
|
||||
const double vertical_frequency = GetVerticalFrequency();
|
||||
|
||||
const double frames_per_second = vertical_frequency / 2.0;
|
||||
const double frame_limit = AdjustToHostRefreshRate(vertical_frequency, frames_per_second * EmuConfig.GS.LimitScalar);
|
||||
|
||||
const double tick_rate = GetTickFrequency() / 2.0;
|
||||
const s64 ticks = static_cast<s64>(tick_rate / std::max(frame_limit, 1.0));
|
||||
|
||||
u32 total_scanlines = 0;
|
||||
bool custom = false;
|
||||
|
||||
switch (gsVideoMode)
|
||||
if (vSyncInfo.Framerate != frames_per_second || vSyncInfo.VideoMode != gsVideoMode || force)
|
||||
{
|
||||
case GS_VideoMode::Uninitialized: // SYSCALL instruction hasn't executed yet, give some temporary values.
|
||||
if(gsIsInterlaced)
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_I;
|
||||
else
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_NI;
|
||||
break;
|
||||
case GS_VideoMode::PAL:
|
||||
case GS_VideoMode::DVD_PAL:
|
||||
custom = (EmuConfig.GS.FrameratePAL != Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_PAL);
|
||||
if (gsIsInterlaced)
|
||||
total_scanlines = SCANLINES_TOTAL_PAL_I;
|
||||
else
|
||||
total_scanlines = SCANLINES_TOTAL_PAL_NI;
|
||||
break;
|
||||
case GS_VideoMode::NTSC:
|
||||
case GS_VideoMode::DVD_NTSC:
|
||||
custom = (EmuConfig.GS.FramerateNTSC != Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_NTSC);
|
||||
if (gsIsInterlaced)
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_I;
|
||||
else
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_NI;
|
||||
break;
|
||||
case GS_VideoMode::SDTV_480P:
|
||||
case GS_VideoMode::SDTV_576P:
|
||||
case GS_VideoMode::HDTV_720P:
|
||||
case GS_VideoMode::VESA:
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_I;
|
||||
break;
|
||||
case GS_VideoMode::HDTV_1080P:
|
||||
case GS_VideoMode::HDTV_1080I:
|
||||
total_scanlines = SCANLINES_TOTAL_1080;
|
||||
break;
|
||||
case GS_VideoMode::Unknown:
|
||||
default:
|
||||
if (gsIsInterlaced)
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_I;
|
||||
else
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_NI;
|
||||
Console.Error("PCSX2-Counters: Unknown video mode detected");
|
||||
pxAssertDev(false , "Unknown video mode detected via SetGsCrt");
|
||||
}
|
||||
const double frame_limit = AdjustToHostRefreshRate(vertical_frequency, frames_per_second * EmuConfig.GS.LimitScalar);
|
||||
|
||||
const bool video_mode_initialized = gsVideoMode != GS_VideoMode::Uninitialized;
|
||||
const double tick_rate = GetTickFrequency() / 2.0;
|
||||
const s64 ticks = static_cast<s64>(tick_rate / std::max(frame_limit, 1.0));
|
||||
|
||||
u32 total_scanlines = 0;
|
||||
bool custom = false;
|
||||
|
||||
switch (gsVideoMode)
|
||||
{
|
||||
case GS_VideoMode::Uninitialized: // SYSCALL instruction hasn't executed yet, give some temporary values.
|
||||
if (gsIsInterlaced)
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_I;
|
||||
else
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_NI;
|
||||
break;
|
||||
case GS_VideoMode::PAL:
|
||||
case GS_VideoMode::DVD_PAL:
|
||||
custom = (EmuConfig.GS.FrameratePAL != Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_PAL);
|
||||
if (gsIsInterlaced)
|
||||
total_scanlines = SCANLINES_TOTAL_PAL_I;
|
||||
else
|
||||
total_scanlines = SCANLINES_TOTAL_PAL_NI;
|
||||
break;
|
||||
case GS_VideoMode::NTSC:
|
||||
case GS_VideoMode::DVD_NTSC:
|
||||
custom = (EmuConfig.GS.FramerateNTSC != Pcsx2Config::GSOptions::DEFAULT_FRAME_RATE_NTSC);
|
||||
if (gsIsInterlaced)
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_I;
|
||||
else
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_NI;
|
||||
break;
|
||||
case GS_VideoMode::SDTV_480P:
|
||||
case GS_VideoMode::SDTV_576P:
|
||||
case GS_VideoMode::HDTV_720P:
|
||||
case GS_VideoMode::VESA:
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_I;
|
||||
break;
|
||||
case GS_VideoMode::HDTV_1080P:
|
||||
case GS_VideoMode::HDTV_1080I:
|
||||
total_scanlines = SCANLINES_TOTAL_1080;
|
||||
break;
|
||||
case GS_VideoMode::Unknown:
|
||||
default:
|
||||
if (gsIsInterlaced)
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_I;
|
||||
else
|
||||
total_scanlines = SCANLINES_TOTAL_NTSC_NI;
|
||||
Console.Error("PCSX2-Counters: Unknown video mode detected");
|
||||
pxAssertDev(false, "Unknown video mode detected via SetGsCrt");
|
||||
}
|
||||
|
||||
const bool video_mode_initialized = gsVideoMode != GS_VideoMode::Uninitialized;
|
||||
|
||||
if (vSyncInfo.Framerate != frames_per_second || vSyncInfo.VideoMode != gsVideoMode)
|
||||
{
|
||||
// NBA Jam 2004 PAL will fail to display 3D on the menu if this value isn't correct on reset.
|
||||
if (video_mode_initialized && vSyncInfo.VideoMode != gsVideoMode)
|
||||
CSRreg.FIELD = 1;
|
||||
@@ -465,16 +468,14 @@ u32 UpdateVSyncRate()
|
||||
vsyncCounter.sCycle = cpuRegs.cycle;
|
||||
vsyncCounter.Mode = MODE_VRENDER;
|
||||
cpuRcntSet();
|
||||
|
||||
PerformanceMetrics::SetVerticalFrequency(vertical_frequency);
|
||||
|
||||
if (m_iTicks != ticks)
|
||||
m_iTicks = ticks;
|
||||
|
||||
m_iStart = GetCPUTicks();
|
||||
}
|
||||
|
||||
PerformanceMetrics::SetVerticalFrequency(vertical_frequency);
|
||||
|
||||
if (m_iTicks != ticks)
|
||||
m_iTicks = ticks;
|
||||
|
||||
m_iStart = GetCPUTicks();
|
||||
|
||||
return static_cast<u32>(m_iTicks);
|
||||
}
|
||||
|
||||
void frameLimitReset()
|
||||
|
||||
@@ -145,6 +145,6 @@ extern u32 rcntRcount(int index);
|
||||
template< uint page > extern bool rcntWrite32( u32 mem, mem32_t& value );
|
||||
template< uint page > extern u16 rcntRead32( u32 mem ); // returns u16 by design! (see implementation for details)
|
||||
|
||||
extern u32 UpdateVSyncRate();
|
||||
extern void UpdateVSyncRate(bool force);
|
||||
extern void frameLimitReset();
|
||||
|
||||
|
||||
@@ -598,6 +598,12 @@ u32 R5900DebugInterface::getPC()
|
||||
return cpuRegs.pc;
|
||||
}
|
||||
|
||||
// Taken from COP0.cpp
|
||||
bool R5900DebugInterface::getCPCOND0()
|
||||
{
|
||||
return (((dmacRegs.stat.CIS | ~dmacRegs.pcr.CPC) & 0x3FF) == 0x3ff);
|
||||
}
|
||||
|
||||
void R5900DebugInterface::setPc(u32 newPc)
|
||||
{
|
||||
cpuRegs.pc = newPc;
|
||||
@@ -945,6 +951,11 @@ u32 R3000DebugInterface::getPC()
|
||||
return psxRegs.pc;
|
||||
}
|
||||
|
||||
bool R3000DebugInterface::getCPCOND0()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void R3000DebugInterface::setPc(u32 newPc)
|
||||
{
|
||||
psxRegs.pc = newPc;
|
||||
|
||||
@@ -77,6 +77,7 @@ public:
|
||||
virtual u128 getHI() = 0;
|
||||
virtual u128 getLO() = 0;
|
||||
virtual u32 getPC() = 0;
|
||||
virtual bool getCPCOND0() = 0;
|
||||
virtual void setPc(u32 newPc) = 0;
|
||||
virtual void setRegister(int cat, int num, u128 newValue) = 0;
|
||||
|
||||
@@ -129,6 +130,7 @@ public:
|
||||
u128 getHI() override;
|
||||
u128 getLO() override;
|
||||
u32 getPC() override;
|
||||
bool getCPCOND0() override;
|
||||
void setPc(u32 newPc) override;
|
||||
void setRegister(int cat, int num, u128 newValue) override;
|
||||
[[nodiscard]] SymbolMap& GetSymbolMap() const override;
|
||||
@@ -168,6 +170,7 @@ public:
|
||||
u128 getHI() override;
|
||||
u128 getLO() override;
|
||||
u32 getPC() override;
|
||||
bool getCPCOND0() override;
|
||||
void setPc(u32 newPc) override;
|
||||
void setRegister(int cat, int num, u128 newValue) override;
|
||||
[[nodiscard]] SymbolMap& GetSymbolMap() const override;
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace MIPSAnalyst
|
||||
const R5900::OPCODE& opcode = R5900::GetInstruction(op);
|
||||
|
||||
int branchType = (opcode.flags & BRANCHTYPE_MASK);
|
||||
if ((opcode.flags & IS_BRANCH) && (branchType == BRANCHTYPE_BRANCH || branchType == BRANCHTYPE_BC1))
|
||||
if ((opcode.flags & IS_BRANCH) && (branchType == BRANCHTYPE_BRANCH || branchType == BRANCHTYPE_BC1 || branchType == BRANCHTYPE_BC0))
|
||||
return addr + 4 + ((signed short)(op&0xFFFF)<<2);
|
||||
else
|
||||
return INVALIDTARGET;
|
||||
@@ -71,7 +71,7 @@ namespace MIPSAnalyst
|
||||
const R5900::OPCODE& opcode = R5900::GetInstruction(op);
|
||||
|
||||
int branchType = (opcode.flags & BRANCHTYPE_MASK);
|
||||
if ((opcode.flags & IS_BRANCH) && (branchType == BRANCHTYPE_BRANCH || branchType == BRANCHTYPE_BC1))
|
||||
if ((opcode.flags & IS_BRANCH) && (branchType == BRANCHTYPE_BRANCH || branchType == BRANCHTYPE_BC1 || branchType == BRANCHTYPE_BC0))
|
||||
{
|
||||
if (!(opcode.flags & IS_LINKED))
|
||||
return addr + 4 + ((signed short)(op&0xFFFF)<<2);
|
||||
@@ -409,6 +409,20 @@ namespace MIPSAnalyst
|
||||
value = info.cpu->getRegister(EECAT_FCR,31)._u32[0] & 0x00800000;
|
||||
info.branchTarget = info.opcodeAddress + 4 + ((s16)(op&0xFFFF)<<2);
|
||||
|
||||
switch (opcode.flags & CONDTYPE_MASK)
|
||||
{
|
||||
case CONDTYPE_EQ:
|
||||
info.conditionMet = value == 0;
|
||||
break;
|
||||
case CONDTYPE_NE:
|
||||
info.conditionMet = value != 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BRANCHTYPE_BC0:
|
||||
info.isConditional = true;
|
||||
value = info.cpu->getCPCOND0();
|
||||
info.branchTarget = info.opcodeAddress + 4 + ((s16)(op&0xFFFF)<<2);
|
||||
switch (opcode.flags & CONDTYPE_MASK)
|
||||
{
|
||||
case CONDTYPE_EQ:
|
||||
|
||||