Compare commits

...
44 Commits
Author SHA1 Message Date
lightningterror 5cb7abf10c GS/GL: Make sure we always insert a barrier when tex is rt/ds. 2026-04-01 23:05:31 +02:00
JordanTheToasterandGovanifY 7561f7ef70 GameDB: Silent Hill Shattered Memories fixes 2026-03-31 23:42:34 +02:00
lightningterror ac69bb2142 GS/HW: Don't bind source tex when using tex is fb hle.
Slot 2 will be used for fb read instead of slot 0, don't bind it when it's not needed.
2026-03-31 02:07:12 +02:00
PCSX2 BotandTy 2c7c8e19e2 [ci skip] PAD: Update to latest controller database. 2026-03-30 12:21:27 -04:00
PCSX2 Botandlightningterror 59d00a0134 [ci skip] Qt: Update Base Translation. 2026-03-30 02:06:50 +02:00
TJnotJTandlightningterror 372fadfb99 GS/HW: Disable depth if zero clear, ZBP == FBP, and depth/RT different bpp. 2026-03-29 21:53:14 +02:00
TJnotJTandlightningterror 406c2c0bbf GS/HW: Cleanup DATE configuration. 2026-03-29 21:10:33 +02:00
TJnotJTandlightningterror a5ba35ce92 GS/HW: Check overlap of required rect with valid area in source lookup.
Check recent transfers for RT in source lookup if it has dirty rects or the valid area does not intersect with the required rect. The latter check is needed in case a recent transfer did not intersect the valid area of the RT.
2026-03-29 21:04:09 +02:00
TellowKrinkleandTy f6b2887ae0 GS: Add unsafe setting warnings for debug settings
It's pretty common to forget to turn them off after debugging...
2026-03-29 11:39:20 -04:00
TellowKrinkleandTy cba474000e Deps: Use strict with shasum check
Catch any mistakes we make with the hash list
2026-03-29 11:38:45 -04:00
TellowKrinkleandTy cb64246288 Deps: Use better GitHub archive URLs 2026-03-29 11:38:45 -04:00
TellowKrinkleandTy 4006be49f8 Deps: Remove empty lines from shasum file
shasum util complains about them
2026-03-29 11:38:45 -04:00
TellowKrinkleandTy 085f1dcb68 Deps: Hash check files before downloading
When working on the build scripts, it's convenient to not have to redownload everything every time you try to run and it fails to build
2026-03-29 11:38:45 -04:00
PCSX2 BotandTy 1372d71fa7 [ci skip] Qt: Update Base Translation. 2026-03-29 11:28:05 -04:00
TheLastRarandTy 2fda2d512d GS/HW: Reduce number of cached palettes 2026-03-29 11:28:00 -04:00
TheLastRarandTy 1edc304453 OSD: Add option to show descriptor usage in D3D12 2026-03-29 11:28:00 -04:00
TellowKrinkleandTy a291936bf8 GS:SW: Use unaligned loads to reduce constant size on AVX2
Allows more instructions to use 1-byte offsets
2026-03-28 17:49:17 -04:00
TellowKrinkleandTy 9b343bae3e GS:SW: Split g_const into separate structs for 128 and 256 bit vectors
Allows more code to access members with 8b offsets
2026-03-28 17:49:17 -04:00
TellowKrinkleandTy 6336cc82e8 Common: Remove unused functions 2026-03-28 17:49:17 -04:00
TellowKrinkleandTy 3450e3c238 Revert "Core: Reserve memory map as early as possible"
This reverts commit 337daf7ed9.

