mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-25 00:14:30 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cb7abf10c | ||
|
|
7561f7ef70 | ||
|
|
ac69bb2142 | ||
|
|
2c7c8e19e2 | ||
|
|
59d00a0134 | ||
|
|
372fadfb99 | ||
|
|
406c2c0bbf | ||
|
|
a5ba35ce92 | ||
|
|
f6b2887ae0 | ||
|
|
cba474000e | ||
|
|
cb64246288 | ||
|
|
4006be49f8 | ||
|
|
085f1dcb68 | ||
|
|
1372d71fa7 | ||
|
|
2fda2d512d | ||
|
|
1edc304453 | ||
|
|
a291936bf8 | ||
|
|
9b343bae3e | ||
|
|
6336cc82e8 | ||
|
|
3450e3c238 | ||
|
|
49017c4813 | ||
|
|
27a88dd333 | ||
|
|
6f4f6cf7de | ||
|
|
0020cac123 | ||
|
|
1160758a81 | ||
|
|
5c205d6287 | ||
|
|
e814408026 | ||
|
|
46e85c4586 | ||
|
|
f4b16a8762 | ||
|
|
cdc8201222 | ||
|
|
94c10ca9f9 | ||
|
|
724155ba91 | ||
|
|
6ffa916336 | ||
|
|
e3badc754d | ||
|
|
df9783f41f | ||
|
|
e9c6d51566 | ||
|
|
a8c8223f69 | ||
|
|
9b3f827991 | ||
|
|
2d2bfd64ff | ||
|
|
73a825cbb1 | ||
|
|
3e0e72e50c | ||
|
|
259350c974 | ||
|
|
e14b4475ff | ||
|
|
b4f030cd37 |
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,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; }
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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(); });
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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."));
|
||||
|
||||
|
||||
@@ -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 & 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 & 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>
|
||||
|
||||
+1511
-1484
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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&)
|
||||
|
||||
@@ -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])));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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])
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -123,6 +123,7 @@ struct microVU
|
||||
s32 cycles; // Cycles Counter
|
||||
|
||||
VURegs& regs() const { return ::vuRegs[index]; }
|
||||
void* textPtr() const { return (index && THREAD_VU1) ? (void*)®s().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]; }
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -411,6 +411,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
gprMap[RTEXTPTR.GetId()].usable = !xGetTextPtr();
|
||||
gprMap[RFASTMEMBASE.GetId()].usable = !cop2mode || !CHECK_FASTMEM;
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -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_)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user