It's no longer needed
2026-03-28 17:49:17 -04:00
TellowKrinkleandTy 49017c4813 Core: Reserve data and code areas together
They need to stay near each other for the x86 JIT to work
2026-03-28 17:49:17 -04:00
TellowKrinkleandTy 27a88dd333 Common: Allow non-file mappings in SharedMemoryMappingArea 2026-03-28 17:49:17 -04:00
TellowKrinkleandTy 6f4f6cf7de Common: Switch back to Linux allocation routines on macOS
We don't need MAP_FIXED anymore
2026-03-28 17:49:17 -04:00
TellowKrinkleandTy 0020cac123 Core: Map sys memory anywhere 2026-03-28 17:49:17 -04:00
TellowKrinkleandTy 1160758a81 GS:SW: Prepare DrawScanline for being more than 2GB from const data 2026-03-28 17:49:17 -04:00
TellowKrinkleandTy 5c205d6287 EE:Rec: Allow rec memory anywhere 2026-03-28 17:49:17 -04:00
TellowKrinkleandTy e814408026 EE:Rec: Avoid rbx
Will be used for holding a pointer to the PCSX2 text section
2026-03-28 17:49:17 -04:00
KamFretoZandTy 46e85c4586 VMManager: Make Prefer English also applies to other things 2026-03-27 17:21:33 -04:00
Heit0fffandTy f4b16a8762 GameDB: NCAA Final Four 2004 - disable mVU Flag Hack 2026-03-27 17:07:32 -04:00
TheLastRarandTy cdc8201222 CI: Use latest VS installed on runner 2026-03-27 16:49:58 -04:00
TheLastRarandTy 94c10ca9f9 Deps: Try locating VS2026 if VS2022 is not installed 2026-03-27 16:49:58 -04:00
chaoticgdandTy 724155ba91 Docs: Fix cubeb license 2026-03-26 16:04:49 -04:00
PCSX2 BotandTy 6ffa916336 [ci skip] Qt: Update Base Translation. 2026-03-26 08:15:16 -04:00
SternXDandlightningterror e3badc754d OSD: Use standard font for input overlay 2026-03-25 17:54:09 +01:00
JordanTheToasterandlightningterror df9783f41f Deps: Update Qt to 6.11.0 2026-03-25 16:15:42 +01:00
chaoticgdandlightningterror e9c6d51566 Qt: Fix position of game list header menu 2026-03-25 15:55:55 +01:00
PCSX2 Botandlightningterror a8c8223f69 [ci skip] Qt: Update Base Translation. 2026-03-25 11:47:10 +01:00
TellowKrinkle 9b3f827991 GHActions: Accept commit names starting with numbers
[ci skip]
2026-03-25 01:23:12 -05:00
TheLastRarandTy 2d2bfd64ff GHActions: Bump microsoft/setup-msbuild 2026-03-24 12:40:49 -04:00
TellowKrinkleandTy 73a825cbb1 Common:Darwin: Mach exceptions don't need mutex
They run on their own thread, so there's no possibility of concurrent access.
2026-03-24 12:40:37 -04:00
TellowKrinkleandTy 3e0e72e50c Common:Darwin: Don't crash from the mach exception thread
We want crash reports to point to the correct thread.
2026-03-24 12:40:37 -04:00
TellowKrinkleandTy 259350c974 GS: Install page fault handler on GS thread too 2026-03-24 12:40:37 -04:00
PCSX2 Botandlightningterror e14b4475ff [ci skip] PAD: Update to latest controller database. 2026-03-23 21:30:01 +01:00
TyandGitHub b4f030cd37 GHActions: Support '\' and 2026-03-23 09:43:52 -04:00
70 changed files with 2763 additions and 2661 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
uses: gsactions/commit-message-checker@16fa2d5de096ae0d35626443bcd24f1e756cafee
with:
accessToken: ${{ secrets.GITHUB_TOKEN }}
pattern: '^[A-Z][A-Za-z0-9 \["]+:.+'
pattern: '^[A-Z0-9][A-Za-z0-9 \["\/\\]+:.+'
excludeTitle: true
excludeDescription: true
checkAllCommitMessages: true
@@ -18,7 +18,7 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
QT=6.10.2
QT=6.11.0
QTAPNG=1.3.0
FFMPEG=8.0
@@ -47,19 +47,19 @@ cd deps-build
export PKG_CONFIG_PATH="$INSTALLDIR/lib/pkgconfig:$PKG_CONFIG_PATH"
cat > SHASUMS <<EOF
aeb78d29291a2b5fd53cb55950f8f5065b4978c25fb1d77f627d695ab9adf21e qtbase-everywhere-src-$QT.tar.xz
8b8f9c718638081e7b3c000e7f31910140b1202a98e98df5d1b496fe6f639d67 qtimageformats-everywhere-src-$QT.tar.xz
f07ff80f38caf235187200345392ca7479445ddf49a36c3694cd52a735dad6e1 qtsvg-everywhere-src-$QT.tar.xz
1e3d2c07c1fd76d2425c6eaeeaa62ffaff5f79210c4e1a5bc2a6a9db668d5b24 qttools-everywhere-src-$QT.tar.xz
b3b3813bc9d76b545716dc8b6e659fa71b6e2bc14569e9fab6dab8b30650a644 qttranslations-everywhere-src-$QT.tar.xz
391998eb432719df26a6a67d8efdc67f8bf2afdd76c1ee3381ebff4fe7527ee2 qtwayland-everywhere-src-$QT.tar.xz
grep . > SHASUMS <<EOF
231ad85979864d914dc9568a1b71c91d6cf20d7b2021d059103bf0eb51cb755e qtbase-everywhere-src-$QT.tar.xz
d3adb02ac5e2fe24068dbdaee0d7cc68cc3fa8553291c1bfce77c9fe8e940cc8 qtimageformats-everywhere-src-$QT.tar.xz
dfa8d653be07087d9407ed4a4ebae847f8953e0b7abd829f089803ab652a30e6 qtsvg-everywhere-src-$QT.tar.xz
cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everywhere-src-$QT.tar.xz
54f48b2fe4316892ff930195f170a5385644acc7393505f3155c066b8e1ffe56 qttranslations-everywhere-src-$QT.tar.xz
e710e6e760f92922b86e4dd68f6bbe94ef6510919519d1b0068e874b5ad84d37 qtwayland-everywhere-src-$QT.tar.xz
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
207f96964dc9475b13c1f66565bf145d2658089d65b4cf786d351da2857fc269 harfbuzz-$HARFBUZZ.tar.gz
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
96e5c2d7f2c482a60d5804da48a2eb9a0db0719b2c65dcc169fbfdcf37f3a45d libbacktrace-$LIBBACKTRACE.tar.gz
075920b826834ac4ddf97661cc73491047855859affd671d52079c6867c1c6c0 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
d925722864837ad5ae2a82070d4b2e0603dc72af44bd457c3962298258b8e82d libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
@@ -79,36 +79,38 @@ bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslan
cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
EOF
curl -L \
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.zip" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/vulkan-sdk-$VULKAN.tar.gz" \
-O "https://github.com/FFmpeg/nv-codec-headers/releases/download/n$NVENC/nv-codec-headers-$NVENC.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz" \
-o "QtApng-$QTAPNG.tar.gz" "https://github.com/jurplel/QtApng/archive/refs/tags/$QTAPNG.tar.gz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz" \
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
curl -L \
-O "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz" \
-O "https://github.com/harfbuzz/harfbuzz/archive/$HARFBUZZ/harfbuzz-$HARFBUZZ.tar.gz" \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE/libbacktrace-$LIBBACKTRACE.tar.gz" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/vulkan-sdk-$VULKAN.tar.gz" \
-O "https://github.com/FFmpeg/nv-codec-headers/releases/download/n$NVENC/nv-codec-headers-$NVENC.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtwayland-everywhere-src-$QT.tar.xz" \
-O "https://github.com/jurplel/QtApng/archive/$QTAPNG/QtApng-$QTAPNG.tar.gz" \
-O "https://github.com/google/shaderc/archive/v$SHADERC/shaderc-$SHADERC.tar.gz" \
-O "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG/shaderc-glslang-$SHADERC_GLSLANG.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS/shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS/KDDockWidgets-$KDDOCKWIDGETS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz"
fi
shasum -a 256 --check SHASUMS
shasum -a 256 --check --strict SHASUMS
if [ "$BUILD_FFMPEG" -ne 0 ]; then
echo "Installing vulkan headers..."
@@ -143,7 +145,7 @@ fi
echo "Building libbacktrace..."
rm -fr "libbacktrace-$LIBBACKTRACE"
unzip "$LIBBACKTRACE.zip"
tar xf "libbacktrace-$LIBBACKTRACE.tar.gz"
cd "libbacktrace-$LIBBACKTRACE"
./configure --prefix="$INSTALLDIR" --with-pic
make
@@ -33,10 +33,10 @@ SHADERC_SPIRVTOOLS=971a7b6e8d7740035bbff089bbbf9f42951ecfd5
mkdir -p deps-build
cd deps-build
cat > SHASUMS <<EOF
grep . > SHASUMS <<EOF
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
f63fc519f150465bd0bdafcdf3d0e9c23474f4c474171cd515ea1b3a72c081fb harfbuzz-$HARFBUZZ.tar.gz
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
96e5c2d7f2c482a60d5804da48a2eb9a0db0719b2c65dcc169fbfdcf37f3a45d libbacktrace-$LIBBACKTRACE.tar.gz
a050a892d3b4a7bb010c3a95c7301e49656d72a64f1fc709a90b8aded192bed2 libpng-$LIBPNG.tar.xz
e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWEBP.tar.gz
dad488474a51a0b01d547cd2834893d6299328d2e30f479a3564088b5476bae2 $SDL.tar.gz
@@ -51,28 +51,30 @@ c693867f10a7760ef1bcf85419d51783586768cc2c601d03841bc6a8b2554b9c shaderc-spirv-
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
EOF
curl -L \
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.zip" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
curl -L \
-O "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz" \
-O "https://github.com/harfbuzz/harfbuzz/archive/$HARFBUZZ/harfbuzz-$HARFBUZZ.tar.gz" \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE/libbacktrace-$LIBBACKTRACE.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/google/shaderc/archive/v$SHADERC/shaderc-$SHADERC.tar.gz" \
-O "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG/shaderc-glslang-$SHADERC_GLSLANG.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS/shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz"
fi
shasum -a 256 --check SHASUMS
shasum -a 256 --check --strict SHASUMS
echo "Building libbacktrace..."
rm -fr "libbacktrace-$LIBBACKTRACE"
unzip "$LIBBACKTRACE.zip"
tar xf "libbacktrace-$LIBBACKTRACE.tar.gz"
cd "libbacktrace-$LIBBACKTRACE"
./configure --prefix="$INSTALLDIR"
make
@@ -43,7 +43,7 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
QT=6.10.2
QT=6.11.0
QTAPNG=1.3.0
FREETYPE=2.14.1
@@ -83,12 +83,12 @@ CMAKE_ARCH_X64=-DCMAKE_OSX_ARCHITECTURES="x86_64"
CMAKE_ARCH_ARM64=-DCMAKE_OSX_ARCHITECTURES="arm64"
CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
cat > SHASUMS <<EOF
aeb78d29291a2b5fd53cb55950f8f5065b4978c25fb1d77f627d695ab9adf21e qtbase-everywhere-src-$QT.tar.xz
8b8f9c718638081e7b3c000e7f31910140b1202a98e98df5d1b496fe6f639d67 qtimageformats-everywhere-src-$QT.tar.xz
f07ff80f38caf235187200345392ca7479445ddf49a36c3694cd52a735dad6e1 qtsvg-everywhere-src-$QT.tar.xz
1e3d2c07c1fd76d2425c6eaeeaa62ffaff5f79210c4e1a5bc2a6a9db668d5b24 qttools-everywhere-src-$QT.tar.xz
b3b3813bc9d76b545716dc8b6e659fa71b6e2bc14569e9fab6dab8b30650a644 qttranslations-everywhere-src-$QT.tar.xz
grep . > SHASUMS <<EOF
231ad85979864d914dc9568a1b71c91d6cf20d7b2021d059103bf0eb51cb755e qtbase-everywhere-src-$QT.tar.xz
d3adb02ac5e2fe24068dbdaee0d7cc68cc3fa8553291c1bfce77c9fe8e940cc8 qtimageformats-everywhere-src-$QT.tar.xz
dfa8d653be07087d9407ed4a4ebae847f8953e0b7abd829f089803ab652a30e6 qtsvg-everywhere-src-$QT.tar.xz
cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everywhere-src-$QT.tar.xz
54f48b2fe4316892ff930195f170a5385644acc7393505f3155c066b8e1ffe56 qttranslations-everywhere-src-$QT.tar.xz
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
@@ -101,7 +101,7 @@ e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWE
017c06f75ffed25f6cda9b5369ec6da0ac35a6616adf7abe4222516a0237f37a libpng-$LIBPNG-apng.patch.gz
075920b826834ac4ddf97661cc73491047855859affd671d52079c6867c1c6c0 libjpeg-turbo-$LIBJPEGTURBO.tar.gz
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c v$MOLTENVK.tar.gz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c MoltenVK-$MOLTENVK.tar.gz
51dbf24fe72e43dd7cb9a289d3cab47112010f1a2ed69b6fc8ac0dff31991ed2 KDDockWidgets-$KDDOCKWIDGETS.tar.gz
7bd4e79ce18b1d47517e7e91fbb7cf19d4f01942804a519bc7c0bf32b6325dd5 plutovg-$PLUTOVG.tar.gz
78561b571ac224030cdc450ca2986b4de915c2ba7616004a6d71a379bffd15f3 plutosvg-$PLUTOSVG.tar.gz
@@ -112,33 +112,35 @@ bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslan
cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
EOF
curl -C - -L \
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-o "QtApng-$QTAPNG.tar.gz" "https://github.com/jurplel/QtApng/archive/refs/tags/$QTAPNG.tar.gz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz" \
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
curl -L \
-O "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz" \
-O "https://github.com/harfbuzz/harfbuzz/archive/$HARFBUZZ/harfbuzz-$HARFBUZZ.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/v$MOLTENVK/MoltenVK-$MOLTENVK.tar.gz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://github.com/jurplel/QtApng/archive/$QTAPNG/QtApng-$QTAPNG.tar.gz" \
-O "https://github.com/google/shaderc/archive/v$SHADERC/shaderc-$SHADERC.tar.gz" \
-O "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG/shaderc-glslang-$SHADERC_GLSLANG.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS/shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS/KDDockWidgets-$KDDOCKWIDGETS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz"
fi
shasum -a 256 --check SHASUMS
shasum -a 256 --check --strict SHASUMS
echo "Installing SDL..."
rm -fr "$SDL"
@@ -282,7 +284,7 @@ cd ..
# MoltenVK already builds universal binaries, nothing special to do here.
echo "Installing MoltenVK..."
rm -fr "MoltenVK-${MOLTENVK}"
tar xf "v$MOLTENVK.tar.gz"
tar xf "MoltenVK-$MOLTENVK.tar.gz"
cd "MoltenVK-${MOLTENVK}"
./fetchDependencies --macos
make macos MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0 MVK_CONFIG_USE_METAL_PRIVATE_API=1
@@ -20,7 +20,7 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
QT=6.10.2
QT=6.11.0
QTAPNG=1.3.0
FREETYPE=2.14.1
@@ -59,12 +59,12 @@ CMAKE_COMMON=(
-DCMAKE_INSTALL_NAME_DIR='$<INSTALL_PREFIX>/lib'
)
cat > SHASUMS <<EOF
aeb78d29291a2b5fd53cb55950f8f5065b4978c25fb1d77f627d695ab9adf21e qtbase-everywhere-src-$QT.tar.xz
8b8f9c718638081e7b3c000e7f31910140b1202a98e98df5d1b496fe6f639d67 qtimageformats-everywhere-src-$QT.tar.xz
f07ff80f38caf235187200345392ca7479445ddf49a36c3694cd52a735dad6e1 qtsvg-everywhere-src-$QT.tar.xz
1e3d2c07c1fd76d2425c6eaeeaa62ffaff5f79210c4e1a5bc2a6a9db668d5b24 qttools-everywhere-src-$QT.tar.xz
b3b3813bc9d76b545716dc8b6e659fa71b6e2bc14569e9fab6dab8b30650a644 qttranslations-everywhere-src-$QT.tar.xz
grep . > SHASUMS <<EOF
231ad85979864d914dc9568a1b71c91d6cf20d7b2021d059103bf0eb51cb755e qtbase-everywhere-src-$QT.tar.xz
d3adb02ac5e2fe24068dbdaee0d7cc68cc3fa8553291c1bfce77c9fe8e940cc8 qtimageformats-everywhere-src-$QT.tar.xz
dfa8d653be07087d9407ed4a4ebae847f8953e0b7abd829f089803ab652a30e6 qtsvg-everywhere-src-$QT.tar.xz
cfb1993d7a10848965b01b9cf33a54b8a4ba4e5e3a6d28d59483e73f10d9fc76 qttools-everywhere-src-$QT.tar.xz
54f48b2fe4316892ff930195f170a5385644acc7393505f3155c066b8e1ffe56 qttranslations-everywhere-src-$QT.tar.xz
f1d3be3489f758efe1a8f12118a212febbe611aa670af32e0159fa3c1feab2a6 QtApng-$QTAPNG.tar.gz
32427e8c471ac095853212a37aef816c60b42052d4d9e48230bab3bdf2936ccc freetype-$FREETYPE.tar.xz
@@ -88,33 +88,35 @@ bd58dca4dac67dcf7640292d7d63e0416274d40ee2200f7301878cec11ac6647 shaderc-glslan
cabb35f4eef0da3ef72ad9edd596af4191d7507a8f35c05df526d2d5ff889f59 shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz
EOF
curl -L \
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-o "QtApng-$QTAPNG.tar.gz" "https://github.com/jurplel/QtApng/archive/refs/tags/$QTAPNG.tar.gz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \
-o "shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS.tar.gz" \
-o "KDDockWidgets-$KDDOCKWIDGETS.tar.gz" "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS.tar.gz" \
-o "plutovg-$PLUTOVG.tar.gz" "https://github.com/sammycage/plutovg/archive/v$PLUTOVG.tar.gz" \
-o "plutosvg-$PLUTOSVG.tar.gz" "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG.tar.gz"
if ! shasum -sa 256 --check SHASUMS 2> /dev/null; then
curl -L \
-O "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz" \
-O "https://github.com/harfbuzz/harfbuzz/archive/$HARFBUZZ/harfbuzz-$HARFBUZZ.tar.gz" \
-O "https://libsdl.org/release/$SDL.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://github.com/lz4/lz4/releases/download/v$LZ4/lz4-$LZ4.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
-O "https://download.sourceforge.net/libpng-apng/libpng-$LIBPNG-apng.patch.gz" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://github.com/jurplel/QtApng/archive/$QTAPNG/QtApng-$QTAPNG.tar.gz" \
-O "https://github.com/google/shaderc/archive/v$SHADERC/shaderc-$SHADERC.tar.gz" \
-O "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG/shaderc-glslang-$SHADERC_GLSLANG.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS/shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" \
-O "https://github.com/KhronosGroup/SPIRV-Tools/archive/$SHADERC_SPIRVTOOLS/shaderc-spirv-tools-$SHADERC_SPIRVTOOLS.tar.gz" \
-O "https://github.com/KDAB/KDDockWidgets/archive/v$KDDOCKWIDGETS/KDDockWidgets-$KDDOCKWIDGETS.tar.gz" \
-O "https://github.com/sammycage/plutovg/archive/v$PLUTOVG/plutovg-$PLUTOVG.tar.gz" \
-O "https://github.com/sammycage/plutosvg/archive/v$PLUTOSVG/plutosvg-$PLUTOSVG.tar.gz"
fi
shasum -a 256 --check SHASUMS
shasum -a 256 --check --strict SHASUMS
echo "Installing SDL..."
rm -fr "$SDL"
@@ -2,17 +2,24 @@
setlocal enabledelayedexpansion
echo Setting environment...
rem Favour VS2022 over VS2026 for now.
if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" (
for /f "usebackq tokens=*" %%i in (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[17, 18)" -latest -property installationPath`) do set "VSINSTPATH=%%i"
if defined VSINSTPATH (
echo VSINSTPATH=!VSINSTPATH!
call "!VSINSTPATH!\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" || goto error
) else (
echo Visual Studio 2022 not found.
goto error
for /f "usebackq tokens=*" %%i in (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[18, 19)" -latest -property installationPath`) do set "VSINSTPATH=%%i"
if defined VSINSTPATH (
echo VSINSTPATH=!VSINSTPATH!
call "!VSINSTPATH!\VC\Auxiliary\Build\vcvarsamd64_arm64.bat" || goto error
) else (
echo Visual Studio not found.
goto error
)
)
) else (
echo Visual Studio 2022 not found.
echo Visual Studio not found.
goto error
)
@@ -47,8 +54,8 @@ echo INSTALLDIR=%INSTALLDIR%
cd "%BUILDDIR%"
set QT=6.10.2
set QTMINOR=6.10
set QT=6.11.0
set QTMINOR=6.11
set QTAPNG=1.3.0
set FREETYPE=2.14.1
@@ -73,11 +80,11 @@ set SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
set AGILITYSDK=1.618.5
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 690e08ce807041150d388b5351de2e591febf0a0bc973b56e1197e2df9a2d96f || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" a407e489ca8d68639530e881aea797f58754e355ca06024a73358bd9cc5fca17 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" fd9f4f6e983a55f6b0ba4c49ce13f8b014cd30d12e75a49a478a640462f9bf64 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" a498357aed659c66aa87ceb556eacab55e3e7d7c9b9599049066de70eb7efa59 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" cf5e04a2048c02369f579c1251f61af965f241cde2d69de3db90e6c9f0ee2bf3 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 590d5ae246c85fa14d6458a36ff75a11236acfe8987c2475090aab1770acbdf8 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 5dfb3c0cb84d2c935c1716b3b86358ca496fb9216676e7e28fee1357fb4a050e || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" c92e1b46170b8671bbd46c783939f0c2dba4986882c5ebd37aaa9eba5b224fbe || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" ded4420823cb7b1bc49f38c5c56dd43ec27b6577ccbc7f620790abfabcc33b62 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" f9c4fd4fd73dff51e9043d2825b04361b678f63798ed798021ef47f1ff0bfccf || goto error
call :downloadfile "QtApng-%QTAPNG%.zip" "https://github.com/jurplel/QtApng/archive/refs/tags/%QTAPNG%.zip" 5176082cdd468047a7eb1ec1f106b032f57df207aa318d559b29606b00d159ac || goto error
call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects/freetype/files/freetype2/%FREETYPE%/freetype-%FREETYPE%.tar.gz/download 174d9e53402e1bf9ec7277e22ec199ba3e55a6be2c0740cb18c0ee9850fc8c34 || goto error
@@ -214,7 +221,7 @@ echo Building Qt base...
rmdir /S /Q "qtbase-everywhere-src-%QT%"
%SEVENZIP% x "qtbase-everywhere-src-%QT%.zip" || goto error
cd "qtbase-everywhere-src-%QT%" || goto error
cmake -B build %ARM64TOOLCHAIN% -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DQT_HOST_PATH="%X64INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON %QTBUILDSPEC% || goto error
cmake -B build %ARM64TOOLCHAIN% -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DQT_HOST_PATH="%X64INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON -DQT_FEATURE_windows_ioring=OFF %QTBUILDSPEC% || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
@@ -2,17 +2,24 @@
setlocal enabledelayedexpansion
echo Setting environment...
rem Favour VS2022 over VS2026 for now.
if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" (
for /f "usebackq tokens=*" %%i in (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[17, 18)" -latest -property installationPath`) do set "VSINSTPATH=%%i"
if defined VSINSTPATH (
echo VSINSTPATH=!VSINSTPATH!
call "!VSINSTPATH!\VC\Auxiliary\Build\vcvars64.bat" || goto error
) else (
echo Visual Studio 2022 not found.
goto error
for /f "usebackq tokens=*" %%i in (`call "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -version "[18, 19)" -latest -property installationPath`) do set "VSINSTPATH=%%i"
if defined VSINSTPATH (
echo VSINSTPATH=!VSINSTPATH!
call "!VSINSTPATH!\VC\Auxiliary\Build\vcvars64.bat" || goto error
) else (
echo Visual Studio not found.
goto error
)
)
) else (
echo Visual Studio 2022 not found.
echo Visual Studio not found.
goto error
)
@@ -54,8 +61,8 @@ set "PATH=%PATH%;%INSTALLDIR%\bin"
cd "%BUILDDIR%"
set QT=6.10.2
set QTMINOR=6.10
set QT=6.11.0
set QTMINOR=6.11
set QTAPNG=1.3.0
set FFMPEG=8.1
@@ -90,11 +97,11 @@ set SHADERC_SPIRVTOOLS=fbe4f3ad913c44fe8700545f8ffe35d1382b7093
set AGILITYSDK=1.619.0
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 690e08ce807041150d388b5351de2e591febf0a0bc973b56e1197e2df9a2d96f || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" a407e489ca8d68639530e881aea797f58754e355ca06024a73358bd9cc5fca17 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" fd9f4f6e983a55f6b0ba4c49ce13f8b014cd30d12e75a49a478a640462f9bf64 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" a498357aed659c66aa87ceb556eacab55e3e7d7c9b9599049066de70eb7efa59 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" cf5e04a2048c02369f579c1251f61af965f241cde2d69de3db90e6c9f0ee2bf3 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 590d5ae246c85fa14d6458a36ff75a11236acfe8987c2475090aab1770acbdf8 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 5dfb3c0cb84d2c935c1716b3b86358ca496fb9216676e7e28fee1357fb4a050e || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" c92e1b46170b8671bbd46c783939f0c2dba4986882c5ebd37aaa9eba5b224fbe || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" ded4420823cb7b1bc49f38c5c56dd43ec27b6577ccbc7f620790abfabcc33b62 || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" f9c4fd4fd73dff51e9043d2825b04361b678f63798ed798021ef47f1ff0bfccf || goto error
call :downloadfile "QtApng-%QTAPNG%.zip" "https://github.com/jurplel/QtApng/archive/refs/tags/%QTAPNG%.zip" 5176082cdd468047a7eb1ec1f106b032f57df207aa318d559b29606b00d159ac || goto error
call :downloadfile "ffmpeg-%FFMPEG%.tar.xz" "https://ffmpeg.org/releases/ffmpeg-%FFMPEG%.tar.xz" b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a || goto error
@@ -373,7 +380,7 @@ echo Building Qt base...
rmdir /S /Q "qtbase-everywhere-src-%QT%"
%SEVENZIP% x "qtbase-everywhere-src-%QT%.zip" || goto error
cd "qtbase-everywhere-src-%QT%" || goto error
cmake -B build -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON %QTBUILDSPEC% || goto error
cmake -B build -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON -DQT_FEATURE_windows_ioring=OFF %QTBUILDSPEC% || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error
cd .. || goto error
+11 -4
View File
@@ -105,7 +105,14 @@ jobs:
- name: Setup msbuild
if: inputs.configuration != 'CMake'
uses: microsoft/setup-msbuild@v2
uses: microsoft/setup-msbuild@v3
- name: Locate vcvars
if: inputs.configuration == 'CMake'
shell: cmd
run: |
for /f "usebackq tokens=*" %%i in (`call vswhere -latest -property installationPath`) do set "VSINSTPATH=%%i"
echo VCVARSPATH=%VSINSTPATH%\VC\Auxiliary\Build\vcvars64.bat>>%GITHUB_ENV%
- name: Download patches
shell: cmd
@@ -132,14 +139,14 @@ jobs:
id: cmake
shell: cmd
run: |
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
call "%VCVARSPATH%" || exit /b
cmake . -B build ${{ inputs.cmakeFlags }} "-DCMAKE_PREFIX_PATH=%cd%\deps" -DQT_BUILD=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DDISABLE_ADVANCE_SIMD=ON -G Ninja
- name: Build PCSX2
shell: cmd
run: |
if "${{ inputs.configuration }}"=="CMake" (
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
call "%VCVARSPATH%" || exit /b
cmake --build build --config Release || exit /b
cmake --install build --config Release || exit /b
) else (
@@ -152,7 +159,7 @@ jobs:
if: inputs.configuration == 'CMake'
shell: cmd
run: |
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
call "%VCVARSPATH%" || exit /b
set PATH=%PATH%;%GITHUB_WORKSPACE%\bin
cmake --build build --config Release --target unittests
+1 -1
View File
@@ -118,7 +118,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<div id="cubeb">
<h3>cubeb - <a href="https://github.com/mozilla/cubeb">https://github.com/mozilla/cubeb</a></h3>
<pre>
Copyright 2011 Mozilla Foundation
Copyright © 2011 Mozilla Foundation
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
+24 -2
View File
@@ -11823,6 +11823,8 @@ SCUS-97277:
SCUS-97278:
name: "NCAA Final Four 2004"
region: "NTSC-U"
speedHacks:
mvuFlag: 0 # Fixes disappearing basketball.
SCUS-97279:
name: "Jet Li - Rise to Honor"
region: "NTSC-U"
@@ -12060,6 +12062,8 @@ SCUS-97369:
SCUS-97370:
name: "NCAA Final Four 2004"
region: "NTSC-U"
speedHacks:
mvuFlag: 0 # Fixes disappearing basketball.
SCUS-97372:
name: "Jet Li - Rise to Honor [Demo]"
region: "NTSC-U"
@@ -30279,8 +30283,11 @@ SLES-55569:
name: "Silent Hill - Shattered Memories"
region: "PAL-M5"
gsHWFixes:
minimumBlendingLevel: 2 # Fixes pause menu transition.
disablePartialInvalidation: 1 # Fixes missing graphics.
halfPixelOffset: 2 # Fixes ghosting.
textureInsideRT: 1 # Fixes pause menu transition.
halfPixelOffset: 5 # Fixes post-processing and bloom misaligment.
nativeScaling: 2 # Fixes post-processing smoothness and position.
SLES-55572:
name: "Marvel Super Hero Squad"
region: "PAL-M6"
@@ -33547,6 +33554,12 @@ SLKA-25465:
name: "사일런트 힐: 섀터드 메모리즈" # Undumped on ReDump as of 2025-08-28
name-en: "Silent Hill - Shattered Memories"
region: "NTSC-K"
gsHWFixes:
minimumBlendingLevel: 2 # Fixes pause menu transition.
disablePartialInvalidation: 1 # Fixes missing graphics.
textureInsideRT: 1 # Fixes pause menu transition.
halfPixelOffset: 5 # Fixes post-processing and bloom misaligment.
nativeScaling: 2 # Fixes post-processing smoothness and position.
SLKA-25466:
name: "비트매니아 IIDX 16 엠프레스 + 프리미엄 베스트 [Disc 1 of 2 - Empress Disc]" # Undumped and unconfirmed on ReDump as of 2025-08-28
name-en: "Beatmania IIDX 16 - Empress + Premium Best [Disc 1 of 2 - Empress Disc]"
@@ -34919,6 +34932,12 @@ SLPM-55231:
name-sort: "さいれんとひる しゃったーどめもりーず"
name-en: "Silent Hill - Shattered Memories"
region: "NTSC-J"
gsHWFixes:
minimumBlendingLevel: 2 # Fixes pause menu transition.
disablePartialInvalidation: 1 # Fixes missing graphics.
textureInsideRT: 1 # Fixes pause menu transition.
halfPixelOffset: 5 # Fixes post-processing and bloom misaligment.
nativeScaling: 2 # Fixes post-processing smoothness and position.
SLPM-55233:
name: "金色のコルダ [KOEI The Best]"
name-sort: "きんいろのこるだ [KOEI The Best]"
@@ -74636,8 +74655,11 @@ SLUS-21899:
region: "NTSC-U"
compat: 5
gsHWFixes:
minimumBlendingLevel: 2 # Fixes pause menu transition.
disablePartialInvalidation: 1 # Fixes missing graphics.
halfPixelOffset: 2 # Fixes ghosting.
textureInsideRT: 1 # Fixes pause menu transition.
halfPixelOffset: 5 # Fixes post-processing and bloom misaligment.
nativeScaling: 2 # Fixes post-processing smoothness and position.
SLUS-21900:
name: "Scooby-Doo! First Frights"
region: "NTSC-U"
+7 -5
View File
@@ -140,7 +140,6 @@
03000000ad1b000001f9000000000000,BB 070,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
03000000bc2000005250000000000000,Beitong G3,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a3,righty:a4,start:b15,x:b3,y:b4,platform:Windows,
030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000bc2000000055000000000000,Betop BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000790000000700000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
@@ -386,7 +385,6 @@
030000008f0e00001300000000000000,Logic3,a:b2,b:b1,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:b3,y:b0,platform:Windows,
030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,
030000006d04000016c2000000000000,Logitech Dual Action,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,
030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006d04000018c2000000000000,Logitech F510,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,
@@ -396,6 +394,7 @@
030000006d0400001ac2000000000000,Logitech Precision,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000009c2000000000000,Logitech WingMan,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
030000006d0400000bc2000000000000,Logitech WingMan Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows,
030000006d04000011c2000000000000,Logitech WingMan Cordless,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,
030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,
03000000380700005645000000000000,Lynx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000222200006000000000000000,Macally,a:b1,b:b2,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,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,
@@ -486,6 +485,7 @@
03000000ec110000e1a7000000000000,Nintendo Switch,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000007e0500006920000000000000,Nintendo Switch 2 Pro Controller,a:b0,b:b1,back:b14,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b12,leftstick:b15,lefttrigger:b13,leftx:a0,lefty:a1~,misc1:b17,misc2:b20,paddle1:b18,paddle2:b19,rightshoulder:b4,rightstick:b7,righttrigger:b5,rightx:a2,righty:a3~,start:b6,x:b2,y:b3,platform:Windows,
030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
030000000d0500000208000000000000,Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows,
030000007e0500007320000000000000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Windows,
030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,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:Windows,
@@ -942,6 +942,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000120c0000200e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
03000000120c0000210e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
030000008305000031b0000000000000,Cideko AK08b,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:Mac OS X,
03000000501d00009e61000001000000,CoreOrbits GamerPad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000d8140000cecf000000000000,Cthulhu,a:b1,b:b2,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:b0,y:b3,platform:Mac OS X,
03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,
03000000a306000022f6000001030000,Cyborg V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -1337,6 +1338,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
03000000373500009710000001020000,GameSir Kaleid Flux,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
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,
03000000373500000410000044010000,GameSir T4 Kaleid,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
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,
03000000373500009410000010010000,GameSir Tegenaria Lite,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
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,
@@ -1434,7 +1436,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,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,
030000006d04000016c2000010010000,Logitech Dual Action,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,
030000006d04000016c2000011010000,Logitech Dual Action,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,
030000006d0400001dc2000014400000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1443,7 +1444,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006d04000019c2000011010000,Logitech F710,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,
030000006d0400001fc2000005030000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d04000018c2000010010000,Logitech RumblePad 2,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,
030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,
030000006d04000019c2000010010000,Logitech RumblePad 2,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,
030000006d04000011c2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,
030000006d0400000ac2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,
05000000380700006652000025010000,Mad Catz CTRLR,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,
03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -1546,7 +1548,7 @@ 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,
050000005a1d00000218000003000000,Nokia GC 5000,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
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,
030000000d0500000308000010010000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux,
030000007e0500007320000011010000,NSO GameCube Controller,a:b1,b:b3,dpdown:b8,dpleft:b10,dpright:b9,dpup:b11,guide:b16,leftshoulder:b13,lefttrigger:b12,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b4,rightx:a2,righty:a3~,start:b6,x:b0,y:b2,platform:Linux,
030000007e0500001920000011810000,NSO N64 Controller,+rightx:b2,+righty:b3,-rightx:b4,-righty:b10,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b5,rightshoulder:b7,righttrigger:b9,start:b11,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,
+1
View File
@@ -149,6 +149,7 @@ elseif(APPLE)
Darwin/DarwinThreads.cpp
Darwin/DarwinMisc.cpp
Darwin/DarwinMisc.h
Linux/LnxHostSys.cpp
)
target_compile_options(common PRIVATE -fobjc-arc)
target_link_options(common PRIVATE -fobjc-link-runtime)
+18 -218
View File
@@ -17,19 +17,13 @@
#include <cstring>
#include <cstdlib>
#include <optional>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <thread>
#include <time.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/mach_time.h>
#include <mach/mach_vm.h>
#include <mach/message.h>
#include <mach/task.h>
#include <mach/thread_state.h>
#include <mach/vm_map.h>
#include <mutex>
#include <ApplicationServices/ApplicationServices.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
@@ -298,7 +292,7 @@ static CPUInfo CalcCPUInfo()
std::vector<DarwinMisc::CPUClass> classes = DarwinMisc::GetCPUClasses();
out.num_clusters = static_cast<u32>(classes.size());
out.num_big_cores = classes.empty() ? 0 : classes[0].num_physical;
out.num_threads = classes.empty() ? 0 : classes[0].num_logical;
out.num_threads = classes.empty() ? 0 : classes[0].num_logical;
out.num_small_cores = 0;
for (std::size_t i = 1; i < classes.size(); i++)
{
@@ -324,200 +318,6 @@ size_t HostSys::GetRuntimeCacheLineSize()
return static_cast<size_t>(std::max<s64>(sysctlbyname_T<s64>("hw.cachelinesize").value_or(0), 0));
}
static __ri vm_prot_t MachProt(const PageProtectionMode& mode)
{
vm_prot_t machmode = (mode.CanWrite()) ? VM_PROT_WRITE : 0;
machmode |= (mode.CanRead()) ? VM_PROT_READ : 0;
machmode |= (mode.CanExecute()) ? (VM_PROT_EXECUTE | VM_PROT_READ) : 0;
return machmode;
}
void* HostSys::Mmap(void* base, size_t size, const PageProtectionMode& mode)
{
pxAssertMsg((size & (__pagesize - 1)) == 0, "Size is page aligned");
if (mode.IsNone())
return nullptr;
#ifdef ARCH_ARM64
// We can't allocate executable memory with mach_vm_allocate() on Apple Silicon.
// Instead, we need to use MAP_JIT with mmap(), which does not support fixed mappings.
if (mode.CanExecute())
{
if (base)
return nullptr;
const u32 mmap_prot = mode.CanWrite() ? (PROT_READ | PROT_WRITE | PROT_EXEC) : (PROT_READ | PROT_EXEC);
const u32 flags = MAP_PRIVATE | MAP_ANON | MAP_JIT;
void* const res = mmap(nullptr, size, mmap_prot, flags, -1, 0);
return (res == MAP_FAILED) ? nullptr : res;
}
#endif
kern_return_t ret = mach_vm_allocate(mach_task_self(), reinterpret_cast<mach_vm_address_t*>(&base), size,
base ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE);
if (ret != KERN_SUCCESS)
{
DEV_LOG("mach_vm_allocate() returned {}", ret);
return nullptr;
}
ret = mach_vm_protect(mach_task_self(), reinterpret_cast<mach_vm_address_t>(base), size, false, MachProt(mode));
if (ret != KERN_SUCCESS)
{
DEV_LOG("mach_vm_protect() returned {}", ret);
mach_vm_deallocate(mach_task_self(), reinterpret_cast<mach_vm_address_t>(base), size);
return nullptr;
}
return base;
}
void HostSys::Munmap(void* base, size_t size)
{
if (!base)
return;
mach_vm_deallocate(mach_task_self(), reinterpret_cast<mach_vm_address_t>(base), size);
}
void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
{
pxAssertMsg((size & (__pagesize - 1)) == 0, "Size is page aligned");
kern_return_t res = mach_vm_protect(mach_task_self(), reinterpret_cast<mach_vm_address_t>(baseaddr), size, false,
MachProt(mode));
if (res != KERN_SUCCESS) [[unlikely]]
{
ERROR_LOG("mach_vm_protect() failed: {}", res);
pxFailRel("mach_vm_protect() failed");
}
}
std::string HostSys::GetFileMappingName(const char* prefix)
{
// name actually is not used.
return {};
}
void* HostSys::CreateSharedMemory(const char* name, size_t size)
{
mach_vm_size_t vm_size = size;
mach_port_t port;
const kern_return_t res = mach_make_memory_entry_64(
mach_task_self(), &vm_size, 0, MAP_MEM_NAMED_CREATE | VM_PROT_READ | VM_PROT_WRITE, &port, MACH_PORT_NULL);
if (res != KERN_SUCCESS)
{
ERROR_LOG("mach_make_memory_entry_64() failed: {}", res);
return nullptr;
}
return reinterpret_cast<void*>(static_cast<uintptr_t>(port));
}
void HostSys::DestroySharedMemory(void* ptr)
{
mach_port_deallocate(mach_task_self(), static_cast<mach_port_t>(reinterpret_cast<uintptr_t>(ptr)));
}
void* HostSys::MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode)
{
mach_vm_address_t ptr = reinterpret_cast<mach_vm_address_t>(baseaddr);
const kern_return_t res = mach_vm_map(mach_task_self(), &ptr, size, 0, baseaddr ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE,
static_cast<mach_port_t>(reinterpret_cast<uintptr_t>(handle)), offset, FALSE,
MachProt(mode), VM_PROT_READ | VM_PROT_WRITE, VM_INHERIT_NONE);
if (res != KERN_SUCCESS)
{
ERROR_LOG("mach_vm_map() failed: {}", res);
return nullptr;
}
return reinterpret_cast<void*>(ptr);
}
void HostSys::UnmapSharedMemory(void* baseaddr, size_t size)
{
const kern_return_t res = mach_vm_deallocate(mach_task_self(), reinterpret_cast<mach_vm_address_t>(baseaddr), size);
if (res != KERN_SUCCESS)
pxFailRel("Failed to unmap shared memory");
}
#ifdef ARCH_ARM64
void HostSys::FlushInstructionCache(void* address, u32 size)
{
__builtin___clear_cache(reinterpret_cast<char*>(address), reinterpret_cast<char*>(address) + size);
}
#endif
SharedMemoryMappingArea::SharedMemoryMappingArea(u8* base_ptr, size_t size, size_t num_pages)
: m_base_ptr(base_ptr)
, m_size(size)
, m_num_pages(num_pages)
{
}
SharedMemoryMappingArea::~SharedMemoryMappingArea()
{
pxAssertRel(m_num_mappings == 0, "No mappings left");
if (mach_vm_deallocate(mach_task_self(), reinterpret_cast<mach_vm_address_t>(m_base_ptr), m_size) != KERN_SUCCESS)
pxFailRel("Failed to release shared memory area");
}
std::unique_ptr<SharedMemoryMappingArea> SharedMemoryMappingArea::Create(size_t size)
{
pxAssertRel(Common::IsAlignedPow2(size, __pagesize), "Size is page aligned");
mach_vm_address_t alloc = 0;
const kern_return_t res =
mach_vm_map(mach_task_self(), &alloc, size, 0, VM_FLAGS_ANYWHERE,
MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_NONE);
if (res != KERN_SUCCESS)
{
ERROR_LOG("mach_vm_map() failed: {}", res);
return {};
}
return std::unique_ptr<SharedMemoryMappingArea>(new SharedMemoryMappingArea(reinterpret_cast<u8*>(alloc), size, size / __pagesize));
}
u8* SharedMemoryMappingArea::Map(void* file_handle, size_t file_offset, void* map_base, size_t map_size, const PageProtectionMode& mode)
{
pxAssert(static_cast<u8*>(map_base) >= m_base_ptr && static_cast<u8*>(map_base) < (m_base_ptr + m_size));
const kern_return_t res =
mach_vm_map(mach_task_self(), reinterpret_cast<mach_vm_address_t*>(&map_base), map_size, 0, VM_FLAGS_OVERWRITE,
static_cast<mach_port_t>(reinterpret_cast<uintptr_t>(file_handle)), file_offset, false,
MachProt(mode), VM_PROT_READ | VM_PROT_WRITE, VM_INHERIT_NONE);
if (res != KERN_SUCCESS) [[unlikely]]
{
ERROR_LOG("mach_vm_map() failed: {}", res);
return nullptr;
}
m_num_mappings++;
return static_cast<u8*>(map_base);
}
bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size)
{
pxAssert(static_cast<u8*>(map_base) >= m_base_ptr && static_cast<u8*>(map_base) < (m_base_ptr + m_size));
const kern_return_t res =
mach_vm_map(mach_task_self(), reinterpret_cast<mach_vm_address_t*>(&map_base), map_size, 0, VM_FLAGS_OVERWRITE,
MEMORY_OBJECT_NULL, 0, false, VM_PROT_NONE, VM_PROT_NONE, VM_INHERIT_NONE);
if (res != KERN_SUCCESS) [[unlikely]]
{
ERROR_LOG("mach_vm_map() failed: {}", res);
return false;
}
m_num_mappings--;
return true;
}
#ifdef ARCH_ARM64
static thread_local int s_code_write_depth = 0;
@@ -578,6 +378,7 @@ namespace PageFaultHandler
{
#ifdef USE_MACH_EXCEPTION_PORTS
static void SignalHandler(mach_port_t port);
static mach_port_t s_port = 0;
#else
static void SignalHandler(int sig, siginfo_t* info, void* ctx);
#endif
@@ -661,7 +462,6 @@ void PageFaultHandler::SignalHandler(mach_port_t port)
return;
}
s_exception_handler_mutex.lock();
thread_state64_t* state = (thread_state64_t*)msg_in.old_state;
HandlerResult result = HandlerResult::ExecuteNextHandler;
@@ -686,15 +486,10 @@ void PageFaultHandler::SignalHandler(mach_port_t port)
if (result != HandlerResult::ContinueExecution) // cooked
{
// Continue to the next exception handler (debugger or crash)
msg_out.RetCode = KERN_FAILURE;
msg_out.flavor = 0;
msg_out.new_stateCnt = 0;
// The crash handler on macOS or Linux doesn't use context passed to it
// Stubbing it here is fine
CrashHandler::CrashSignalHandler(-1, nullptr, nullptr);
pxFailRel("CrashSignalHandler returned when it should have terminated us!");
}
else
{
@@ -709,8 +504,6 @@ void PageFaultHandler::SignalHandler(mach_port_t port)
offsetof(__typeof__(msg_out), new_state) + msg_out.new_stateCnt * sizeof(natural_t);
send_size = msg_out.Head.msgh_size;
option |= MACH_SEND_MSG;
s_exception_handler_mutex.unlock();
}
}
@@ -751,22 +544,27 @@ bool PageFaultHandler::Install(Error* error)
return false;
}
if ((r = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, -1)))
{
mach_port_deallocate(mach_task_self(), port);
pxFailRel(fmt::format("mach_port_mod_refs: {:x}", r).c_str());
return false;
}
mach_port_t previous;
if ((r = mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_NO_SENDERS, 0, port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous)))
{
mach_port_deallocate(mach_task_self(), port);
pxFailRel(fmt::format("mach_port_mod_refs: {:x}", r).c_str());
pxFailRel(fmt::format("mach_port_request_notification: {:x}", r).c_str());
return false;
}
s_installed = true;
s_port = port;
return true;
}
bool PageFaultHandler::InstallSecondaryThread()
{
kern_return_t r = thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, s_port, EXCEPTION_STATE | MACH_EXCEPTION_CODES, THREAD_STATE64);
if (r)
{
pxFailRel(fmt::format("thread_set_exception_ports(secondary): {:x}", r).c_str());
return false;
}
return true;
}
@@ -839,4 +637,6 @@ bool PageFaultHandler::Install(Error* error)
s_installed = true;
return true;
}
bool PageFaultHandler::InstallSecondaryThread() { return true; }
#endif
+3 -11
View File
@@ -91,20 +91,11 @@ static __fi PageProtectionMode PageAccess_Any()
// --------------------------------------------------------------------------------------
namespace HostSys
{
// Maps a block of memory for use as a recompiled code buffer.
// Returns NULL on allocation failure.
extern void* Mmap(void* base, size_t size, const PageProtectionMode& mode);
// Unmaps a block allocated by SysMmap
extern void Munmap(void* base, size_t size);
extern void MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode);
extern std::string GetFileMappingName(const char* prefix);
extern void* CreateSharedMemory(const char* name, size_t size);
extern void DestroySharedMemory(void* ptr);
extern void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode);
extern void UnmapSharedMemory(void* baseaddr, size_t size);
/// JIT write protect for Apple Silicon. Needs to be called prior to writing to any RWX pages.
#if !defined(__APPLE__) || !defined(ARCH_ARM64)
@@ -142,12 +133,13 @@ namespace PageFaultHandler
HandlerResult HandlePageFault(void* exception_pc, void* fault_address, bool is_write);
bool Install(Error* error = nullptr);
bool InstallSecondaryThread();
} // namespace PageFaultHandler
class SharedMemoryMappingArea
{
public:
static std::unique_ptr<SharedMemoryMappingArea> Create(size_t size);
static std::unique_ptr<SharedMemoryMappingArea> Create(size_t size, bool jit = false);
~SharedMemoryMappingArea();
@@ -159,7 +151,7 @@ public:
__fi u8* PagePointer(size_t page) const { return m_base_ptr + __pagesize * page; }
u8* Map(void* file_handle, size_t file_offset, void* map_base, size_t map_size, const PageProtectionMode& mode);
bool Unmap(void* map_base, size_t map_size);
bool Unmap(void* map_base, size_t map_size, bool is_file = true);
private:
SharedMemoryMappingArea(u8* base_ptr, size_t size, size_t num_pages);
+46 -61
View File
@@ -14,8 +14,10 @@
#include <fcntl.h>
#include <mutex>
#include <sys/mman.h>
#include <ucontext.h>
#include <unistd.h>
#ifndef __APPLE__
#include <ucontext.h>
#endif
#include "fmt/format.h"
@@ -23,12 +25,6 @@
#include "cpuinfo.h"
#endif
// FreeBSD does not have MAP_FIXED_NOREPLACE, but does have MAP_EXCL.
// MAP_FIXED combined with MAP_EXCL behaves like MAP_FIXED_NOREPLACE.
#if defined(__FreeBSD__) && !defined(MAP_FIXED_NOREPLACE)
#define MAP_FIXED_NOREPLACE (MAP_FIXED | MAP_EXCL)
#endif
static __ri uint LinuxProt(const PageProtectionMode& mode)
{
u32 lnxmode = 0;
@@ -43,34 +39,6 @@ static __ri uint LinuxProt(const PageProtectionMode& mode)
return lnxmode;
}
void* HostSys::Mmap(void* base, size_t size, const PageProtectionMode& mode)
{
pxAssertMsg((size & (__pagesize - 1)) == 0, "Size is page aligned");
if (mode.IsNone())
return nullptr;
const u32 prot = LinuxProt(mode);
u32 flags = MAP_PRIVATE | MAP_ANONYMOUS;
if (base)
flags |= MAP_FIXED_NOREPLACE;
void* res = mmap(base, size, prot, flags, -1, 0);
if (res == MAP_FAILED)
return nullptr;
return res;
}
void HostSys::Munmap(void* base, size_t size)
{
if (!base)
return;
munmap((void*)base, size);
}
void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
{
pxAssertMsg((size & (__pagesize - 1)) == 0, "Size is page aligned");
@@ -120,23 +88,7 @@ void HostSys::DestroySharedMemory(void* ptr)
close(static_cast<int>(reinterpret_cast<intptr_t>(ptr)));
}
void* HostSys::MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode)
{
const uint lnxmode = LinuxProt(mode);
const int flags = (baseaddr != nullptr) ? (MAP_SHARED | MAP_FIXED_NOREPLACE) : MAP_SHARED;
void* ptr = mmap(baseaddr, size, lnxmode, flags, static_cast<int>(reinterpret_cast<intptr_t>(handle)), static_cast<off_t>(offset));
if (ptr == MAP_FAILED)
return nullptr;
return ptr;
}
void HostSys::UnmapSharedMemory(void* baseaddr, size_t size)
{
if (munmap(baseaddr, size) != 0)
pxFailRel("Failed to unmap shared memory");
}
#ifndef __APPLE__
size_t HostSys::GetRuntimePageSize()
{
@@ -183,6 +135,8 @@ size_t HostSys::GetRuntimeCacheLineSize()
#endif
}
#endif
SharedMemoryMappingArea::SharedMemoryMappingArea(u8* base_ptr, size_t size, size_t num_pages)
: m_base_ptr(base_ptr)
, m_size(size)
@@ -199,11 +153,16 @@ SharedMemoryMappingArea::~SharedMemoryMappingArea()
}
std::unique_ptr<SharedMemoryMappingArea> SharedMemoryMappingArea::Create(size_t size)
std::unique_ptr<SharedMemoryMappingArea> SharedMemoryMappingArea::Create(size_t size, bool jit)
{
pxAssertRel(Common::IsAlignedPow2(size, __pagesize), "Size is page aligned");
void* alloc = mmap(nullptr, size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
uint flags = MAP_ANONYMOUS | MAP_PRIVATE;
#ifdef __APPLE__
if (jit)
flags |= MAP_JIT;
#endif
void* alloc = mmap(nullptr, size, PROT_NONE, flags, -1, 0);
if (alloc == MAP_FAILED)
return nullptr;
@@ -214,18 +173,29 @@ u8* SharedMemoryMappingArea::Map(void* file_handle, size_t file_offset, void* ma
{
pxAssert(static_cast<u8*>(map_base) >= m_base_ptr && static_cast<u8*>(map_base) < (m_base_ptr + m_size));
// MAP_FIXED is okay here, since we've reserved the entire region, and *want* to overwrite the mapping.
const uint lnxmode = LinuxProt(mode);
void* const ptr = mmap(map_base, map_size, lnxmode, MAP_SHARED | MAP_FIXED,
static_cast<int>(reinterpret_cast<intptr_t>(file_handle)), static_cast<off_t>(file_offset));
if (ptr == MAP_FAILED)
return nullptr;
if (file_handle)
{
const int fd = static_cast<int>(reinterpret_cast<intptr_t>(file_handle));
// MAP_FIXED is okay here, since we've reserved the entire region, and *want* to overwrite the mapping.
void* const ptr = mmap(map_base, map_size, lnxmode, MAP_SHARED | MAP_FIXED, fd, static_cast<off_t>(file_offset));
if (ptr == MAP_FAILED)
return nullptr;
}
else
{
// macOS doesn't seem to allow MAP_JIT with MAP_FIXED
// So we do the MAP_JIT in the allocation, and just mprotect here
// Note that this will only work the first time for a given region
if (mprotect(map_base, map_size, lnxmode) < 0)
return nullptr;
}
m_num_mappings++;
return static_cast<u8*>(ptr);
return static_cast<u8*>(map_base);
}
bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size)
bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size, bool is_file)
{
pxAssert(static_cast<u8*>(map_base) >= m_base_ptr && static_cast<u8*>(map_base) < (m_base_ptr + m_size));
@@ -236,6 +206,17 @@ bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size)
return true;
}
#ifdef ARCH_ARM64
void HostSys::FlushInstructionCache(void* address, u32 size)
{
__builtin___clear_cache(reinterpret_cast<char*>(address), reinterpret_cast<char*>(address) + size);
}
#endif
#ifndef __APPLE__ // These are done in DarwinMisc
namespace PageFaultHandler
{
static std::recursive_mutex s_exception_handler_mutex;
@@ -370,3 +351,7 @@ bool PageFaultHandler::Install(Error* error)
s_installed = true;
return true;
}
bool PageFaultHandler::InstallSecondaryThread() { return true; }
#endif // __APPLE__
+34 -48
View File
@@ -34,22 +34,6 @@ static DWORD ConvertToWinApi(const PageProtectionMode& mode)
return winmode;
}
void* HostSys::Mmap(void* base, size_t size, const PageProtectionMode& mode)
{
if (mode.IsNone())
return nullptr;
return VirtualAlloc(base, size, MEM_RESERVE | MEM_COMMIT, ConvertToWinApi(mode));
}
void HostSys::Munmap(void* base, size_t size)
{
if (!base)
return;
VirtualFree((void*)base, 0, MEM_RELEASE);
}
void HostSys::MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode)
{
pxAssert((size & (__pagesize - 1)) == 0);
@@ -76,29 +60,6 @@ void HostSys::DestroySharedMemory(void* ptr)
CloseHandle(static_cast<HANDLE>(ptr));
}
void* HostSys::MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode)
{
void* ret = MapViewOfFileEx(static_cast<HANDLE>(handle), FILE_MAP_READ | FILE_MAP_WRITE,
static_cast<DWORD>(offset >> 32), static_cast<DWORD>(offset), size, baseaddr);
if (!ret)
return nullptr;
const DWORD prot = ConvertToWinApi(mode);
if (prot != PAGE_READWRITE)
{
DWORD old_prot;
if (!VirtualProtect(ret, size, prot, &old_prot))
pxFail("Failed to protect memory mapping");
}
return ret;
}
void HostSys::UnmapSharedMemory(void* baseaddr, size_t size)
{
if (!UnmapViewOfFile(baseaddr))
pxFail("Failed to unmap shared memory");
}
size_t HostSys::GetRuntimePageSize()
{
SYSTEM_INFO si = {};
@@ -182,7 +143,7 @@ SharedMemoryMappingArea::PlaceholderMap::iterator SharedMemoryMappingArea::FindP
return m_placeholder_ranges.end();
}
std::unique_ptr<SharedMemoryMappingArea> SharedMemoryMappingArea::Create(size_t size)
std::unique_ptr<SharedMemoryMappingArea> SharedMemoryMappingArea::Create(size_t size, bool jit)
{
pxAssertRel(Common::IsAlignedPow2(size, __pagesize), "Size is page aligned");
@@ -240,11 +201,22 @@ u8* SharedMemoryMappingArea::Map(void* file_handle, size_t file_offset, void* ma
}
// actually do the mapping, replacing the placeholder on the range
if (!MapViewOfFile3(static_cast<HANDLE>(file_handle), GetCurrentProcess(),
map_base, file_offset, map_size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0))
if (file_handle)
{
Console.Error("(SharedMemoryMappingArea) MapViewOfFile3() failed: %u", GetLastError());
return nullptr;
if (!MapViewOfFile3(static_cast<HANDLE>(file_handle), GetCurrentProcess(),
map_base, file_offset, map_size, MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0))
{
Console.Error("(SharedMemoryMappingArea) MapViewOfFile3() failed: %u", GetLastError());
return nullptr;
}
}
else
{
if (!VirtualAlloc2(GetCurrentProcess(), map_base, map_size, MEM_RESERVE | MEM_COMMIT | MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0))
{
Console.Error("(SharedMemoryMappingArea) VirtualAlloc2() failed: %u", GetLastError());
return nullptr;
}
}
const DWORD prot = ConvertToWinApi(mode);
@@ -259,7 +231,7 @@ u8* SharedMemoryMappingArea::Map(void* file_handle, size_t file_offset, void* ma
return static_cast<u8*>(map_base);
}
bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size)
bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size, bool is_file)
{
pxAssert(static_cast<u8*>(map_base) >= m_base_ptr && static_cast<u8*>(map_base) < (m_base_ptr + m_size));
@@ -268,10 +240,22 @@ bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size)
pxAssert(Common::IsAlignedPow2(map_size, __pagesize));
// unmap the specified range
if (!UnmapViewOfFile2(GetCurrentProcess(), map_base, MEM_PRESERVE_PLACEHOLDER))
if (is_file)
{
Console.Error("(SharedMemoryMappingArea) UnmapViewOfFile2() failed: %u", GetLastError());
return false;
if (!UnmapViewOfFile2(GetCurrentProcess(), map_base, MEM_PRESERVE_PLACEHOLDER))
{
Console.Error("(SharedMemoryMappingArea) UnmapViewOfFile2() failed: %u", GetLastError());
return false;
}
}
else
{
// For some reason Windows wants you to alloc with RESERVE | COMMIT but free with just RELEASE
if (!VirtualFreeEx(GetCurrentProcess(), map_base, map_size, MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER))
{
Console.Error("(SharedMemoryMappingArea) VirtualFreeEx() failed: %u", GetLastError());
return false;
}
}
// can we coalesce to the left?
@@ -373,3 +357,5 @@ bool PageFaultHandler::Install(Error* error)
s_installed = true;
return true;
}
bool PageFaultHandler::InstallSecondaryThread() { return true; }
+52 -6
View File
@@ -49,6 +49,7 @@
thread_local u8* x86Ptr;
thread_local u8* xTextPtr;
thread_local XMMSSEType g_xmmtypes[iREGCNT_XMM] = {XMMT_INT};
bool x86Emitter::use_avx;
@@ -297,13 +298,27 @@ const xRegister32
void EmitSibMagic(uint regfield, const void* address, int extraRIPOffset)
{
sptr displacement = (sptr)address;
sptr textRelative = (sptr)address - (sptr)xTextPtr;
sptr ripRelative = (sptr)address - ((sptr)x86Ptr + sizeof(s8) + sizeof(s32) + extraRIPOffset);
// Can we use an 8-bit offset from the text pointer?
if (textRelative == (s8)textRelative && xTextPtr)
{
ModRM(1, regfield, RTEXTPTR.GetId());
xWrite<s8>((s8)textRelative);
return;
}
// Can we use a rip-relative address? (Prefer this over eiz because it's a byte shorter)
if (ripRelative == (s32)ripRelative)
else if (ripRelative == (s32)ripRelative)
{
ModRM(0, regfield, ModRm_UseDisp32);
displacement = ripRelative;
}
// How about from the text pointer?
else if (textRelative == (s32)textRelative && xTextPtr)
{
ModRM(2, regfield, RTEXTPTR.GetId());
displacement = textRelative;
}
else
{
pxAssertMsg(displacement == (s32)displacement, "SIB target is too far away, needs an indirect register");
@@ -664,6 +679,12 @@ const xRegister32
x86Ptr = (u8*)ptr;
}
// Assigns the current emitter text base address.
__emitinline void xSetTextPtr(void* ptr)
{
xTextPtr = (u8*)ptr;
}
// Retrieves the current emitter buffer target address.
// This is provided instead of using x86Ptr directly, since we may in the future find
// a need to change the storage class system for the x86Ptr 'under the hood.'
@@ -672,6 +693,12 @@ const xRegister32
return x86Ptr;
}
// Retrieves the current emitter text base address.
__emitinline u8* xGetTextPtr()
{
return xTextPtr;
}
__emitinline void xAlignPtr(uint bytes)
{
// forward align
@@ -1362,6 +1389,8 @@ const xRegister32
// Align for any following instructions
stackAlign(m_offset, true);
#endif
if (u8* ptr = xGetTextPtr())
xLoadFarAddr(RTEXTPTR, ptr);
}
xScopedStackFrame::~xScopedStackFrame()
@@ -1423,11 +1452,14 @@ const xRegister32
{
return offset + base;
}
else
if (u8* ptr = xGetTextPtr())
{
xLEA(tmpRegister, ptr[base]);
return offset + tmpRegister;
sptr tbase = (sptr)base - (sptr)ptr;
if (tbase == (s32)tbase)
return offset + RTEXTPTR + tbase;
}
xLEA(tmpRegister, ptr[base]);
return offset + tmpRegister;
}
void xLoadFarAddr(const xAddressReg& dst, void* addr)
@@ -1435,9 +1467,23 @@ const xRegister32
sptr iaddr = (sptr)addr;
sptr rip = (sptr)xGetPtr() + 7; // LEA will be 7 bytes
sptr disp = iaddr - rip;
if (disp == (s32)disp)
u8* textPtr = xGetTextPtr();
sptr textdisp = iaddr - (sptr)textPtr;
bool isRTextPtr = dst == RTEXTPTR;
bool canUseTextPtr = textPtr && !isRTextPtr;
if (disp == (s32)disp || (canUseTextPtr && (textdisp == (s32)textdisp)))
{
xLEA(dst, ptr[addr]);
if (isRTextPtr && textPtr)
{
// Prevent LEA from trying to use RTEXTPTR to load RTEXTPTR
xSetTextPtr(nullptr);
xLEA(dst, ptr[addr]);
xSetTextPtr(textPtr);
}
else
{
xLEA(dst, ptr[addr]);
}
}
else
{
+4
View File
@@ -135,11 +135,13 @@ namespace x86Emitter
static const int Sib_UseDisp32 = 5; // same index value as EBP (used in Base field)
extern void xSetPtr(void* ptr);
extern void xSetTextPtr(void* ptr);
extern void xAlignPtr(uint bytes);
extern void xAdvancePtr(uint bytes);
extern void xAlignCallTarget();
extern u8* xGetPtr();
extern u8* xGetTextPtr();
extern u8* xGetAlignedCallTarget();
extern JccComparisonType xInvertCond(JccComparisonType src);
@@ -632,6 +634,8 @@ extern const xRegister32
calleeSavedReg1d,
calleeSavedReg2d;
/// Holds a pointer to program text at all times so we don't need to be within 2GB of text
static constexpr const xAddressReg& RTEXTPTR = rbx;
// clang-format on
-2
View File
@@ -974,8 +974,6 @@ int main(int argc, char* argv[])
if (!GSRunner::ParseCommandLineArgs(argc, argv, params))
return EXIT_FAILURE;
SysMemory::ReserveMemory();
if (s_use_window.value_or(true) && !GSRunner::CreatePlatformWindow())
{
Console.Error("Failed to create window.");
+11 -6
View File
@@ -576,8 +576,11 @@ void GameListWidget::onListViewContextMenuRequested(const QPoint& point)
void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
{
QHeaderView* const header = m_table_view->horizontalHeader();
QMenu menu(this);
QHeaderView* header = m_table_view->horizontalHeader();
QMenu* menu = new QMenu(this);
menu->setAttribute(Qt::WA_DeleteOnClose);
// Iterate through all available columns defined in the model.
for (int column = 0; column < GameListModel::Column_Count; column++)
{
@@ -586,7 +589,7 @@ void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
continue;
// Create a checkable menu item for each column title.
const QString title = m_model->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString();
QAction* const action = menu.addAction(title);
QAction* const action = menu->addAction(title);
action->setCheckable(true);
action->setChecked(!header->isSectionHidden(column));
// Update the GUI when the user toggles a column with left-click actions in the right-click menu on the column.
@@ -599,12 +602,14 @@ void GameListWidget::onTableViewHeaderContextMenuRequested(const QPoint& point)
});
}
menu.addSeparator();
menu->addSeparator();
// Add a "panic button" that fully restores the default column layout.
// This allows users to recover without editing configuration files such as [GameListTableView] has a key with
// and variable HeaderState which you can remove the line to also do the same effect but old method is not user-friendly.
menu.addAction(tr("Reset All Columns"), this, &GameListWidget::resetTableHeaderToDefault);
menu.exec(m_table_view->viewport()->mapToGlobal(point));
menu->addAction(tr("Reset All Columns"), this, &GameListWidget::resetTableHeaderToDefault);
menu->popup(header->mapToGlobal(point));
}
void GameListWidget::onCoverScaleChanged()
+1 -1
View File
@@ -2861,7 +2861,7 @@ SettingsWindow* MainWindow::getSettingsWindow()
connect(m_settings_window->getInterfaceSettingsWidget(), &InterfaceSettingsWidget::themeChanged, this, &MainWindow::onThemeChanged);
connect(m_settings_window->getInterfaceSettingsWidget(), &InterfaceSettingsWidget::languageChanged, this, &MainWindow::onLanguageChanged);
connect(m_settings_window->getInterfaceSettingsWidget(), &InterfaceSettingsWidget::backgroundChanged, m_game_list_widget, [this] { m_game_list_widget->setCustomBackground(); });
connect(m_settings_window->getGameListSettingsWidget(), &GameListSettingsWidget::preferEnglishGameListChanged, this, [] {
connect(m_settings_window->getInterfaceSettingsWidget(), &InterfaceSettingsWidget::preferEnglishGameListChanged, this, [] {
g_main_window->m_game_list_widget->refreshGridCovers();
Host::RunOnGSThread([] { FullscreenUI::PreferEnglishGameListChanged(); });
});
-2
View File
@@ -2411,8 +2411,6 @@ int main(int argc, char* argv[])
if (!QtHost::ParseCommandLineOptions(app.arguments(), autoboot))
return EXIT_FAILURE;
SysMemory::ReserveMemory();
// Bail out if we can't find any config.
if (!QtHost::InitializeConfig())
return EXIT_FAILURE;
@@ -15,21 +15,12 @@
#include "MainWindow.h"
#include "QtHost.h"
#include "QtUtils.h"
#include "SettingWidgetBinder.h"
GameListSettingsWidget::GameListSettingsWidget(SettingsWindow* settings_dialog, QWidget* parent)
: SettingsWidget(settings_dialog, parent)
{
SettingsInterface* sif = dialog()->getSettingsInterface();
setupTab(m_ui);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.preferEnglishGameList, "UI", "PreferEnglishGameList", false);
connect(m_ui.preferEnglishGameList, &QCheckBox::checkStateChanged, this, [this] { emit preferEnglishGameListChanged(); });
dialog()->registerWidgetHelp(m_ui.preferEnglishGameList, tr("Prefer English Titles"), tr("Unchecked"),
tr("For games with both a title in the game's native language and one in English, prefer the English title."));
m_ui.searchDirectoryList->setSelectionMode(QAbstractItemView::SingleSelection);
m_ui.searchDirectoryList->setSelectionBehavior(QAbstractItemView::SelectRows);
m_ui.searchDirectoryList->setAlternatingRowColors(true);
@@ -20,9 +20,6 @@ public:
bool addExcludedPath(const std::string& path);
void refreshExclusionList();
Q_SIGNALS:
void preferEnglishGameListChanged();
public Q_SLOTS:
void addSearchDirectory(QWidget* parent_widget);
+7 -24
View File
@@ -10,7 +10,7 @@
<height>800</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,0">
<layout class="QVBoxLayout" name="verticalLayout" stretch="1">
<property name="leftMargin">
<number>0</number>
</property>
@@ -36,12 +36,12 @@
<property name="text">
<string>Search Directories (will be scanned for games)</string>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
<property name="buddy">
<cstring>searchDirectoryList</cstring>
</property>
<property name="textInteractionFlags">
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
<item>
@@ -118,12 +118,12 @@
<property name="text">
<string>Excluded Paths (will not be scanned)</string>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
<property name="buddy">
<cstring>excludedPaths</cstring>
</property>
<property name="textInteractionFlags">
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
<item>
@@ -253,22 +253,6 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gameListGroup">
<property name="title">
<string>Display</string>
</property>
<layout class="QGridLayout" name="gridLayout_gameList">
<item row="0" column="0">
<widget class="QCheckBox" name="preferEnglishGameList">
<property name="text">
<string>Prefer English Titles</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<tabstops>
@@ -281,7 +265,6 @@
<tabstop>excludedPaths</tabstop>
<tabstop>scanForNewGames</tabstop>
<tabstop>rescanAllGames</tabstop>
<tabstop>preferEnglishGameList</tabstop>
</tabstops>
<resources>
<include location="../resources/resources.qrc"/>
@@ -100,6 +100,8 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* settings_dialog
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.promptOnStateLoadSaveFailure, "UI", "PromptOnStateLoadSaveFailure", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.savestateSelector, "EmuCore", "UseSavestateSelector", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.discordPresence, "EmuCore", "EnableDiscordPresence", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.preferEnglishGameList, "UI", "PreferEnglishGameList", false);
connect(m_ui.preferEnglishGameList, &QCheckBox::checkStateChanged, this, [this] { emit preferEnglishGameListChanged(); });
#ifdef __linux__ // Mouse locking is only supported on X11
const bool mouse_lock_supported = QGuiApplication::platformName().toLower() == "xcb";
@@ -199,6 +201,8 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* settings_dialog
tr("Unchecked"), tr("Pauses the emulator when a controller with bindings is disconnected."));
dialog()->registerWidgetHelp(m_ui.promptOnStateLoadSaveFailure, tr("Prompt On State Load/Save Failure"),
tr("Checked"), tr("Displays a modal dialog when a save state load/save operation fails."));
dialog()->registerWidgetHelp(m_ui.preferEnglishGameList, tr("Prefer English Titles"), tr("Unchecked"),
tr("For games with both a title in the game's native language and one in English, prefer the English title. Affects how game titles are displayed on the game list, window title and Discord Presence"));
dialog()->registerWidgetHelp(m_ui.startFullscreen, tr("Start Fullscreen"), tr("Unchecked"),
tr("Automatically switches to fullscreen mode when a game is started."));
dialog()->registerWidgetHelp(m_ui.hideMouseCursor, tr("Hide Cursor In Fullscreen"), tr("Unchecked"),
@@ -22,6 +22,7 @@ Q_SIGNALS:
void themeChanged();
void languageChanged();
void backgroundChanged();
void preferEnglishGameListChanged();
private Q_SLOTS:
void onRenderToSeparateWindowChanged();
+27 -21
View File
@@ -29,6 +29,13 @@
<string>Behaviour</string>
</property>
<layout class="QGridLayout" name="formLayout_4">
<item row="1" column="0">
<widget class="QCheckBox" name="inhibitScreensaver">
<property name="text">
<string>Inhibit Screensaver</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="pauseOnFocusLoss">
<property name="text">
@@ -36,13 +43,6 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="discordPresence">
<property name="text">
<string>Enable Discord Presence</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="confirmShutdown">
<property name="text">
@@ -50,10 +50,17 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="promptOnStateLoadSaveFailure">
<item row="3" column="0">
<widget class="QCheckBox" name="savestateSelector">
<property name="text">
<string>Prompt On State Load/Save Failure</string>
<string>Use Save State Selector</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="discordPresence">
<property name="text">
<string>Enable Discord Presence</string>
</property>
</widget>
</item>
@@ -71,21 +78,21 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="inhibitScreensaver">
<item row="3" column="1">
<widget class="QCheckBox" name="promptOnStateLoadSaveFailure">
<property name="text">
<string>Inhibit Screensaver</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="savestateSelector">
<property name="text">
<string>Use Save State Selector</string>
<string>Prompt On State Load/Save Failure</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="preferEnglishGameList">
<property name="text">
<string>Prefer English Game Titles</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="mouseLock">
<property name="text">
<string>Enable Mouse Lock</string>
@@ -395,7 +402,6 @@
<tabstop>pauseOnControllerDisconnection</tabstop>
<tabstop>savestateSelector</tabstop>
<tabstop>promptOnStateLoadSaveFailure</tabstop>
<tabstop>mouseLock</tabstop>
<tabstop>startFullscreen</tabstop>
<tabstop>doubleClickTogglesFullscreen</tabstop>
<tabstop>renderToSeparateWindow</tabstop>
+10 -1
View File
@@ -61,6 +61,7 @@ OSDSettingsWidget::OSDSettingsWidget(SettingsWindow* settings_dialog, QWidget* p
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showGSStats, "EmuCore/GS", "OsdShowGSStats", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showUsageCPU, "EmuCore/GS", "OsdShowCPU", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showUsageGPU, "EmuCore/GS", "OsdShowGPU", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showDebugGPU, "EmuCore/GS", "OsdShowGPUDebug", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showStatusIndicators, "EmuCore/GS", "OsdShowIndicators", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showFrameTimes, "EmuCore/GS", "OsdShowFrameTimes", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showHardwareInfo, "EmuCore/GS", "OsdShowHardwareInfo", false);
@@ -74,6 +75,11 @@ OSDSettingsWidget::OSDSettingsWidget(SettingsWindow* settings_dialog, QWidget* p
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showTextureReplacements, "EmuCore/GS", "OsdShowTextureReplacements", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.warnAboutUnsafeSettings, "EmuCore", "OsdWarnAboutUnsafeSettings", true);
#ifndef _WIN32
// Currently DX12 only
m_ui.showDebugGPU->deleteLater();
#endif
connect(m_ui.showSettings, &QCheckBox::checkStateChanged, this, &OSDSettingsWidget::onOsdShowSettingsToggled);
//////////////////////////////////////////////////////////////////////////
@@ -117,7 +123,10 @@ OSDSettingsWidget::OSDSettingsWidget(SettingsWindow* settings_dialog, QWidget* p
dialog()->registerWidgetHelp(m_ui.showStatusIndicators, tr("Show Status Indicators"), tr("Checked"),
tr("Shows icon indicators for emulation states such as Pausing, Turbo, Fast-Forward, and Slow-Motion."));
#ifdef _WIN32
dialog()->registerWidgetHelp(m_ui.showDebugGPU, tr("Show GPU Debug Info"),
tr("Unchecked"), tr("Shows debug information about the renderer."));
#endif
dialog()->registerWidgetHelp(m_ui.showFrameTimes, tr("Show Frame Times"), tr("Unchecked"),
tr("Displays a graph showing the average frametimes."));
+80 -73
View File
@@ -321,7 +321,7 @@
</layout>
</item>
<item row="9" column="0" colspan="2">
<layout class="QGridLayout" name="optionLayout" rowstretch="0,0,0,0,0,0,0,0,0,0">
<layout class="QGridLayout" name="optionLayout" rowstretch="0,0,0,0,0,0,0,0,0,0,0">
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetDefaultConstraint</enum>
</property>
@@ -331,34 +331,6 @@
<property name="spacing">
<number>7</number>
</property>
<item row="1" column="0">
<widget class="QCheckBox" name="showFrameTimes">
<property name="text">
<string>Show Frame Times</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="showUsageCPU">
<property name="text">
<string>Show CPU Usage</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="showResolution">
<property name="text">
<string>Show Resolution</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="showVPS">
<property name="text">
<string>Show VPS</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="showUsageGPU">
<property name="text">
@@ -366,31 +338,17 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="showSpeedPercentages">
<item row="1" column="0">
<widget class="QCheckBox" name="showFrameTimes">
<property name="text">
<string>Show Speed Percentages</string>
<string>Show Frame Times</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="showGSStats">
<item row="7" column="2">
<widget class="QLabel" name="warningLabel">
<property name="text">
<string>Show GS Statistics</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="showStatusIndicators">
<property name="text">
<string>Show Status Indicators</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="showFPS">
<property name="text">
<string>Show FPS</string>
<string>Messages</string>
</property>
</widget>
</item>
@@ -401,20 +359,6 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="Column1_SystemInformation">
<property name="text">
<string>System Information</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="Column2_SettingsAndInputs">
<property name="text">
<string>Settings &amp; Inputs</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="showHardwareInfo">
<property name="text">
@@ -429,13 +373,6 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="showSettings">
<property name="text">
<string>Show Settings</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QCheckBox" name="showPatches">
<property name="text">
@@ -443,6 +380,20 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QCheckBox" name="showResolution">
<property name="text">
<string>Show Resolution</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="showUsageCPU">
<property name="text">
<string>Show CPU Usage</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QCheckBox" name="showInputs">
<property name="text">
@@ -471,10 +422,17 @@
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QLabel" name="warningLabel">
<item row="6" column="0">
<widget class="QCheckBox" name="showGSStats">
<property name="text">
<string>Messages</string>
<string>Show GS Statistics</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="showStatusIndicators">
<property name="text">
<string>Show Status Indicators</string>
</property>
</widget>
</item>
@@ -485,6 +443,55 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="showFPS">
<property name="text">
<string>Show FPS</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="Column1_SystemInformation">
<property name="text">
<string>System Information</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="showSpeedPercentages">
<property name="text">
<string>Show Speed Percentages</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="showSettings">
<property name="text">
<string>Show Settings</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="showVPS">
<property name="text">
<string>Show VPS</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="Column2_SettingsAndInputs">
<property name="text">
<string>Settings &amp; Inputs</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QCheckBox" name="showDebugGPU">
<property name="text">
<string>Show GPU Debug Info</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
File diff suppressed because it is too large Load Diff
+1
View File
@@ -772,6 +772,7 @@ struct Pcsx2Config
OsdShowGSStats : 1,
OsdShowCPU : 1,
OsdShowGPU : 1,
OsdShowGPUDebug : 1,
OsdShowIndicators : 1,
OsdShowFrameTimes : 1,
OsdShowHardwareInfo : 1,
@@ -102,6 +102,18 @@ void D3D12DescriptorHeapManager::Free(D3D12DescriptorHandle* handle)
handle->Clear();
}
u32 D3D12DescriptorHeapManager::GetAllocatedDescriptors()
{
u32 ret = 0;
for (u32 group = 0; group < m_free_slots.size(); group++)
{
BitSetType& bs = m_free_slots[group];
ret += BITSET_SIZE - bs.count();
}
return ret;
}
D3D12DescriptorAllocator::D3D12DescriptorAllocator() = default;
D3D12DescriptorAllocator::~D3D12DescriptorAllocator() = default;
@@ -62,6 +62,9 @@ public:
void Free(D3D12DescriptorHandle* handle);
void Free(u32 index);
u32 GetNumDescriptors() const { return m_num_descriptors; }
u32 GetAllocatedDescriptors();
private:
wil::com_ptr_nothrow<ID3D12DescriptorHeap> m_descriptor_heap;
u32 m_num_descriptors = 0;
+269 -223
View File
@@ -5228,6 +5228,226 @@ void GSRendererHW::EmulateZbuffer(const GSTextureCache::Target* ds)
m_conf.ps.zwrite = m_conf.ps.zfloor || m_conf.ps.zclamp;
}
bool GSRendererHW::EmulateDATEEarlyFail(DATEOptions& date, GSTextureCache::Target* rt)
{
if (!date.enabled)
return false;
const bool is_overlap_alpha = m_prim_overlap != PRIM_OVERLAP_NO && !(m_cached_ctx.FRAME.FBMSK & 0x80000000);
if (m_cached_ctx.TEST.DATM == 0)
{
// Some pixels are >= 1 so some fail, or some pixels get written but the written alpha matches or exceeds 1 (so overlap doesn't always pass).
date.enabled = rt->m_alpha_max >= 128 || (is_overlap_alpha && rt->m_alpha_min < 128 && (GetAlphaMinMax().max >= 128 || (m_context->FBA.FBA || IsCoverageAlpha())));
// All pixels fail.
if (date.enabled && rt->m_alpha_min >= 128)
return true;
}
else
{
// Some pixels are < 1 so some fail, or some pixels get written but the written alpha goes below 1 (so overlap doesn't always pass).
date.enabled = rt->m_alpha_min < 128 || (is_overlap_alpha && rt->m_alpha_max >= 128 && (GetAlphaMinMax().min < 128 && !(m_context->FBA.FBA || IsCoverageAlpha())));
// All pixels fail.
if (date.enabled && rt->m_alpha_max < 128)
return true;
}
return false;
}
void GSRendererHW::EmulateDATESelectMethod(DATEOptions& date_options, GSTextureCache::Target* rt, int& blend_alpha_min, int& blend_alpha_max)
{
if (!date_options.enabled)
return;
const GSDevice::FeatureSupport& features = g_gs_device->Features();
const bool complex_alpha_test = m_cached_ctx.TEST.ATE &&
m_cached_ctx.TEST.ATST != ATST_ALWAYS &&
m_cached_ctx.TEST.ATST != ATST_NEVER &&
m_cached_ctx.TEST.AFAIL != AFAIL_KEEP;
if (m_cached_ctx.TEST.DATM)
{
blend_alpha_min = std::max(blend_alpha_min, 128);
blend_alpha_max = std::max(blend_alpha_max, 128);
}
else
{
blend_alpha_min = std::min(blend_alpha_min, 127);
blend_alpha_max = std::min(blend_alpha_max, 127);
}
// It is way too complex to emulate texture shuffle with DATE, so use accurate path.
// No overlap should be triggered on gl/vk only as they support DATE_BARRIER.
if (features.framebuffer_fetch)
{
// Full DATE is "free" with framebuffer fetch. The barrier gets cleared below.
date_options.barrier = true;
m_conf.require_full_barrier = true;
}
else if ((features.texture_barrier && m_prim_overlap == PRIM_OVERLAP_NO) || m_texture_shuffle)
{
GL_PERF("DATE: Accurate with %s", (features.texture_barrier && m_prim_overlap == PRIM_OVERLAP_NO) ? "no overlap" : "texture shuffle");
if (features.texture_barrier)
{
m_conf.require_full_barrier = true;
date_options.barrier = true;
}
}
// When Blending is disabled and Edge Anti Aliasing is enabled,
// the output alpha is Coverage (which we force to 128) so DATE will fail/pass guaranteed on second pass.
else if (m_conf.colormask.wa && (m_context->FBA.FBA || IsCoverageAlpha()) && features.stencil_buffer)
{
GL_PERF("DATE: Fast with FBA, all pixels will be >= 128");
date_options.stencil_one = !m_cached_ctx.TEST.DATM;
}
else if (m_conf.colormask.wa && !complex_alpha_test && !(m_cached_ctx.FRAME.FBMSK & 0x80000000))
{
// Performance note: check alpha range with GetAlphaMinMax()
// Note: all my dump are already above 120fps, but it seems to reduce GPU load
// with big upscaling
if (m_cached_ctx.TEST.DATM && GetAlphaMinMax().max < 128 && features.stencil_buffer)
{
// Only first pixel (write 0) will pass (alpha is 1)
GL_PERF("DATE: Fast with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
date_options.stencil_one = true;
}
else if (!m_cached_ctx.TEST.DATM && GetAlphaMinMax().min >= 128 && features.stencil_buffer)
{
// Only first pixel (write 1) will pass (alpha is 0)
GL_PERF("DATE: Fast with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
date_options.stencil_one = true;
}
else if (features.texture_barrier && ((m_vt.m_primclass == GS_SPRITE_CLASS && ComputeDrawlistGetSize(rt->m_scale) < 10) || (m_index.tail < 30)))
{
// texture barrier will split the draw call into n draw call. It is very efficient for
// few primitive draws. Otherwise it sucks.
GL_PERF("DATE: Accurate with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
m_conf.require_full_barrier = true;
date_options.barrier = true;
}
else if ((features.texture_barrier || features.multidraw_fb_copy) && m_conf.require_full_barrier)
{
// Full barrier is enabled (likely sw fbmask), we need to use date barrier.
GL_PERF("DATE: Accurate with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
m_conf.require_full_barrier = true;
date_options.barrier = true;
}
else if (features.primitive_id)
{
GL_PERF("DATE: Accurate with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
date_options.primid = true;
}
else if (features.texture_barrier || features.multidraw_fb_copy)
{
GL_PERF("DATE: Accurate with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
m_conf.require_full_barrier = true;
date_options.barrier = true;
}
else if (features.stencil_buffer)
{
// Might be inaccurate in some cases but we shouldn't hit this path.
GL_PERF("DATE: Fast with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
date_options.stencil_one = true;
}
}
else if (features.texture_barrier && !m_conf.colormask.wa)
{
GL_PERF("DATE: Accurate with no alpha write");
m_conf.require_one_barrier = true;
date_options.barrier = true;
}
// Will save my life !
pxAssert(!(date_options.barrier && date_options.stencil_one));
pxAssert(!(date_options.primid && date_options.stencil_one));
pxAssert(!(date_options.primid && date_options.barrier));
}
void GSRendererHW::EmulateDATEGetConfig(DATEOptions& date_options, bool scale_rt_alpha, GSDevice::RecycledTexture& temp_ds)
{
if (!date_options.enabled)
{
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Off;
return;
}
const GSDevice::FeatureSupport& features = g_gs_device->Features();
// Always swap DATE with DATE_BARRIER if we have barriers on when alpha write is masked.
// This is always enabled on VK/GL/DX12 but not on DX11 as copies are slow so we can selectively enable it like now.
if (!m_conf.colormask.wa && (m_conf.require_one_barrier || m_conf.require_full_barrier))
date_options.barrier = true;
if (m_conf.ps.scanmsk & 2)
date_options.primid = false; // to have discard in the shader work correctly
if (date_options.stencil_one)
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::StencilOne;
else if (date_options.primid)
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking;
else if (date_options.barrier)
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Full;
else if (features.stencil_buffer)
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Stencil;
if (scale_rt_alpha)
m_conf.datm = static_cast<SetDATM>(m_cached_ctx.TEST.DATM + 2);
else
m_conf.datm = static_cast<SetDATM>(m_cached_ctx.TEST.DATM);
if (m_conf.destination_alpha >= GSHWDrawConfig::DestinationAlphaMode::Stencil &&
m_conf.destination_alpha <= GSHWDrawConfig::DestinationAlphaMode::StencilOne && !m_conf.ds)
{
const bool is_one_barrier = (features.texture_barrier && m_conf.require_full_barrier &&
(m_prim_overlap == PRIM_OVERLAP_NO || m_conf.ps.shuffle || m_channel_shuffle));
if ((temp_ds.reset(g_gs_device->CreateDepthStencil(m_conf.rt->GetWidth(), m_conf.rt->GetHeight(),
GSTexture::Format::DepthStencil, false)), temp_ds))
{
m_conf.ds = temp_ds.get();
}
else if (features.primitive_id && !(m_conf.ps.scanmsk & 2) && (!m_conf.require_full_barrier || is_one_barrier))
{
date_options.stencil_one = false;
date_options.primid = true;
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking;
DevCon.Warning("HW: Depth buffer creation failed for Stencil Date. Fallback to PrimIDTracking.");
}
else
{
date_options.enabled = false;
date_options.stencil_one = false;
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Off;
DevCon.Warning("HW: Depth buffer creation failed for Stencil Date.");
}
}
if (date_options.barrier)
{
m_conf.ps.date = 5 + m_cached_ctx.TEST.DATM;
}
else if (date_options.stencil_one)
{
const bool multidraw_fb_copy = features.multidraw_fb_copy && (m_conf.require_one_barrier || m_conf.require_full_barrier);
if (features.texture_barrier || multidraw_fb_copy)
{
m_conf.require_one_barrier = true;
m_conf.ps.date = 5 + m_cached_ctx.TEST.DATM;
}
m_conf.depth.date = 1;
m_conf.depth.date_one = 1;
}
else if (date_options.primid)
{
m_conf.ps.date = 1 + m_cached_ctx.TEST.DATM;
}
else if (date_options.enabled)
{
m_conf.depth.date = 1;
}
}
void GSRendererHW::EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GSTextureCache::Source* tex)
{
// Uncomment to disable texture shuffle emulation.
@@ -5682,7 +5902,7 @@ __ri u32 GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool t
return true;
}
void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const bool DATE, bool& DATE_PRIMID, bool& DATE_BARRIER,
void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, DATEOptions& date_options,
GSTextureCache::Target* rt, bool can_scale_rt_alpha, bool& new_rt_alpha_scale)
{
const GIFRegALPHA& ALPHA = m_context->ALPHA;
@@ -6116,7 +6336,8 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
if (can_scale_rt_alpha && !new_rt_alpha_scale && m_conf.colormask.wa)
{
const bool afail_fb_only = m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY;
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover && !(DATE || !afail_fb_only || !IsDepthAlwaysPassing());
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover &&
!(date_options.enabled || !afail_fb_only || !IsDepthAlwaysPassing());
// Restrict this to only when we're overwriting the whole target.
new_rt_alpha_scale = full_cover;
@@ -6263,7 +6484,8 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
{
const bool afail_always_fb_alpha = m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY || (m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp != 32);
const bool always_passing_alpha = !m_cached_ctx.TEST.ATE || afail_always_fb_alpha || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ATST_ALWAYS);
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover && !(DATE_PRIMID || DATE_BARRIER || !always_passing_alpha || !IsDepthAlwaysPassing());
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover &&
!(date_options.primid || date_options.barrier || !always_passing_alpha || !IsDepthAlwaysPassing());
if (!full_cover)
{
@@ -6461,12 +6683,12 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
// Switch DATE_PRIMID with DATE_BARRIER in such cases to ensure accuracy.
// No mix of COLCLIP + sw blend + DATE_PRIMID, neither sw fbmask + DATE_PRIMID.
// Note: Do the swap in the end, saves the expensive draw splitting/barriers when mixed software blending is used.
if (sw_blending && DATE_PRIMID && m_conf.require_full_barrier &&
if (sw_blending && date_options.primid && m_conf.require_full_barrier &&
(features.texture_barrier || (features.multidraw_fb_copy && !no_prim_overlap)))
{
GL_PERF("DATE: Swap DATE_PRIMID with DATE_BARRIER");
DATE_PRIMID = false;
DATE_BARRIER = true;
date_options.primid = false;
date_options.barrier = true;
}
}
@@ -7342,7 +7564,7 @@ void GSRendererHW::GetAlphaTestConfigPS(const u32 atst, const u8 aref, const boo
}
}
void GSRendererHW::EmulateAlphaTest(const bool& DATE, bool& DATE_BARRIER, bool& DATE_one, bool& DATE_PRIMID)
void GSRendererHW::EmulateAlphaTest(DATEOptions& date_options)
{
const GSDevice::FeatureSupport& features = g_gs_device->Features();
@@ -7528,13 +7750,13 @@ void GSRendererHW::EmulateAlphaTest(const bool& DATE, bool& DATE_BARRIER, bool&
// Swap stencil DATE for PrimID DATE, for both Z on and off cases.
// Because we're making some pixels pass, but not updating A, the stencil won't be synced.
if (DATE && !DATE_BARRIER && features.primitive_id)
if (date_options.enabled && !date_options.barrier && features.primitive_id)
{
if (!DATE_PRIMID)
if (!date_options.primid)
GL_INS("Alpha test: Swap stencil DATE for PrimID, due to AFAIL");
DATE_one = false;
DATE_PRIMID = true;
date_options.stencil_one = false;
date_options.primid = true;
}
// The actual blend setup will be done later after determining blending.
@@ -7720,10 +7942,12 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
#endif
const GSDrawingEnvironment& env = *m_draw_env;
bool DATE = rt && m_cached_ctx.TEST.DATE && m_cached_ctx.FRAME.PSM != PSMCT24;
bool DATE_PRIMID = false;
bool DATE_BARRIER = false;
bool DATE_one = false;
DATEOptions date_options;
date_options.enabled = rt && m_cached_ctx.TEST.DATE && m_cached_ctx.FRAME.PSM != PSMCT24;
date_options.primid = false;
date_options.barrier = false;
date_options.stencil_one = false;
ResetStates();
@@ -7762,28 +7986,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
const GSDevice::FeatureSupport features = g_gs_device->Features();
if (DATE)
{
const bool is_overlap_alpha = m_prim_overlap != PRIM_OVERLAP_NO && !(m_cached_ctx.FRAME.FBMSK & 0x80000000);
if (m_cached_ctx.TEST.DATM == 0)
{
// Some pixles are >= 1 so some fail, or some pixels get written but the written alpha matches or exceeds 1 (so overlap doesn't always pass).
DATE = rt->m_alpha_max >= 128 || (is_overlap_alpha && rt->m_alpha_min < 128 && (GetAlphaMinMax().max >= 128 || (m_context->FBA.FBA || IsCoverageAlpha())));
// All pixels fail.
if (DATE && rt->m_alpha_min >= 128)
return;
}
else
{
// Some pixles are < 1 so some fail, or some pixels get written but the written alpha goes below 1 (so overlap doesn't always pass).
DATE = rt->m_alpha_min < 128 || (is_overlap_alpha && rt->m_alpha_max >= 128 && (GetAlphaMinMax().min < 128 && !(m_context->FBA.FBA || IsCoverageAlpha())));
// All pixels fail.
if (DATE && rt->m_alpha_max < 128)
return;
}
}
if (EmulateDATEEarlyFail(date_options, rt))
return;
const int afail_type = m_cached_ctx.TEST.GetAFAIL(m_cached_ctx.FRAME.PSM);
if (m_cached_ctx.TEST.ATE && ((afail_type != AFAIL_FB_ONLY && afail_type != AFAIL_RGB_ONLY) || !NeedsBlending() || !IsUsingAsInBlend()))
@@ -7820,7 +8024,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
const bool afail_always_fb_alpha = m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY || (m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp != 32);
const bool always_passing_alpha = !m_cached_ctx.TEST.ATE || afail_always_fb_alpha || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ATST_ALWAYS);
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover && !(DATE || !always_passing_alpha || !IsDepthAlwaysPassing());
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover &&
!(date_options.enabled || !always_passing_alpha || !IsDepthAlwaysPassing());
// On DX FBMask emulation can be missing on lower blend levels, so we'll do whatever the API does.
const u32 fb_mask = m_conf.colormask.wa ? (m_conf.ps.fbmask ? m_conf.cb_ps.FbMask.a : 0) : 0xFF;
@@ -7896,110 +8101,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
}
}
// DATE: selection of the algorithm. Must be done before blending because GL42 is not compatible with blending
const bool complex_alpha_test = m_cached_ctx.TEST.ATE &&
m_cached_ctx.TEST.ATST != ATST_ALWAYS &&
m_cached_ctx.TEST.ATST != ATST_NEVER &&
m_cached_ctx.TEST.AFAIL != AFAIL_KEEP;
if (DATE)
{
if (m_cached_ctx.TEST.DATM)
{
blend_alpha_min = std::max(blend_alpha_min, 128);
blend_alpha_max = std::max(blend_alpha_max, 128);
}
else
{
blend_alpha_min = std::min(blend_alpha_min, 127);
blend_alpha_max = std::min(blend_alpha_max, 127);
}
// It is way too complex to emulate texture shuffle with DATE, so use accurate path.
// No overlap should be triggered on gl/vk only as they support DATE_BARRIER.
if (features.framebuffer_fetch)
{
// Full DATE is "free" with framebuffer fetch. The barrier gets cleared below.
DATE_BARRIER = true;
m_conf.require_full_barrier = true;
}
else if ((features.texture_barrier && m_prim_overlap == PRIM_OVERLAP_NO) || m_texture_shuffle)
{
GL_PERF("DATE: Accurate with %s", (features.texture_barrier && m_prim_overlap == PRIM_OVERLAP_NO) ? "no overlap" : "texture shuffle");
if (features.texture_barrier)
{
m_conf.require_full_barrier = true;
DATE_BARRIER = true;
}
}
// When Blending is disabled and Edge Anti Aliasing is enabled,
// the output alpha is Coverage (which we force to 128) so DATE will fail/pass guaranteed on second pass.
else if (m_conf.colormask.wa && (m_context->FBA.FBA || IsCoverageAlpha()) && features.stencil_buffer)
{
GL_PERF("DATE: Fast with FBA, all pixels will be >= 128");
DATE_one = !m_cached_ctx.TEST.DATM;
}
else if (m_conf.colormask.wa && !complex_alpha_test && !(m_cached_ctx.FRAME.FBMSK & 0x80000000))
{
// Performance note: check alpha range with GetAlphaMinMax()
// Note: all my dump are already above 120fps, but it seems to reduce GPU load
// with big upscaling
if (m_cached_ctx.TEST.DATM && GetAlphaMinMax().max < 128 && features.stencil_buffer)
{
// Only first pixel (write 0) will pass (alpha is 1)
GL_PERF("DATE: Fast with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
DATE_one = true;
}
else if (!m_cached_ctx.TEST.DATM && GetAlphaMinMax().min >= 128 && features.stencil_buffer)
{
// Only first pixel (write 1) will pass (alpha is 0)
GL_PERF("DATE: Fast with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
DATE_one = true;
}
else if (features.texture_barrier && ((m_vt.m_primclass == GS_SPRITE_CLASS && ComputeDrawlistGetSize(rt->m_scale) < 10) || (m_index.tail < 30)))
{
// texture barrier will split the draw call into n draw call. It is very efficient for
// few primitive draws. Otherwise it sucks.
GL_PERF("DATE: Accurate with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
m_conf.require_full_barrier = true;
DATE_BARRIER = true;
}
else if ((features.texture_barrier || features.multidraw_fb_copy) && m_conf.require_full_barrier)
{
// Full barrier is enabled (likely sw fbmask), we need to use date barrier.
GL_PERF("DATE: Accurate with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
m_conf.require_full_barrier = true;
DATE_BARRIER = true;
}
else if (features.primitive_id)
{
GL_PERF("DATE: Accurate with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
DATE_PRIMID = true;
}
else if (features.texture_barrier || features.multidraw_fb_copy)
{
GL_PERF("DATE: Accurate with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
m_conf.require_full_barrier = true;
DATE_BARRIER = true;
}
else if (features.stencil_buffer)
{
// Might be inaccurate in some cases but we shouldn't hit this path.
GL_PERF("DATE: Fast with alpha %d-%d", GetAlphaMinMax().min, GetAlphaMinMax().max);
DATE_one = true;
}
}
else if (features.texture_barrier && !m_conf.colormask.wa)
{
GL_PERF("DATE: Accurate with no alpha write");
m_conf.require_one_barrier = true;
DATE_BARRIER = true;
}
// Will save my life !
pxAssert(!(DATE_BARRIER && DATE_one));
pxAssert(!(DATE_PRIMID && DATE_one));
pxAssert(!(DATE_PRIMID && DATE_BARRIER));
}
// DATE: selection of the algorithm.
EmulateDATESelectMethod(date_options, rt, blend_alpha_min, blend_alpha_max);
// Before emulateblending, dither will be used
m_conf.ps.dither = GSConfig.Dithering > 0 && m_conf.ps.dst_fmt == GSLocalMemory::PSM_FMT_16 && env.DTHE.DTHE;
@@ -8010,7 +8113,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
m_conf.colormask.wa = 0;
}
// Not gonna spend too much time with this, it's not likely to be used much, can't be less accurate than it was.
if (ds)
{
@@ -8120,14 +8222,14 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
m_conf.ps.no_color1 = true;
// Perform alpha test first pass setup here as bending depends on it.
EmulateAlphaTest(DATE, DATE_BARRIER, DATE_one, DATE_PRIMID);
EmulateAlphaTest(date_options);
// AA1: Set alpha source to coverage 128 when there is no alpha blending.
m_conf.ps.fixed_one_a = IsCoverageAlpha();
if ((!IsOpaque() || m_context->ALPHA.IsBlack()) && rt && ((m_conf.colormask.wrgba & 0x7) || (m_texture_shuffle && !m_copy_16bit_to_target_shuffle && !m_same_group_texture_shuffle)))
{
EmulateBlending(blend_alpha_min, blend_alpha_max, DATE, DATE_PRIMID, DATE_BARRIER, rt, can_scale_rt_alpha, new_scale_rt_alpha);
EmulateBlending(blend_alpha_min, blend_alpha_max, date_options, rt, can_scale_rt_alpha, new_scale_rt_alpha);
}
else
{
@@ -8137,7 +8239,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
{
const bool afail_always_fb_alpha = m_cached_ctx.TEST.AFAIL == AFAIL_FB_ONLY || (m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].trbpp != 32);
const bool always_passing_alpha = !m_cached_ctx.TEST.ATE || afail_always_fb_alpha || (m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ATST_ALWAYS);
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover && !(DATE || !always_passing_alpha || !IsDepthAlwaysPassing());
const bool full_cover = rt->m_valid.rintersect(m_r).eq(rt->m_valid) && m_primitive_covers_without_gaps == NoGapsType::FullCover &&
!(date_options.enabled || !always_passing_alpha || !IsDepthAlwaysPassing());
// Restrict this to only when we're overwriting the whole target.
new_scale_rt_alpha = full_cover || rt->m_last_draw >= s_n;
@@ -8159,11 +8262,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
return;
}
// Always swap DATE with DATE_BARRIER if we have barriers on when alpha write is masked.
// This is always enabled on vk/gl but not on dx11/12 as copies are slow so we can selectively enable it like now.
if (DATE && !m_conf.colormask.wa && (m_conf.require_one_barrier || m_conf.require_full_barrier))
DATE_BARRIER = true;
if ((m_conf.ps.tex_is_fb && rt && rt->m_rt_alpha_scale) || (tex && tex->m_from_target && tex->m_target_direct && tex->m_from_target->m_rt_alpha_scale))
m_conf.ps.rta_source_correction = 1;
@@ -8184,52 +8282,9 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
m_conf.colormask.wrgba = 0;
}
if (m_conf.ps.scanmsk & 2)
DATE_PRIMID = false; // to have discard in the shader work correctly
// DATE setup, no DATE_BARRIER please
if (!DATE)
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Off;
else if (DATE_one)
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::StencilOne;
else if (DATE_PRIMID)
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking;
else if (DATE_BARRIER)
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Full;
else if (features.stencil_buffer)
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Stencil;
if (new_scale_rt_alpha)
m_conf.datm = static_cast<SetDATM>(m_cached_ctx.TEST.DATM + 2);
else
m_conf.datm = static_cast<SetDATM>(m_cached_ctx.TEST.DATM);
// If we're doing stencil DATE and we don't have a depth buffer, we need to allocate a temporary one.
GSDevice::RecycledTexture temp_ds;
if (m_conf.destination_alpha >= GSHWDrawConfig::DestinationAlphaMode::Stencil &&
m_conf.destination_alpha <= GSHWDrawConfig::DestinationAlphaMode::StencilOne && !m_conf.ds)
{
const bool is_one_barrier = (features.texture_barrier && m_conf.require_full_barrier && (m_prim_overlap == PRIM_OVERLAP_NO || m_conf.ps.shuffle || m_channel_shuffle));
if ((temp_ds.reset(g_gs_device->CreateDepthStencil(m_conf.rt->GetWidth(), m_conf.rt->GetHeight(), GSTexture::Format::DepthStencil, false)), temp_ds))
{
m_conf.ds = temp_ds.get();
}
else if (features.primitive_id && !(m_conf.ps.scanmsk & 2) && (!m_conf.require_full_barrier || is_one_barrier))
{
DATE_one = false;
DATE_PRIMID = true;
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking;
DevCon.Warning("HW: Depth buffer creation failed for Stencil Date. Fallback to PrimIDTracking.");
}
else
{
DATE = false;
DATE_one = false;
m_conf.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Off;
DevCon.Warning("HW: Depth buffer creation failed for Stencil Date.");
}
}
// DATE backend configuration
GSDevice::RecycledTexture temp_ds; // If we're doing stencil DATE and we don't have a depth buffer, we need to allocate a temporary one.
EmulateDATEGetConfig(date_options, new_scale_rt_alpha, temp_ds);
// vs
@@ -8308,30 +8363,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
m_conf.ps.iip = (m_vt.m_primclass == GS_SPRITE_CLASS) ? 0 : PRIM->IIP;
m_conf.vs.iip = m_conf.ps.iip;
if (DATE_BARRIER)
{
m_conf.ps.date = 5 + m_cached_ctx.TEST.DATM;
}
else if (DATE_one)
{
const bool multidraw_fb_copy = features.multidraw_fb_copy && (m_conf.require_one_barrier || m_conf.require_full_barrier);
if (features.texture_barrier || multidraw_fb_copy)
{
m_conf.require_one_barrier = true;
m_conf.ps.date = 5 + m_cached_ctx.TEST.DATM;
}
m_conf.depth.date = 1;
m_conf.depth.date_one = 1;
}
else if (DATE_PRIMID)
{
m_conf.ps.date = 1 + m_cached_ctx.TEST.DATM;
}
else if (DATE)
{
m_conf.depth.date = 1;
}
m_conf.ps.fba = m_context->FBA.FBA;
if (m_conf.ps.dither || m_conf.blend_multi_pass.dither)
@@ -8420,7 +8451,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
const GSVector4i scissor(GSVector4i(GSVector4(rtscale) * GSVector4(hacked_scissor)).rintersect(GSVector4i::loadh(rtsize)));
m_conf.drawarea = m_channel_shuffle ? scissor : scissor.rintersect(ComputeBoundingBox(rtsize, rtscale));
m_conf.scissor = (DATE && !DATE_BARRIER) ? m_conf.drawarea : scissor;
m_conf.scissor = (date_options.enabled && !date_options.barrier) ? m_conf.drawarea : scissor;
// ComputeDrawlistGetSize expects the original index layout, so needs to be called before we modify it via HandleProvokingVertexFirst/SetupIA.
if (m_conf.require_full_barrier && (g_gs_device->Features().texture_barrier || g_gs_device->Features().multidraw_fb_copy))
@@ -9070,6 +9101,20 @@ bool GSRendererHW::DetectRedundantBufferClear(bool& no_rt, bool& no_ds, u32 fm_m
if (((~m_cached_ctx.FRAME.FBMSK & fm_mask) & GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].fmsk) == 0)
return false;
// Frame and Z have different bit depths and we're doing a zero clear. We don't care about page alignment here.
// If we don't disable one or the other, the texture cache could get corrupted on target lookup.
// Only Tokyo Xtreme Racer 3 is know to hit this path, and draws small vertical strips with 32 bit color and 16 bit depth.
const bool is_zero_color_clear = m_vt.m_eq.rgba == 0xFFFF && GetConstantDirectWriteMemClearColor() == 0;
const bool is_zero_depth_clear = m_vt.m_eq.z && GetConstantDirectWriteMemClearDepth() == 0;
if (GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp != GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].bpp &&
is_zero_color_clear && is_zero_depth_clear)
{
m_cached_ctx.ZBUF.ZMSK = true;
no_ds = true;
no_rt = false;
return true;
}
// Make sure the width is page aligned, so we don't break powerdrome-style clears where Z writes the right side of the page.
// We can't check page alignment on the size entirely, because Ratchet does 256x127 clears...
// Test cases: Devil May Cry 3, Tom & Jerry.
@@ -9902,8 +9947,9 @@ void GSRendererHW::EndHLEHardwareDraw(bool force_copy_on_hazard /* = false */)
if (!force_copy_on_hazard && config.tex == config.rt)
{
// Sample RT 1:1.
config.require_one_barrier = !features.framebuffer_fetch;
config.tex = nullptr;
config.ps.tex_is_fb = true;
config.require_one_barrier = !features.framebuffer_fetch;
}
else if (!force_copy_on_hazard && config.tex == config.ds && !config.depth.zwe &&
features.test_and_sample_depth)
+15 -2
View File
@@ -106,6 +106,15 @@ private:
SHUFFLE_READWRITE,
};
// Intermediate struct for determining DATE config.
struct DATEOptions
{
bool enabled;
bool barrier;
bool primid;
bool stencil_one;
};
bool HasEEUpload(GSVector4i r);
CLUTDrawTestResult PossibleCLUTDraw();
CLUTDrawTestResult PossibleCLUTDrawAggressive();
@@ -122,7 +131,7 @@ private:
void SetupIA(float target_scale, float sx, float sy, bool req_vert_backup);
void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GSTextureCache::Source* tex);
u32 EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt = nullptr);
void EmulateBlending(int rt_alpha_min, int rt_alpha_max, const bool DATE, bool& DATE_PRIMID, bool& DATE_BARRIER, GSTextureCache::Target* rt,
void EmulateBlending(int rt_alpha_min, int rt_alpha_max, DATEOptions& date_options, GSTextureCache::Target* rt,
bool can_scale_rt_alpha, bool& new_rt_alpha_scale);
void CleanupDraw(bool invalidate_temp_src);
@@ -136,9 +145,13 @@ private:
void EmulateZbuffer(const GSTextureCache::Target* ds);
static void GetAlphaTestConfigPS(const u32 atst, const u8 aref, const bool invert_test, u32& ps_atst_out, float& aref_out);
void EmulateAlphaTest(const bool& DATE, bool& DATE_BARRIER, bool& DATE_one, bool& DATE_PRIMID);
void EmulateAlphaTest(DATEOptions& date_options);
void EmulateAlphaTestSecondPass();
bool EmulateDATEEarlyFail(DATEOptions& date, GSTextureCache::Target* rt);
void EmulateDATESelectMethod(DATEOptions& date, GSTextureCache::Target* rt, int& blend_alpha_min, int& blend_alpha_max);
void EmulateDATEGetConfig(DATEOptions& date, bool scale_rt_alpha, GSDevice::RecycledTexture& temp_ds);
void SetTCOffset();
bool NextDrawColClip() const;
bool IsPossibleChannelShuffle() const;
+26 -12
View File
@@ -1428,11 +1428,15 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
const bool width_match = (std::max(64U, bw * 64U) >> GSLocalMemory::m_psm[psm].info.pageShiftX()) ==
(std::max(64U, t->m_TEX0.TBW * 64U) >> GSLocalMemory::m_psm[t->m_TEX0.PSM].info.pageShiftX());
if (bp == t->m_TEX0.TBP0 && !t->m_dirty.empty() && GSUtil::GetChannelMask(psm) == GSUtil::GetChannelMask(t->m_TEX0.PSM) && GSRendererHW::GetInstance()->m_draw_transfers.size() > 0)
// Check for transfers that may have occurred within the textures valid area or completely outside it.
// Transfers completely outside the valid area may not have been given a dirty rect, so we need both checks.
const bool t_maybe_dirty = !t->m_dirty.empty() || !t->OverlapsValid(bp, bw, psm, req_rect);
if ((bp == t->m_TEX0.TBP0 && t_maybe_dirty && GSUtil::GetChannelMask(psm) == GSUtil::GetChannelMask(t->m_TEX0.PSM) && GSRendererHW::GetInstance()->m_draw_transfers.size() > 0) || GSState::s_n==421)
{
bool can_use = true;
if (!possible_shuffle && !(GSLocalMemory::m_psm[TEX0.PSM].bpp == 16 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32) && !width_match && t->m_dirty.size() >= 1 && !t->m_dirty.GetTotalRect(t->m_TEX0, t->m_unscaled_size).eq(t->m_valid))
if (!possible_shuffle && !(GSLocalMemory::m_psm[TEX0.PSM].bpp == 16 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32) && !width_match && t_maybe_dirty && !t->m_dirty.GetTotalRect(t->m_TEX0, t->m_unscaled_size).eq(t->m_valid))
{
std::vector<GSState::GSUploadQueue>::reverse_iterator iter;
@@ -7289,7 +7293,7 @@ GSTextureCache::Surface::Surface() = default;
GSTextureCache::Surface::~Surface() = default;
bool GSTextureCache::Surface::Inside(u32 bp, u32 bw, u32 psm, const GSVector4i& rect)
bool GSTextureCache::Surface::Inside(u32 bp, u32 bw, u32 psm, const GSVector4i& rect) const
{
// Valid only for color formats.
const GSOffset off(GSLocalMemory::m_psm[psm].info, bp, bw, psm);
@@ -7298,7 +7302,7 @@ bool GSTextureCache::Surface::Inside(u32 bp, u32 bw, u32 psm, const GSVector4i&
return start_block >= m_TEX0.TBP0 && end_block <= UnwrappedEndBlock();
}
bool GSTextureCache::Surface::Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i& rect)
bool GSTextureCache::Surface::OverlapsHelper(u32 start_block0, u32 end_block0, u32 bp, u32 bw, u32 psm, const GSVector4i& rect) const
{
const GSOffset off(GSLocalMemory::m_psm[psm].info, bp, bw, psm);
@@ -7324,8 +7328,12 @@ bool GSTextureCache::Surface::Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i
if (end_block > GS_MAX_BLOCKS && bp < m_end_block && m_end_block < m_TEX0.TBP0)
bp += GS_MAX_BLOCKS;
const bool overlap = GSTextureCache::CheckOverlap(m_TEX0.TBP0, UnwrappedEndBlock(), start_block, end_block);
return overlap;
return GSTextureCache::CheckOverlap(start_block0, end_block0, start_block, end_block);
}
bool GSTextureCache::Surface::Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i& rect) const
{
return OverlapsHelper(m_TEX0.TBP0, UnwrappedEndBlock(), bp, bw, psm, rect);
}
// GSTextureCache::Source
@@ -7690,6 +7698,12 @@ GSTextureCache::Target::~Target()
#endif
}
bool GSTextureCache::Target::OverlapsValid(u32 bp, u32 bw, u32 psm, const GSVector4i& rect) const
{
const u32 valid_start_block = GSLocalMemory::m_psm[m_TEX0.PSM].info.bn(m_valid.x, m_valid.y, m_TEX0.TBP0, m_TEX0.TBW);
return OverlapsHelper(valid_start_block, UnwrappedEndBlock(), bp, bw, psm, rect);
}
void GSTextureCache::Target::Update(bool cannot_scale)
{
m_age = 0;
@@ -8552,7 +8566,7 @@ GSTextureCache::PaletteMap::PaletteMap()
{
for (auto& map : m_maps)
{
map.reserve(MAX_SIZE);
map.reserve(MAX_CACHED_PALETES);
}
}
@@ -8588,10 +8602,10 @@ std::shared_ptr<GSTextureCache::Palette> GSTextureCache::PaletteMap::LookupPalet
// No palette with matching clut content, MISS
if (map.size() > MAX_SIZE)
if (map.size() > MAX_CACHED_PALETES)
{
// If the map is too big, try to clean it by disposing and removing unused palettes, before adding the new one
GL_INS("TC: WARNING, %u-bit PaletteMap (Size %u): Max size %u exceeded, clearing unused palettes.", pal * sizeof(u32), map.size(), MAX_SIZE);
GL_INS("TC: WARNING, %u-bit PaletteMap (Size %u): Max size %u exceeded, clearing unused palettes.", pal * sizeof(u32), map.size(), MAX_CACHED_PALETES);
const u32 current_size = map.size();
@@ -8615,11 +8629,11 @@ std::shared_ptr<GSTextureCache::Palette> GSTextureCache::PaletteMap::LookupPalet
if (cleared_palette_count == 0)
{
GL_INS("TC: ERROR, %u-bit PaletteMap (Size %u): Max size %u exceeded, could not clear any palette, negative performance impact.", pal * sizeof(u32), map.size(), MAX_SIZE);
GL_INS("TC: ERROR, %u-bit PaletteMap (Size %u): Max size %u exceeded, could not clear any palette, negative performance impact.", pal * sizeof(u32), map.size(), MAX_CACHED_PALETES);
}
else
{
map.reserve(MAX_SIZE); // Ensure map capacity is not modified by the clearing
map.reserve(MAX_CACHED_PALETES); // Ensure map capacity is not modified by the clearing
GL_INS("TC: INFO, %u-bit PaletteMap (Size %u): Cleared %u palettes.", pal * sizeof(u32), map.size(), cleared_palette_count);
}
}
@@ -8638,7 +8652,7 @@ void GSTextureCache::PaletteMap::Clear()
for (auto& map : m_maps)
{
map.clear(); // Clear all the nodes of the map, deleting Palette objects managed by shared pointers as they should be unused elsewhere
map.reserve(MAX_SIZE); // Ensure map capacity is not modified by the clearing
map.reserve(MAX_CACHED_PALETES); // Ensure map capacity is not modified by the clearing
}
}
+6 -3
View File
@@ -141,6 +141,7 @@ public:
Surface();
~Surface();
bool OverlapsHelper(u32 start_block0, u32 end_block0, u32 bp, u32 bw, u32 psm, const GSVector4i& rect) const;
public:
GSTexture* m_texture = nullptr;
GIFRegTEX0 m_TEX0 = {};
@@ -167,8 +168,8 @@ public:
/// Can be used for overlap tests.
u32 UnwrappedEndBlock() const { return (m_end_block + (Wraps() ? GS_MAX_BLOCKS : 0)); }
bool Inside(u32 bp, u32 bw, u32 psm, const GSVector4i& rect);
bool Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i& rect);
bool Inside(u32 bp, u32 bw, u32 psm, const GSVector4i& rect) const;
bool Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i& rect) const;
};
struct PaletteKey
@@ -258,6 +259,8 @@ public:
static Target* Create(GIFRegTEX0 TEX0, int w, int h, float scale, int type, bool clear);
bool OverlapsValid(u32 bp, u32 bw, u32 psm, const GSVector4i& rect) const;
__fi bool HasValidAlpha() const { return (m_valid_alpha_low | m_valid_alpha_high); }
bool HasValidBitsForFormat(u32 psm, bool req_color, bool req_alpha, bool width_match);
@@ -349,7 +352,7 @@ public:
class PaletteMap
{
private:
static const u16 MAX_SIZE = 65535; // Max size of each map.
static const u16 MAX_CACHED_PALETES = 4096; // Max size of each map.
// Array of 2 maps, the first for 64B palettes and the second for 1024B palettes.
// Each map stores the key PaletteKey (clut copy, pal value) pointing to the relevant shared pointer to Palette object.
+6 -2
View File
@@ -2726,10 +2726,14 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
// 2. Fullscreen sprite writes gray, rta hw blend blends based on dst alpha.
// On Nvidia, 2 seems to not pick up the data written by 1 unless we add a second barrier.
// Pretty sure GL is supposed to guarantee that the blend unit is coherent with previous pixel write out, so calling this a bug.
bool broken_blend_coherency_barrier = false;
if (m_bugs.broken_blend_coherency)
rt_hazard_barrier |= (psel.ps.IsFeedbackLoopRT() || psel.ps.blend_c == 1) && GLState::rt == config.rt;
broken_blend_coherency_barrier = (psel.ps.IsFeedbackLoopRT() || psel.ps.blend_c == 1) && GLState::rt == config.rt;
if (config.require_one_barrier || !m_features.texture_barrier)
{
rt_hazard_barrier = false; // Already in place or not available
broken_blend_coherency_barrier = false;
}
// additional non-pipeline config stuff
const bool point_size_enabled = config.vs.point_size;
@@ -2821,7 +2825,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
}
// Be careful of the rt already being bound and the blend using the RT without a barrier.
if (fb_optimization_needs_barrier && rt_hazard_barrier)
if ((fb_optimization_needs_barrier && broken_blend_coherency_barrier) || rt_hazard_barrier)
{
// Ensure all depth writes are finished before sampling
GL_INS("GL: Texture barrier to flush depth or rt before reading");
+19 -16
View File
@@ -15,7 +15,8 @@
#if MULTI_ISA_COMPILE_ONCE
// Lack of a better home
constexpr GSScanlineConstantData g_const;
constexpr GSScanlineConstantData256B g_const_256b;
constexpr GSScanlineConstantData128B g_const_128b;
#endif
MULTI_ISA_UNSHARED_IMPL;
@@ -206,10 +207,11 @@ void GSDrawScanline::CSetupPrim(const GSVertexSW* vertex, const u16* index, cons
constexpr int vlen = sizeof(VectorF) / sizeof(float);
#if _M_SSE >= 0x501
const GSVector8* shift = (GSVector8*)g_const.m_shift_256b;
const GSVector4 step_shift = GSVector4::broadcast32(&shift[0]);
auto load_shift = [](int i) { return GSVector8::load<false>(&g_const_256b.m_shift[8 - i]); };
const GSVector4 step_shift = GSVector4::broadcast32(&g_const_256b.m_shift[0]);
#else
const GSVector4* shift = (GSVector4*)g_const.m_shift_128b;
static const GSVector4* shift = reinterpret_cast<const GSVector4*>(g_const_128b.m_shift);
auto load_shift = [](int i) { return shift[1 + i]; };
const GSVector4 step_shift = shift[0];
#endif
@@ -233,22 +235,23 @@ void GSDrawScanline::CSetupPrim(const GSVertexSW* vertex, const u16* index, cons
for (int i = 0; i < vlen; i++)
{
local.d[i].f = VectorI(df * shift[1 + i]).xxzzlh();
local.d[i].f = VectorI(df * load_shift(i)).xxzzlh();
}
}
if (has_z && !sel.zequal)
{
const GSVector4 dz = GSVector4::broadcast64(&dscan.p.z);
const VectorF dzf(static_cast<float>(dscan.p.F64[1]));
#if _M_SSE >= 0x501
GSVector4::storel(&local.d8.p.z, dz.mul64(GSVector4::f32to64(shift)));
double dz = dscan.p.F64[1] * g_const_256b.m_shift[0];
memcpy(&local.d8.p.z, &dz, sizeof(dz));
#else
const GSVector4 dz = GSVector4::broadcast64(&dscan.p.z);
local.d4.z = dz.mul64(GSVector4::f32to64(shift));
#endif
for (int i = 0; i < vlen; i++)
{
local.d[i].z = dzf * shift[i + 1];
local.d[i].z = dzf * load_shift(i);
}
}
}
@@ -296,7 +299,7 @@ void GSDrawScanline::CSetupPrim(const GSVertexSW* vertex, const u16* index, cons
for (int i = 0; i < vlen; i++)
{
VectorF v = dstq * shift[1 + i];
VectorF v = dstq * load_shift(i);
if (sel.fst)
{
@@ -336,8 +339,8 @@ void GSDrawScanline::CSetupPrim(const GSVertexSW* vertex, const u16* index, cons
for (int i = 0; i < vlen; i++)
{
VectorI r = (VectorI(dr * shift[1 + i]) & mask16).pu32();
VectorI b = (VectorI(db * shift[1 + i]) & mask16).pu32();
VectorI r = (VectorI(dr * load_shift(i)) & mask16).ps32();
VectorI b = (VectorI(db * load_shift(i)) & mask16).ps32();
local.d[i].rb = r.upl16(b);
}
@@ -347,8 +350,8 @@ void GSDrawScanline::CSetupPrim(const GSVertexSW* vertex, const u16* index, cons
for (int i = 0; i < vlen; i++)
{
VectorI g = (VectorI(dg * shift[1 + i]) & mask16).pu32();
VectorI a = (VectorI(da * shift[1 + i]) & mask16).pu32();
VectorI g = (VectorI(dg * load_shift(i)) & mask16).ps32();
VectorI a = (VectorI(da * load_shift(i)) & mask16).ps32();
local.d[i].ga = g.upl16(a);
}
@@ -495,7 +498,7 @@ __ri void GSDrawScanline::CDrawScanline(int pixels, int left, int top, const GSV
constexpr int vlen = sizeof(VectorF) / sizeof(float);
#if _M_SSE < 0x501
const GSVector4i* const_test = (GSVector4i*)g_const.m_test_128b;
const GSVector4i* const_test = (GSVector4i*)g_const_128b.m_test;
#endif
VectorI test;
VectorF z0, z1;
@@ -515,7 +518,7 @@ __ri void GSDrawScanline::CDrawScanline(int pixels, int left, int top, const GSV
steps = pixels + skip - vlen;
left -= skip;
#if _M_SSE >= 0x501
test = GSVector8i::i8to32(g_const.m_test_256b[skip]) | GSVector8i::i8to32(g_const.m_test_256b[15 + (steps & (steps >> 31))]);
test = GSVector8i::i8to32(&g_const_256b.m_test[16 - skip]) | GSVector8i::i8to32(&g_const_256b.m_test[0 - (steps & (steps >> 31))]);
#else
test = const_test[skip] | const_test[7 + (steps & (steps >> 31))];
#endif
@@ -1747,7 +1750,7 @@ __ri void GSDrawScanline::CDrawScanline(int pixels, int left, int top, const GSV
if (!sel.notest)
{
#if _M_SSE >= 0x501
test = GSVector8i::i8to32(g_const.m_test_256b[15 + (steps & (steps >> 31))]);
test = GSVector8i::i8to32(&g_const_256b.m_test[0 - (steps & (steps >> 31))]);
#else
test = const_test[7 + (steps & (steps >> 31))];
#endif
@@ -16,7 +16,6 @@ using namespace Xbyak;
#pragma clang diagnostic ignored "-Winvalid-offsetof" // We know what we're doing.
#endif
#define _rip_const(cptr) ptr[rip + ((char*)(cptr))]
#define _rip_local(field) ptr[_m_local + offsetof(GSScanlineLocalData, field)]
#define _rip_local_offset(field, offset) ptr[_m_local + offsetof(GSScanlineLocalData, field) + (offset)]
#define _rip_global(field) ptr[_m_local__gd + offsetof(GSScanlineGlobalData, field)]
@@ -68,6 +67,29 @@ using namespace Xbyak;
#define _rip_local_d_p(x) _rip_local_d(x)
#endif
#if USING_YMM
static constexpr const GSScanlineConstantData256B& g_const = g_const_256b;
#else
static constexpr const GSScanlineConstantData128B& g_const = g_const_128b;
#endif
template <typename A, typename B>
static bool IsInRipRelativeRange(A* a, B* b)
{
uptr ai = reinterpret_cast<uptr>(a);
uptr bi = reinterpret_cast<uptr>(b);
sptr diff = static_cast<sptr>(bi - ai);
return diff == static_cast<s32>(diff);
}
template <typename A, typename B>
static s32 CalcOffset(A* from, B* to)
{
uptr ai = reinterpret_cast<uptr>(from);
uptr bi = reinterpret_cast<uptr>(to);
return static_cast<s32>(bi - ai);
}
GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(u64 key, void* code, size_t maxsize)
: GSNewCodeGenerator(code, maxsize)
#ifdef _WIN32
@@ -83,6 +105,7 @@ GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(u64 key, void* code, si
, t2(rcx), t3(rsi)
, _m_local(r8)
#endif
, _m_const(r14)
, _m_local__gd(r12)
, _m_local__gd__vm(t3)
, _m_local__gd__clut(r11)
@@ -90,7 +113,7 @@ GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(u64 key, void* code, si
, _rb(xym5), _ga(xym6), _fm(xym3), _zm(xym4), _fd(xym2), _test(xym15)
, _z(xym8), _f(xym9), _s(xym10), _t(xym11), _q(xym12), _f_rb(xym13), _f_ga(xym14)
{
// Free: r14, r15, rbp, to use, remember to save them.
// Free: r15, rbp, to use, remember to save them.
m_sel.key = key;
use_lod = m_sel.mmin;
if (isYmm)
@@ -315,8 +338,16 @@ void GSDrawScanlineCodeGenerator::Generate()
if (GSDrawScanline::ShouldUseCDrawScanline(m_sel.key))
{
jmp(reinterpret_cast<const void*>(static_cast<void (*)(int, int, int, const GSVertexSW&, GSScanlineLocalData&)>(
&GSDrawScanline::CDrawScanline)));
auto cds = static_cast<void(*)(int, int, int, const GSVertexSW&, GSScanlineLocalData&)>(&GSDrawScanline::CDrawScanline);
if (IsInRipRelativeRange(actual.getCode(), cds))
{
jmp(reinterpret_cast<void*>(cds));
}
else
{
mov(rax, reinterpret_cast<uptr>(cds));
actual.jmp(ptr[rax]);
}
return;
}
@@ -329,6 +360,7 @@ void GSDrawScanlineCodeGenerator::Generate()
push(rdi);
push(r12);
push(r13);
push(r14);
sub(rsp, _64_win_stack_size);
@@ -340,14 +372,22 @@ void GSDrawScanlineCodeGenerator::Generate()
mov(ptr[rsp + _64_rz_rbx], rbx);
mov(ptr[rsp + _64_rz_r12], r12);
mov(ptr[rsp + _64_rz_r13], r13);
mov(ptr[rsp + _64_rz_r14], r14);
#endif
#ifdef _WIN32
// Local (5th arg) is passed on the stack in Windows.
// 32 bytes shadow space less the 5 pushed registers and return address = 80.
mov(_m_local, ptr[rsp + _64_win_stack_size + 80]);
// 32 bytes shadow space less the 6 pushed registers and return address = 88.
mov(_m_local, ptr[rsp + _64_win_stack_size + 88]);
#endif
const void* code = actual.getCode();
const char* codeEnd = reinterpret_cast<const char*>(code) + (1024 * 1024);
if (IsInRipRelativeRange(code, &g_const) && IsInRipRelativeRange(codeEnd, &g_const))
lea(_m_const, ptr[rip + &g_const]);
else
mov(_m_const, reinterpret_cast<uptr>(&g_const));
mov(_m_local__gd, _rip_local(gd));
if (need_clut)
@@ -577,6 +617,7 @@ L("exit");
}
add(rsp, _64_win_stack_size);
pop(r14);
pop(r13);
pop(r12);
pop(rdi);
@@ -586,6 +627,7 @@ L("exit");
mov(rbx, ptr[rsp + _64_rz_rbx]);
mov(r12, ptr[rsp + _64_rz_r12]);
mov(r13, ptr[rsp + _64_rz_r13]);
mov(r14, ptr[rsp + _64_rz_r14]);
#endif
if (isYmm)
vzeroupper();
@@ -612,27 +654,29 @@ void GSDrawScanlineCodeGenerator::Init()
lea(a0.cvt32(), ptr[a0 + a1 - vecints]);
// GSVector4i test = m_test[skip] | m_test[7 + (steps & (steps >> 31))];
mov(eax, a0.cvt32());
sar(eax, 31); // GH: 31 to extract the sign of the register
and_(eax, a0.cvt32());
if (isXmm)
shl(eax, 4); // * sizeof(m_test[0])
cdqe();
if (isXmm)
{
lea(t1, _rip_const(&g_const.m_test_128b[0]));
// GSVector4i test = m_test[skip] | m_test[7 + (steps & (steps >> 31))];
mov(eax, a0.cvt32());
sar(eax, 31); // GH: 31 to extract the sign of the register
and_(eax, a0.cvt32());
shl(eax, 4); // * sizeof(m_test[0])
cdqe();
shl(a1.cvt32(), 4); // * sizeof(m_test[0])
movdqa(_test, ptr[a1 + t1]);
por(_test, ptr[rax + t1 + (offsetof(GSScanlineConstantData, m_test_128b[7]) - offsetof(GSScanlineConstantData, m_test_128b[0]))]);
movdqa(_test, ptr[a1 + _m_const + offsetof(GSScanlineConstantData128B, m_test[0])]);
por(_test, ptr[rax + _m_const + offsetof(GSScanlineConstantData128B, m_test[7])]);
}
else
{
lea(t1, _rip_const(&g_const.m_test_256b[0]));
pmovsxbd(_test, ptr[a1 * 8 + t1]);
pmovsxbd(xym0, ptr[rax * 8 + t1 + (offsetof(GSScanlineConstantData, m_test_256b[15]) - offsetof(GSScanlineConstantData, m_test_256b[0]))]);
// GSVector8i test = loadu(&m_test[16 - skip]) | loadu(&m_test[steps >= 0 ? 0 : -steps]);
mov(eax, a1.cvt32());
neg(rax); // rax = -skip
pmovsxbd(_test, ptr[rax + _m_const + offsetof(GSScanlineConstantData256B, m_test[16])]);
xor_(t0.cvt32(), t0.cvt32());
mov(eax, a0.cvt32());
neg(eax); // eax = -steps
cmovs(eax, t0.cvt32()); // if (eax < 0) eax = 0
pmovsxbd(xym0, ptr[rax + _m_const + offsetof(GSScanlineConstantData256B, m_test[0])]);
por(_test, xym0);
shl(a1.cvt32(), 5); // * sizeof(m_test[0])
}
@@ -875,7 +919,7 @@ void GSDrawScanlineCodeGenerator::Init()
/// Inputs: a0=steps, t0=fza_offset
/// Outputs[x86]: xym0=z xym2=s, xym3=t, xym4=q, xym5=rb, xym6=ga, xym7=test
/// Destroys[x86]: all
/// Destroys[x64]: xym0, xym1, xym2, xym3
/// Destroys[x64]: xym0, xym1, xym2, xym3, t2
void GSDrawScanlineCodeGenerator::Step()
{
// steps -= 4;
@@ -1001,21 +1045,22 @@ void GSDrawScanlineCodeGenerator::Step()
if (!m_sel.notest)
{
#if USING_XMM
// test = m_test[7 + (steps & (steps >> 31))];
mov(eax, a0.cvt32());
sar(eax, 31); // GH: 31 to extract the sign of the register
and_(eax, a0.cvt32());
if (isXmm)
shl(eax, 4);
shl(eax, 4);
cdqe();
#if USING_XMM
lea(t2, _rip_const(&g_const.m_test_128b[7]));
movdqa(_test, ptr[rax + t2]);
movdqa(_test, ptr[rax + _m_const + offsetof(GSScanlineConstantData128B, m_test[7])]);
#else
lea(t2, _rip_const(&g_const.m_test_256b[15]));
pmovsxbd(_test, ptr[rax * 8 + t2]);
// test = loadu(&m_test[steps >= 0 ? 0 : -steps]);
xor_(t2.cvt32(), t2.cvt32());
mov(eax, a0.cvt32());
neg(eax); // eax = -steps
cmovs(eax, t2.cvt32()); // if (eax < 0) eax = 0;
pmovsxbd(_test, ptr[rax + _m_const + offsetof(GSScanlineConstantData256B, m_test[0])]);
#endif
}
}
@@ -1051,7 +1096,7 @@ void GSDrawScanlineCodeGenerator::TestZ(const XYm& temp1, const XYm& temp2)
// zs = GSVector8i(zl, zh);
// zs += VectorI::x80000000();
broadcastsd(temp1, _rip_const(&GSVector4::m_xc1e00000000fffff));
broadcastsd(temp1, ptr[_m_const + CalcOffset(&g_const, &GSVector4::m_xc1e00000000fffff)]);
addpd(xym7, temp1);
addpd(temp1, _z);
@@ -1551,6 +1596,14 @@ void GSDrawScanlineCodeGenerator::Wrap(const XYm& uv0, const XYm& uv1)
}
}
static s32 log2_coeff_offset(int i)
{
// Yay, you can't offsetof with non-constant array indices
uptr base = reinterpret_cast<uptr>(&g_const);
uptr target = reinterpret_cast<uptr>(&g_const.m_log2_coef[i]);
return static_cast<s32>(target - base);
};
/// Input[x86]: xym4=q, xym2=s, xym3=t
/// Output: _rb, _ga
/// Destroys everything except xym7[x86]
@@ -1602,32 +1655,54 @@ void GSDrawScanlineCodeGenerator::SampleTextureLOD()
pslld(xym4, 9);
psrld(xym4, 9);
#if USING_YMM
auto load_log2_coeff = [this](const XYm& reg, int i)
{
vbroadcastss(reg, ptr[_m_const + log2_coeff_offset(i)]);
};
auto log2_coeff = [this, &load_log2_coeff](int i)
{
load_log2_coeff(xym6, i);
return xym6;
};
#else
auto log2_coeff = [this](int i) -> Address
{
if (isXmm)
return _rip_const(&g_const.m_log2_coef_128b[i]);
else
return _rip_const(&g_const.m_log2_coef_256b[i]);
return ptr[_m_const + log2_coeff_offset(i)];
};
auto load_log2_coeff = [this, &log2_coeff](const XYm& reg, int i)
{
movaps(reg, log2_coeff(i));
};
#endif
orps(xym4, log2_coeff(3));
load_log2_coeff(xym1, 3);
orps(xym4, xym1);
// xym4 = mant(q) | 1.0f
if (hasFMA)
{
movaps(xym5, log2_coeff(0)); // c0
load_log2_coeff(xym5, 0); // c0
vfmadd213ps(xym5, xym4, log2_coeff(1)); // c0 * xym4 + c1
vfmadd213ps(xym5, xym4, log2_coeff(2)); // (c0 * xym4 + c1) * xym4 + c2
subps(xym4, log2_coeff(3)); // xym4 - 1.0f
subps(xym4, xym1); // xym4 - 1.0f
vfmadd213ps(xym4, xym5, xym0); // ((c0 * xym4 + c1) * xym4 + c2) * (xym4 - 1.0f) + xym0
}
else
{
THREEARG(mulps, xym5, xym4, log2_coeff(0));
if (hasAVX)
{
vmulps(xym5, xym4, log2_coeff(0));
}
else
{
load_log2_coeff(xym5, 0);
mulps(xym5, xym4);
}
addps(xym5, log2_coeff(1));
mulps(xym5, xym4);
subps(xym4, log2_coeff(3));
subps(xym4, xym1);
addps(xym5, log2_coeff(2));
mulps(xym4, xym5);
addps(xym4, xym0);
@@ -41,9 +41,12 @@ class GSDrawScanlineCodeGenerator : public GSNewCodeGenerator
constexpr static int _64_top = 8 * 0;
// XMM registers will be saved to `rsp + _64_win_xmm_start + id - 6`
// Which will put xmm6 after the temporaries, them xmm7, etc
constexpr static int _64_win_xmm_start = 8 * 2;
constexpr static int _64_win_xmm_start = 8 * 1;
// Align the xmm variables on the stack with this
// Since we don't call any other functions, we don't need to keep rsp itself aligned
constexpr static int _64_win_xmm_align = 8 * 1;
// Windows has no redzone and also has 10 xmm registers to save
constexpr static int _64_win_stack_size = _64_win_xmm_start + 16 * 10;
constexpr static int _64_win_stack_size = _64_win_xmm_align + _64_win_xmm_start + 16 * 10;
#else
// System-V has a redzone so stick everything there
constexpr static int _64_rz_rbx = -8 * 1;
@@ -62,7 +65,7 @@ class GSDrawScanlineCodeGenerator : public GSNewCodeGenerator
/// Note: a2 and t3 are only available on x86-64
/// Outside of Init, usable registers are a0, t0, t1, t2, t3[x64], rax, rbx, rdx, r10+
const AddressReg a0, a1, a2, a3, t0, t1, t2, t3;
const AddressReg _m_local, _m_local__gd, _m_local__gd__vm, _m_local__gd__clut;
const AddressReg _m_local, _m_const, _m_local__gd, _m_local__gd__vm, _m_local__gd__clut;
// If use_lod, m_local.gd->tex, else m_local.gd->tex[0]
const AddressReg _m_local__gd__tex;
/// Available on both x86 and x64, not always valid
@@ -204,10 +204,12 @@ public:
FORWARD_OO_OI(or_)
FORWARD_OO_OI(sub)
FORWARD_OO_OI(xor_)
FORWARD(2, BASE, cmovs, const Reg&, const Operand&)
FORWARD(2, BASE, lea, const Reg&, const Address&)
FORWARD(2, BASE, mov, const Operand&, size_t)
FORWARD(2, BASE, mov, ARGS_OO)
FORWARD(2, BASE, movzx, const Reg&, const Operand&)
FORWARD(1, BASE, neg, const Operand&)
FORWARD(1, BASE, not_, const Operand&)
FORWARD(1, BASE, pop, const Operand&)
FORWARD(1, BASE, push, const Operand&)
@@ -243,6 +245,8 @@ public:
AFORWARD(2, minps, ARGS_XO)
SFORWARD(2, movaps, ARGS_XO)
SFORWARD(2, movaps, const Address&, const Xmm&)
SFORWARD(2, movups, ARGS_XO)
SFORWARD(2, movups, const Address&, const Xmm&)
SFORWARD(2, movd, const Address&, const Xmm&)
SFORWARD(2, movd, const Reg32&, const Xmm&)
SFORWARD(2, movd, const Xmm&, const Address&)
+43 -48
View File
@@ -243,41 +243,45 @@ struct alignas(32) GSScanlineLocalData // per prim variables, each thread has it
const GSScanlineGlobalData* gd;
};
// Constant shared by all threads (to reduce cache miss)
struct GSScanlineConstantData : public GSAlignedClass<32>
namespace GSScanlineConstantData
{
alignas(32) u8 m_test_256b[16][8] = {
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00},
{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00},
{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff},
{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
{0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
static constexpr float log2_coef[] = {
0.204446009836232697516f,
-1.04913055217340124191f,
2.28330284476918490682f,
1.0f
};
alignas(32) float m_shift_256b[9][8] = {
{ 8.0f , 8.0f , 8.0f , 8.0f , 8.0f , 8.0f , 8.0f , 8.0f},
{ 0.0f , 1.0f , 2.0f , 3.0f , 4.0f , 5.0f , 6.0f , 7.0f},
{ -1.0f , 0.0f , 1.0f , 2.0f , 3.0f , 4.0f , 5.0f , 6.0f},
{ -2.0f , -1.0f , 0.0f , 1.0f , 2.0f , 3.0f , 4.0f , 5.0f},
{ -3.0f , -2.0f , -1.0f , 0.0f , 1.0f , 2.0f , 3.0f , 4.0f},
{ -4.0f , -3.0f , -2.0f , -1.0f , 0.0f , 1.0f , 2.0f , 3.0f},
{ -5.0f , -4.0f , -3.0f , -2.0f , -1.0f , 0.0f , 1.0f , 2.0f},
{ -6.0f , -5.0f , -4.0f , -3.0f , -2.0f , -1.0f , 0.0f , 1.0f},
{ -7.0f , -6.0f , -5.0f , -4.0f , -3.0f , -2.0f , -1.0f , 0.0f},
};
alignas(32) float m_log2_coef_256b[4][8] = {};
};
alignas(16) u32 m_test_128b[8][4] = {
// Constant shared by all threads (to reduce cache miss)
struct alignas(64) GSScanlineConstantData256B
{
// All AVX processors support unaligned access with little to no penalty as long as you don't cross a cache line.
// Take advantage of that to store single vectors that we index with single-element alignment
alignas(32) u8 m_test[24] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
float m_log2_coef[4] = {};
alignas(64) float m_shift[16] = {
8.0f, -7.0f, -6.0f, -5.0f, -4.0f, -3.0f, -2.0f, -1.0f,
0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f,
};
constexpr GSScanlineConstantData256B()
{
using namespace GSScanlineConstantData;
for (size_t n = 0; n < std::size(log2_coef); ++n)
{
m_log2_coef[n] = log2_coef[n];
}
}
};
struct alignas(64) GSScanlineConstantData128B
{
alignas(16) u32 m_test[8][4] = {
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0xffffffff, 0x00000000, 0x00000000, 0x00000000},
{0xffffffff, 0xffffffff, 0x00000000, 0x00000000},
@@ -287,34 +291,25 @@ struct GSScanlineConstantData : public GSAlignedClass<32>
{0x00000000, 0x00000000, 0x00000000, 0xffffffff},
{0x00000000, 0x00000000, 0x00000000, 0x00000000},
};
alignas(16) float m_shift_128b[5][4] = {
alignas(16) float m_shift[5][4] = {
{ 4.0f , 4.0f , 4.0f , 4.0f},
{ 0.0f , 1.0f , 2.0f , 3.0f},
{ -1.0f , 0.0f , 1.0f , 2.0f},
{ -2.0f , -1.0f , 0.0f , 1.0f},
{ -3.0f , -2.0f , -1.0f , 0.0f},
};
alignas(16) float m_log2_coef_128b[4][4] = {};
alignas(16) float m_log2_coef[4][4] = {};
constexpr GSScanlineConstantData()
constexpr GSScanlineConstantData128B()
{
constexpr float log2_coef[] = {
0.204446009836232697516f,
-1.04913055217340124191f,
2.28330284476918490682f,
1.0f
};
using namespace GSScanlineConstantData;
for (size_t n = 0; n < std::size(log2_coef); ++n)
{
for (size_t i = 0; i < 4; ++i)
{
m_log2_coef_128b[n][i] = log2_coef[n];
m_log2_coef_256b[n][i] = log2_coef[n];
m_log2_coef_256b[n][i + 4] = log2_coef[n];
}
m_log2_coef[n][i] = log2_coef[n];
}
}
};
extern const GSScanlineConstantData g_const;
extern const GSScanlineConstantData256B g_const_256b;
extern const GSScanlineConstantData128B g_const_128b;
@@ -104,13 +104,18 @@ void GSSetupPrimCodeGenerator::Generate()
{
if (isXmm)
mov(rax, (size_t)g_const.m_shift_128b);
mov(rax, (size_t)g_const_128b.m_shift);
else
mov(rax, (size_t)g_const.m_shift_256b);
mov(rax, (size_t)g_const_256b.m_shift);
for (int i = 0; i < (m_sel.notest ? 2 : many_regs ? 9 : 5); i++)
{
movaps(XYm(3 + i), ptr[rax + i * vecsize]);
if (isXmm)
movaps(XYm(3 + i), ptr[rax + i * vecsize]);
else if (i == 0)
vbroadcastss(xym3, ptr[rax]);
else
movups(XYm(3 + i), ptr[rax + (9 - i) * sizeof(float)]);
}
}
@@ -253,7 +258,7 @@ void GSSetupPrimCodeGenerator::Depth_YMM()
if (i < 4 || many_regs)
vmulps(ymm0, Ymm(4 + i), ymm1);
else
vmulps(ymm0, ymm1, ptr[g_const.m_shift_256b[i + 1]]);
vmulps(ymm0, ymm1, ptr[&g_const_256b.m_shift[8 - i]]);
cvttps2dq(ymm0, ymm0);
pshuflw(ymm0, ymm0, _MM_SHUFFLE(2, 2, 0, 0));
pshufhw(ymm0, ymm0, _MM_SHUFFLE(2, 2, 0, 0));
@@ -281,7 +286,7 @@ void GSSetupPrimCodeGenerator::Depth_YMM()
if (i < 4 || many_regs)
vmulps(ymm1, Ymm(4 + i), ymm0);
else
vmulps(ymm1, ymm0, ptr[g_const.m_shift_256b[i + 1]]);
vmulps(ymm1, ymm0, ptr[&g_const_256b.m_shift[8 - i]]);
movaps(_rip_local_di(i, z), ymm1);
}
}
@@ -356,7 +361,7 @@ void GSSetupPrimCodeGenerator::Texture()
if (i < 4 || many_regs)
THREEARG(mulps, xym2, XYm(4 + i), xym1);
else
vmulps(ymm2, ymm1, ptr[g_const.m_shift_256b[i + 1]]);
vmulps(ymm2, ymm1, ptr[&g_const_256b.m_shift[8 - i]]);
if (m_sel.fst)
{
@@ -429,7 +434,7 @@ void GSSetupPrimCodeGenerator::Color()
if (i < 4 || many_regs)
THREEARG(mulps, xym0, XYm(4 + i), xym2);
else
vmulps(ymm0, ymm2, ptr[g_const.m_shift_256b[i + 1]]);
vmulps(ymm0, ymm2, ptr[&g_const_256b.m_shift[8 - i]]);
cvttps2dq(xym0, xym0);
pand(xym0, mask16);
packusdw(xym0, xym0);
@@ -439,7 +444,7 @@ void GSSetupPrimCodeGenerator::Color()
if (i < 4 || many_regs)
THREEARG(mulps, xym1, XYm(4 + i), xym3);
else
vmulps(ymm1, ymm3, ptr[g_const.m_shift_256b[i + 1]]);
vmulps(ymm1, ymm3, ptr[&g_const_256b.m_shift[8 - i]]);
cvttps2dq(xym1, xym1);
pand(xym1, mask16);
packusdw(xym1, xym1);
@@ -467,7 +472,7 @@ void GSSetupPrimCodeGenerator::Color()
if (i < 4 || many_regs)
THREEARG(mulps, xym0, XYm(4 + i), xym2);
else
vmulps(ymm0, ymm2, ptr[g_const.m_shift_256b[i + 1]]);
vmulps(ymm0, ymm2, ptr[&g_const_256b.m_shift[8 - i]]);
cvttps2dq(xym0, xym0);
pand(xym0, mask16);
packusdw(xym0, xym1);
@@ -477,7 +482,7 @@ void GSSetupPrimCodeGenerator::Color()
if (i < 4 || many_regs)
THREEARG(mulps, xym1, XYm(4 + i), xym3);
else
vmulps(ymm1, ymm3, ptr[g_const.m_shift_256b[i + 1]]);
vmulps(ymm1, ymm3, ptr[&g_const_256b.m_shift[8 - i]]);
cvttps2dq(xym1, xym1);
pand(xym1, mask16);
packusdw(xym1, xym1);
@@ -20,6 +20,8 @@ static const auto& _locals = x3;
static const auto& _scratchaddr = x7;
static const auto& _vscratch = v31;
static constexpr const GSScanlineConstantData128B& g_const = g_const_128b;
#define _local(field) MemOperand(_locals, offsetof(GSScanlineLocalData, field))
#define armAsm (&m_emitter)
@@ -38,10 +40,10 @@ void GSSetupPrimCodeGenerator::Generate()
const bool needs_shift = ((m_en.z || m_en.f) && m_sel.prim != GS_SPRITE_CLASS) || m_en.t || (m_en.c && m_sel.iip);
if (needs_shift)
{
armAsm->Mov(x4, reinterpret_cast<intptr_t>(g_const.m_shift_128b));
armAsm->Mov(x4, reinterpret_cast<intptr_t>(g_const.m_shift));
for (int i = 0; i < (m_sel.notest ? 2 : 5); i++)
{
armAsm->Ldr(VRegister(3 + i, kFormat16B), MemOperand(x4, i * sizeof(g_const.m_shift_128b[0])));
armAsm->Ldr(VRegister(3 + i, kFormat16B), MemOperand(x4, i * sizeof(g_const.m_shift[0])));
}
}
-5
View File
@@ -3187,9 +3187,6 @@ void FullscreenUI::DrawGameListSettingsWindow()
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TAG, "Show Titles"),
FSUI_CSTR("Shows Titles for Games when in Game Grid View Mode"), "UI",
"FullscreenUIShowGameGridTitles", true);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GLOBE, "Prefer English Titles"),
FSUI_CSTR("For games with both a title in the game's native language and one in English, prefer the English title."), "UI",
"PreferEnglishGameList", false);
}
MenuHeading(FSUI_CSTR("Cover Settings"));
@@ -4095,7 +4092,6 @@ TRANSLATE_NOOP("FullscreenUI", "Sets which view the game list will open to.");
TRANSLATE_NOOP("FullscreenUI", "Determines which field the game list will be sorted by.");
TRANSLATE_NOOP("FullscreenUI", "Reverses the game list sort order from the default (usually ascending to descending).");
TRANSLATE_NOOP("FullscreenUI", "Shows Titles for Games when in Game Grid View Mode");
TRANSLATE_NOOP("FullscreenUI", "For games with both a title in the game's native language and one in English, prefer the English title.");
TRANSLATE_NOOP("FullscreenUI", "Cover Settings");
TRANSLATE_NOOP("FullscreenUI", "Downloads covers from a user-specified URL template.");
TRANSLATE_NOOP("FullscreenUI", "Operations");
@@ -4209,7 +4205,6 @@ TRANSLATE_NOOP("FullscreenUI", "Default View");
TRANSLATE_NOOP("FullscreenUI", "Sort By");
TRANSLATE_NOOP("FullscreenUI", "Sort Reversed");
TRANSLATE_NOOP("FullscreenUI", "Show Titles");
TRANSLATE_NOOP("FullscreenUI", "Prefer English Titles");
TRANSLATE_NOOP("FullscreenUI", "Covers Directory");
TRANSLATE_NOOP("FullscreenUI", "Download Covers");
TRANSLATE_NOOP("FullscreenUI", "Scan For New Games");
+13 -2
View File
@@ -897,7 +897,7 @@ void FullscreenUI::DrawFloatSpinBoxSetting(SettingsInterface* bsi, const char* t
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.25f, 0.25f, 0.25f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
if (ImGui::InputText("##value", str_value, std::size(str_value), ImGuiInputTextFlags_CharsDecimal))
{
@@ -2185,6 +2185,9 @@ void FullscreenUI::DrawInterfaceSettingsPage()
"UI", "FullscreenUITheme", "Dark", s_theme_name, s_theme_value, std::size(s_theme_name), true);
DrawToggleSetting(
bsi, FSUI_ICONSTR(ICON_FA_LIST, "Default To Game List"), FSUI_CSTR("When Big Picture mode is started, the game list will be displayed instead of the main menu."), "UI", "FullscreenUIDefaultToGameList", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GLOBE, "Prefer English Game Titles"),
FSUI_CSTR("For games with both a title in the game's native language and one in English, prefer the English title. Affects how game titles are displayed on the game list, window title and Discord Presence"), "UI",
"PreferEnglishGameList", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CIRCLE_INFO, "Use Save State Selector"),
FSUI_CSTR("Show a save state selector UI when switching slots instead of showing a notification bubble."),
"EmuCore", "UseSavestateSelector", true);
@@ -3355,7 +3358,7 @@ void FullscreenUI::DrawOSDSettingsPage()
}
}
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BOLD, "Bold OSD Text"),
FSUI_CSTR("Draws OSD text with heavier weight for improved readability."),
FSUI_CSTR("Draws OSD text with heavier weight for improved readability."),
"EmuCore/GS", "OsdBoldText", true);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CODE_MERGE, "Show PCSX2 Version"),
FSUI_CSTR("Shows the current PCSX2 version."), "EmuCore/GS",
@@ -3383,6 +3386,10 @@ void FullscreenUI::DrawOSDSettingsPage()
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_PLAY, "Show Status Indicators"),
FSUI_CSTR("Shows indicators when fast forwarding, pausing, and other abnormal states are active."), "EmuCore/GS",
"OsdShowIndicators", true);
#ifdef _WIN32
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BUG, "Show GPU Debug Info"),
FSUI_CSTR("Shows debug information about the renderer."), "EmuCore/GS", "OsdShowGPUDebug", false);
#endif
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_HEARTBEAT_ALT, "Show Frame Times"),
FSUI_CSTR("Shows a visual history of frame times."), "EmuCore/GS", "OsdShowFrameTimes", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_SLIDERS, "Show Settings"),
@@ -5133,6 +5140,7 @@ TRANSLATE_NOOP("FullscreenUI", "Clears all settings set for this game.");
TRANSLATE_NOOP("FullscreenUI", "Appearance");
TRANSLATE_NOOP("FullscreenUI", "Selects the color style to be used for Big Picture Mode.");
TRANSLATE_NOOP("FullscreenUI", "When Big Picture mode is started, the game list will be displayed instead of the main menu.");
TRANSLATE_NOOP("FullscreenUI", "For games with both a title in the game's native language and one in English, prefer the English title. Affects how game titles are displayed on the game list, window title and Discord Presence");
TRANSLATE_NOOP("FullscreenUI", "Show a save state selector UI when switching slots instead of showing a notification bubble.");
TRANSLATE_NOOP("FullscreenUI", "Background");
TRANSLATE_NOOP("FullscreenUI", "Select a custom background image to use in Big Picture Mode menus.\n\nSupported formats: PNG, JPG, JPEG, BMP.");
@@ -5333,6 +5341,7 @@ TRANSLATE_NOOP("FullscreenUI", "Shows statistics about the emulated GS such as p
TRANSLATE_NOOP("FullscreenUI", "Shows the host's CPU utilization based on threads.");
TRANSLATE_NOOP("FullscreenUI", "Shows the host's GPU utilization.");
TRANSLATE_NOOP("FullscreenUI", "Shows indicators when fast forwarding, pausing, and other abnormal states are active.");
TRANSLATE_NOOP("FullscreenUI", "Shows debug information about the renderer.");
TRANSLATE_NOOP("FullscreenUI", "Shows a visual history of frame times.");
TRANSLATE_NOOP("FullscreenUI", "Shows the current configuration in the bottom-right corner of the display.");
TRANSLATE_NOOP("FullscreenUI", "Shows the amount of currently active patches/cheats on the bottom-right corner of the display.");
@@ -5744,6 +5753,7 @@ TRANSLATE_NOOP("FullscreenUI", "Copy Settings");
TRANSLATE_NOOP("FullscreenUI", "Clear Settings");
TRANSLATE_NOOP("FullscreenUI", "Theme");
TRANSLATE_NOOP("FullscreenUI", "Default To Game List");
TRANSLATE_NOOP("FullscreenUI", "Prefer English Game Titles");
TRANSLATE_NOOP("FullscreenUI", "Use Save State Selector");
TRANSLATE_NOOP("FullscreenUI", "Background Image");
TRANSLATE_NOOP("FullscreenUI", "Select Background Image");
@@ -5842,6 +5852,7 @@ TRANSLATE_NOOP("FullscreenUI", "Show GS Statistics");
TRANSLATE_NOOP("FullscreenUI", "Show CPU Usage");
TRANSLATE_NOOP("FullscreenUI", "Show GPU Usage");
TRANSLATE_NOOP("FullscreenUI", "Show Status Indicators");
TRANSLATE_NOOP("FullscreenUI", "Show GPU Debug Info");
TRANSLATE_NOOP("FullscreenUI", "Show Frame Times");
TRANSLATE_NOOP("FullscreenUI", "Show Settings");
TRANSLATE_NOOP("FullscreenUI", "Show Patches");
+29 -1
View File
@@ -8,6 +8,9 @@
#include "GS/GSCapture.h"
#include "GS/GSVector.h"
#include "GS/Renderers/Common/GSDevice.h"
#ifdef _WIN32
#include "GS/Renderers/DX12/GSDevice12.h"
#endif
#include "GS/Renderers/HW/GSTextureReplacements.h"
#include "Host.h"
#include "IconsFontAwesome.h"
@@ -66,6 +69,7 @@ SmallString s_cpu_usage_vu_line;
std::vector<SmallString> s_software_thread_lines;
SmallString s_capture_line;
SmallString s_gpu_usage_line;
SmallString s_gpu_debug_info_line;
SmallString s_speed_icon;
constexpr ImU32 white_color = IM_COL32(255, 255, 255, 255);
@@ -482,6 +486,22 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
FormatProcessorStat(s_gpu_usage_line, PerformanceMetrics::GetGPUUsage(), PerformanceMetrics::GetGPUAverageTime());
DRAW_LINE(osd_font, font_size, s_gpu_usage_line.c_str(), white_color);
}
if (GSConfig.OsdShowGPUDebug)
{
#ifdef _WIN32
if (g_gs_device->GetRenderAPI() == RenderAPI::D3D12)
{
GSDevice12* dev12 = static_cast<GSDevice12*>(g_gs_device.get());
s_gpu_debug_info_line.format("D3D12 Descriptor Heaps | SRV/UAV: {}/{} | RTV: {}/{} | DSV {}/{}",
dev12->GetDescriptorHeapManager().GetAllocatedDescriptors(), dev12->GetDescriptorHeapManager().GetNumDescriptors(),
dev12->GetRTVHeapManager().GetAllocatedDescriptors(), dev12->GetRTVHeapManager().GetNumDescriptors(),
dev12->GetDSVHeapManager().GetAllocatedDescriptors(), dev12->GetDSVHeapManager().GetNumDescriptors());
DRAW_LINE(osd_font, font_size, s_gpu_debug_info_line.c_str(), white_color);
}
#endif
}
}
// No refresh yet. Display cached lines.
else
@@ -526,6 +546,14 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
if (GSConfig.OsdShowGPU)
DRAW_LINE(osd_font, font_size, s_gpu_usage_line.c_str(), white_color);
if (GSConfig.OsdShowGPUDebug)
{
#ifdef _WIN32
if (g_gs_device->GetRenderAPI() == RenderAPI::D3D12)
DRAW_LINE(osd_font, font_size, s_gpu_debug_info_line.c_str(), white_color);
#endif
}
}
// Check every OSD frame because this is an animation.
@@ -908,7 +936,7 @@ __ri void ImGuiManager::DrawInputsOverlay(float scale, float margin, float spaci
return;
const float shadow_offset = std::ceil(scale);
ImFont* const font = ImGuiManager::GetOSDFont();
ImFont* const font = ImGuiManager::GetStandardFont();
const float font_size = ImGuiManager::GetFontSizeStandard();
const float line_height = ImGuiFullscreen::GetLineHeight({ font, font_size });
+6 -1
View File
@@ -145,6 +145,11 @@ void MTGS::ThreadEntryPoint()
{
Threading::SetNameOfCurrentThread("GS");
// GS can hit SMC write traps when executing InitAndReadFIFO
// As racey as it sounds, it should be safe, since InitAndReadFIFO is requested and immediately waited for,
// so the EE thread shouldn't be touching any of its codegen structures while it happens.
PageFaultHandler::InstallSecondaryThread();
// Explicitly set rounding mode to default (nearest, FTZ off).
// Otherwise it appears to get inherited from the EE thread on Linux.
FPControlRegister::SetCurrent(FPControlRegister::GetDefault());
@@ -1077,4 +1082,4 @@ void Gif_AddBlankGSPacket(u32 size, GIF_PATH path)
void Gif_MTGS_Wait(bool isMTVU)
{
MTGS::WaitGS(false, true, isMTVU);
}
}
+20 -89
View File
@@ -50,9 +50,6 @@ namespace Ps2MemSize
namespace SysMemory
{
static u8* TryAllocateVirtualMemory(const char* name, void* file_handle, uptr base, size_t size);
static u8* AllocateVirtualMemory(const char* name, void* file_handle, size_t size, size_t offset_from_base);
static bool AllocateMemoryMap();
static void DumpMemoryMap();
static void ReleaseMemoryMap();
@@ -60,6 +57,7 @@ namespace SysMemory
static u8* s_data_memory;
static void* s_data_memory_file_handle;
static u8* s_code_memory;
static std::unique_ptr<SharedMemoryMappingArea> s_memory_mapping_area;
} // namespace SysMemory
static void memAllocate();
@@ -87,77 +85,6 @@ namespace HostMemoryMap
}
} // namespace HostMemoryMap
u8* SysMemory::TryAllocateVirtualMemory(const char* name, void* file_handle, uptr base, size_t size)
{
u8* baseptr;
if (file_handle)
baseptr = static_cast<u8*>(HostSys::MapSharedMemory(file_handle, 0, (void*)base, size, PageAccess_ReadWrite()));
else
baseptr = static_cast<u8*>(HostSys::Mmap((void*)base, size, PageAccess_Any()));
if (!baseptr)
return nullptr;
if (base != 0 && (uptr)baseptr != base)
{
if (file_handle)
{
if (baseptr)
HostSys::UnmapSharedMemory(baseptr, size);
}
else
{
if (baseptr)
HostSys::Munmap(baseptr, size);
}
return nullptr;
}
DevCon.WriteLn(Color_Gray, "%-32s @ 0x%016" PRIXPTR " -> 0x%016" PRIXPTR " %s", name,
baseptr, (uptr)baseptr + size, fmt::format("[{}mb]", size / _1mb).c_str());
return baseptr;
}
u8* SysMemory::AllocateVirtualMemory(const char* name, void* file_handle, size_t size, size_t offset_from_base)
{
// ARM64 does not need the rec areas to be in +/- 2GB.
#ifdef _M_X86
pxAssertRel(Common::IsAlignedPow2(size, __pagesize), "Virtual memory size is page aligned");
// Everything looks nicer when the start of all the sections is a nice round looking number.
// Also reduces the variation in the address due to small changes in code.
// Breaks ASLR but so does anything else that tries to make addresses constant for our debugging pleasure
uptr codeBase = (uptr)(void*)AllocateVirtualMemory / (1 << 28) * (1 << 28);
// The allocation is ~640mb in size, slighly under 3*2^28.
// We'll hope that the code generated for the PCSX2 executable stays under 512mb (which is likely)
// On x86-64, code can reach 8*2^28 from its address [-6*2^28, 4*2^28] is the region that allows for code in the 640mb allocation to reach 512mb of code that either starts at codeBase or 256mb before it.
// We start high and count down because on macOS code starts at the beginning of useable address space, so starting as far ahead as possible reduces address variations due to code size. Not sure about other platforms. Obviously this only actually affects what shows up in a debugger and won't affect performance or correctness of anything.
for (int offset = 4; offset >= -6; offset--)
{
uptr base = codeBase + (offset << 28) + offset_from_base;
if ((sptr)base < 0 || (sptr)(base + size - 1) < 0)
{
// VTLB will throw a fit if we try to put EE main memory here
continue;
}
if (u8* ret = TryAllocateVirtualMemory(name, file_handle, base, size))
return ret;
DevCon.Warning("%s: host memory @ 0x%016" PRIXPTR " -> 0x%016" PRIXPTR " is unavailable; attempting to map elsewhere...", name,
base, base + size);
}
#else
return TryAllocateVirtualMemory(name, file_handle, 0, size);
#endif
return nullptr;
}
bool SysMemory::AllocateMemoryMap()
{
s_data_memory_file_handle = HostSys::CreateSharedMemory(HostSys::GetFileMappingName("pcsx2").c_str(), HostMemoryMap::MainSize);
@@ -168,16 +95,23 @@ bool SysMemory::AllocateMemoryMap()
return false;
}
if ((s_data_memory = AllocateVirtualMemory("Data Memory", s_data_memory_file_handle, HostMemoryMap::MainSize, 0)) == nullptr)
if (!(s_memory_mapping_area = SharedMemoryMappingArea::Create(HostMemoryMap::MainSize + HostMemoryMap::CodeSize, true)))
{
Host::ReportErrorAsync("Error", "Failed to map data memory at an acceptable location.");
Host::ReportErrorAsync("Error", "Failed to map main memory.");
ReleaseMemoryMap();
return false;
}
if ((s_code_memory = AllocateVirtualMemory("Code Memory", nullptr, HostMemoryMap::CodeSize, HostMemoryMap::MainSize)) == nullptr)
if ((s_data_memory = s_memory_mapping_area->Map(s_data_memory_file_handle, 0, s_memory_mapping_area->BasePointer(), HostMemoryMap::MainSize, PageAccess_ReadWrite())) == nullptr)
{
Host::ReportErrorAsync("Error", "Failed to allocate code memory at an acceptable location.");
Host::ReportErrorAsync("Error", "Failed to map data memory.");
ReleaseMemoryMap();
return false;
}
if ((s_code_memory = s_memory_mapping_area->Map(nullptr, 0, s_memory_mapping_area->OffsetPointer(HostMemoryMap::MainSize), HostMemoryMap::CodeSize, PageAccess_Any())) == nullptr)
{
Host::ReportErrorAsync("Error", "Failed to allocate code memory.");
ReleaseMemoryMap();
return false;
}
@@ -186,6 +120,7 @@ bool SysMemory::AllocateMemoryMap()
HostMemoryMap::IOPmem = (uptr)(s_data_memory + HostMemoryMap::IOPmemOffset);
HostMemoryMap::VUmem = (uptr)(s_data_memory + HostMemoryMap::VUmemOffset);
DumpMemoryMap();
return true;
}
@@ -218,16 +153,18 @@ void SysMemory::ReleaseMemoryMap()
{
if (s_code_memory)
{
HostSys::Munmap(s_code_memory, HostMemoryMap::CodeSize);
s_memory_mapping_area->Unmap(s_code_memory, HostMemoryMap::CodeSize, false);
s_code_memory = nullptr;
}
if (s_data_memory)
{
HostSys::UnmapSharedMemory(s_data_memory, HostMemoryMap::MainSize);
s_memory_mapping_area->Unmap(s_data_memory, HostMemoryMap::MainSize, true);
s_data_memory = nullptr;
}
s_memory_mapping_area.reset();
if (s_data_memory_file_handle)
{
HostSys::DestroySharedMemory(s_data_memory_file_handle);
@@ -235,21 +172,13 @@ void SysMemory::ReleaseMemoryMap()
}
}
void SysMemory::ReserveMemory()
{
if (!s_data_memory_file_handle)
AllocateMemoryMap();
}
bool SysMemory::Allocate()
{
DevCon.WriteLn(Color_StrongBlue, "Allocating host memory for virtual systems...");
if (!s_data_memory_file_handle && !AllocateMemoryMap())
if (!AllocateMemoryMap())
return false;
DumpMemoryMap();
memAllocate();
iopMemAlloc();
vuMemAllocate();
@@ -281,6 +210,8 @@ void SysMemory::Release()
vuMemRelease();
iopMemRelease();
memRelease();
ReleaseMemoryMap();
}
u8* SysMemory::GetDataPtr(size_t offset)
-2
View File
@@ -98,8 +98,6 @@ namespace HostMemoryMap
namespace SysMemory
{
/// Call this as early as possible to maximize chance of getting the address space we want
void ReserveMemory();
bool Allocate();
void Reset();
void Release();
+2
View File
@@ -732,6 +732,7 @@ Pcsx2Config::GSOptions::GSOptions()
OsdShowGSStats = false;
OsdShowCPU = false;
OsdShowGPU = false;
OsdShowGPUDebug = false;
OsdShowIndicators = true;
OsdShowFrameTimes = false;
OsdShowHardwareInfo = false;
@@ -957,6 +958,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBool(OsdShowVPS);
SettingsWrapBitBool(OsdShowCPU);
SettingsWrapBitBool(OsdShowGPU);
SettingsWrapBitBool(OsdShowGPUDebug);
SettingsWrapBitBool(OsdShowResolution);
SettingsWrapBitBool(OsdShowGSStats);
SettingsWrapBitBool(OsdShowIndicators);
+25 -4
View File
@@ -341,7 +341,7 @@ std::string VMManager::GetTitle(bool prefer_en)
{
std::unique_lock lock(s_info_mutex);
std::string out = s_title;
if (!s_title_en_search.empty())
if (prefer_en && !s_title_en_search.empty())
{
size_t pos = out.find(s_title_en_search);
if (pos != out.npos)
@@ -1221,8 +1221,10 @@ void VMManager::ReportGameChangeToHost()
{
const std::string& disc_path = CDVDsys_GetFile(CDVDsys_GetSourceType());
const u32 crc_to_report = HasBootedELF() ? s_current_crc : 0;
FullscreenUI::GameChanged(disc_path, s_disc_serial, GetTitle(true), s_disc_crc, crc_to_report);
Host::OnGameChanged(s_title, s_elf_override, disc_path, s_disc_serial, s_disc_crc, crc_to_report);
const bool prefer_english = Host::GetBaseBoolSettingValue("UI", "PreferEnglishGameList", false);
const std::string game_title = GetTitle(prefer_english);
FullscreenUI::GameChanged(disc_path, s_disc_serial, game_title, s_disc_crc, crc_to_report);
Host::OnGameChanged(game_title, s_elf_override, disc_path, s_disc_serial, s_disc_crc, crc_to_report);
}
bool VMManager::HasBootedELF()
@@ -3266,6 +3268,11 @@ void VMManager::WarnAboutUnsafeSettings()
append(ICON_FA_IMAGES,
TRANSLATE_SV("VMManager", "Accurate Alpha Test is enabled, this may reduce performance."));
}
if (EmuConfig.GS.DepthFeedbackMode != GSDepthFeedbackMode::Auto)
{
append(ICON_FA_IMAGES,
TRANSLATE_SV("VMManager", "Overriding default depth feedback mode, this may break rendering in some games."));
}
if (EmuConfig.GS.UseDebugDevice)
{
append(ICON_FA_BUG,
@@ -3296,6 +3303,11 @@ void VMManager::WarnAboutUnsafeSettings()
TRANSLATE_SV("VMManager", "Graphics API is not set to Automatic. This may cause performance problems and graphical issues."));
}
}
if (EmuConfig.GS.DumpGSData)
{
const std::string& dir = is_sw_renderer ? EmuConfig.GS.SWDumpDirectory : EmuConfig.GS.HWDumpDirectory;
append(ICON_FA_LAYER_GROUP, fmt::format(TRANSLATE_FS("VMManager", "Dumping draw data to {}."), dir));
}
if (EmuConfig.GS.TextureFiltering != BiFiltering::PS2)
{
append(ICON_FA_FILTER,
@@ -3757,12 +3769,21 @@ void VMManager::UpdateDiscordPresence(bool update_session_time)
if (update_session_time)
s_discord_presence_time_epoch = std::time(nullptr);
std::string rp_title;
const bool prefer_english = Host::GetBaseBoolSettingValue("UI", "PreferEnglishGameList", false);
if (!s_title.empty())
rp_title = GetTitle(prefer_english);
// https://discord.com/developers/docs/rich-presence/how-to#updating-presence-update-presence-payload-fields
DiscordRichPresence rp = {};
rp.largeImageKey = "4k-pcsx2";
rp.largeImageText = "PCSX2 PS2 Emulator";
rp.startTimestamp = s_discord_presence_time_epoch;
rp.details = s_title.empty() ? TRANSLATE("VMManager", "No Game Running") : s_title.c_str();
if (rp_title.empty())
rp.details = TRANSLATE("VMManager", "No Game Running");
else
rp.details = rp_title.c_str();
std::string state_string;
+4 -5
View File
@@ -367,14 +367,13 @@ struct eeProfiler
}
}
// Warning dirty ebx
void EmitMem()
void EmitMem(int addr_reg)
{
// Compact the 4GB virtual address to a 512KB virtual address
if (g_cpu.hasBMI2)
{
xPEXT(ebx, ecx, ptr[&memMask]);
xADD(ptr32[(rbx * 4) + memStats], 1);
xPEXT(arg1regd, xRegister32(addr_reg), ptr[&memMask]);
xADD(ptr32[(arg1reg * 4) + memStats], 1);
}
}
@@ -406,7 +405,7 @@ struct eeProfiler
__fi void Reset() {}
__fi void EmitOp(eeOpcode op) {}
__fi void Print() {}
__fi void EmitMem() {}
__fi void EmitMem(int addrReg) {}
__fi void EmitConstMem(u32 add) {}
__fi void EmitSlowMem() {}
__fi void EmitFastMem() {}
+8 -8
View File
@@ -22,7 +22,8 @@ void dVifRelease(int idx)
}
VifUnpackSSE_Dynarec::VifUnpackSSE_Dynarec(const nVifStruct& vif_, const nVifBlock& vifBlock_)
: v(vif_)
: vifPtr(rax)
, v(vif_)
, vB(vifBlock_)
{
const int wl = vB.wl ? vB.wl : 256; //0 is taken as 256 (KH2)
@@ -48,9 +49,6 @@ __fi void makeMergeMaskAllColumns(u32& x)
__fi void VifUnpackSSE_Dynarec::SetMasks(int cS) const
{
const int idx = v.idx;
const vifStruct& vif = MTVU_VifX;
//This could have ended up copying the row when there was no row to write.1810080
const u32 m0 = vB.mask; //The actual mask example 0x03020100
const u32 m3 = ((m0 & 0xaaaaaaaa) >> 1) & ~m0; //all the upper bits, so our example 0x01010000 & 0xFCFDFEFF = 0x00010000 just the cols (shifted right for maskmerge)
@@ -58,14 +56,14 @@ __fi void VifUnpackSSE_Dynarec::SetMasks(int cS) const
if ((doMask && m2) || doMode)
{
xMOVAPS(rowReg, ptr128[&vif.MaskRow]);
xMOVAPS(rowReg, ptr128[vifPtr + (sptr)offsetof(vifStruct, MaskRow)]);
MSKPATH3_LOG("Moving row");
}
if (doMask && m3)
{
VIF_LOG("Merging Cols");
xMOVAPS(colRegs[0], ptr128[&vif.MaskCol]);
xMOVAPS(colRegs[0], ptr128[vifPtr + (sptr)offsetof(vifStruct, MaskCol)]);
if ((cS >= 2) && (m3 & 0x0000ff00)) xPSHUF.D(colRegs[1], colRegs[0], _v1);
if ((cS >= 3) && (m3 & 0x00ff0000)) xPSHUF.D(colRegs[2], colRegs[0], _v2);
if ((cS >= 4) && (m3 & 0xff000000)) xPSHUF.D(colRegs[3], colRegs[0], _v3);
@@ -143,8 +141,7 @@ void VifUnpackSSE_Dynarec::doMaskWrite(const xRegisterSSE& regX) const
void VifUnpackSSE_Dynarec::writeBackRow() const
{
const int idx = v.idx;
xMOVAPS(ptr128[&(MTVU_VifX.MaskRow)], rowReg);
xMOVAPS(ptr128[vifPtr + (sptr)offsetof(vifStruct, MaskRow)], rowReg);
VIF_LOG("nVif: writing back row reg! [doMode = %d]", doMode);
}
@@ -247,6 +244,7 @@ void VifUnpackSSE_Dynarec::ProcessMasks()
void VifUnpackSSE_Dynarec::CompileRoutine()
{
const int idx = v.idx;
const int wl = vB.wl ? vB.wl : 256; // 0 is taken as 256 (KH2)
const int upkNum = vB.upkType & 0xf;
const u8& vift = nVifT[upkNum];
@@ -260,6 +258,7 @@ void VifUnpackSSE_Dynarec::CompileRoutine()
VIF_LOG("Compiling new block, unpack number %x, mode %x, masking %x, vNum %x", upkNum, doMode, doMask, vNum);
pxAssume(vCL == 0);
xLoadFarAddr(vifPtr, &MTVU_VifX);
// Need a zero register for V2_32/V3 unpacks.
const bool needXmmZero = (upkNum >= 8 && upkNum <= 10) || upkNum == 4;
@@ -434,6 +433,7 @@ _vifT __fi nVifBlock* dVifCompile(nVifBlock& block, bool isFill)
}
// Compile the block now
xSetTextPtr(nullptr);
xSetPtr(v.recWritePtr);
block.startPtr = (uptr)xGetAlignedCallTarget();
+6 -3
View File
@@ -330,9 +330,11 @@ void VifUnpackSSE_Simple::doMaskWrite(const xRegisterSSE& regX) const
{
xMOVAPS(xmm3, ptr[dstIndirect]);
const int offX = std::min(curCycle, 3);
xPAND(regX, ptr32[nVifMask[0][offX]]);
xPAND(xmm3, ptr32[nVifMask[1][offX]]);
xPOR (regX, ptr32[nVifMask[2][offX]]);
sptr base = reinterpret_cast<sptr>(nVifMask[2]);
xLoadFarAddr(rax, nVifMask);
xPAND(regX, ptr128[rax + (reinterpret_cast<sptr>(nVifMask[0][offX]) - base)]);
xPAND(xmm3, ptr128[rax + (reinterpret_cast<sptr>(nVifMask[1][offX]) - base)]);
xPOR (regX, ptr128[rax + (reinterpret_cast<sptr>(nVifMask[2][offX]) - base)]);
xPOR (regX, xmm3);
xMOVAPS(ptr[dstIndirect], regX);
}
@@ -363,6 +365,7 @@ void VifUnpackSSE_Init()
{
DevCon.WriteLn("Generating SSE-optimized unpacking functions for VIF interpreters...");
xSetTextPtr(nullptr);
xSetPtr(SysMemory::GetVIFUnpackRec());
for (int a = 0; a < 2; a++)
+1
View File
@@ -98,6 +98,7 @@ public:
bool inputMasked;
protected:
xAddressReg vifPtr;
const nVifStruct& v; // vif0 or vif1
const nVifBlock& vB; // some pre-collected data from VifStruct
int vCL; // internal copy of vif->cl
+4
View File
@@ -52,6 +52,10 @@ bool _isAllocatableX86reg(int x86reg)
if (CHECK_FASTMEM && x86reg == 5)
return false;
// rbx is used to reference PCSX2 program text
if (xGetTextPtr() && x86reg == RTEXTPTR.GetId())
return false;
#ifdef ENABLE_VTUNE
// vtune needs ebp...
if (!CHECK_FASTMEM && x86reg == 5)
+12 -8
View File
@@ -176,10 +176,10 @@ static const void* _DynGen_JITCompile()
xFastCall((void*)iopRecRecompile, ptr32[&psxRegs.pc]);
xMOV(eax, ptr[&psxRegs.pc]);
xMOV(ebx, eax);
xMOV(edx, eax);
xSHR(eax, 16);
xMOV(rcx, ptrNative[xComplexAddress(rcx, psxRecLUT, rax * wordsize)]);
xJMP(ptrNative[rbx * (wordsize / 4) + rcx]);
xJMP(ptrNative[rdx * (wordsize / 4) + rcx]);
return retval;
}
@@ -190,10 +190,10 @@ static const void* _DynGen_DispatcherReg()
u8* retval = xGetPtr();
xMOV(eax, ptr[&psxRegs.pc]);
xMOV(ebx, eax);
xMOV(edx, eax);
xSHR(eax, 16);
xMOV(rcx, ptrNative[xComplexAddress(rcx, psxRecLUT, rax * wordsize)]);
xJMP(ptrNative[rbx * (wordsize / 4) + rcx]);
xJMP(ptrNative[rdx * (wordsize / 4) + rcx]);
return retval;
}
@@ -918,6 +918,8 @@ static void recReserve()
pxFailRel("Failed to allocate R3000 InstCache array.");
}
#define R3000A_TEXTPTR (&psxRegs.GPR.r[33])
void recResetIOP()
{
DevCon.WriteLn("iR3000A Recompiler reset.");
@@ -928,6 +930,7 @@ void recResetIOP()
extraRam = !extraRam;
}
xSetTextPtr(R3000A_TEXTPTR);
xSetPtr(SysMemory::GetIOPRec());
_DynGen_Dispatchers();
recPtr = xGetPtr();
@@ -1202,16 +1205,16 @@ static void iPsxBranchTest(u32 newpc, u32 cpuBranch)
}
else
{
xMOV(rbx, ptr64[&psxRegs.cycle]);
xADD(rbx, blockCycles);
xMOV(ptr64[&psxRegs.cycle], rbx); // update cycles
xMOV(r12, ptr64[&psxRegs.cycle]);
xADD(r12, blockCycles);
xMOV(ptr64[&psxRegs.cycle], r12); // update cycles
// jump if iopCycleEE <= 0 (iop's timeslice timed out, so time to return control to the EE)
iPsxAddEECycles(blockCycles);
xJLE(iopExitRecompiledCode);
// check if an event is pending
xSUB(rbx, ptr64[&psxRegs.iopNextEventCycle]);
xSUB(r12, ptr64[&psxRegs.iopNextEventCycle]);
xForwardJS<u8> nointerruptpending;
xFastCall((void*)iopEventTest);
@@ -1613,6 +1616,7 @@ static void iopRecRecompile(const u32 startpc)
recResetIOP();
}
xSetTextPtr(R3000A_TEXTPTR);
xSetPtr(recPtr);
recPtr = xGetAlignedCallTarget();
+5
View File
@@ -21,6 +21,11 @@ extern u32 target; // branch target
extern u32 s_nBlockCycles; // cycles of current block recompiling
extern bool s_nBlockInterlocked; // Current block has VU0 interlocking
// x86 can use shorter displacement if it fits in an s8, so offset 144 bytes into the cpuRegs
// This will allow us to reach r1-r16 with a shorter encoding
// TODO: Actually figure out what things are used most often, maybe rearrange the cpuRegs struct, and point at that
#define R5900_TEXTPTR (&cpuRegs.GPR.r[9])
//////////////////////////////////////////////////////////////////////////////////////////
//
+14 -8
View File
@@ -384,10 +384,10 @@ static const void* _DynGen_JITCompile()
// void(**base)() = (void(**)())recLUT[addr >> 16];
// base[addr >> 2]();
xMOV(eax, ptr[&cpuRegs.pc]);
xMOV(ebx, eax);
xMOV(edx, eax);
xSHR(eax, 16);
xMOV(rcx, ptrNative[xComplexAddress(rcx, recLUT, rax * wordsize)]);
xJMP(ptrNative[rbx * (wordsize / 4) + rcx]);
xJMP(ptrNative[rdx * (wordsize / 4) + rcx]);
return retval;
}
@@ -402,10 +402,10 @@ static const void* _DynGen_DispatcherReg()
// void(**base)() = (void(**)())recLUT[addr >> 16];
// base[addr >> 2]();
xMOV(eax, ptr[&cpuRegs.pc]);
xMOV(ebx, eax);
xMOV(edx, eax);
xSHR(eax, 16);
xMOV(rcx, ptrNative[xComplexAddress(rcx, recLUT, rax * wordsize)]);
xJMP(ptrNative[rbx * (wordsize / 4) + rcx]);
xJMP(ptrNative[rdx * (wordsize / 4) + rcx]);
return retval;
}
@@ -439,6 +439,9 @@ static const void* _DynGen_EnterRecompiledCode()
// We never return through this function, instead we fastjmp() out.
// So we don't need to worry about preserving callee-saved registers, but we do need to align the stack.
xSUB(rsp, stack_size);
if (u8* ptr = xGetTextPtr())
xLoadFarAddr(RTEXTPTR, ptr);
#endif
if (CHECK_FASTMEM)
@@ -611,6 +614,7 @@ static void recResetRaw()
EE::Profiler.Reset();
xSetTextPtr(R5900_TEXTPTR);
xSetPtr(SysMemory::GetEERec());
_DynGen_Dispatchers();
vtlb_DynGenDispatchers();
@@ -877,6 +881,7 @@ u8* recBeginThunk()
if (recPtr >= recPtrEnd)
eeRecNeedsReset = true;
xSetTextPtr(R5900_TEXTPTR);
xSetPtr(recPtr);
recPtr = xGetAlignedCallTarget();
@@ -2127,17 +2132,17 @@ static bool recSkipTimeoutLoop(s32 reg, bool is_timeout_loop)
// if new_v0 > 0 { jump to dispatcher because loop exited early }
// else new_v0 is 0, so exit loop
xMOV(rbx, ptr64[&cpuRegs.cycle]); // ebx = cycle
xMOV(r12, ptr64[&cpuRegs.cycle]); // ebx = cycle
xMOV(rcx, ptr64[&cpuRegs.nextEventCycle]); // ecx = nextEventCycle
xCMP(rbx, rcx);
xCMP(r12, rcx);
xJAE((void*)DispatcherEvent); // jump to dispatcher if event immediately
xMOV(edx, ptr32[&cpuRegs.GPR.r[reg].UL[0]]); // eax = v0
xLEA(rax, ptrNative[rdx * 8 + rbx]); // edx = v0 * 8 + cycle
xLEA(rax, ptrNative[rdx * 8 + r12]); // edx = v0 * 8 + cycle
xCMP(rcx, rax);
xCMOVB(rax, rcx); // eax = new_cycles = min(v8 * 8, nextEventCycle)
xMOV(ptr64[&cpuRegs.cycle], rax); // writeback new_cycles
xSUB(rax, rbx); // new_cycles -= cycle
xSUB(rax, r12); // new_cycles -= cycle
xSHR(rax, 3); // compute new v0 value
xSUB(rdx, rax); // v0 -= cycle_diff
xMOV(ptr32[&cpuRegs.GPR.r[reg].UL[0]], edx); // write back new value of v0
@@ -2171,6 +2176,7 @@ static void recRecompile(const u32 startpc)
recResetRaw();
}
xSetTextPtr(R5900_TEXTPTR);
xSetPtr(recPtr);
recPtr = xGetAlignedCallTarget();
+5 -7
View File
@@ -119,14 +119,12 @@ static void __vectorcall LogWriteQuad(u32 addr, __m128i val)
namespace vtlb_private
{
// ------------------------------------------------------------------------
// Prepares eax, ecx, and, ebx for Direct or Indirect operations.
// Returns the writeback pointer for ebx (return address from indirect handling)
// Prepares eax and ecx for Direct or Indirect operations.
//
static void DynGen_PrepRegs(int addr_reg, int value_reg, u32 sz, bool xmm)
{
EE::Profiler.EmitMem();
_freeX86reg(arg1regd);
EE::Profiler.EmitMem(addr_reg);
xMOV(arg1regd, xRegister32(addr_reg));
if (value_reg >= 0)
@@ -269,7 +267,7 @@ static void DynGen_HandlerTest(const GenDirectFn& gen_direct, int mode, int bits
// ------------------------------------------------------------------------
// Generates the various instances of the indirect dispatchers
// In: arg1reg: vtlb entry, arg2reg: data ptr (if mode >= 64), rbx: function return ptr
// In: arg1reg: vtlb entry, arg2reg: data ptr (if mode >= 64)
// Out: eax: result (if mode < 64)
static void DynGen_IndirectTlbDispatcher(int mode, int bits, bool sign)
{
@@ -347,6 +345,7 @@ void vtlb_DynGenDispatchers()
for (int sign = 0; sign < (!mode && bits < 3 ? 2 : 1); sign++)
{
xSetPtr(GetIndirectDispatcherPtr(mode, bits, !!sign));
xSetTextPtr(R5900_TEXTPTR);
DynGen_IndirectTlbDispatcher(mode, bits, !!sign);
}
@@ -941,14 +940,13 @@ void vtlb_DynBackpatchLoadStore(uptr code_address, u32 code_size, u32 guest_pc,
u32 num_gprs = 0;
u32 num_fprs = 0;
const u32 rbxid = static_cast<u32>(rbx.GetId());
const u32 arg1id = static_cast<u32>(arg1reg.GetId());
const u32 arg2id = static_cast<u32>(arg2reg.GetId());
const u32 arg3id = static_cast<u32>(arg3reg.GetId());
for (u32 i = 0; i < iREGCNT_GPR; i++)
{
if ((gpr_bitmask & (1u << i)) && (i == rbxid || i == arg1id || i == arg2id || xRegisterBase::IsCallerSaved(i)) && (!is_load || is_xmm || data_register != i))
if ((gpr_bitmask & (1u << i)) && (i == arg1id || i == arg2id || xRegisterBase::IsCallerSaved(i)) && (!is_load || is_xmm || data_register != i))
num_gprs++;
}
for (u32 i = 0; i < iREGCNT_XMM; i++)
+1
View File
@@ -42,6 +42,7 @@ void mVUreset(microVU& mVU, bool resetReserve)
VU0.VI[REG_VPU_STAT].UL &= ~0x100;
}
xSetTextPtr(mVU.textPtr());
xSetPtr(mVU.cache);
mVUdispatcherAB(mVU);
mVUdispatcherCD(mVU);
+1
View File
@@ -123,6 +123,7 @@ struct microVU
s32 cycles; // Cycles Counter
VURegs& regs() const { return ::vuRegs[index]; }
void* textPtr() const { return (index && THREAD_VU1) ? (void*)&regs().VF[9] : (void*)R5900_TEXTPTR; }
__fi REG_VI& getVI(uint reg) const { return regs().VI[reg]; }
__fi VECTOR& getVF(uint reg) const { return regs().VF[reg]; }
+12 -9
View File
@@ -207,15 +207,17 @@ static void mVUGenerateCopyPipelineState(mV)
{
mVU.copyPLState = xGetAlignedCallTarget();
xLoadFarAddr(rdx, reinterpret_cast<u8*>(&mVU.prog.lpState));
if (g_cpu.vectorISA >= ProcessorFeatures::VectorISA::AVX)
{
xMOVAPS(ymm0, ptr[rax]);
xMOVAPS(ymm1, ptr[rax + 32u]);
xMOVAPS(ymm2, ptr[rax + 64u]);
xMOVUPS(ptr[reinterpret_cast<u8*>(&mVU.prog.lpState)], ymm0);
xMOVUPS(ptr[reinterpret_cast<u8*>(&mVU.prog.lpState) + 32u], ymm1);
xMOVUPS(ptr[reinterpret_cast<u8*>(&mVU.prog.lpState) + 64u], ymm2);
xMOVUPS(ptr[rdx], ymm0);
xMOVUPS(ptr[rdx + 32u], ymm1);
xMOVUPS(ptr[rdx + 64u], ymm2);
xVZEROUPPER();
}
@@ -228,12 +230,12 @@ static void mVUGenerateCopyPipelineState(mV)
xMOVAPS(xmm4, ptr[rax + 64u]);
xMOVAPS(xmm5, ptr[rax + 80u]);
xMOVUPS(ptr[reinterpret_cast<u8*>(&mVU.prog.lpState)], xmm0);
xMOVUPS(ptr[reinterpret_cast<u8*>(&mVU.prog.lpState) + 16u], xmm1);
xMOVUPS(ptr[reinterpret_cast<u8*>(&mVU.prog.lpState) + 32u], xmm2);
xMOVUPS(ptr[reinterpret_cast<u8*>(&mVU.prog.lpState) + 48u], xmm3);
xMOVUPS(ptr[reinterpret_cast<u8*>(&mVU.prog.lpState) + 64u], xmm4);
xMOVUPS(ptr[reinterpret_cast<u8*>(&mVU.prog.lpState) + 80u], xmm5);
xMOVUPS(ptr[rdx], xmm0);
xMOVUPS(ptr[rdx + 16u], xmm1);
xMOVUPS(ptr[rdx + 32u], xmm2);
xMOVUPS(ptr[rdx + 48u], xmm3);
xMOVUPS(ptr[rdx + 64u], xmm4);
xMOVUPS(ptr[rdx + 80u], xmm5);
}
xRET();
@@ -326,6 +328,7 @@ _mVUt void* mVUexecute(u32 startPC, u32 cycles)
mVU.cycles = cycles;
mVU.totalCycles = cycles;
xSetTextPtr(mVU.textPtr());
xSetPtr(mVU.prog.x86ptr); // Set x86ptr to where last program left off
return mVUsearchProg<vuIndex>(startPC & vuLimit, (uptr)&mVU.prog.lpState); // Find and set correct program
}
+1
View File
@@ -411,6 +411,7 @@ public:
}
}
gprMap[RTEXTPTR.GetId()].usable = !xGetTextPtr();
gprMap[RFASTMEMBASE.GetId()].usable = !cop2mode || !CHECK_FASTMEM;
}
+10 -10
View File
@@ -1175,7 +1175,7 @@ mVUop(mVU_ILW)
xADD(gprT1, gprT2);
}
mVUaddrFix(mVU, gprT1q);
mVUaddrFix(mVU, gprT1q, gprT2q);
}
const xRegister32& regT = mVU.regAlloc->allocGPR(-1, _It_, mVUlow.backupVI);
@@ -1202,7 +1202,7 @@ mVUop(mVU_ILWR)
if (_Is_)
{
mVU.regAlloc->moveVIToGPR(gprT1, _Is_);
mVUaddrFix (mVU, gprT1q);
mVUaddrFix (mVU, gprT1q, gprT2q);
const xRegister32& regT = mVU.regAlloc->allocGPR(-1, _It_, mVUlow.backupVI);
xMOVZX(regT, ptr16[xComplexAddress(gprT2q, ptr, gprT1q)]);
@@ -1250,7 +1250,7 @@ mVUop(mVU_ISW)
xADD(gprT1, gprT2);
}
mVUaddrFix(mVU, gprT1q);
mVUaddrFix(mVU, gprT1q, gprT2q);
}
// If regT is dirty, the high bits might not be zero.
@@ -1281,7 +1281,7 @@ mVUop(mVU_ISWR)
if (_Is_)
{
mVU.regAlloc->moveVIToGPR(gprT1, _Is_);
mVUaddrFix(mVU, gprT1q);
mVUaddrFix(mVU, gprT1q, gprT2q);
is = gprT1q;
}
const xRegister32& regT = mVU.regAlloc->allocGPR(_It_, -1, false, true);
@@ -1348,7 +1348,7 @@ mVUop(mVU_LQ)
xADD(gprT1, gprT2);
}
mVUaddrFix(mVU, gprT1q);
mVUaddrFix(mVU, gprT1q, gprT2q);
}
const xmm& Ft = mVU.regAlloc->allocReg(-1, _Ft_, _X_Y_Z_W);
@@ -1372,7 +1372,7 @@ mVUop(mVU_LQD)
xDEC(regS);
xMOVSX(gprT1, xRegister16(regS)); // TODO: Confirm
mVU.regAlloc->clearNeeded(regS);
mVUaddrFix(mVU, gprT1q);
mVUaddrFix(mVU, gprT1q, gprT2q);
is = gprT1q;
}
else
@@ -1410,7 +1410,7 @@ mVUop(mVU_LQI)
xMOVSX(gprT1, xRegister16(regS)); // TODO: Confirm
xINC(regS);
mVU.regAlloc->clearNeeded(regS);
mVUaddrFix(mVU, gprT1q);
mVUaddrFix(mVU, gprT1q, gprT2q);
is = gprT1q;
}
if (!mVUlow.noWriteVF)
@@ -1453,7 +1453,7 @@ mVUop(mVU_SQ)
xADD(gprT1, gprT2);
}
mVUaddrFix(mVU, gprT1q);
mVUaddrFix(mVU, gprT1q, gprT2q);
}
const xmm& Fs = mVU.regAlloc->allocReg(_Fs_, _XYZW_PS ? -1 : 0, _X_Y_Z_W);
@@ -1477,7 +1477,7 @@ mVUop(mVU_SQD)
xDEC(regT);
xMOVZX(gprT1, xRegister16(regT));
mVU.regAlloc->clearNeeded(regT);
mVUaddrFix(mVU, gprT1q);
mVUaddrFix(mVU, gprT1q, gprT2q);
it = gprT1q;
}
else
@@ -1507,7 +1507,7 @@ mVUop(mVU_SQI)
xMOVZX(gprT1, xRegister16(regT));
xINC(regT);
mVU.regAlloc->clearNeeded(regT);
mVUaddrFix(mVU, gprT1q);
mVUaddrFix(mVU, gprT1q, gprT2q);
}
const xmm& Fs = mVU.regAlloc->allocReg(_Fs_, _XYZW_PS ? -1 : 0, _X_Y_Z_W);
if (_It_)
+4 -4
View File
@@ -141,10 +141,10 @@ static const char branchSTR[16][8] = {
#define gprT1b ax // Low 16-bit of gprT1 (eax)
#define gprT2b cx // Low 16-bit of gprT2 (ecx)
#define gprF0 ebx // Status Flag 0
#define gprF1 r12d // Status Flag 1
#define gprF2 r13d // Status Flag 2
#define gprF3 r14d // Status Flag 3
#define gprF0 r12d // Status Flag 0
#define gprF1 r13d // Status Flag 1
#define gprF2 r14d // Status Flag 2
#define gprF3 r15d // Status Flag 3
// Function Params
#define mP microVU& mVU, int recPass
+11 -2
View File
@@ -295,7 +295,7 @@ static void mVUwaitMTVU()
}
// Transforms the Address in gprReg to valid VU0/VU1 Address
__fi void mVUaddrFix(mV, const xAddressReg& gprReg)
__fi void mVUaddrFix(mV, const xAddressReg& gprReg, const xAddressReg& tmpReg)
{
if (isVU1)
{
@@ -324,7 +324,16 @@ __fi void mVUaddrFix(mV, const xAddressReg& gprReg)
xFastCall((void*)mVU.waitMTVU);
}
xAND(xRegister32(gprReg.Id), 0x3f); // ToDo: theres a potential problem if VU0 overrides VU1's VF0/VI0 regs!
xADD(gprReg, (u128*)VU1.VF - (u128*)VU0.Mem);
sptr offset = (u128*)VU1.VF - (u128*)VU0.Mem;
if (offset == (s32)offset)
{
xADD(gprReg, (s32)offset);
}
else
{
xMOV64(tmpReg, offset);
xADD(gprReg, tmpReg);
}
jmpB.SetTarget();
xSHL(gprReg, 4); // multiply by 16 (shift left by 4)
}