mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-08-17 11:23:10 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf64a2bc8e | ||
|
|
39fd3479b7 | ||
|
|
536133289f | ||
|
|
3f280649a9 | ||
|
|
6c80aa8c98 | ||
|
|
65c39f600f | ||
|
|
3b5a9f6c6a | ||
|
|
665db4bdad | ||
|
|
b34e7fa303 | ||
|
|
abc0458d4f | ||
|
|
1e35398a84 | ||
|
|
be3253bf87 | ||
|
|
241a762d04 | ||
|
|
b944687191 | ||
|
|
736c66ee31 | ||
|
|
d96f31d01b | ||
|
|
e30c096d87 | ||
|
|
be71b98c55 | ||
|
|
6bec3162f6 | ||
|
|
c863876dee | ||
|
|
f5d0542f06 | ||
|
|
b1650eb503 | ||
|
|
82b090e234 | ||
|
|
7f1e416d31 | ||
|
|
4312bf711c | ||
|
|
f8061448d1 | ||
|
|
e934bec4b7 | ||
|
|
4e5d7ba8ef | ||
|
|
59fd815c3d | ||
|
|
b901c6af71 | ||
|
|
b2fb6c7804 | ||
|
|
84c5f8f738 | ||
|
|
39c7f11b98 | ||
|
|
86a2d73931 | ||
|
|
8eb50c3517 | ||
|
|
d9defb19f9 | ||
|
|
874804bcfd | ||
|
|
b0f9662811 | ||
|
|
24850823a2 | ||
|
|
951604475b | ||
|
|
74f3bb2aa9 | ||
|
|
4442b798c9 | ||
|
|
f10a8de2c1 | ||
|
|
329b29269b | ||
|
|
5b3ffe6bab | ||
|
|
fb14500b41 | ||
|
|
ad29594d08 | ||
|
|
37e2142cca | ||
|
|
1e5f1de12c | ||
|
|
0f93dbcd5e | ||
|
|
e415d85dbe | ||
|
|
4c8bf53e69 | ||
|
|
83fcd4bd1f | ||
|
|
bfd960ad1b | ||
|
|
6b81808ecc | ||
|
|
c615a6f6e2 | ||
|
|
40b522b42f | ||
|
|
f2655b763f | ||
|
|
fd145e65aa | ||
|
|
6596b7f27e | ||
|
|
9d767838d6 | ||
|
|
f55219bb1b | ||
|
|
805b647c73 | ||
|
|
fd0351ca8f | ||
|
|
ed5a7802f3 | ||
|
|
44f8317b7e | ||
|
|
0200933ddd | ||
|
|
f712b2b63a | ||
|
|
71923e7cba | ||
|
|
532d14611c | ||
|
|
3a91a07d51 | ||
|
|
6a8287ea9f | ||
|
|
dc051541bd | ||
|
|
3265c2a614 | ||
|
|
f798401e93 |
@@ -0,0 +1 @@
|
||||
*.txt
|
||||
@@ -0,0 +1,38 @@
|
||||
import os
|
||||
|
||||
relevant_categories = [
|
||||
"# Mac OS X",
|
||||
"# Linux"
|
||||
]
|
||||
|
||||
header_lines = []
|
||||
new_db_contents = []
|
||||
|
||||
def is_relevant_category(line):
|
||||
for category in relevant_categories:
|
||||
if category in line:
|
||||
return True
|
||||
return False
|
||||
|
||||
with open("./game_controller_db.txt") as file:
|
||||
lines = file.readlines()
|
||||
finished_header = False
|
||||
processing_section = False
|
||||
for line in lines:
|
||||
if finished_header is False:
|
||||
header_lines.append(line)
|
||||
if line == "\n":
|
||||
finished_header = True
|
||||
if processing_section and line == "\n":
|
||||
processing_section = False
|
||||
new_db_contents.append("\n")
|
||||
if is_relevant_category(line) and processing_section is False:
|
||||
processing_section = True
|
||||
new_db_contents.append(line)
|
||||
elif processing_section:
|
||||
new_db_contents.append(line)
|
||||
|
||||
os.remove("./game_controller_db.txt")
|
||||
with open("./game_controller_db.txt", "w") as f:
|
||||
f.writelines(header_lines)
|
||||
f.writelines(new_db_contents)
|
||||
@@ -37,11 +37,15 @@ mkdir -p squashfs-root/usr/share/icons && cp ./squashfs-root/PCSX2.png ./squashf
|
||||
mkdir -p squashfs-root/usr/share/icons/hicolor/scalable/apps && cp ./squashfs-root/PCSX2.png ./squashfs-root/usr/share/icons/hicolor/scalable/apps
|
||||
mkdir -p squashfs-root/usr/share/pixmaps && cp ./squashfs-root/PCSX2.png ./squashfs-root/usr/share/pixmaps
|
||||
mkdir -p squashfs-root/usr/lib/
|
||||
mkdir -p squashfs-root/usr/optional/libstdc++
|
||||
mkdir -p squashfs-root/usr/optional/libgcc_s
|
||||
cp ./.github/workflows/scripts/linux/AppRun "$GITHUB_WORKSPACE"/squashfs-root/AppRun
|
||||
curl -sSfL "https://github.com/AppImage/AppImageKit/releases/download/continuous/AppRun-$APPARCH" -o "$GITHUB_WORKSPACE"/squashfs-root/AppRun-patched
|
||||
curl -sSfL "https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/AppRun-patched-$APPARCH" -o "$GITHUB_WORKSPACE"/squashfs-root/AppRun-patched
|
||||
curl -sSfL "https://github.com/darealshinji/AppImageKit-checkrt/releases/download/continuous/exec-$APPARCH.so" -o "$GITHUB_WORKSPACE"/squashfs-root/usr/optional/exec.so
|
||||
chmod a+x ./squashfs-root/AppRun
|
||||
chmod a+x ./squashfs-root/runtime
|
||||
chmod a+x ./squashfs-root/AppRun-patched
|
||||
chmod a+x ./squashfs-root/usr/optional/exec.so
|
||||
echo "$name" > "$GITHUB_WORKSPACE"/squashfs-root/version.txt
|
||||
mkdir -p "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/app
|
||||
cp -r "$GITHUB_WORKSPACE"/bin/Langs "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/
|
||||
@@ -49,6 +53,8 @@ cp "$GITHUB_WORKSPACE"/bin/docs/{Configuration_Guide.pdf,PCSX2_FAQ.pdf} "$GITHUB
|
||||
cp "$GITHUB_WORKSPACE"/bin/cheats_ws.zip "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/app
|
||||
cp ./bin/GameIndex.yaml "$GITHUB_WORKSPACE"/squashfs-root/usr/bin/app/GameIndex.yaml
|
||||
cp /usr/lib/$LIBARCH/libthai.so.0 "$GITHUB_WORKSPACE"/squashfs-root/usr/lib/
|
||||
cp --dereference /usr/lib/"$LIBARCH"/libstdc++.so.6 "$GITHUB_WORKSPACE"/squashfs-root/usr/optional/libstdc++/libstdc++.so.6
|
||||
cp --dereference /lib/"$LIBARCH"/libgcc_s.so.1 "$GITHUB_WORKSPACE"/squashfs-root/usr/optional/libgcc_s/libgcc_s.so.1
|
||||
export UPD_INFO="gh-releases-zsync|PCSX2|pcsx2|latest|$name.AppImage.zsync"
|
||||
export OUTPUT="$name.AppImage"
|
||||
/tmp/squashfs-root/AppRun --appdir="$GITHUB_WORKSPACE"/squashfs-root/ --plugin gtk -d "$GITHUB_WORKSPACE"/squashfs-root/PCSX2.desktop -i "$GITHUB_WORKSPACE"/squashfs-root/PCSX2.png --output appimage
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
set -e
|
||||
|
||||
if [ "${COMPILER}" = "gcc" ]; then
|
||||
export CC=gcc
|
||||
export CXX=g++
|
||||
export CC=gcc-10
|
||||
export CXX=g++-10
|
||||
else
|
||||
export CC=clang
|
||||
export CXX=clang++
|
||||
|
||||
@@ -6,100 +6,42 @@ set -e
|
||||
declare -a BUILD_PACKAGES=(
|
||||
"ccache"
|
||||
"cmake"
|
||||
"g++-8-multilib"
|
||||
"ninja-build"
|
||||
)
|
||||
|
||||
declare -a GCC_PACKAGES=(
|
||||
# Nothing Unique Needed
|
||||
)
|
||||
|
||||
declare -a CLANG_PACKAGES=(
|
||||
"clang-format"
|
||||
"clang-tidy"
|
||||
"clang-tools"
|
||||
"clang"
|
||||
"clangd-10"
|
||||
"libc++-dev"
|
||||
"libc++1"
|
||||
"libc++abi-dev"
|
||||
"libc++abi1"
|
||||
"libclang-dev"
|
||||
"libclang1"
|
||||
"liblldb-10-dev"
|
||||
"libllvm-10-ocaml-dev"
|
||||
"libomp-dev"
|
||||
"libomp5"
|
||||
"lld"
|
||||
"lldb"
|
||||
"llvm-dev"
|
||||
"llvm-runtime"
|
||||
"llvm"
|
||||
"python3-clang-10"
|
||||
)
|
||||
|
||||
# Packages - PCSX2
|
||||
declare -a PCSX2_PACKAGES=(
|
||||
"curl"
|
||||
"fuse"
|
||||
"gettext"
|
||||
"libaio-dev"
|
||||
"libasound2-dev"
|
||||
"libatk1.0-dev"
|
||||
"libatk-bridge2.0-dev"
|
||||
"libbz2-dev"
|
||||
"libcairo2-dev"
|
||||
"libcggl"
|
||||
"libdbus-1-dev"
|
||||
"libegl1-mesa-dev"
|
||||
"libfontconfig1-dev"
|
||||
"libgdk-pixbuf2.0-dev"
|
||||
"libgirepository-1.0-1"
|
||||
"libgl-dev"
|
||||
"libgl1-mesa-dev"
|
||||
"libgl1-mesa-dri"
|
||||
"libgl1"
|
||||
"libgles2-mesa-dev"
|
||||
"libglew-dev"
|
||||
"libglib2.0-dev"
|
||||
"libglu1-mesa-dev"
|
||||
"libglu1-mesa"
|
||||
"libglvnd-dev"
|
||||
"libglx-mesa0"
|
||||
"libglx0"
|
||||
"libgtk-3-dev"
|
||||
"libgtk2.0-dev"
|
||||
"libharfbuzz-dev"
|
||||
"libibus-1.0-dev"
|
||||
"libjack-jackd2-dev"
|
||||
"libjpeg-dev"
|
||||
"libllvm10"
|
||||
"liblzma-dev"
|
||||
"liblzma5"
|
||||
"libpango1.0-dev"
|
||||
"libpcap0.8-dev"
|
||||
"libpng-dev"
|
||||
"libportaudiocpp0"
|
||||
"libpulse-dev"
|
||||
"librsvg2-dev"
|
||||
"libsdl1.2-dev"
|
||||
"libsdl2-dev"
|
||||
"libsamplerate0-dev"
|
||||
"libsoundtouch-dev"
|
||||
"libwxgtk3.0-dev"
|
||||
"libwxgtk3.0-gtk3-0v5"
|
||||
"libwxgtk3.0-gtk3-dev"
|
||||
"libx11-xcb-dev"
|
||||
"libxext-dev"
|
||||
"libxft-dev"
|
||||
"libxml2-dev"
|
||||
"nvidia-cg-toolkit"
|
||||
"pkg-config"
|
||||
"portaudio19-dev"
|
||||
"python"
|
||||
"zlib1g-dev"
|
||||
)
|
||||
|
||||
if [ "${COMPILER}" = "gcc" ]; then
|
||||
BUILD_PACKAGES+=("g++-10-multilib")
|
||||
else
|
||||
BUILD_PACKAGES+=("clang-9")
|
||||
PCSX2_PACKAGES+=("libstdc++-10-dev")
|
||||
fi
|
||||
|
||||
# - https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-README.md
|
||||
ARCH=""
|
||||
echo "${PLATFORM}"
|
||||
@@ -111,41 +53,14 @@ fi
|
||||
sudo apt-get -qq update
|
||||
|
||||
# Install packages needed for building
|
||||
BUILD_PACKAGE_STR=""
|
||||
for i in "${BUILD_PACKAGES[@]}"; do
|
||||
BUILD_PACKAGE_STR="${BUILD_PACKAGE_STR} ${i}"
|
||||
done
|
||||
|
||||
if [ "${COMPILER}" = "gcc" ]; then
|
||||
for i in "${GCC_PACKAGES[@]}"; do
|
||||
BUILD_PACKAGE_STR="${BUILD_PACKAGE_STR} ${i}"
|
||||
done
|
||||
else
|
||||
for i in "${CLANG_PACKAGES[@]}"; do
|
||||
BUILD_PACKAGE_STR="${BUILD_PACKAGE_STR} ${i}"
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Will install the following packages for building - ${BUILD_PACKAGE_STR}"
|
||||
echo "Will install the following packages for building - ${BUILD_PACKAGES[*]}"
|
||||
#sudo apt remove gcc-9 g++-9
|
||||
sudo apt-get -y install ${BUILD_PACKAGE_STR}
|
||||
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 10
|
||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 10
|
||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc 30
|
||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 30
|
||||
sudo apt-get -y install "${BUILD_PACKAGES[@]}"
|
||||
|
||||
# Install packages needed by pcsx2
|
||||
PCSX2_PACKAGES_STR=""
|
||||
for i in "${PCSX2_PACKAGES[@]}"; do
|
||||
PCSX2_PACKAGES_STR="${PCSX2_PACKAGES_STR} ${i}${ARCH}"
|
||||
done
|
||||
if [ "${PLATFORM}" == "x86" ]; then
|
||||
echo "Installing workaround attempt"
|
||||
sudo apt-get -y install libgcc-s1:i386
|
||||
fi
|
||||
echo "Will install the following packages for pcsx2 - ${PCSX2_PACKAGES_STR}"
|
||||
sudo apt-get -y install ${PCSX2_PACKAGES_STR}
|
||||
PCSX2_PACKAGES=("${PCSX2_PACKAGES[@]/%/"${ARCH}"}")
|
||||
echo "Will install the following packages for pcsx2 - ${PCSX2_PACKAGES[*]}"
|
||||
sudo apt-get -y install "${PCSX2_PACKAGES[@]}"
|
||||
|
||||
cd /tmp
|
||||
curl -sSfLO https://github.com/NixOS/patchelf/releases/download/0.12/patchelf-0.12.tar.bz2
|
||||
|
||||
@@ -11,9 +11,21 @@ for (var i = 0; i < assets.length; i++) {
|
||||
continue;
|
||||
}
|
||||
if (asset.name.includes("windows")) {
|
||||
windowsAssetLinks += `- [${asset.name}](${asset.browser_download_url})\n`
|
||||
let friendlyName = asset.name;
|
||||
try {
|
||||
friendlyName = asset.name.split("windows-")[1].split(".7z")[0].replace("-", " ");
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
windowsAssetLinks += `- [${friendlyName}](${asset.browser_download_url})\n`
|
||||
} else if (asset.name.includes("linux")) {
|
||||
linuxAssetLinks += `- [${asset.name}](${asset.browser_download_url})\n`
|
||||
let friendlyName = asset.name;
|
||||
try {
|
||||
friendlyName = asset.name.split("linux-")[1].split(".AppImage")[0].replace("-", " ");
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
linuxAssetLinks += `- [${friendlyName}](${asset.browser_download_url})\n`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +36,8 @@ const embed = new MessageEmbed()
|
||||
.addFields(
|
||||
{ name: 'Version', value: github.context.payload.release.tag_name, inline: true },
|
||||
{ name: 'Release Link', value: `[Github Release](${github.context.payload.release.html_url})`, inline: true },
|
||||
{ name: 'Installation Steps', value: '[See Here](https://github.com/PCSX2/pcsx2/wiki/Nightly-Build-Usage-Guide)', inline: true }
|
||||
{ name: 'Installation Steps', value: '[See Here](https://github.com/PCSX2/pcsx2/wiki/Nightly-Build-Usage-Guide)', inline: true },
|
||||
{ name: 'Included Changes', value: github.context.payload.release.body, inline: false }
|
||||
);
|
||||
|
||||
if (windowsAssetLinks != "") {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
name: 🏭 Update Controller Database
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 16 * * 1" # every monday @ 12pm EST - https://crontab.guru/#0_16_*_*_1
|
||||
|
||||
jobs:
|
||||
update-controller-db:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Get Latest DB and Prepare DB File
|
||||
run: |
|
||||
cd .github/workflows/scripts/controller-db/
|
||||
wget -O game_controller_db.txt https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt
|
||||
python ./update-db.py
|
||||
mv ./game_controller_db.txt ${{github.workspace}}/pcsx2/PAD/Linux/res/game_controller_db.txt
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v3
|
||||
with:
|
||||
title: "pad-linux: Update to latest controller database"
|
||||
commit-message: "pad-linux: Update to latest controller database."
|
||||
committer: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
||||
author: "PCSX2 Bot <PCSX2Bot@users.noreply.github.com>"
|
||||
body: "Weekly automatic update of SDL Controller DB for Linux / Mac OS"
|
||||
reviewers: lightningterror
|
||||
+349
-43
@@ -1039,6 +1039,7 @@ SCCS-40004:
|
||||
SCCS-40005:
|
||||
name: "ICO"
|
||||
region: "NTSC-C"
|
||||
compat: 5
|
||||
clampModes:
|
||||
eeClampMode: 2 # Otherwise freezes in various spots, check full intro.
|
||||
vuClampMode: 1 # Otherwise camera does not focus correctly on main character.
|
||||
@@ -1069,15 +1070,18 @@ SCCS-40016:
|
||||
SCCS-40017:
|
||||
name: "EyeToy: Play"
|
||||
region: "NTSC-C"
|
||||
compat: 5
|
||||
SCCS-40018:
|
||||
name: "Saru EyeToy: Oosawagi! Ukkiuki Game Tenkomori!!"
|
||||
region: "NTSC-C"
|
||||
compat: 5
|
||||
SCCS-40019:
|
||||
name: "Formula One 04"
|
||||
region: "NTSC-C"
|
||||
SCCS-40022:
|
||||
name: "World Soccer Winning Eleven 8: Asia Championship"
|
||||
region: "NTSC-C"
|
||||
compat: 5
|
||||
SCCS-60002:
|
||||
name: "Gran Turismo 4 [Review Copy]"
|
||||
region: "NTSC-C"
|
||||
@@ -1543,6 +1547,9 @@ SCED-52442:
|
||||
SCED-52452:
|
||||
name: "Official PlayStation 2 Magazine Demo 45"
|
||||
region: "PAL-M5"
|
||||
SCED-52461:
|
||||
name: "SingStar [Press Kit]"
|
||||
region: "PAL-E"
|
||||
SCED-52549:
|
||||
name: "Official PlayStation 2 Magazine Demo 47"
|
||||
region: "PAL-M5"
|
||||
@@ -1570,6 +1577,9 @@ SCED-52818:
|
||||
SCED-52932:
|
||||
name: "Bonus Demo 8 (old)"
|
||||
region: "PAL-M5"
|
||||
SCED-52935:
|
||||
name: "SingStar Party [Demo]"
|
||||
region: "PAL-E"
|
||||
SCED-52938:
|
||||
name: "Official PlayStation 2 Magazine Demo 52"
|
||||
region: "PAL-M5"
|
||||
@@ -1717,12 +1727,18 @@ SCED-53292:
|
||||
SCED-53293:
|
||||
name: "Official PlayStation 2 Magazine Demo 63"
|
||||
region: "PAL-M5"
|
||||
SCED-53316:
|
||||
name: "SingStar Pop [Demo]"
|
||||
region: "PAL-E"
|
||||
SCED-53325:
|
||||
name: "Official PlayStation 2 Magazine Demo 58" # Spanish/Portuguese
|
||||
region: "PAL-M5"
|
||||
SCED-53348:
|
||||
name: "Official PlayStation 2 Magazine Demo 58" # French
|
||||
region: "PAL-F"
|
||||
SCED-53684:
|
||||
name: "SingStar '80s [Demo]"
|
||||
region: "PAL-E"
|
||||
SCED-53854:
|
||||
name: "Official PS2 Magazine French Christmas Special" # French
|
||||
region: "PAL-F"
|
||||
@@ -3016,13 +3032,13 @@ SCES-53891:
|
||||
name: "SingStar Rocks!"
|
||||
region: "PAL-G"
|
||||
SCES-53893:
|
||||
name: "SingStar Rocks!"
|
||||
name: "SingStar Rocks! [Promo]"
|
||||
region: "PAL-DU"
|
||||
SCES-53894:
|
||||
name: "SingStar Rocks!"
|
||||
region: "PAL-HR"
|
||||
SCES-53895:
|
||||
name: "SingStar Rocks!"
|
||||
name: "SingStar Rocks! [Promo]"
|
||||
region: "PAL-S"
|
||||
SCES-53897:
|
||||
name: "SingStar Rocks!"
|
||||
@@ -3079,7 +3095,7 @@ SCES-54073:
|
||||
name: "Buzz! The Big Quiz"
|
||||
region: "PAL-Unk"
|
||||
SCES-54077:
|
||||
name: "SingStar [Promo]"
|
||||
name: "SingStar top.it"
|
||||
region: "PAL-I"
|
||||
SCES-54078:
|
||||
name: "SingStar Norsk på Norsk"
|
||||
@@ -3088,7 +3104,7 @@ SCES-54128:
|
||||
name: "Deutsch Rock-Pop"
|
||||
region: "PAL-G"
|
||||
SCES-54129:
|
||||
name: "SingStar"
|
||||
name: "SingStar La Edad de Oro del Pop Español"
|
||||
region: "PAL-S"
|
||||
SCES-54131:
|
||||
name: "SingStar Anthems"
|
||||
@@ -3099,7 +3115,7 @@ SCES-54145:
|
||||
region: "PAL-M10"
|
||||
compat: 5
|
||||
SCES-54191:
|
||||
name: "SingStar Legends"
|
||||
name: "SingStar Legends [Promo]"
|
||||
region: "PAL-E"
|
||||
SCES-54197:
|
||||
name: "SingStar Legends"
|
||||
@@ -3168,6 +3184,24 @@ SCES-54330:
|
||||
SCES-54353:
|
||||
name: "SingStar Legends"
|
||||
region: "PAL-D"
|
||||
SCES-54370:
|
||||
name: "SingStar Pop Hits"
|
||||
region: "PAL-E"
|
||||
SCES-54371:
|
||||
name: "SingStar Pop Hits"
|
||||
region: "PAL-G"
|
||||
SCES-54372:
|
||||
name: "SingStar Pop Hits - 40 Principales"
|
||||
region: "PAL-S"
|
||||
SCES-54373:
|
||||
name: "SingStar Pop Hits"
|
||||
region: "PAL-SC" # Scandinavian (Danish,Norwegian,Finnish)
|
||||
SCES-54374:
|
||||
name: "SingStar Pop Hits"
|
||||
region: "PAL-F"
|
||||
SCES-54375:
|
||||
name: "SingStar Pop Hits"
|
||||
region: "PAL-P"
|
||||
SCES-54477:
|
||||
name: "SOCOM - US Navy Seals - Combined Assault"
|
||||
region: "PAL-M5"
|
||||
@@ -3218,20 +3252,29 @@ SCES-54572:
|
||||
SCES-54573:
|
||||
name: "SingStar Pop Hits"
|
||||
region: "PAL-SC"
|
||||
SCES-54574:
|
||||
name: "SingStar Pop Hits"
|
||||
region: "PAL-F"
|
||||
SCES-54575:
|
||||
name: "SingStar Pop Hits"
|
||||
region: "PAL-P"
|
||||
SCES-54576:
|
||||
name: "SingStar Pop Hits"
|
||||
region: "PAL-PL"
|
||||
SCES-54597:
|
||||
name: "Buzz! The Mega Quiz"
|
||||
region: "PAL-M3"
|
||||
name: "SingStar Rock Ballads"
|
||||
region: "PAL-E"
|
||||
SCES-54598:
|
||||
name: "SingStar - Svenska Hits Schlager"
|
||||
region: "PAL-SW"
|
||||
SCES-54599:
|
||||
name: "SingStar - '90s"
|
||||
name: "SingStar '90s"
|
||||
region: "PAL-E"
|
||||
SCES-54600:
|
||||
name: "SingStar - Die Toten Hosen"
|
||||
region: "PAL-G"
|
||||
SCES-54601:
|
||||
name: "SingStar - Apres-Ski Party"
|
||||
name: "SingStar - Après-Ski Party"
|
||||
region: "PAL-G"
|
||||
SCES-54625:
|
||||
name: "Buzz! Junior - Monster Rumble"
|
||||
@@ -3239,12 +3282,18 @@ SCES-54625:
|
||||
SCES-54638:
|
||||
name: "Gaelic Games - Football 2"
|
||||
region: "PAL-E-GA"
|
||||
SCES-54641:
|
||||
name: "SingStar - Après-Ski Party 2"
|
||||
region: "PAL-G"
|
||||
SCES-54676:
|
||||
name: "Buzz! Junior - RoboJam"
|
||||
region: "PAL-M7"
|
||||
SCES-54688:
|
||||
name: "ATV Offroad Fury 4"
|
||||
region: "PAL-M12"
|
||||
SCES-54741:
|
||||
name: "SingStar Deutsch Rock-Pop Vol. 2"
|
||||
region: "PAL-G"
|
||||
SCES-54748:
|
||||
name: "WipEout Pulse"
|
||||
region: "PAL-M5"
|
||||
@@ -3260,6 +3309,21 @@ SCES-54761:
|
||||
SCES-54762:
|
||||
name: "SingStar R&B"
|
||||
region: "PAL-G"
|
||||
SCES-54764:
|
||||
name: "SingStar Pop Hits 2"
|
||||
region: "PAL-F"
|
||||
SCES-54765:
|
||||
name: "SingStar R&B"
|
||||
region: "PAL-PL"
|
||||
SCES-54768:
|
||||
name: "SingStar Latino"
|
||||
region: "PAL-S"
|
||||
SCES-54769:
|
||||
name: "SingStar Latino"
|
||||
region: "PAL-P"
|
||||
SCES-54773:
|
||||
name: "SingStar Pop Hits"
|
||||
region: "PAL-E"
|
||||
SCES-54794:
|
||||
name: "Syphon Filter - Dark Mirror"
|
||||
region: "PAL-M5"
|
||||
@@ -3278,20 +3342,80 @@ SCES-54848:
|
||||
SCES-54851:
|
||||
name: "Buzz! The Hollywood Quiz"
|
||||
region: "PAL-M3"
|
||||
SCES-54869:
|
||||
name: "SingStar Italian Party"
|
||||
region: "PAL-I"
|
||||
SCES-54909:
|
||||
name: "SingStar '90s"
|
||||
region: "PAL-S"
|
||||
SCES-54910:
|
||||
name: "SingStar Rock Ballads"
|
||||
region: "PAL-S"
|
||||
SCES-55056:
|
||||
name: "SingStar Summer Party"
|
||||
region: "PAL-E"
|
||||
SCES-55057:
|
||||
name: "SingStar Summer Party"
|
||||
region: "PAL-G"
|
||||
SCES-55058:
|
||||
name: "SingStar Summer Party"
|
||||
region: "PAL-S"
|
||||
SCES-55059:
|
||||
name: "SingStar Italian Greatest Hits"
|
||||
region: "PAL-I"
|
||||
SCES-55061:
|
||||
name: "SingStar Wakacyjna Impreza!"
|
||||
region: "PAL-PL"
|
||||
SCES-55062:
|
||||
name: "SingStar Pop Hits 3"
|
||||
region: "PAL-F"
|
||||
SCES-55077:
|
||||
name: "SingStar Party Hits"
|
||||
region: "PAL-E"
|
||||
SCES-55093:
|
||||
name: "Buzz! The Pop Quiz"
|
||||
region: "PAL-E"
|
||||
SCES-55094:
|
||||
name: "Buzz! The Pop Quiz"
|
||||
region: "PAL-M3"
|
||||
SCES-55127:
|
||||
name: "SingStar Summer Party"
|
||||
region: "PAL-DU"
|
||||
SCES-55128:
|
||||
name: "SingStar Summer Party"
|
||||
region: "PAL-P"
|
||||
SCES-55158:
|
||||
name: "SingStar Pop Hits 4"
|
||||
region: "PAL-F"
|
||||
SCES-55159:
|
||||
name: "SingStar Amped"
|
||||
region: "PAL-G"
|
||||
SCES-55160:
|
||||
name: "SingStar Hottest Hits"
|
||||
region: "PAL-E"
|
||||
SCES-55173:
|
||||
name: "SingStar Operación Triunfo"
|
||||
region: "PAL-S"
|
||||
SCES-55176:
|
||||
name: "SingStar Amped"
|
||||
region: "PAL-E"
|
||||
SCES-55177:
|
||||
name: "SingStar SuomiRock"
|
||||
region: "PAL-FI"
|
||||
SCES-55178:
|
||||
name: "Singstar Boy Bands vs Girl Bands"
|
||||
region: "PAL-M5"
|
||||
name: "SingStar Boy Bands vs Girl Bands"
|
||||
region: "PAL-E"
|
||||
SCES-55179:
|
||||
name: "SingStar Schlager"
|
||||
region: "PAL-G"
|
||||
SCES-55181:
|
||||
name: "SingStar Italian Party 2"
|
||||
region: "PAL-I"
|
||||
SCES-55182:
|
||||
name: "SingStar Clásicos"
|
||||
region: "PAL-S"
|
||||
SCES-55183:
|
||||
name: "SingStar Turkish Party"
|
||||
name: "SingStar Turkish Party [Promo]"
|
||||
region: "PAL-TU"
|
||||
SCES-55210:
|
||||
name: "Buzz! Junior - Ace Racers"
|
||||
@@ -3299,6 +3423,36 @@ SCES-55210:
|
||||
SCES-55213:
|
||||
name: "Buzz! Escuela de Talentos"
|
||||
region: "PAL-S"
|
||||
SCES-55241:
|
||||
name: "SingStar Russian Hit"
|
||||
region: "PAL-R"
|
||||
SCES-55255:
|
||||
name: "SingStar Singalong with Disney"
|
||||
region: "PAL-E"
|
||||
SCES-55256:
|
||||
name: "SingStar Canciones Disney"
|
||||
region: "PAL-S"
|
||||
SCES-55257:
|
||||
name: "SingStar - Chansons Magiques de Disney"
|
||||
region: "PAL-F"
|
||||
SCES-55258:
|
||||
name: "SingStar Best of Disney"
|
||||
region: "PAL-G"
|
||||
SCES-55259:
|
||||
name: "SingStar Canções Disney"
|
||||
region: "PAL-P"
|
||||
SCES-55260:
|
||||
name: "SingStar e la Magia Disney"
|
||||
region: "PAL-I"
|
||||
SCES-55261:
|
||||
name: "SingStar Sjung med Disney"
|
||||
region: "PAL-SW"
|
||||
SCES-55262:
|
||||
name: "SingStar Syng med Disney"
|
||||
region: "PAL-D"
|
||||
SCES-55360:
|
||||
name: "SingStar Singalong with Disney"
|
||||
region: "PAL-G"
|
||||
SCES-55361:
|
||||
name: "SingStar Boy Bands vs Girl Bands"
|
||||
region: "PAL-G"
|
||||
@@ -3311,6 +3465,9 @@ SCES-55385:
|
||||
SCES-55387:
|
||||
name: "Buzz! Deutschlands Superquiz"
|
||||
region: "PAL-G"
|
||||
SCES-55401:
|
||||
name: "SingStar Zingt met Disney"
|
||||
region: "PAL-DU"
|
||||
SCES-55435:
|
||||
name: "SingStar ABBA"
|
||||
region: "PAL-E"
|
||||
@@ -3320,18 +3477,54 @@ SCES-55436:
|
||||
SCES-55437:
|
||||
name: "SingStar ABBA"
|
||||
region: "PAL-G"
|
||||
SCES-55438:
|
||||
name: "SingStar ABBA"
|
||||
region: "PAL-S"
|
||||
SCES-55439:
|
||||
name: "SingStar ABBA"
|
||||
region: "PAL-I"
|
||||
SCES-55453:
|
||||
name: "SingStar Queen"
|
||||
region: "PAL-E"
|
||||
SCES-55454:
|
||||
name: "SingStar Queen"
|
||||
region: "PAL-G"
|
||||
SCES-55455:
|
||||
name: "SingStar Queen"
|
||||
region: "PAL-S"
|
||||
SCES-55464:
|
||||
name: "Hanuman: Boy Warrior"
|
||||
region: "PAL-E-HI"
|
||||
compat: 5
|
||||
SCES-55478:
|
||||
name: "SingStar Afrikaanse Treffers"
|
||||
region: "PAL-AF"
|
||||
SCES-55485:
|
||||
name: "SingStar Queen"
|
||||
region: "PAL-I"
|
||||
SCES-55489:
|
||||
name: "SingStar Mallorca Party"
|
||||
region: "PAL-G"
|
||||
SCES-55510:
|
||||
name: "Jak and Daxter: The Lost Frontier"
|
||||
region: "PAL-M12"
|
||||
gameFixes:
|
||||
- VUKickstartHack # Fixes Character SPS.
|
||||
SCES-55513:
|
||||
name: "SingStar Polskie Hity"
|
||||
region: "PAL-PL"
|
||||
SCES-55514:
|
||||
name: "SingStar Studio 100"
|
||||
region: "PAL-DU"
|
||||
SCES-55515:
|
||||
name: "SingStar Morangos com Açúcar"
|
||||
region: "PAL-P"
|
||||
SCES-55521:
|
||||
name: "SingStar SuomiPop"
|
||||
region: "PAL-FI"
|
||||
SCES-55527:
|
||||
name: "SingStar 2009"
|
||||
region: "PAL-S"
|
||||
SCES-55535:
|
||||
name: "Desi Adda: Games of India"
|
||||
region: "PAL-M4"
|
||||
@@ -3339,24 +3532,81 @@ SCES-55535:
|
||||
SCES-55538:
|
||||
name: "SingStar"
|
||||
region: "PAL-G"
|
||||
SCES-55540:
|
||||
name: "SingStar Mecano"
|
||||
region: "PAL-S"
|
||||
SCES-55549:
|
||||
name: "SingStar MoTown [Promo]"
|
||||
region: "PAL-E"
|
||||
SCES-55551:
|
||||
name: "SingStar MoTown"
|
||||
region: "PAL-I"
|
||||
SCES-55552:
|
||||
name: "SingStar MoTown"
|
||||
region: "PAL-G"
|
||||
SCES-55553:
|
||||
name: "SingStar MoTown"
|
||||
region: "PAL-DU"
|
||||
SCES-55554:
|
||||
name: "Singstar Take That"
|
||||
name: "SingStar Take That"
|
||||
region: "PAL-M5"
|
||||
SCES-55557:
|
||||
name: "SingStar Take That"
|
||||
region: "PAL-G"
|
||||
SCES-55564:
|
||||
name: "SingStar Made in Germany"
|
||||
region: "PAL-G"
|
||||
SCES-55566:
|
||||
name: "SingStar Miliki"
|
||||
region: "PAL-S"
|
||||
SCES-55567:
|
||||
name: "SingStar The Wiggles"
|
||||
region: "PAL-E"
|
||||
SCES-55568:
|
||||
name: "SingStar Svenska Stjärnor"
|
||||
region: "PAL-E"
|
||||
SCES-55570:
|
||||
name: "SingStar Chartbreaker"
|
||||
region: "PAL-G"
|
||||
SCES-55573:
|
||||
name: "MotorStorm - Arctic Edge"
|
||||
region: "PAL-M14"
|
||||
SCES-55594:
|
||||
name: "SingStar Vasco"
|
||||
region: "PAL-I"
|
||||
SCES-55606:
|
||||
name: "SingStar Die größten Solokünstler"
|
||||
region: "PAL-G"
|
||||
SCES-55611:
|
||||
name: "SingStar Chart Hits"
|
||||
region: "PAL-E"
|
||||
SCES-55612:
|
||||
name: "SingStar SuomiHitIt"
|
||||
region: "PAL-FI"
|
||||
SCES-55616:
|
||||
name: "SingStar Polskie Hity 2"
|
||||
region: "PAL-PL"
|
||||
SCES-55617:
|
||||
name: "SingStar Fussballhits"
|
||||
region: "PAL-G"
|
||||
SCES-55618:
|
||||
name: "SingStar Kent"
|
||||
region: "PAL-SW"
|
||||
SCES-55619:
|
||||
name: "SingStar Portugal Hits"
|
||||
region: "PAL-P"
|
||||
SCES-55621:
|
||||
name: "SingStar Patito Feo"
|
||||
region: "PAL-S"
|
||||
SCES-55640:
|
||||
name: "SingStar Cantautori Italiani"
|
||||
region: "PAL-I"
|
||||
SCES-55641:
|
||||
name: "SingStar Après-Ski Party 2"
|
||||
region: "PAL-G"
|
||||
SCES-55650:
|
||||
name: "SingStar SuomiSuosikit"
|
||||
region: "PAL-FI"
|
||||
SCES-55661:
|
||||
name: "RA.ONE: The Game"
|
||||
region: "PAL-E"
|
||||
@@ -4983,7 +5233,7 @@ SCUS-90174:
|
||||
roundModes:
|
||||
vuRoundMode: 2 # Fixes very minor lines appearing at certain points during the game.
|
||||
SCUS-94346:
|
||||
name: "Singstar Latino"
|
||||
name: "SingStar Latino"
|
||||
region: "NTSC-U"
|
||||
SCUS-97097:
|
||||
name: "Network Adapter Start-Up Disc"
|
||||
@@ -6386,7 +6636,7 @@ SCUS-97568:
|
||||
name: "MLB '07 - The Show [Demo]"
|
||||
region: "NTSC-U"
|
||||
SCUS-97571:
|
||||
name: "SingStar Rocks! [with Microphone]"
|
||||
name: "SingStar Rocks!"
|
||||
region: "NTSC-U"
|
||||
compat: 3
|
||||
SCUS-97572:
|
||||
@@ -6396,7 +6646,7 @@ SCUS-97579:
|
||||
name: "ATV Off-Road Fury 4 [Demo]"
|
||||
region: "NTSC-U"
|
||||
SCUS-97580:
|
||||
name: "SingStar Pop [with Microphone]"
|
||||
name: "SingStar Pop"
|
||||
region: "NTSC-U"
|
||||
SCUS-97583:
|
||||
name: "MLB '08 - The Show"
|
||||
@@ -6408,10 +6658,10 @@ SCUS-97589:
|
||||
name: "NBA '08 featuring The Life Vol.3"
|
||||
region: "NTSC-U"
|
||||
SCUS-97590:
|
||||
name: "SingStar Rocks! [Game Only]"
|
||||
name: "SingStar Rocks!"
|
||||
region: "NTSC-U"
|
||||
SCUS-97591:
|
||||
name: "SingStar Pop [Game Only]"
|
||||
name: "SingStar Pop"
|
||||
region: "NTSC-U"
|
||||
SCUS-97592:
|
||||
name: "Buzz! The Mega Quiz"
|
||||
@@ -6441,11 +6691,11 @@ SCUS-97610:
|
||||
roundModes:
|
||||
vuRoundMode: 1 # Fixes the display of scores and text ingame.
|
||||
SCUS-97611:
|
||||
name: "SingStar Amped [with Microphone]"
|
||||
name: "SingStar Amped"
|
||||
region: "NTSC-U"
|
||||
compat: 3
|
||||
SCUS-97612:
|
||||
name: "SingStar Amped [Game Only]"
|
||||
name: "SingStar Amped"
|
||||
region: "NTSC-U"
|
||||
SCUS-97615:
|
||||
name: "Ratchet & Clank - Size Matters"
|
||||
@@ -6457,7 +6707,7 @@ SCUS-97616:
|
||||
region: "NTSC-U"
|
||||
compat: 3
|
||||
SCUS-97618:
|
||||
name: "SingStar 80's [Game Only]"
|
||||
name: "SingStar 80's"
|
||||
region: "NTSC-U"
|
||||
SCUS-97620:
|
||||
name: "Syphon Filter - Dark Mirror [Demo]"
|
||||
@@ -6477,14 +6727,14 @@ SCUS-97621:
|
||||
patch=1,EE,002461e0,word,4bc069fc
|
||||
patch=1,EE,002461e4,word,4a54c3bc
|
||||
SCUS-97622:
|
||||
name: "SingStar 80's [with Microphone]"
|
||||
name: "SingStar '80s"
|
||||
region: "NTSC-U"
|
||||
SCUS-97623:
|
||||
name: "Secret Agent Clank"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
SCUS-97626:
|
||||
name: "SingStar 90's"
|
||||
name: "SingStar '90s"
|
||||
region: "NTSC-U"
|
||||
SCUS-97627:
|
||||
name: "SingStar Pop Volume 2"
|
||||
@@ -6497,14 +6747,14 @@ SCUS-97634:
|
||||
name: "Buzz! Jr. RoboJam [Game Only]"
|
||||
region: "NTSC-U"
|
||||
SCUS-97636:
|
||||
name: "SingStar 90's [Game Only]"
|
||||
name: "SingStar '90s"
|
||||
region: "NTSC-U"
|
||||
SCUS-97640:
|
||||
name: "SingStar Legends"
|
||||
region: "NTSC-U"
|
||||
compat: 3
|
||||
SCUS-97642:
|
||||
name: "SingStar Abba"
|
||||
name: "SingStar ABBA"
|
||||
region: "NTSC-U"
|
||||
compat: 3
|
||||
SCUS-97643:
|
||||
@@ -6514,6 +6764,12 @@ SCUS-97643:
|
||||
SCUS-97644:
|
||||
name: "MLB '09: The Show"
|
||||
region: "NTSC-U"
|
||||
SCUS-97649:
|
||||
name: "SingStar Pop Vol. 2"
|
||||
region: "NTSC-U"
|
||||
SCUS-97650:
|
||||
name: "SingStar Country"
|
||||
region: "NTSC-U"
|
||||
SCUS-97651:
|
||||
name: "SingStar Country"
|
||||
region: "NTSC-U"
|
||||
@@ -7313,6 +7569,8 @@ SLES-50201:
|
||||
name: "Evil Twin - Cyprien's Chronicles"
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
clampModes:
|
||||
eeClampMode: 2 # Fixes texture mipmapping.
|
||||
SLES-50202:
|
||||
name: "DNA - Dark Native Apostle"
|
||||
region: "PAL-M5"
|
||||
@@ -8170,6 +8428,8 @@ SLES-50662:
|
||||
name: "Shadow of Zorro, The"
|
||||
region: "PAL-M5"
|
||||
compat: 4
|
||||
clampModes:
|
||||
eeClampMode: 2 # Fixes texture mipmapping.
|
||||
SLES-50670:
|
||||
name: "ESPN Winter X-Games Snowboarding 2"
|
||||
region: "PAL-M3"
|
||||
@@ -9499,6 +9759,8 @@ SLES-51289:
|
||||
name: "Gunfighter 2 - Legend of Jesse James"
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
gameFixes:
|
||||
- GIFFIFOHack # Fixes flickering textures.
|
||||
SLES-51290:
|
||||
name: "Sword of the Samurai"
|
||||
region: "PAL-E"
|
||||
@@ -9717,8 +9979,9 @@ SLES-51391:
|
||||
SLES-51392:
|
||||
name: "Evolution Snowboarding"
|
||||
region: "PAL-M3"
|
||||
compat: 5
|
||||
patches:
|
||||
2B2E1535:
|
||||
C24C7FE3:
|
||||
content: |-
|
||||
author=kozarovv
|
||||
// Skip PSS movies, workaround for EE Cache requirement.
|
||||
@@ -10989,19 +11252,29 @@ SLES-52125:
|
||||
SLES-52132:
|
||||
name: "Hitman - Contracts"
|
||||
region: "PAL-E"
|
||||
roundModes:
|
||||
vuRoundMode: 0 # Fixes effects and textures.
|
||||
SLES-52133:
|
||||
name: "Hitman - Contracts"
|
||||
region: "PAL-F"
|
||||
roundModes:
|
||||
vuRoundMode: 0 # Fixes effects and textures.
|
||||
SLES-52134:
|
||||
name: "Hitman - Contracts"
|
||||
region: "PAL-I"
|
||||
compat: 4
|
||||
roundModes:
|
||||
vuRoundMode: 0 # Fixes effects and textures.
|
||||
SLES-52135:
|
||||
name: "Hitman - Contracts"
|
||||
region: "PAL-G"
|
||||
roundModes:
|
||||
vuRoundMode: 0 # Fixes effects and textures.
|
||||
SLES-52136:
|
||||
name: "Hitman - Contracts"
|
||||
region: "PAL-S"
|
||||
roundModes:
|
||||
vuRoundMode: 0 # Fixes effects and textures.
|
||||
SLES-52143:
|
||||
name: "Carmen Sandiego - The Secret of the Stolen Drums"
|
||||
region: "PAL-M4"
|
||||
@@ -18787,6 +19060,8 @@ SLKA-25217:
|
||||
SLKA-25218:
|
||||
name: "Hitman - Contracts"
|
||||
region: "NTSC-K"
|
||||
roundModes:
|
||||
vuRoundMode: 0 # Fixes effects and textures.
|
||||
SLKA-25219:
|
||||
name: "Monster Hunter G"
|
||||
region: "NTSC-K"
|
||||
@@ -19132,9 +19407,15 @@ SLPM-55008:
|
||||
name: "Sengoku Basara X"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
SLPM-55024:
|
||||
name: "Jikkyou Powerful Pro Yakyuu 15"
|
||||
region: "NTSC-J"
|
||||
SLPM-55033:
|
||||
name: "J. League Winning Eleven 2008 - Club Championship"
|
||||
region: "NTSC-J"
|
||||
SLPM-55062:
|
||||
name: "Jikkyou Powerful Major League 3"
|
||||
region: "NTSC-J"
|
||||
SLPM-55063:
|
||||
name: "Hakuouki - Shinsengumi Kitan [Limited Edition]"
|
||||
region: "NTSC-J"
|
||||
@@ -19211,6 +19492,9 @@ SLPM-55138:
|
||||
SLPM-55148:
|
||||
name: "007: Nagusame no Houshuu"
|
||||
region: "NTSC-J"
|
||||
SLPM-55155:
|
||||
name: "Jikkyou Powerful Major League 2009"
|
||||
region: "NTSC-J"
|
||||
SLPM-55170:
|
||||
name: "Skip Beat!"
|
||||
region: "NTSC-J"
|
||||
@@ -19408,7 +19692,7 @@ SLPM-62007:
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
SLPM-62008:
|
||||
name: "Powerful Pro Baseball 7"
|
||||
name: "Jikkyou Powerful Pro Yakyuu 7"
|
||||
region: "NTSC-J"
|
||||
SLPM-62009:
|
||||
name: "Ganbare Nippon Olympics 2000"
|
||||
@@ -19466,6 +19750,9 @@ SLPM-62031:
|
||||
SLPM-62032:
|
||||
name: "ESPN NBA 2Night"
|
||||
region: "NTSC-J"
|
||||
SLPM-62034:
|
||||
name: "Jikkyou Powerful Pro Yakyuu 7 Ketteiban"
|
||||
region: "NTSC-J"
|
||||
SLPM-62035:
|
||||
name: "Got to Do! Hot Spring Table Tennis"
|
||||
region: "NTSC-J"
|
||||
@@ -19495,7 +19782,7 @@ SLPM-62048:
|
||||
name: "Battle Gear 2"
|
||||
region: "NTSC-J"
|
||||
SLPM-62049:
|
||||
name: "Densha de Go! 3 - Takkyuu!!"
|
||||
name: "Densha de Go! 3 - Tsuukin-hen"
|
||||
region: "NTSC-J"
|
||||
SLPM-62051:
|
||||
name: "Yanya Caballista - featuring Gawoo"
|
||||
@@ -19537,6 +19824,9 @@ SLPM-62069:
|
||||
SLPM-62070:
|
||||
name: "Uchu-Jintte Naani"
|
||||
region: "NTSC-J"
|
||||
SLPM-62071:
|
||||
name: "Jikkyou Powerful Pro Yakyuu 8"
|
||||
region: "NTSC-J"
|
||||
SLPM-62072:
|
||||
name: "Horse Breaker"
|
||||
region: "NTSC-J"
|
||||
@@ -19630,6 +19920,9 @@ SLPM-62118:
|
||||
name: "Bomberman Kart"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
SLPM-62119:
|
||||
name: "Jikkyou Powerful Pro Yakyuu 8 Ketteiban"
|
||||
region: "NTSC-J"
|
||||
SLPM-62120:
|
||||
name: "Jikkyou World Soccer 2001"
|
||||
region: "NTSC-J"
|
||||
@@ -19767,6 +20060,9 @@ SLPM-62186:
|
||||
SLPM-62190:
|
||||
name: "High Heat - Major League Baseball 2003"
|
||||
region: "NTSC-J"
|
||||
SLPM-62192:
|
||||
name: "Jikkyou Powerful Pro Yakyuu 9"
|
||||
region: "NTSC-J"
|
||||
SLPM-62193:
|
||||
name: "J League Perfect Striker 5"
|
||||
region: "NTSC-J"
|
||||
@@ -19984,7 +20280,7 @@ SLPM-62273:
|
||||
name: "Mai-Shin 3"
|
||||
region: "NTSC-J"
|
||||
SLPM-62274:
|
||||
name: "Powerful Pro Baseball 9 Ketteiban"
|
||||
name: "Jikkyou Powerful Pro Yakyuu 9 Ketteiban"
|
||||
region: "NTSC-J"
|
||||
SLPM-62275:
|
||||
name: "Space Raiders"
|
||||
@@ -21523,8 +21819,9 @@ SLPM-65053:
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
SLPM-65054:
|
||||
name: "Princess Abarenbou"
|
||||
name: "Abarenbou Princess"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
SLPM-65056:
|
||||
name: "Orega Kantoku da Vol.2 - Getitou Pennant Race"
|
||||
region: "NTSC-J"
|
||||
@@ -21786,7 +22083,7 @@ SLPM-65144:
|
||||
gameFixes:
|
||||
- VUKickstartHack # Fixes SPS.
|
||||
SLPM-65148:
|
||||
name: "Densha de Go! Ryojouhen"
|
||||
name: "Densha de Go! Ryojou-hen"
|
||||
region: "NTSC-J"
|
||||
SLPM-65150:
|
||||
name: "Aero Dancing 4 - New Generation"
|
||||
@@ -22007,6 +22304,13 @@ SLPM-65230:
|
||||
SLPM-65231:
|
||||
name: "Evolution Snowboarding"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
patches:
|
||||
F96A2390:
|
||||
content: |-
|
||||
author=kozarovv
|
||||
// Skip PSS movies, workaround for EE Cache requirement.
|
||||
patch=1,EE,00122d00,word,100000d9
|
||||
SLPM-65232:
|
||||
name: "Devil May Cry 2 [Dante Disc]"
|
||||
region: "NTSC-J"
|
||||
@@ -22272,7 +22576,7 @@ SLPM-65316:
|
||||
name: "Pop'n Music 8"
|
||||
region: "NTSC-J"
|
||||
SLPM-65317:
|
||||
name: "Jikkyou Powerful Pro Baseball 10"
|
||||
name: "Jikkyou Powerful Pro Yakyuu 10"
|
||||
region: "NTSC-J"
|
||||
SLPM-65318:
|
||||
name: "Shoubushi Tetsuya 2"
|
||||
@@ -22650,7 +22954,7 @@ SLPM-65444:
|
||||
clampModes:
|
||||
eeClampMode: 3 # Fixes cutscene freezes.
|
||||
SLPM-65445:
|
||||
name: "Powerful Pro Baseball 10 - Decision"
|
||||
name: "Jikkyou Powerful Pro Yakyuu 10 Chou Ketteiban - 2003 Memorial"
|
||||
region: "NTSC-J"
|
||||
SLPM-65446:
|
||||
name: "James Bond 007 - Everything or Nothing"
|
||||
@@ -24530,7 +24834,7 @@ SLPM-66060:
|
||||
name: "Boukoku no Aegis 2035 - Warship Gunner"
|
||||
region: "NTSC-J"
|
||||
SLPM-66061:
|
||||
name: "Jikkyou Powerful Pro Baseball 12"
|
||||
name: "Jikkyou Powerful Pro Yakyuu 12"
|
||||
region: "NTSC-J"
|
||||
SLPM-66062:
|
||||
name: "Mahou Sensei Negima! Gold Medal"
|
||||
@@ -25617,7 +25921,7 @@ SLPM-66416:
|
||||
name: "Mystereet"
|
||||
region: "NTSC-J"
|
||||
SLPM-66417:
|
||||
name: "Jikkyou Powerful Pro Major League"
|
||||
name: "Jikkyou Powerful Major League"
|
||||
region: "NTSC-J"
|
||||
SLPM-66418:
|
||||
name: "Growlanser V - Generations"
|
||||
@@ -25728,7 +26032,7 @@ SLPM-66449:
|
||||
name: "We Are"
|
||||
region: "NTSC-J"
|
||||
SLPM-66450:
|
||||
name: "Jikkyou Powerful Pro Baseball 13"
|
||||
name: "Jikkyou Powerful Pro Yakyuu 13"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
SLPM-66451:
|
||||
@@ -26188,7 +26492,7 @@ SLPM-66589:
|
||||
name: "NBA Live '07"
|
||||
region: "NTSC-J"
|
||||
SLPM-66590:
|
||||
name: "Jikkyou Powerful Pro Yakyuu 13 Chou Ketteiban"
|
||||
name: "Jikkyou Powerful Pro Yakyuu 13 Ketteiban"
|
||||
region: "NTSC-J"
|
||||
SLPM-66591:
|
||||
name: "FlatOut 2 GTR"
|
||||
@@ -27087,7 +27391,7 @@ SLPM-66874:
|
||||
name: "Lucky Star"
|
||||
region: "NTSC-J"
|
||||
SLPM-66875:
|
||||
name: "Jikkyou Powerful Pro Major League 2"
|
||||
name: "Jikkyou Powerful Major League 2"
|
||||
region: "NTSC-J"
|
||||
SLPM-66876:
|
||||
name: "Izumo 2 [GN Software Best]"
|
||||
@@ -27209,7 +27513,7 @@ SLPM-66915:
|
||||
name: "Yu-Gi-Oh Duel Monsters GX - Tag Force Evolution"
|
||||
region: "NTSC-J"
|
||||
SLPM-66916:
|
||||
name: "Jikkyou Powerful Pro Yakyuu 14 Chou Ketteiban"
|
||||
name: "Jikkyou Powerful Pro Yakyuu 14 Ketteiban"
|
||||
region: "NTSC-J"
|
||||
SLPM-66917:
|
||||
name: "Grand Theft Auto - Vice City Stories"
|
||||
@@ -30118,6 +30422,8 @@ SLPS-25405:
|
||||
SLPS-25406:
|
||||
name: "Hitman - Contracts"
|
||||
region: "NTSC-J"
|
||||
roundModes:
|
||||
vuRoundMode: 0 # Fixes effects and textures.
|
||||
SLPS-25407:
|
||||
name: "King of Fighters 2003, The"
|
||||
region: "NTSC-J"
|
||||
@@ -34502,9 +34808,9 @@ SLUS-20545:
|
||||
SLUS-20546:
|
||||
name: "Evolution Snowboarding"
|
||||
region: "NTSC-U"
|
||||
compat: 4
|
||||
compat: 5
|
||||
patches:
|
||||
2B2E1535:
|
||||
D3F68D3F:
|
||||
content: |-
|
||||
author=kozarovv
|
||||
// Skip PSS movies, workaround for EE Cache requirement.
|
||||
@@ -35881,7 +36187,7 @@ SLUS-20882:
|
||||
region: "NTSC-U"
|
||||
compat: 3
|
||||
roundModes:
|
||||
vuRoundMode: 2 # Fixes missing light shafts under lamps.
|
||||
vuRoundMode: 0 # Fixes effects and textures.
|
||||
SLUS-20883:
|
||||
name: "Tom Clancy's Rainbow Six 3"
|
||||
region: "NTSC-U"
|
||||
@@ -41131,7 +41437,7 @@ TCPS-10058:
|
||||
name: "Densha de Go! Shinkansen [with Controller]"
|
||||
region: "NTSC-J"
|
||||
TCPS-10068:
|
||||
name: "Densha de Go! Ryojo-hen [with Controller]"
|
||||
name: "Densha de Go! Ryojou-hen [with Controller]"
|
||||
region: "NTSC-J"
|
||||
TCPS-10074:
|
||||
name: "Space Invaders 25th Anniversary Bundle"
|
||||
|
||||
@@ -220,7 +220,9 @@ option(USE_PGO_OPTIMIZE "Enable PGO optimization (use profile)")
|
||||
|
||||
# Note1: Builtin strcmp/memcmp was proved to be slower on Mesa than stdlib version.
|
||||
# Note2: float operation SSE is impacted by the PCSX2 SSE configuration. In particular, flush to zero denormal.
|
||||
if(NOT MSVC)
|
||||
if(MSVC)
|
||||
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/Zc:externConstexpr>")
|
||||
else()
|
||||
add_compile_options(-pipe -fvisibility=hidden -pthread -fno-builtin-strcmp -fno-builtin-memcmp -mfpmath=sse -fno-operator-names)
|
||||
endif()
|
||||
|
||||
@@ -328,9 +330,9 @@ endif()
|
||||
# MacOS-specific things
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13)
|
||||
|
||||
if (APPLE AND ${CMAKE_OSX_DEPLOYMENT_TARGET} VERSION_LESS 10.14 AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 10)
|
||||
if (APPLE AND ${CMAKE_OSX_DEPLOYMENT_TARGET} VERSION_LESS 10.14 AND NOT ${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 9)
|
||||
# Older versions of the macOS stdlib don't have operator new(size_t, align_val_t)
|
||||
# Disable use of them with this flag
|
||||
# Not great, but also no worse that what we were getting before we turned on C++17
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// An implementation of bit_cast until we get c++20
|
||||
|
||||
template<class T2, class T1>
|
||||
T2 bit_cast(const T1& src)
|
||||
{
|
||||
static_assert(sizeof(T2) == sizeof(T1), "bit_cast: types must be equal size");
|
||||
static_assert(std::is_pod<T1>::value, "bit_cast: source must be POD");
|
||||
static_assert(std::is_pod<T2>::value, "bit_cast: destination must be POD");
|
||||
T2 dst;
|
||||
memcpy(&dst, &src, sizeof(T2));
|
||||
return dst;
|
||||
}
|
||||
@@ -82,11 +82,7 @@ static u64 getthreadtime(thread_port_t thread)
|
||||
(u64)info.system_time.microseconds;
|
||||
}
|
||||
|
||||
// Returns the current timestamp (not relative to a real world clock) in
|
||||
// units of 100 nanoseconds. The weird units are to mirror the Windows
|
||||
// counterpart in WinThreads.cpp, which uses the GetThreadTimes() API. On
|
||||
// OSX/Darwin, this is only accurate up until 1ms (and possibly less), so
|
||||
// not very good.
|
||||
// Returns the current timestamp (not relative to a real world clock) in microseconds
|
||||
u64 Threading::GetThreadCpuTime()
|
||||
{
|
||||
// we could also use mach_thread_self() and mach_port_deallocate(), but
|
||||
@@ -95,7 +91,7 @@ u64 Threading::GetThreadCpuTime()
|
||||
// to be user-space instead. In contract,
|
||||
// pthread_mach_thread_np(pthread_self()) is entirely in user-space.
|
||||
u64 us = getthreadtime(pthread_mach_thread_np(pthread_self()));
|
||||
return us * 10ULL;
|
||||
return us;
|
||||
}
|
||||
|
||||
u64 Threading::pxThread::GetCpuTime() const
|
||||
@@ -109,7 +105,7 @@ u64 Threading::pxThread::GetCpuTime() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getthreadtime((thread_port_t)m_native_id) * 10ULL;
|
||||
return getthreadtime((thread_port_t)m_native_id);
|
||||
}
|
||||
|
||||
void Threading::pxThread::_platform_specific_OnStartInThread()
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
|
||||
#include "common/emitter/x86_intrin.h"
|
||||
|
||||
// The C++ standard doesn't allow `offsetof` to be used on non-constant values (e.g. `offsetof(class, field[i])`)
|
||||
// Use this in those situations
|
||||
#define OFFSETOF(a, b) (reinterpret_cast<size_t>(&(static_cast<a*>(0)->b)))
|
||||
|
||||
// Renamed ARRAYSIZE to ArraySize -- looks nice and gets rid of Windows.h conflicts (air)
|
||||
// Notes: I'd have used ARRAY_SIZE instead but ran into cross-platform lib conflicts with
|
||||
// that as well. >_<
|
||||
|
||||
@@ -100,6 +100,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Align.h" />
|
||||
<ClInclude Include="BitCast.h" />
|
||||
<ClInclude Include="EmbeddedImage.h" />
|
||||
<ClInclude Include="boost_spsc_queue.hpp" />
|
||||
<ClInclude Include="FastJmp.h" />
|
||||
|
||||
@@ -291,6 +291,9 @@
|
||||
<ClInclude Include="WindowInfo.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BitCast.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GL\Context.h">
|
||||
<Filter>Header Files\GL</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
#include "Elfheader.h"
|
||||
#include "ps2/BiosTools.h"
|
||||
|
||||
#ifndef DISABLE_RECORDING
|
||||
#include "Recording/InputRecording.h"
|
||||
#endif
|
||||
|
||||
// This typically reflects the Sony-assigned serial code for the Disc, if one exists.
|
||||
// (examples: SLUS-2113, etc).
|
||||
// If the disc is homebrew then it probably won't have a valid serial; in which case
|
||||
@@ -780,6 +784,34 @@ void cdvdReset()
|
||||
cdvd.Action = cdvdAction_None;
|
||||
cdvd.ReadTime = cdvdBlockReadTime(MODE_DVDROM);
|
||||
|
||||
// If we are recording, always use the same RTC setting
|
||||
// for games that use the RTC to seed their RNG -- this is very important to be the same everytime!
|
||||
#ifndef DISABLE_RECORDING
|
||||
if (g_InputRecording.IsActive())
|
||||
{
|
||||
Console.WriteLn("Input Recording Active - Using Constant RTC of 04-03-2020 (DD-MM-YYYY)");
|
||||
// Why not just 0 everything? Some games apparently require the date to be valid in terms of when
|
||||
// the PS2 / Game actually came out. (MGS3). So set it to a value well beyond any PS2 game's release date.
|
||||
cdvd.RTC.second = 0;
|
||||
cdvd.RTC.minute = 0;
|
||||
cdvd.RTC.hour = 0;
|
||||
cdvd.RTC.day = 4;
|
||||
cdvd.RTC.month = 3;
|
||||
cdvd.RTC.year = 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
// CDVD internally uses GMT+9. If you think the time's wrong, you're wrong.
|
||||
// Set up your time zone and winter/summer in the BIOS. No PS2 BIOS I know of features automatic DST.
|
||||
wxDateTime curtime(wxDateTime::GetTimeNow());
|
||||
cdvd.RTC.second = (u8)curtime.GetSecond();
|
||||
cdvd.RTC.minute = (u8)curtime.GetMinute();
|
||||
cdvd.RTC.hour = (u8)curtime.GetHour(wxDateTime::GMT9);
|
||||
cdvd.RTC.day = (u8)curtime.GetDay(wxDateTime::GMT9);
|
||||
cdvd.RTC.month = (u8)curtime.GetMonth(wxDateTime::GMT9) + 1; // WX returns Jan as "0"
|
||||
cdvd.RTC.year = (u8)(curtime.GetYear(wxDateTime::GMT9) - 2000);
|
||||
}
|
||||
#else
|
||||
// CDVD internally uses GMT+9. If you think the time's wrong, you're wrong.
|
||||
// Set up your time zone and winter/summer in the BIOS. No PS2 BIOS I know of features automatic DST.
|
||||
wxDateTime curtime(wxDateTime::GetTimeNow());
|
||||
@@ -789,6 +821,7 @@ void cdvdReset()
|
||||
cdvd.RTC.day = (u8)curtime.GetDay(wxDateTime::GMT9);
|
||||
cdvd.RTC.month = (u8)curtime.GetMonth(wxDateTime::GMT9) + 1; // WX returns Jan as "0"
|
||||
cdvd.RTC.year = (u8)(curtime.GetYear(wxDateTime::GMT9) - 2000);
|
||||
#endif
|
||||
|
||||
g_GameStarted = false;
|
||||
g_GameLoading = false;
|
||||
|
||||
+12
-16
@@ -639,21 +639,12 @@ set(pcsx2GSSources
|
||||
GS/Renderers/HW/GSTextureCache.cpp
|
||||
GS/Renderers/SW/GSDrawScanline.cpp
|
||||
GS/Renderers/SW/GSDrawScanlineCodeGenerator.cpp
|
||||
GS/Renderers/SW/GSDrawScanlineCodeGenerator.x64.cpp
|
||||
GS/Renderers/SW/GSDrawScanlineCodeGenerator.x64.avx.cpp
|
||||
GS/Renderers/SW/GSDrawScanlineCodeGenerator.x64.avx2.cpp
|
||||
GS/Renderers/SW/GSDrawScanlineCodeGenerator.x86.cpp
|
||||
GS/Renderers/SW/GSDrawScanlineCodeGenerator.x86.avx.cpp
|
||||
GS/Renderers/SW/GSDrawScanlineCodeGenerator.x86.avx2.cpp
|
||||
GS/Renderers/SW/GSDrawScanlineCodeGenerator.all.cpp
|
||||
GS/Renderers/SW/GSNewCodeGenerator.cpp
|
||||
GS/Renderers/SW/GSRasterizer.cpp
|
||||
GS/Renderers/SW/GSRendererSW.cpp
|
||||
GS/Renderers/SW/GSSetupPrimCodeGenerator.cpp
|
||||
GS/Renderers/SW/GSSetupPrimCodeGenerator.x64.cpp
|
||||
GS/Renderers/SW/GSSetupPrimCodeGenerator.x64.avx.cpp
|
||||
GS/Renderers/SW/GSSetupPrimCodeGenerator.x64.avx2.cpp
|
||||
GS/Renderers/SW/GSSetupPrimCodeGenerator.x86.cpp
|
||||
GS/Renderers/SW/GSSetupPrimCodeGenerator.x86.avx.cpp
|
||||
GS/Renderers/SW/GSSetupPrimCodeGenerator.x86.avx2.cpp
|
||||
GS/Renderers/SW/GSSetupPrimCodeGenerator.all.cpp
|
||||
GS/Renderers/SW/GSTextureCacheSW.cpp
|
||||
GS/Renderers/SW/GSTextureSW.cpp
|
||||
GS/Renderers/OpenGL/GLLoader.cpp
|
||||
@@ -664,6 +655,7 @@ set(pcsx2GSSources
|
||||
GS/Renderers/OpenGL/GSTextureCacheOGL.cpp
|
||||
GS/Renderers/OpenGL/GSTextureOGL.cpp
|
||||
GS/Window/GSSetting.cpp
|
||||
GS/Window/GSwxDialog.cpp
|
||||
)
|
||||
|
||||
# GS headers
|
||||
@@ -679,7 +671,6 @@ set(pcsx2GSHeaders
|
||||
GS/GSDrawingEnvironment.h
|
||||
GS/GSDump.h
|
||||
GS/GS_types.h
|
||||
GS/GS_codegen.h
|
||||
GS/GS.h
|
||||
GS/GSLocalMemory.h
|
||||
GS/GSLzma.h
|
||||
@@ -712,11 +703,14 @@ set(pcsx2GSHeaders
|
||||
GS/Renderers/HW/GSTextureCache.h
|
||||
GS/Renderers/HW/GSVertexHW.h
|
||||
GS/Renderers/SW/GSDrawScanlineCodeGenerator.h
|
||||
GS/Renderers/SW/GSDrawScanlineCodeGenerator.all.h
|
||||
GS/Renderers/SW/GSDrawScanline.h
|
||||
GS/Renderers/SW/GSNewCodeGenerator.h
|
||||
GS/Renderers/SW/GSRasterizer.h
|
||||
GS/Renderers/SW/GSRendererSW.h
|
||||
GS/Renderers/SW/GSScanlineEnvironment.h
|
||||
GS/Renderers/SW/GSSetupPrimCodeGenerator.h
|
||||
GS/Renderers/SW/GSSetupPrimCodeGenerator.all.h
|
||||
GS/Renderers/SW/GSTextureCacheSW.h
|
||||
GS/Renderers/SW/GSTextureSW.h
|
||||
GS/Renderers/SW/GSVertexSW.h
|
||||
@@ -731,7 +725,7 @@ set(pcsx2GSHeaders
|
||||
GS/Window/GSCaptureDlg.h
|
||||
GS/Window/GSDialog.h
|
||||
GS/Window/GSSetting.h
|
||||
GS/Window/GSSettingsDlg.h
|
||||
GS/Window/GSwxDialog.h
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
@@ -796,6 +790,7 @@ if(WIN32)
|
||||
)
|
||||
|
||||
list(APPEND pcsx2GSSources
|
||||
GS/Renderers/DX11/D3D.cpp
|
||||
GS/Renderers/DX11/GSDevice11.cpp
|
||||
GS/Renderers/DX11/GSRendererDX11.cpp
|
||||
GS/Renderers/DX11/GSTexture11.cpp
|
||||
@@ -803,9 +798,9 @@ if(WIN32)
|
||||
GS/Renderers/DX11/GSTextureFX11.cpp
|
||||
GS/Window/GSCaptureDlg.cpp
|
||||
GS/Window/GSDialog.cpp
|
||||
GS/Window/GSSettingsDlg.cpp
|
||||
)
|
||||
list(APPEND pcsx2GSHeaders
|
||||
GS/Renderers/DX11/D3D.h
|
||||
GS/Renderers/DX11/GSDevice11.h
|
||||
GS/Renderers/DX11/GSRendererDX11.h
|
||||
GS/Renderers/DX11/GSTexture11.h
|
||||
@@ -894,7 +889,6 @@ else(WIN32)
|
||||
|
||||
list(APPEND pcsx2GSSources
|
||||
GS/GS_res.cpp
|
||||
GS/Window/GSLinuxDialog.cpp
|
||||
)
|
||||
|
||||
list(APPEND pcsx2GSHeaders
|
||||
@@ -969,6 +963,7 @@ set(pcsx2GuiSources
|
||||
gui/Debugger/CtrlDisassemblyView.cpp
|
||||
gui/Debugger/CtrlRegisterList.cpp
|
||||
gui/Debugger/CtrlMemView.cpp
|
||||
gui/Debugger/CtrlMemSearch.cpp
|
||||
gui/Debugger/DebuggerLists.cpp
|
||||
gui/Debugger/DisassemblyDialog.cpp
|
||||
gui/Debugger/DebugEvents.cpp
|
||||
@@ -1028,6 +1023,7 @@ set(pcsx2GuiHeaders
|
||||
gui/Debugger/BreakpointWindow.h
|
||||
gui/Debugger/CtrlDisassemblyView.h
|
||||
gui/Debugger/CtrlMemView.h
|
||||
gui/Debugger/CtrlMemSearch.h
|
||||
gui/Debugger/CtrlRegisterList.h
|
||||
gui/Debugger/DebugEvents.h
|
||||
gui/Debugger/DebuggerLists.h
|
||||
|
||||
+26
-18
@@ -120,14 +120,17 @@ public:
|
||||
auto* padding = new wxBoxSizer(wxVERTICAL);
|
||||
auto* top_box = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
int space = wxSizerFlags().Border().GetBorderInPixels();
|
||||
int two_space = wxSizerFlags().DoubleBorder().GetBorderInPixels();
|
||||
|
||||
// Ethernet section
|
||||
auto* eth_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Ethernet"));
|
||||
|
||||
m_eth_enable = new wxCheckBox(this, wxID_ANY, _("Enabled"));
|
||||
eth_sizer->Add(m_eth_enable);
|
||||
eth_sizer->AddSpacer(5);
|
||||
eth_sizer->AddSpacer(space);
|
||||
|
||||
auto* eth_adapter_box = new wxGridBagSizer(5, 5);
|
||||
auto* eth_adapter_box = new wxGridBagSizer(space, space);
|
||||
for (const AdapterEntry& adapter : PCAPAdapter::GetAdapters())
|
||||
addAdapter(adapter);
|
||||
#ifdef _WIN32
|
||||
@@ -166,42 +169,44 @@ public:
|
||||
m_dns1_address .create(6, this, eth_adapter_box, _("DNS1 Address:"));
|
||||
m_dns2_address .create(7, this, eth_adapter_box, _("DNS2 Address:"));
|
||||
|
||||
eth_adapter_box->AddGrowableCol(1);
|
||||
eth_adapter_box->AddGrowableCol(2);
|
||||
eth_sizer->Add(eth_adapter_box, wxSizerFlags().Expand());
|
||||
|
||||
// HDD section
|
||||
auto* hdd_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Hard Disk Drive"));
|
||||
|
||||
m_hdd_enable = new wxCheckBox(this, wxID_ANY, _("Enabled"));
|
||||
hdd_sizer->Add(m_hdd_enable);
|
||||
hdd_sizer->AddSpacer(5);
|
||||
|
||||
auto* hdd_grid = new wxFlexGridSizer(2, 0, 5);
|
||||
hdd_grid->AddGrowableCol(1);
|
||||
auto* hdd_file_label = new wxStaticText(this, wxID_ANY, _("HDD File:"));
|
||||
auto* hdd_file_label = new wxStaticText(this, wxID_ANY, _("HDD File"));
|
||||
m_hdd_file = new wxFilePickerCtrl(this, wxID_ANY, wxEmptyString, _("HDD image file"), "HDD|*.raw", wxDefaultPosition, wxDefaultSize, wxFLP_SAVE | wxFLP_USE_TEXTCTRL);
|
||||
hdd_grid->Add(hdd_file_label, wxSizerFlags().Centre().Right());
|
||||
hdd_grid->Add(m_hdd_file, wxSizerFlags().Expand());
|
||||
auto* hdd_size_label = new wxStaticText(this, wxID_ANY, _("HDD Size (GiB):"));
|
||||
auto* hdd_size_label = new wxStaticText(this, wxID_ANY, _("HDD Size (GiB)"));
|
||||
auto* hdd_size_box = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_hdd_size_slider = new wxSlider(this, wxID_ANY, HDD_MIN_GB, HDD_MIN_GB, HDD_MAX_GB, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL | wxSL_MIN_MAX_LABELS | wxSL_AUTOTICKS);
|
||||
m_hdd_size_slider = new wxSlider(this, wxID_ANY, HDD_MIN_GB, HDD_MIN_GB, HDD_MAX_GB, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL | wxSL_AUTOTICKS);
|
||||
m_hdd_size_slider->SetPageSize(10);
|
||||
for (int i = 15; i < HDD_MAX_GB; i += 5)
|
||||
m_hdd_size_slider->SetTick(i);
|
||||
m_hdd_size_slider->SetTickFreq(10);
|
||||
m_hdd_size_spin = new wxSpinCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, HDD_MIN_GB, HDD_MAX_GB, HDD_MIN_GB);
|
||||
m_hdd_size_spin->SetSizeHints(m_hdd_size_spin->GetSizeFromTextSize(30));
|
||||
hdd_size_box->Add(m_hdd_size_slider, wxSizerFlags(1).Centre());
|
||||
hdd_size_box->AddSpacer(space);
|
||||
hdd_size_box->Add(m_hdd_size_spin, wxSizerFlags(0).Centre());
|
||||
hdd_grid->Add(hdd_size_label, wxSizerFlags().Centre().Right());
|
||||
hdd_grid->Add(hdd_size_box, wxSizerFlags().Expand());
|
||||
|
||||
hdd_sizer->Add(hdd_grid, wxSizerFlags().Expand());
|
||||
hdd_sizer->Add(m_hdd_enable);
|
||||
hdd_sizer->AddSpacer(two_space);
|
||||
hdd_sizer->Add(hdd_file_label, wxSizerFlags().Left());
|
||||
hdd_sizer->AddSpacer(space);
|
||||
hdd_sizer->Add(m_hdd_file, wxSizerFlags().Expand());
|
||||
hdd_sizer->AddSpacer(two_space);
|
||||
hdd_sizer->Add(hdd_size_label, wxSizerFlags().Left());
|
||||
hdd_sizer->AddSpacer(space);
|
||||
hdd_sizer->Add(hdd_size_box, wxSizerFlags().Expand());
|
||||
|
||||
top_box->Add(eth_sizer, wxSizerFlags().Expand());
|
||||
top_box->AddSpacer(space);
|
||||
top_box->Add(hdd_sizer, wxSizerFlags().Expand());
|
||||
top_box->AddSpacer(space);
|
||||
top_box->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), wxSizerFlags().Right());
|
||||
|
||||
padding->Add(top_box, wxSizerFlags().Expand().Border(wxALL, 5));
|
||||
padding->Add(top_box, wxSizerFlags().Expand().Border());
|
||||
SetSizerAndFit(padding);
|
||||
SetMaxSize(wxSize(wxDefaultCoord, GetMinSize().y));
|
||||
|
||||
@@ -321,6 +326,9 @@ public:
|
||||
}
|
||||
m_eth_adapter->Set(options);
|
||||
m_eth_adapter->SetSelection(selection);
|
||||
// Update minimum sizes for the possibly increased dropdown size
|
||||
// Nothing else seems to update the minimum size of the window
|
||||
SetSizerAndFit(GetSizer(), false);
|
||||
}
|
||||
|
||||
void OnCheck(wxCommandEvent&)
|
||||
|
||||
+20
-47
@@ -14,6 +14,7 @@
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GS/Window/GSwxDialog.h"
|
||||
#include "GS.h"
|
||||
#include "GSUtil.h"
|
||||
#include "Renderers/SW/GSRendererSW.h"
|
||||
@@ -30,20 +31,11 @@
|
||||
|
||||
#include "Renderers/DX11/GSRendererDX11.h"
|
||||
#include "Renderers/DX11/GSDevice11.h"
|
||||
#include "Window/GSSettingsDlg.h"
|
||||
#include "GS/Renderers/DX11/D3D.h"
|
||||
|
||||
|
||||
static HRESULT s_hr = E_FAIL;
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <gtk/gtk.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
extern bool RunLinuxDialog();
|
||||
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
@@ -156,7 +148,12 @@ int _GSopen(const WindowInfo& wi, const char* title, GSRendererType renderer, in
|
||||
renderer = static_cast<GSRendererType>(theApp.GetConfigI("Renderer"));
|
||||
#ifdef _WIN32
|
||||
if (renderer == GSRendererType::Default)
|
||||
renderer = GSUtil::GetBestRenderer();
|
||||
{
|
||||
if (D3D::ShouldPreferD3D())
|
||||
renderer = GSRendererType::DX1011_HW;
|
||||
else
|
||||
renderer = GSRendererType::OGL_HW;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -306,7 +303,12 @@ int GSopen2(const WindowInfo& wi, uint32 flags)
|
||||
const auto config_renderer = static_cast<GSRendererType>(theApp.GetConfigI("Renderer"));
|
||||
|
||||
if (current_renderer == config_renderer)
|
||||
current_renderer = GSUtil::GetBestRenderer();
|
||||
{
|
||||
if (D3D::ShouldPreferD3D())
|
||||
current_renderer = GSRendererType::DX1011_HW;
|
||||
else
|
||||
current_renderer = GSRendererType::OGL_HW;
|
||||
}
|
||||
else
|
||||
current_renderer = config_renderer;
|
||||
}
|
||||
@@ -562,39 +564,12 @@ void GSconfigure()
|
||||
theApp.SetConfigDir();
|
||||
theApp.Init();
|
||||
|
||||
#ifdef _WIN32
|
||||
GSDialog::InitCommonControls();
|
||||
if (GSSettingsDlg().DoModal() == IDOK)
|
||||
{
|
||||
// Force a reload of the gs state
|
||||
theApp.SetCurrentRendererType(GSRendererType::Undefined);
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
// Rest of macOS UI doesn't use GTK so we need to init it now
|
||||
gtk_init(nullptr, nullptr);
|
||||
// GTK expects us to be using its event loop, rather than Cocoa's
|
||||
// If we call its stuff right now, it'll attempt to drain a static autorelease pool that was already drained by Cocoa (see https://github.com/GNOME/gtk/blob/8c1072fad1cb6a2e292fce2441b4a571f173ce0f/gdk/quartz/gdkeventloop-quartz.c#L640-L646)
|
||||
// We can convince it that touching that pool would be unsafe by running all GTK calls within a CFRunLoop
|
||||
// (Blocks submitted to the main queue by dispatch_async are run by its CFRunLoop)
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (RunLinuxDialog())
|
||||
{
|
||||
theApp.ReloadConfig();
|
||||
// Force a reload of the gs state
|
||||
theApp.SetCurrentRendererType(GSRendererType::Undefined);
|
||||
}
|
||||
});
|
||||
#else
|
||||
|
||||
if (RunLinuxDialog())
|
||||
if (RunwxDialog())
|
||||
{
|
||||
theApp.ReloadConfig();
|
||||
// Force a reload of the gs state
|
||||
theApp.SetCurrentRendererType(GSRendererType::Undefined);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
catch (GSRecoverableError)
|
||||
{
|
||||
@@ -1207,9 +1182,10 @@ void GSApp::Init()
|
||||
// Avoid to clutter the ini file with useless options
|
||||
#ifdef _WIN32
|
||||
// Per OS option.
|
||||
m_default_configuration["Adapter"] = "default";
|
||||
m_default_configuration["adapter_index"] = "0";
|
||||
m_default_configuration["CaptureFileName"] = "";
|
||||
m_default_configuration["CaptureVideoCodecDisplayName"] = "";
|
||||
m_default_configuration["debug_d3d"] = "0";
|
||||
m_default_configuration["dx_break_on_severity"] = "0";
|
||||
// D3D Blending option
|
||||
m_default_configuration["accurate_blending_unit_d3d11"] = "1";
|
||||
@@ -1262,22 +1238,19 @@ void GSApp::Init()
|
||||
m_default_configuration["osd_monitor_enabled"] = "0";
|
||||
m_default_configuration["osd_max_log_messages"] = "2";
|
||||
m_default_configuration["override_geometry_shader"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_compute_shader"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_copy_image"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_clear_texture"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_clip_control"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_direct_state_access"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_draw_buffers_blend"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_get_texture_sub_image"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_gpu_shader5"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_multi_bind"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_shader_image_load_store"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_shader_storage_buffer_object"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_sparse_texture"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_sparse_texture2"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_texture_view"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_vertex_attrib_binding"] = "-1";
|
||||
m_default_configuration["override_GL_ARB_texture_barrier"] = "-1";
|
||||
#ifdef GL_EXT_TEX_SUB_IMAGE
|
||||
m_default_configuration["override_GL_ARB_get_texture_sub_image"] = "-1";
|
||||
#endif
|
||||
m_default_configuration["paltex"] = "0";
|
||||
m_default_configuration["png_compression_level"] = std::to_string(Z_BEST_SPEED);
|
||||
m_default_configuration["preload_frame_with_gs_data"] = "0";
|
||||
|
||||
-215
@@ -97,130 +97,6 @@ IDR_FONT_ROBOTO RCDATA "res\\fonts-roboto\\Roboto-Regul
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_HACKS DIALOGEX 0, 0, 210, 289
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Advanced Settings & Hacks"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
// Rendering Hacks:
|
||||
GROUPBOX "Rendering Hacks",IDC_STATIC,7,7,196,114,0,WS_EX_TRANSPARENT
|
||||
// Column one - HW Hacks
|
||||
CONTROL "Auto Flush",IDC_AUTO_FLUSH_HW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,19,55,8
|
||||
CONTROL "Disable Depth Emulation",IDC_TC_DEPTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,32,92,8
|
||||
CONTROL "Disable Safe Features",IDC_SAFE_FEATURES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,45,85,8
|
||||
// Column two - HW hacks
|
||||
CONTROL "Fast Texture Invalidation",IDC_FAST_TC_INV,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,106,19,93,8
|
||||
CONTROL "Frame Buffer Conversion",IDC_CPU_FB_CONVERSION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,106,32,93,8
|
||||
CONTROL "Memory Wrapping",IDC_MEMORY_WRAPPING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,106,45,75,8
|
||||
CONTROL "Preload Frame Data",IDC_PRELOAD_GS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,106,58,80,8
|
||||
// Columns end
|
||||
//
|
||||
RTEXT "Half-screen Fix:",IDC_HALF_SCREEN_TS_TEXT,14,73,62,8
|
||||
COMBOBOX IDC_HALF_SCREEN_TS,80,70,116,63,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
RTEXT "Trilinear Filtering:",IDC_TRI_FILTER_TEXT,16,88,60,8
|
||||
COMBOBOX IDC_TRI_FILTER,80,85,116,63,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
RTEXT "Skipdraw Range:",IDC_SKIPDRAWHACK_TEXT,14,103,62,8
|
||||
EDITTEXT IDC_SKIPDRAWOFFSETEDIT,80,100,58,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
|
||||
CONTROL "",IDC_SKIPDRAWOFFSET,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,11,14
|
||||
EDITTEXT IDC_SKIPDRAWHACKEDIT,138,100,58,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
|
||||
CONTROL "",IDC_SKIPDRAWHACK,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,11,14
|
||||
// Upscaling Hacks:
|
||||
GROUPBOX "Upscaling Hacks",IDC_STATIC,7,124,196,75,0,WS_EX_TRANSPARENT
|
||||
CONTROL "Align Sprite",IDC_ALIGN_SPRITE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,136,55,8
|
||||
CONTROL "Merge Sprite",IDC_MERGE_PP_SPRITE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,71,136,55,8
|
||||
CONTROL "Wild Arms Offset",IDC_WILDHACK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,130,136,70,8
|
||||
RTEXT "Half-pixel Offset:",IDC_OFFSETHACK_TEXT,14,151,62,8
|
||||
COMBOBOX IDC_OFFSETHACK,80,148,116,63,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
RTEXT "Round Sprite:",IDC_ROUND_SPRITE_TEXT,30,166,46,8
|
||||
COMBOBOX IDC_ROUND_SPRITE,80,163,116,63,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
RTEXT "Texture Offsets:",IDC_TCOFFSET_TEXT,14,181,62,8
|
||||
RTEXT "X:",IDC_TCOFFSETX_TEXT,81,181,10,8
|
||||
EDITTEXT IDC_TCOFFSETX2,94,178,44,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
|
||||
CONTROL "",IDC_TCOFFSETX,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,11,14
|
||||
RTEXT "Y:",IDC_TCOFFSETY_TEXT,139,181,10,8
|
||||
EDITTEXT IDC_TCOFFSETY2,152,178,44,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
|
||||
CONTROL "",IDC_TCOFFSETY,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,11,14
|
||||
// OpenGL Advanced Settings:
|
||||
GROUPBOX "OpenGL Advanced Settings",IDC_STATIC,7,202,196,61,0,WS_EX_TRANSPARENT
|
||||
RTEXT "Geometry Shader:",IDC_GEOMETRY_SHADER_TEXT,14,216,62,8
|
||||
COMBOBOX IDC_GEOMETRY_SHADER_OVERRIDE,80,213,116,63,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
RTEXT "Image Load Store:",IDC_IMAGE_LOAD_STORE_TEXT,14,231,62,8
|
||||
COMBOBOX IDC_IMAGE_LOAD_STORE,80,228,116,63,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
RTEXT "Sparse Texture:",IDC_SPARSE_TEXTURE_TEXT,14,246,62,8
|
||||
COMBOBOX IDC_SPARSE_TEXTURE,80,243,116,63,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
// General Settings:
|
||||
DEFPUSHBUTTON "OK",IDOK,52,269,50,14
|
||||
DEFPUSHBUTTON "Cancel",IDCANCEL,108,269,50,14
|
||||
END
|
||||
|
||||
IDD_SHADER DIALOGEX 0, 0, 248, 230
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Shader Configuration"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "Texture Filtering of Display",IDC_LINEAR_PRESENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,6,100,10
|
||||
CONTROL "FXAA Shader (PgUp)",IDC_FXAA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,19,80,10
|
||||
CONTROL "Shade Boost",IDC_SHADEBOOST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,32,90,10
|
||||
LTEXT "Shade Boost Brightness",IDC_BRIGHTNESS_TEXT,16,50,80,8
|
||||
CONTROL "",IDC_BRIGHTNESS_SLIDER,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,95,48,122,15
|
||||
RTEXT "100",IDC_BRIGHTNESS_VALUE,221,50,12,8
|
||||
LTEXT "Shade Boost Contrast",IDC_CONTRAST_TEXT,16,75,80,8
|
||||
CONTROL "",IDC_CONTRAST_SLIDER,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,95,73,122,15
|
||||
RTEXT "100",IDC_CONTRAST_VALUE,221,75,12,8
|
||||
LTEXT "Shade Boost Saturation",IDC_SATURATION_TEXT,16,100,80,8
|
||||
CONTROL "",IDC_SATURATION_SLIDER,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,95,98,122,15
|
||||
RTEXT "100",IDC_SATURATION_VALUE,221,100,12,8
|
||||
CONTROL "External Shader (Home)",IDC_SHADER_FX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,116,91,10
|
||||
LTEXT "External Shader",IDC_SHADER_FX_TEXT,16,131,75,8
|
||||
EDITTEXT IDC_SHADER_FX_EDIT,16,139,170,14,ES_AUTOHSCROLL
|
||||
PUSHBUTTON "Browse",IDC_SHADER_FX_BUTTON,196,139,37,14
|
||||
LTEXT "External Shader Config",IDC_SHADER_FX_CONF_TEXT,16,156,75,8
|
||||
PUSHBUTTON "Browse",IDC_SHADER_FX_CONF_BUTTON,196,164,37,14
|
||||
EDITTEXT IDC_SHADER_FX_CONF_EDIT,16,164,170,14,ES_AUTOHSCROLL
|
||||
COMBOBOX IDC_TVSHADER,75,184,98,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "TV Shader:",IDC_STATIC,16,186,55,8
|
||||
DEFPUSHBUTTON "OK",IDOK,71,208,50,14
|
||||
DEFPUSHBUTTON "Cancel",IDCANCEL,127,208,50,14
|
||||
END
|
||||
|
||||
IDD_OSD DIALOGEX 0, 0, 210, 205
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "OSD Configuration"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
// Enable/Disable
|
||||
CONTROL "Enable Statistics Monitor",IDC_OSD_MONITOR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,7,88,10
|
||||
CONTROL "Enable Log",IDC_OSD_LOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,112,7,54,10
|
||||
// Font Settings
|
||||
GROUPBOX "Font",IDC_STATIC,7,20,196,100,0,WS_EX_TRANSPARENT
|
||||
LTEXT "Size:",IDC_OSD_SIZE_TEXT,16,34,25,8
|
||||
EDITTEXT IDC_OSD_SIZE_EDIT,112,31,83,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
|
||||
CONTROL "",IDC_OSD_SIZE,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,11,14
|
||||
LTEXT "Red:",IDC_OSD_COLOR_RED_TEXT,16,51,25,8
|
||||
CONTROL "",IDC_OSD_COLOR_RED_SLIDER,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,107,49,76,15
|
||||
RTEXT "255",IDC_OSD_COLOR_RED_AMOUNT,184,52,12,8
|
||||
LTEXT "Green:",IDC_OSD_COLOR_GREEN_TEXT,16,68,25,8
|
||||
CONTROL "",IDC_OSD_COLOR_GREEN_SLIDER,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,107,66,76,15
|
||||
RTEXT "255",IDC_OSD_COLOR_GREEN_AMOUNT,184,69,12,8
|
||||
LTEXT "Blue:",IDC_OSD_COLOR_BLUE_TEXT,16,86,25,8
|
||||
CONTROL "",IDC_OSD_COLOR_BLUE_SLIDER,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,107,83,76,15
|
||||
RTEXT "255",IDC_OSD_COLOR_BLUE_AMOUNT,184,86,12,8
|
||||
LTEXT "Opacity:",IDC_OSD_OPACITY_TEXT,16,104,50,8
|
||||
CONTROL "",IDC_OSD_OPACITY_SLIDER,"msctls_trackbar32",TBS_BOTH | TBS_NOTICKS | WS_TABSTOP,107,100,76,15
|
||||
RTEXT "100",IDC_OSD_OPACITY_AMOUNT,184,104,12,8
|
||||
// Log Settings
|
||||
GROUPBOX "Log Messages",IDC_STATIC,7,125,196,52,0,WS_EX_TRANSPARENT
|
||||
LTEXT "Timeout (seconds):",IDC_OSD_TIMEOUT_TEXT,16,139,75,8
|
||||
EDITTEXT IDC_OSD_TIMEOUT_EDIT,112,135,83,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
|
||||
CONTROL "", IDC_OSD_TIMEOUT,"msctls_updown32", UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,11,14
|
||||
LTEXT "Max:",IDC_OSD_MAX_LOG_TEXT,16,158,25,8
|
||||
EDITTEXT IDC_OSD_MAX_LOG_EDIT,112,155,83,14,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
|
||||
CONTROL "", IDC_OSD_MAX_LOG,"msctls_updown32", UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,11,14
|
||||
// OK/CANCEL
|
||||
DEFPUSHBUTTON "OK",IDOK,52,183,50,14
|
||||
DEFPUSHBUTTON "Cancel",IDCANCEL,108,183,50,14
|
||||
END
|
||||
|
||||
IDD_CAPTURE DIALOGEX 0, 0, 279, 71
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Capture settings"
|
||||
@@ -238,53 +114,6 @@ BEGIN
|
||||
COMBOBOX IDC_COLORSPACE,102,47,48,32,CBS_DROPDOWNLIST | WS_TABSTOP
|
||||
END
|
||||
|
||||
IDD_CONFIG DIALOGEX 0, 0, 242, 315
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Graphics Settings"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
// General Settings:
|
||||
LTEXT "Renderer:",IDC_STATIC,7,8,79,8
|
||||
COMBOBOX IDC_RENDERER,71,6,166,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Adapter:",IDC_ADAPTER_TEXT,7,23,79,8
|
||||
COMBOBOX IDC_ADAPTER,71,21,166,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Interlacing (F5):",IDC_INTERLACE_TEXT,7,38,55,8
|
||||
COMBOBOX IDC_INTERLACE,71,36,166,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Texture Filtering:",IDC_FILTER_TEXT,7,53,79,8
|
||||
COMBOBOX IDC_FILTER,71,51,166,63,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "OSD Configuration",IDC_OSDBUTTON,11,274,108,14
|
||||
PUSHBUTTON "Shader Configuration",IDC_SHADEBUTTON,125,274,108,14
|
||||
DEFPUSHBUTTON "OK",IDOK,69,294,50,14
|
||||
PUSHBUTTON "Cancel",IDCANCEL,125,294,50,14
|
||||
GROUPBOX "Hardware Renderer Settings",IDC_STATIC,7,67,230,154,BS_CENTER
|
||||
CONTROL "Accurate DATE",IDC_ACCURATE_DATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,77,63,10
|
||||
CONTROL "GPU Palette Conversion",IDC_PALTEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,93,87,10
|
||||
CONTROL "Conservative Buffer Allocation",IDC_CONSERVATIVE_FB,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,93,110,10
|
||||
LTEXT "Internal Resolution:",IDC_UPSCALE_MULTIPLIER_TEXT,23,109,79,8
|
||||
COMBOBOX IDC_UPSCALE_MULTIPLIER,105,107,127,98,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Anisotropic Filtering:",IDC_AFCOMBO_TEXT,23,125,79,8
|
||||
COMBOBOX IDC_AFCOMBO,105,123,127,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Dithering (PgDn):",IDC_DITHERING_TEXT,23,141,79,8
|
||||
COMBOBOX IDC_DITHERING,105,139,127,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Mipmapping (Ins):",IDC_MIPMAP_HW_TEXT,23,157,79,8
|
||||
COMBOBOX IDC_MIPMAP_HW,105,155,127,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "CRC Hack Level:",IDC_CRC_LEVEL_TEXT,23,173,79,8
|
||||
COMBOBOX IDC_CRC_LEVEL,105,171,127,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Blending Accuracy:",IDC_ACCURATE_BLEND_UNIT_TEXT,23,189,79,8
|
||||
COMBOBOX IDC_ACCURATE_BLEND_UNIT,105,187,127,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
COMBOBOX IDC_ACCURATE_BLEND_UNIT_D3D11,105,187,127,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
CONTROL "Enable HW Hacks",IDC_HACKS_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,205,71,10
|
||||
PUSHBUTTON "Advanced Settings and Hacks",IDC_HACKSBUTTON,105,203,127,14
|
||||
GROUPBOX "Software Renderer Settings",IDC_STATIC,7,224,230,44,BS_CENTER
|
||||
CONTROL "Auto Flush",IDC_AUTO_FLUSH_SW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,236,90,10
|
||||
CONTROL "Edge Anti-aliasing (Del)",IDC_AA1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,125,236,90,10
|
||||
LTEXT "Rendering threads:",IDC_SWTHREADS_TEXT,125,252,65,8
|
||||
EDITTEXT IDC_SWTHREADS_EDIT,197,250,34,13,ES_AUTOHSCROLL | ES_NUMBER
|
||||
CONTROL "",IDC_SWTHREADS,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,0,0,11,14
|
||||
CONTROL "Mipmapping",IDC_MIPMAP_SW,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,250,90,10
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -294,37 +123,6 @@ END
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_HACKS, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 154
|
||||
VERTGUIDE, 14
|
||||
VERTGUIDE, 84
|
||||
VERTGUIDE, 88
|
||||
VERTGUIDE, 146
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 229
|
||||
HORZGUIDE, 51
|
||||
HORZGUIDE, 64
|
||||
HORZGUIDE, 77
|
||||
END
|
||||
|
||||
IDD_SHADER, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 6
|
||||
RIGHTMARGIN, 242
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 244
|
||||
END
|
||||
|
||||
IDD_OSD, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 6
|
||||
RIGHTMARGIN, 242
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 244
|
||||
END
|
||||
|
||||
IDD_CAPTURE, DIALOG
|
||||
BEGIN
|
||||
VERTGUIDE, 6
|
||||
@@ -332,19 +130,6 @@ BEGIN
|
||||
VERTGUIDE, 271
|
||||
HORZGUIDE, 54
|
||||
END
|
||||
|
||||
IDD_CONFIG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 6
|
||||
RIGHTMARGIN, 237
|
||||
VERTGUIDE, 11
|
||||
VERTGUIDE, 22
|
||||
VERTGUIDE, 101
|
||||
VERTGUIDE, 105
|
||||
VERTGUIDE, 232
|
||||
TOPMARGIN, 6
|
||||
BOTTOMMARGIN, 367
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
template <int i>
|
||||
class GSAlignedClass
|
||||
{
|
||||
public:
|
||||
GSAlignedClass() {}
|
||||
virtual ~GSAlignedClass() {}
|
||||
protected:
|
||||
GSAlignedClass() = default;
|
||||
~GSAlignedClass() = default;
|
||||
|
||||
public:
|
||||
void* operator new(size_t size)
|
||||
{
|
||||
return _aligned_malloc(size, i);
|
||||
|
||||
+28
-52
@@ -158,36 +158,12 @@ void GSClut::Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
m_read.dirty = true;
|
||||
|
||||
(this->*m_wc[TEX0.CSM][TEX0.CPSM][TEX0.PSM])(TEX0, TEXCLUT);
|
||||
|
||||
// Mirror write to other half of buffer to simulate wrapping memory
|
||||
|
||||
int offset = (TEX0.CSA & (TEX0.CPSM < PSM_PSMCT16 ? 15 : 31)) * 16;
|
||||
|
||||
if (TEX0.PSM == PSM_PSMT8 || TEX0.PSM == PSM_PSMT8H)
|
||||
{
|
||||
int size = TEX0.CPSM < PSM_PSMCT16 ? 512 : 256;
|
||||
|
||||
memcpy(m_clut + 512 + offset, m_clut + offset, sizeof(*m_clut) * std::min(size, 512 - offset));
|
||||
memcpy(m_clut, m_clut + 512, sizeof(*m_clut) * std::max(0, size + offset - 512));
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = 16;
|
||||
|
||||
memcpy(m_clut + 512 + offset, m_clut + offset, sizeof(*m_clut) * size);
|
||||
|
||||
if (TEX0.CPSM < PSM_PSMCT16)
|
||||
{
|
||||
memcpy(m_clut + 512 + 256 + offset, m_clut + 256 + offset, sizeof(*m_clut) * size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSClut::WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
ALIGN_STACK(32);
|
||||
//FIXME: Romance of the Three Kingdoms VIII text doesn't like the offset
|
||||
WriteCLUT_T32_I8_CSM1((uint32*)m_mem->BlockPtr32(0, 0, TEX0.CBP, 1), m_clut + ((TEX0.CSA & 15) << 4));
|
||||
WriteCLUT_T32_I8_CSM1((uint32*)m_mem->BlockPtr32(0, 0, TEX0.CBP, 1), m_clut, (TEX0.CSA & 15));
|
||||
}
|
||||
|
||||
void GSClut::WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
@@ -220,16 +196,14 @@ void GSClut::WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& T
|
||||
template <int n>
|
||||
void GSClut::WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
GSOffset* off = m_mem->GetOffset(TEX0.CBP, TEXCLUT.CBW, PSM_PSMCT32);
|
||||
|
||||
uint32* RESTRICT s = &m_mem->m_vm32[off->pixel.row[TEXCLUT.COV]];
|
||||
int* RESTRICT col = &off->pixel.col[0][TEXCLUT.COU << 4];
|
||||
GSOffset off = GSOffset::fromKnownPSM(TEX0.CBP, TEXCLUT.CBW, PSM_PSMCT32);
|
||||
auto pa = off.paMulti(m_mem->m_vm32, TEXCLUT.COU << 4, TEXCLUT.COV);
|
||||
|
||||
uint16* RESTRICT clut = m_clut + ((TEX0.CSA & 15) << 4);
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
uint32 c = s[col[i]];
|
||||
uint32 c = *pa.value(i);
|
||||
|
||||
clut[i] = (uint16)(c & 0xffff);
|
||||
clut[i + 256] = (uint16)(c >> 16);
|
||||
@@ -239,32 +213,28 @@ void GSClut::WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCL
|
||||
template <int n>
|
||||
void GSClut::WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
GSOffset* off = m_mem->GetOffset(TEX0.CBP, TEXCLUT.CBW, PSM_PSMCT16);
|
||||
|
||||
uint16* RESTRICT s = &m_mem->m_vm16[off->pixel.row[TEXCLUT.COV]];
|
||||
int* RESTRICT col = &off->pixel.col[0][TEXCLUT.COU << 4];
|
||||
GSOffset off = GSOffset::fromKnownPSM(TEX0.CBP, TEXCLUT.CBW, PSM_PSMCT16);
|
||||
auto pa = off.paMulti(m_mem->m_vm16, TEXCLUT.COU << 4, TEXCLUT.COV);
|
||||
|
||||
uint16* RESTRICT clut = m_clut + (TEX0.CSA << 4);
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
clut[i] = s[col[i]];
|
||||
clut[i] = *pa.value(i);
|
||||
}
|
||||
}
|
||||
|
||||
template <int n>
|
||||
void GSClut::WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
|
||||
{
|
||||
GSOffset* off = m_mem->GetOffset(TEX0.CBP, TEXCLUT.CBW, PSM_PSMCT16S);
|
||||
|
||||
uint16* RESTRICT s = &m_mem->m_vm16[off->pixel.row[TEXCLUT.COV]];
|
||||
int* RESTRICT col = &off->pixel.col[0][TEXCLUT.COU << 4];
|
||||
GSOffset off = GSOffset::fromKnownPSM(TEX0.CBP, TEXCLUT.CBW, PSM_PSMCT16S);
|
||||
auto pa = off.paMulti(m_mem->m_vm16, TEXCLUT.COU << 4, TEXCLUT.COV);
|
||||
|
||||
uint16* RESTRICT clut = m_clut + (TEX0.CSA << 4);
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
clut[i] = s[col[i]];
|
||||
clut[i] = *pa.value(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,8 +309,7 @@ void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
|
||||
{
|
||||
case PSM_PSMT8:
|
||||
case PSM_PSMT8H:
|
||||
clut += (TEX0.CSA & 15) << 4; // disney golf title screen
|
||||
ReadCLUT_T32_I8(clut, m_buff32);
|
||||
ReadCLUT_T32_I8(clut, m_buff32, (TEX0.CSA & 15) << 4);
|
||||
break;
|
||||
case PSM_PSMT4:
|
||||
case PSM_PSMT4HL:
|
||||
@@ -443,16 +412,16 @@ void GSClut::GetAlphaMinMax32(int& amin_out, int& amax_out)
|
||||
|
||||
//
|
||||
|
||||
void GSClut::WriteCLUT_T32_I8_CSM1(const uint32* RESTRICT src, uint16* RESTRICT clut)
|
||||
void GSClut::WriteCLUT_T32_I8_CSM1(const uint32* RESTRICT src, uint16* RESTRICT clut, uint16 offset)
|
||||
{
|
||||
// 4 blocks
|
||||
|
||||
for (int i = 0; i < 64; i += 16)
|
||||
// This is required when CSA is offset from the base of the CLUT so we point to the right data
|
||||
for (int i = offset; i < 16; i ++)
|
||||
{
|
||||
WriteCLUT_T32_I4_CSM1(&src[i + 0], &clut[i * 2 + 0]);
|
||||
WriteCLUT_T32_I4_CSM1(&src[i + 64], &clut[i * 2 + 16]);
|
||||
WriteCLUT_T32_I4_CSM1(&src[i + 128], &clut[i * 2 + 128]);
|
||||
WriteCLUT_T32_I4_CSM1(&src[i + 192], &clut[i * 2 + 144]);
|
||||
const int off = i << 4; // WriteCLUT_T32_I4_CSM1 loads 16 at a time
|
||||
// Source column
|
||||
const int s = clutTableT32I8[off & 0x70] | (off & 0x80);
|
||||
|
||||
WriteCLUT_T32_I4_CSM1(&src[s], &clut[off]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,11 +501,18 @@ __forceinline void GSClut::WriteCLUT_T16_I4_CSM1(const uint16* RESTRICT src, uin
|
||||
}
|
||||
}
|
||||
|
||||
void GSClut::ReadCLUT_T32_I8(const uint16* RESTRICT clut, uint32* RESTRICT dst)
|
||||
void GSClut::ReadCLUT_T32_I8(const uint16* RESTRICT clut, uint32* RESTRICT dst, int offset)
|
||||
{
|
||||
// Okay this deserves a small explanation
|
||||
// T32 I8 can address up to 256 colors however the offset can be "more than zero" when reading
|
||||
// Previously I assumed that it would wrap around the end of the buffer to the beginning
|
||||
// but it turns out this is incorrect, the address doesn't mirror, it clamps to to the last offset,
|
||||
// probably though some sort of addressing mechanism then picks the color from the lower 0xF of the requested CLUT entry.
|
||||
// if we don't do this, the dirt on GTA SA goes transparent and actually cleans the car driving through dirt.
|
||||
for (int i = 0; i < 256; i += 16)
|
||||
{
|
||||
ReadCLUT_T32_I4(&clut[i], &dst[i]);
|
||||
// Min value + offet or Last CSA * 16 (240)
|
||||
ReadCLUT_T32_I4(&clut[std::min((i + offset), 240)], &dst[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -74,11 +74,11 @@ class alignas(32) GSClut : public GSAlignedClass<32>
|
||||
|
||||
void WriteCLUT_NULL(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
|
||||
static void WriteCLUT_T32_I8_CSM1(const uint32* RESTRICT src, uint16* RESTRICT clut);
|
||||
static void WriteCLUT_T32_I8_CSM1(const uint32* RESTRICT src, uint16* RESTRICT clut, uint16 offset);
|
||||
static void WriteCLUT_T32_I4_CSM1(const uint32* RESTRICT src, uint16* RESTRICT clut);
|
||||
static void WriteCLUT_T16_I8_CSM1(const uint16* RESTRICT src, uint16* RESTRICT clut);
|
||||
static void WriteCLUT_T16_I4_CSM1(const uint16* RESTRICT src, uint16* RESTRICT clut);
|
||||
static void ReadCLUT_T32_I8(const uint16* RESTRICT clut, uint32* RESTRICT dst);
|
||||
static void ReadCLUT_T32_I8(const uint16* RESTRICT clut, uint32* RESTRICT dst, int offset);
|
||||
static void ReadCLUT_T32_I4(const uint16* RESTRICT clut, uint32* RESTRICT dst);
|
||||
//static void ReadCLUT_T32_I4(const uint16* RESTRICT clut, uint32* RESTRICT dst32, uint64* RESTRICT dst64);
|
||||
//static void ReadCLUT_T16_I8(const uint16* RESTRICT clut, uint32* RESTRICT dst);
|
||||
|
||||
@@ -48,9 +48,9 @@ public:
|
||||
|
||||
struct
|
||||
{
|
||||
GSOffset* fb;
|
||||
GSOffset* zb;
|
||||
GSOffset* tex;
|
||||
GSOffset fb;
|
||||
GSOffset zb;
|
||||
GSOffset tex;
|
||||
GSPixelOffset* fzb;
|
||||
GSPixelOffset4* fzb4;
|
||||
} offset;
|
||||
|
||||
+397
-764
File diff suppressed because it is too large
Load Diff
+463
-220
@@ -21,38 +21,6 @@
|
||||
#include "GSBlock.h"
|
||||
#include "GSClut.h"
|
||||
|
||||
class GSOffset : public GSAlignedClass<32>
|
||||
{
|
||||
public:
|
||||
struct alignas(32) Block
|
||||
{
|
||||
short row[256]; // yn (n = 0 8 16 ...)
|
||||
short* col; // blockOffset*
|
||||
};
|
||||
|
||||
struct alignas(32) Pixel
|
||||
{
|
||||
int row[4096]; // yn (n = 0 1 2 ...) NOTE: this wraps around above 2048, only transfers should address the upper half (dark cloud 2 inventing)
|
||||
int* col[8]; // rowOffset*
|
||||
};
|
||||
|
||||
union { uint32 hash; struct { uint32 bp:14, bw:6, psm:6; }; };
|
||||
|
||||
Block block;
|
||||
Pixel pixel;
|
||||
|
||||
std::array<uint32*, 256> pages_as_bit; // texture page coverage based on the texture size. Lazy allocated
|
||||
|
||||
GSOffset(uint32 bp, uint32 bw, uint32 psm);
|
||||
virtual ~GSOffset();
|
||||
|
||||
enum { EOP = 0xffffffff };
|
||||
|
||||
uint32* GetPages(const GSVector4i& rect, uint32* pages = NULL, GSVector4i* bbox = NULL);
|
||||
void* GetPagesAsBits(const GSVector4i& rect, void* pages);
|
||||
uint32* GetPagesAsBits(const GIFRegTEX0& TEX0);
|
||||
};
|
||||
|
||||
struct GSPixelOffset
|
||||
{
|
||||
// 16 bit offsets (m_vm16[...])
|
||||
@@ -73,6 +41,359 @@ struct GSPixelOffset4
|
||||
uint32 fbp, zbp, fpsm, zpsm, bw;
|
||||
};
|
||||
|
||||
class GSOffset;
|
||||
|
||||
class GSSwizzleInfo
|
||||
{
|
||||
friend class GSOffset;
|
||||
/// Table for storing swizzling of blocks within a page
|
||||
const GSBlockSwizzleTable* m_blockSwizzle;
|
||||
/// Table for storing swizzling of pixels within a page in the y dimension
|
||||
const int* m_pixelSwizzleCol;
|
||||
/// Array of tables for storing swizzling of pixels in the x dimension
|
||||
const GSPixelRowOffsetTable* const* m_pixelSwizzleRow;
|
||||
GSVector2i m_pageMask; ///< Mask for getting the offset of a pixel that's within a page (may also be used as page dimensions - 1)
|
||||
GSVector2i m_blockMask; ///< Mask for getting the offset of a pixel that's within a block (may also be used as block dimensions - 1)
|
||||
int m_pixelRowMask; ///< Mask for getting the offset in m_pixelSwizzleRow for a given y value
|
||||
uint8 m_pageShiftX; ///< Amount to rshift x value by to get page offset
|
||||
uint8 m_pageShiftY; ///< Amount to rshift y value by to get page offset
|
||||
uint8 m_blockShiftX; ///< Amount to rshift x value by to get offset in block
|
||||
uint8 m_blockShiftY; ///< Amount to rshift y value by to get offset in block
|
||||
static constexpr uint8 ilog2(uint32 i) { return i < 2 ? 0 : 1 + ilog2(i >> 1); }
|
||||
|
||||
public:
|
||||
GSSwizzleInfo() = default;
|
||||
|
||||
/// @param blockSize Size of block in pixels
|
||||
template <int PageWidth, int PageHeight, int BlocksWide, int BlocksHigh, int PixelRowMask>
|
||||
constexpr GSSwizzleInfo(GSSwizzleTableList<PageHeight, PageWidth, BlocksHigh, BlocksWide, PixelRowMask> list)
|
||||
: m_blockSwizzle(&list.block)
|
||||
, m_pixelSwizzleCol(list.col.value)
|
||||
, m_pixelSwizzleRow(list.row.rows)
|
||||
, m_pageMask{PageWidth - 1, PageHeight - 1}
|
||||
, m_blockMask{(PageWidth / BlocksWide) - 1, (PageHeight / BlocksHigh) - 1}
|
||||
, m_pixelRowMask(PixelRowMask)
|
||||
, m_pageShiftX(ilog2(PageWidth)), m_pageShiftY(ilog2(PageHeight))
|
||||
, m_blockShiftX(ilog2(PageWidth / BlocksWide)), m_blockShiftY(ilog2(PageHeight / BlocksHigh))
|
||||
{
|
||||
static_assert(1 << ilog2(PageWidth) == PageWidth, "PageWidth must be a power of 2");
|
||||
static_assert(1 << ilog2(PageHeight) == PageHeight, "PageHeight must be a power of 2");
|
||||
}
|
||||
|
||||
/// Get the block number of the given pixel
|
||||
uint32 bn(int x, int y, uint32 bp, uint32 bw) const;
|
||||
|
||||
/// Get the address of the given pixel
|
||||
uint32 pa(int x, int y, uint32 bp, uint32 bw) const;
|
||||
};
|
||||
|
||||
class GSOffset : GSSwizzleInfo
|
||||
{
|
||||
int m_bp; ///< Offset's base pointer (same measurement as GS)
|
||||
int m_bwPg; ///< Offset's buffer width in pages (not equal to bw in GS for 8 and 4-bit textures)
|
||||
int m_psm; ///< Offset's pixel storage mode (just for storage, not used by any of the GSOffset algorithms)
|
||||
public:
|
||||
GSOffset() = default;
|
||||
constexpr GSOffset(const GSSwizzleInfo& swz, uint32 bp, uint32 bw, uint32 psm)
|
||||
: GSSwizzleInfo(swz)
|
||||
, m_bp(bp)
|
||||
, m_bwPg(bw >> (m_pageShiftX - 6))
|
||||
, m_psm(psm)
|
||||
{
|
||||
}
|
||||
/// Help the optimizer by using this method instead of GSLocalMemory::GetOffset when the PSM is known
|
||||
constexpr static GSOffset fromKnownPSM(uint32 bp, uint32 bw, GS_PSM psm);
|
||||
|
||||
uint32 bp() const { return m_bp; }
|
||||
uint32 bw() const { return m_bwPg << (m_pageShiftX - 6); }
|
||||
uint32 psm() const { return m_psm; }
|
||||
int blockShiftX() const { return m_blockShiftX; }
|
||||
int blockShiftY() const { return m_blockShiftY; }
|
||||
|
||||
/// Helper class for efficiently getting the numbers of multiple blocks in a scanning pattern (increment x then y)
|
||||
class BNHelper
|
||||
{
|
||||
const GSBlockSwizzleTable* m_blockSwizzle; ///< Block swizzle table from GSOffset
|
||||
int m_baseBP; ///< bp for start of current row (to return to the origin x when advancing y)
|
||||
int m_bp; ///< bp for current position
|
||||
int m_baseBlkX; ///< x of origin in blocks (to return to the origin x when advancing y)
|
||||
int m_blkX; ///< x of current position in blocks
|
||||
int m_blkY; ///< y of current position in blocks
|
||||
int m_pageMaskX; ///< mask for x value of block coordinate to get position within page (to detect page crossing)
|
||||
int m_pageMaskY; ///< mask for y value of block coordinate to get position within page (to detect page crossing)
|
||||
int m_addY; ///< Amount to add to bp to advance one page in y direction
|
||||
public:
|
||||
BNHelper(const GSOffset& off, int x, int y)
|
||||
{
|
||||
m_blockSwizzle = off.m_blockSwizzle;
|
||||
int yAmt = ((y >> (off.m_pageShiftY - 5)) & ~0x1f) * off.m_bwPg;
|
||||
int xAmt = ((x >> (off.m_pageShiftX - 5)) & ~0x1f);
|
||||
m_baseBP = m_bp = off.m_bp + yAmt + xAmt;
|
||||
m_baseBlkX = m_blkX = x >> off.m_blockShiftX;
|
||||
m_blkY = y >> off.m_blockShiftY;
|
||||
m_pageMaskX = (1 << (off.m_pageShiftX - off.m_blockShiftX)) - 1;
|
||||
m_pageMaskY = (1 << (off.m_pageShiftY - off.m_blockShiftY)) - 1;
|
||||
m_addY = 32 * off.m_bwPg;
|
||||
}
|
||||
|
||||
/// Get the current x position as an offset in blocks
|
||||
int blkX() const { return m_blkX; }
|
||||
/// Get the current y position as an offset in blocks
|
||||
int blkY() const { return m_blkY; }
|
||||
|
||||
/// Advance one block in the x direction
|
||||
void nextBlockX()
|
||||
{
|
||||
m_blkX++;
|
||||
if (!(m_blkX & m_pageMaskX))
|
||||
m_bp += 32;
|
||||
}
|
||||
|
||||
/// Advance one block in the y direction and reset x to the origin
|
||||
void nextBlockY()
|
||||
{
|
||||
m_blkY++;
|
||||
if (!(m_blkY & m_pageMaskY))
|
||||
m_baseBP += m_addY;
|
||||
|
||||
m_blkX = m_baseBlkX;
|
||||
m_bp = m_baseBP;
|
||||
}
|
||||
|
||||
/// Get the current block number without wrapping at MAX_BLOCKS
|
||||
uint32 valueNoWrap() const
|
||||
{
|
||||
return m_bp + m_blockSwizzle->lookup(m_blkX, m_blkY);
|
||||
}
|
||||
|
||||
/// Get the current block number
|
||||
uint32 value() const
|
||||
{
|
||||
return valueNoWrap() % MAX_BLOCKS;
|
||||
}
|
||||
};
|
||||
|
||||
/// Get the block number of the given pixel
|
||||
uint32 bn(int x, int y) const
|
||||
{
|
||||
return BNHelper(*this, x, y).value();
|
||||
}
|
||||
|
||||
/// Get a helper class for efficiently calculating multiple block numbers
|
||||
BNHelper bnMulti(int x, int y) const
|
||||
{
|
||||
return BNHelper(*this, x, y);
|
||||
}
|
||||
|
||||
static bool isAligned(const GSVector4i& r, const GSVector2i& mask)
|
||||
{
|
||||
return r.width() > mask.x && r.height() > mask.y && !(r.left & mask.x) && !(r.top & mask.y) && !(r.right & mask.x) && !(r.bottom & mask.y);
|
||||
}
|
||||
|
||||
bool isBlockAligned(const GSVector4i& r) const { return isAligned(r, m_blockMask); }
|
||||
bool isPageAligned(const GSVector4i& r) const { return isAligned(r, m_pageMask); }
|
||||
|
||||
/// Loop over all the blocks in the given rect, calling `fn` on each
|
||||
template <typename Fn>
|
||||
void loopBlocks(const GSVector4i& rect, Fn&& fn) const
|
||||
{
|
||||
BNHelper bn = bnMulti(rect.left, rect.top);
|
||||
int right = (rect.right + m_blockMask.x) >> m_blockShiftX;
|
||||
int bottom = (rect.bottom + m_blockMask.y) >> m_blockShiftY;
|
||||
|
||||
for (; bn.blkY() < bottom; bn.nextBlockY())
|
||||
for (; bn.blkX() < right; bn.nextBlockX())
|
||||
fn(bn.value());
|
||||
}
|
||||
|
||||
/// Calculate the pixel address at the given y position with x of 0
|
||||
int pixelAddressZeroX(int y) const
|
||||
{
|
||||
int base = m_bp << (m_pageShiftX + m_pageShiftY - 5); // Offset from base pointer
|
||||
base += ((y & ~m_pageMask.y) * m_bwPg) << m_pageShiftX; // Offset from pages in y direction
|
||||
// TODO: Old GSOffset masked here but is that useful? Probably should mask at end or not at all...
|
||||
base &= (MAX_PAGES << (m_pageShiftX + m_pageShiftY)) - 1; // Mask
|
||||
base += m_pixelSwizzleCol[y & m_pageMask.y]; // Add offset from y within page
|
||||
return base;
|
||||
}
|
||||
|
||||
/// Helper class for efficiently getting the addresses of multiple pixels in a line (along the x axis)
|
||||
class PAHelper
|
||||
{
|
||||
/// Pixel swizzle array
|
||||
const int* m_pixelSwizzleRow;
|
||||
int m_base;
|
||||
|
||||
public:
|
||||
PAHelper() = default;
|
||||
PAHelper(const GSOffset& off, int x, int y)
|
||||
{
|
||||
m_pixelSwizzleRow = off.m_pixelSwizzleRow[y & off.m_pixelRowMask]->value + x;
|
||||
m_base = off.pixelAddressZeroX(y);
|
||||
}
|
||||
|
||||
/// Get pixel reference for the given x offset from the one used to create the PAHelper
|
||||
uint32 value(int x) const
|
||||
{
|
||||
return m_base + m_pixelSwizzleRow[x];
|
||||
}
|
||||
};
|
||||
|
||||
/// Helper class for efficiently getting the addresses of multiple pixels in a line (along the x axis)
|
||||
/// Slightly more efficient than PAHelper by pre-adding the base offset to the VM pointer
|
||||
template <typename VM>
|
||||
class PAPtrHelper
|
||||
{
|
||||
/// Pixel swizzle array
|
||||
const int* m_pixelSwizzleRow;
|
||||
VM* m_base;
|
||||
|
||||
public:
|
||||
PAPtrHelper() = default;
|
||||
PAPtrHelper(const GSOffset& off, VM* vm, int x, int y)
|
||||
{
|
||||
m_pixelSwizzleRow = off.m_pixelSwizzleRow[y & off.m_pixelRowMask]->value + x;
|
||||
m_base = &vm[off.pixelAddressZeroX(y)];
|
||||
}
|
||||
|
||||
/// Get pixel reference for the given x offset from the one used to create the PAPtrHelper
|
||||
VM* value(int x) const
|
||||
{
|
||||
return m_base + m_pixelSwizzleRow[x];
|
||||
}
|
||||
};
|
||||
|
||||
/// Get the address of the given pixel
|
||||
uint32 pa(int x, int y) const
|
||||
{
|
||||
return PAHelper(*this, 0, y).value(x);
|
||||
}
|
||||
|
||||
/// Get a helper class for efficiently calculating multiple pixel addresses in a line (along the x axis)
|
||||
PAHelper paMulti(int x, int y) const
|
||||
{
|
||||
return PAHelper(*this, x, y);
|
||||
}
|
||||
|
||||
/// Get a helper class for efficiently calculating multiple pixel addresses in a line (along the x axis)
|
||||
template <typename VM>
|
||||
PAPtrHelper<VM> paMulti(VM* vm, int x, int y) const
|
||||
{
|
||||
return PAPtrHelper(*this, vm, x, y);
|
||||
}
|
||||
|
||||
/// Loop over the pixels in the given rectangle
|
||||
/// Fn should be void(*)(VM*, Src*)
|
||||
template <typename VM, typename Src, typename Fn>
|
||||
void loopPixels(const GSVector4i& r, VM* RESTRICT vm, Src* RESTRICT px, int pitch, Fn&& fn) const
|
||||
{
|
||||
px -= r.left;
|
||||
|
||||
for (int y = r.top; y < r.bottom; y++, px = reinterpret_cast<Src*>(reinterpret_cast<uint8*>(px) + pitch))
|
||||
{
|
||||
PAPtrHelper<VM> pa = paMulti(vm, 0, y);
|
||||
for (int x = r.left; x < r.right; x++)
|
||||
{
|
||||
fn(pa.value(x), px + x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper class for looping over the pages in a rect
|
||||
/// Create with GSOffset::pageLooperForRect
|
||||
class PageLooper
|
||||
{
|
||||
int firstRowPgXStart, firstRowPgXEnd; ///< Offset of start/end pages of the first line from x=0 page (only line for textures that don't cross page boundaries)
|
||||
int midRowPgXStart, midRowPgXEnd; ///< Offset of start/end pages of inner lines (which always are always the height of the full page) from y=0 page
|
||||
int lastRowPgXStart, lastRowPgXEnd; ///< Offset of start/end pages of the last line from x=0 page
|
||||
int bp; ///< Page offset of y=top x=0
|
||||
int yInc; ///< Amount to add to bp when increasing y by one page
|
||||
int yCnt; ///< Number of pages the rect covers in the y direction
|
||||
|
||||
friend class GSOffset;
|
||||
|
||||
public:
|
||||
/// Loop over pages, fn can return `false` to break the loop
|
||||
/// Fn: bool(*)(uint32)
|
||||
template <typename Fn>
|
||||
void loopPagesWithBreak(Fn&& fn) const
|
||||
{
|
||||
int lineBP = bp;
|
||||
int nextMin = 0;
|
||||
|
||||
int startOff = firstRowPgXStart;
|
||||
int endOff = firstRowPgXEnd;
|
||||
int yCnt = this->yCnt;
|
||||
for (int y = 0; y < yCnt; y++)
|
||||
{
|
||||
int start = std::max(nextMin, lineBP + startOff);
|
||||
int end = lineBP + endOff;
|
||||
nextMin = end;
|
||||
lineBP += yInc;
|
||||
for (int pos = start; pos < end; pos++)
|
||||
if (!fn(pos % MAX_PAGES))
|
||||
return;
|
||||
|
||||
if (y < yCnt - 1)
|
||||
{
|
||||
startOff = midRowPgXStart;
|
||||
endOff = midRowPgXEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
startOff = lastRowPgXStart;
|
||||
endOff = lastRowPgXEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Loop over pages, calling `fn` on each one with no option to break
|
||||
/// Fn: void(*)(uint32)
|
||||
template <typename Fn>
|
||||
void loopPages(Fn&& fn) const
|
||||
{
|
||||
loopPagesWithBreak([fn = std::forward<Fn>(fn)](uint32 page) { fn(page); return true; });
|
||||
}
|
||||
};
|
||||
|
||||
/// Get an object for looping over the pages in the given rect
|
||||
PageLooper pageLooperForRect(const GSVector4i& rect) const;
|
||||
|
||||
/// Loop over all the pages in the given rect, calling `fn` on each
|
||||
template <typename Fn>
|
||||
void loopPages(const GSVector4i& rect, Fn&& fn) const
|
||||
{
|
||||
pageLooperForRect(rect).loopPages(std::forward<Fn>(fn));
|
||||
}
|
||||
|
||||
/// Use compile-time dimensions from `swz` as a performance optimization
|
||||
/// Also asserts if your assumption was wrong
|
||||
constexpr GSOffset assertSizesMatch(const GSSwizzleInfo& swz) const
|
||||
{
|
||||
GSOffset o = *this;
|
||||
#define MATCH(x) ASSERT(o.x == swz.x); o.x = swz.x;
|
||||
MATCH(m_pageMask)
|
||||
MATCH(m_blockMask)
|
||||
MATCH(m_pixelRowMask)
|
||||
MATCH(m_pageShiftX)
|
||||
MATCH(m_pageShiftY)
|
||||
MATCH(m_blockShiftX)
|
||||
MATCH(m_blockShiftY)
|
||||
#undef MATCH
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline uint32 GSSwizzleInfo::bn(int x, int y, uint32 bp, uint32 bw) const
|
||||
{
|
||||
return GSOffset(*this, bp, bw, 0).bn(x, y);
|
||||
}
|
||||
|
||||
inline uint32 GSSwizzleInfo::pa(int x, int y, uint32 bp, uint32 bw) const
|
||||
{
|
||||
return GSOffset(*this, bp, bw, 0).pa(x, y);
|
||||
}
|
||||
|
||||
class GSLocalMemory : public GSAlignedClass<32>
|
||||
{
|
||||
public:
|
||||
@@ -87,12 +408,12 @@ public:
|
||||
typedef uint32 (GSLocalMemory::*readTexelAddr)(uint32 addr, const GIFRegTEXA& TEXA) const;
|
||||
typedef void (GSLocalMemory::*writeImage)(int& tx, int& ty, const uint8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG);
|
||||
typedef void (GSLocalMemory::*readImage)(int& tx, int& ty, uint8* dst, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG) const;
|
||||
typedef void (GSLocalMemory::*readTexture)(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
typedef void (GSLocalMemory::*readTexture)(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
typedef void (GSLocalMemory::*readTextureBlock)(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
|
||||
|
||||
struct alignas(128) psm_t
|
||||
{
|
||||
pixelAddress pa, bn;
|
||||
GSSwizzleInfo info;
|
||||
readPixel rp;
|
||||
readPixelAddr rpa;
|
||||
writePixel wp;
|
||||
@@ -106,8 +427,6 @@ public:
|
||||
readTextureBlock rtxb, rtxbP;
|
||||
uint16 bpp, trbpp, pal, fmt;
|
||||
GSVector2i bs, pgs;
|
||||
int* rowOffset[8];
|
||||
short* blockOffset;
|
||||
uint8 msk, depth;
|
||||
};
|
||||
|
||||
@@ -124,33 +443,17 @@ public:
|
||||
protected:
|
||||
bool m_use_fifo_alloc;
|
||||
|
||||
static uint32 pageOffset32[32][32][64];
|
||||
static uint32 pageOffset32Z[32][32][64];
|
||||
static uint32 pageOffset16[32][64][64];
|
||||
static uint32 pageOffset16S[32][64][64];
|
||||
static uint32 pageOffset16Z[32][64][64];
|
||||
static uint32 pageOffset16SZ[32][64][64];
|
||||
static uint32 pageOffset8[32][64][128];
|
||||
static uint32 pageOffset4[32][128][128];
|
||||
|
||||
static int rowOffset32[4096];
|
||||
static int rowOffset32Z[4096];
|
||||
static int rowOffset16[4096];
|
||||
static int rowOffset16S[4096];
|
||||
static int rowOffset16Z[4096];
|
||||
static int rowOffset16SZ[4096];
|
||||
static int rowOffset8[2][4096];
|
||||
static int rowOffset4[2][4096];
|
||||
|
||||
static short blockOffset32[256];
|
||||
static short blockOffset32Z[256];
|
||||
static short blockOffset16[256];
|
||||
static short blockOffset16S[256];
|
||||
static short blockOffset16Z[256];
|
||||
static short blockOffset16SZ[256];
|
||||
static short blockOffset8[256];
|
||||
static short blockOffset4[256];
|
||||
public:
|
||||
static constexpr GSSwizzleInfo swizzle32 {swizzleTables32};
|
||||
static constexpr GSSwizzleInfo swizzle32Z {swizzleTables32Z};
|
||||
static constexpr GSSwizzleInfo swizzle16 {swizzleTables16};
|
||||
static constexpr GSSwizzleInfo swizzle16S {swizzleTables16S};
|
||||
static constexpr GSSwizzleInfo swizzle16Z {swizzleTables16Z};
|
||||
static constexpr GSSwizzleInfo swizzle16SZ {swizzleTables16SZ};
|
||||
static constexpr GSSwizzleInfo swizzle8 {swizzleTables8};
|
||||
static constexpr GSSwizzleInfo swizzle4 {swizzleTables4};
|
||||
|
||||
protected:
|
||||
__forceinline static uint32 Expand24To32(uint32 c, const GIFRegTEXA& TEXA)
|
||||
{
|
||||
return (((!TEXA.AEM | (c & 0xffffff)) ? TEXA.TA0 : 0) << 24) | (c & 0xffffff);
|
||||
@@ -170,7 +473,6 @@ protected:
|
||||
|
||||
//
|
||||
|
||||
std::unordered_map<uint32, GSOffset*> m_omap;
|
||||
std::unordered_map<uint32, GSPixelOffset*> m_pomap;
|
||||
std::unordered_map<uint32, GSPixelOffset4*> m_po4map;
|
||||
std::unordered_map<uint64, std::vector<GSVector2i>*> m_p2tmap;
|
||||
@@ -179,7 +481,10 @@ public:
|
||||
GSLocalMemory();
|
||||
virtual ~GSLocalMemory();
|
||||
|
||||
GSOffset* GetOffset(uint32 bp, uint32 bw, uint32 psm);
|
||||
GSOffset GetOffset(uint32 bp, uint32 bw, uint32 psm) const
|
||||
{
|
||||
return GSOffset(m_psm[psm].info, bp, bw, psm);
|
||||
}
|
||||
GSPixelOffset* GetPixelOffset(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF);
|
||||
GSPixelOffset4* GetPixelOffset4(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF);
|
||||
std::vector<GSVector2i>* GetPage2TileMap(const GIFRegTEX0& TEX0);
|
||||
@@ -188,46 +493,46 @@ public:
|
||||
|
||||
static uint32 BlockNumber32(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable32[(y >> 3) & 3][(x >> 3) & 7];
|
||||
return swizzle32.bn(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static uint32 BlockNumber16(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable16[(y >> 3) & 7][(x >> 4) & 3];
|
||||
return swizzle16.bn(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static uint32 BlockNumber16S(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable16S[(y >> 3) & 7][(x >> 4) & 3];
|
||||
return swizzle16S.bn(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static uint32 BlockNumber8(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
// ASSERT((bw & 1) == 0); // allowed for mipmap levels
|
||||
|
||||
return bp + ((y >> 1) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f) + blockTable8[(y >> 4) & 3][(x >> 4) & 7];
|
||||
return swizzle8.bn(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static uint32 BlockNumber4(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
// ASSERT((bw & 1) == 0); // allowed for mipmap levels
|
||||
|
||||
return bp + ((y >> 2) & ~0x1f) * (bw >> 1) + ((x >> 2) & ~0x1f) + blockTable4[(y >> 4) & 7][(x >> 5) & 3];
|
||||
return swizzle4.bn(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static uint32 BlockNumber32Z(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return bp + (y & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable32Z[(y >> 3) & 3][(x >> 3) & 7];
|
||||
return swizzle32Z.bn(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static uint32 BlockNumber16Z(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable16Z[(y >> 3) & 7][(x >> 4) & 3];
|
||||
return swizzle16Z.bn(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static uint32 BlockNumber16SZ(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return bp + ((y >> 1) & ~0x1f) * bw + ((x >> 1) & ~0x1f) + blockTable16SZ[(y >> 3) & 7][(x >> 4) & 3];
|
||||
return swizzle16SZ.bn(x, y, bp, bw);
|
||||
}
|
||||
|
||||
uint8* BlockPtr(uint32 bp) const
|
||||
@@ -275,112 +580,48 @@ public:
|
||||
return &m_vm8[BlockNumber16SZ(x, y, bp, bw) << 8];
|
||||
}
|
||||
|
||||
static uint32 PixelAddressOrg32(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return (BlockNumber32(x, y, bp, bw) << 6) + columnTable32[y & 7][x & 7];
|
||||
}
|
||||
|
||||
static uint32 PixelAddressOrg16(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return (BlockNumber16(x, y, bp, bw) << 7) + columnTable16[y & 7][x & 15];
|
||||
}
|
||||
|
||||
static uint32 PixelAddressOrg16S(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return (BlockNumber16S(x, y, bp, bw) << 7) + columnTable16[y & 7][x & 15];
|
||||
}
|
||||
|
||||
static uint32 PixelAddressOrg8(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return (BlockNumber8(x, y, bp, bw) << 8) + columnTable8[y & 15][x & 15];
|
||||
}
|
||||
|
||||
static uint32 PixelAddressOrg4(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return (BlockNumber4(x, y, bp, bw) << 9) + columnTable4[y & 15][x & 31];
|
||||
}
|
||||
|
||||
static uint32 PixelAddressOrg32Z(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return (BlockNumber32Z(x, y, bp, bw) << 6) + columnTable32[y & 7][x & 7];
|
||||
}
|
||||
|
||||
static uint32 PixelAddressOrg16Z(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return (BlockNumber16Z(x, y, bp, bw) << 7) + columnTable16[y & 7][x & 15];
|
||||
}
|
||||
|
||||
static uint32 PixelAddressOrg16SZ(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
return (BlockNumber16SZ(x, y, bp, bw) << 7) + columnTable16[y & 7][x & 15];
|
||||
}
|
||||
|
||||
static __forceinline uint32 PixelAddress32(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
uint32 page = ((bp >> 5) + (y >> 5) * bw + (x >> 6)) % MAX_PAGES;
|
||||
uint32 word = (page << 11) + pageOffset32[bp & 0x1f][y & 0x1f][x & 0x3f];
|
||||
|
||||
return word;
|
||||
return swizzle32.pa(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static __forceinline uint32 PixelAddress16(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
uint32 page = ((bp >> 5) + (y >> 6) * bw + (x >> 6)) % MAX_PAGES;
|
||||
uint32 word = (page << 12) + pageOffset16[bp & 0x1f][y & 0x3f][x & 0x3f];
|
||||
|
||||
return word;
|
||||
return swizzle16.pa(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static __forceinline uint32 PixelAddress16S(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
uint32 page = ((bp >> 5) + (y >> 6) * bw + (x >> 6)) % MAX_PAGES;
|
||||
uint32 word = (page << 12) + pageOffset16S[bp & 0x1f][y & 0x3f][x & 0x3f];
|
||||
|
||||
return word;
|
||||
return swizzle16S.pa(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static __forceinline uint32 PixelAddress8(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
// ASSERT((bw & 1) == 0); // allowed for mipmap levels
|
||||
|
||||
uint32 page = ((bp >> 5) + (y >> 6) * (bw >> 1) + (x >> 7)) % MAX_PAGES;
|
||||
uint32 word = (page << 13) + pageOffset8[bp & 0x1f][y & 0x3f][x & 0x7f];
|
||||
|
||||
return word;
|
||||
return swizzle8.pa(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static __forceinline uint32 PixelAddress4(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
// ASSERT((bw & 1) == 0); // allowed for mipmap levels
|
||||
|
||||
uint32 page = ((bp >> 5) + (y >> 7) * (bw >> 1) + (x >> 7)) % MAX_PAGES;
|
||||
uint32 word = (page << 14) + pageOffset4[bp & 0x1f][y & 0x7f][x & 0x7f];
|
||||
|
||||
return word;
|
||||
return swizzle4.pa(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static __forceinline uint32 PixelAddress32Z(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
uint32 page = ((bp >> 5) + (y >> 5) * bw + (x >> 6)) % MAX_PAGES;
|
||||
uint32 word = (page << 11) + pageOffset32Z[bp & 0x1f][y & 0x1f][x & 0x3f];
|
||||
|
||||
return word;
|
||||
return swizzle32Z.pa(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static __forceinline uint32 PixelAddress16Z(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
uint32 page = ((bp >> 5) + (y >> 6) * bw + (x >> 6)) % MAX_PAGES;
|
||||
uint32 word = (page << 12) + pageOffset16Z[bp & 0x1f][y & 0x3f][x & 0x3f];
|
||||
|
||||
return word;
|
||||
return swizzle16Z.pa(x, y, bp, bw);
|
||||
}
|
||||
|
||||
static __forceinline uint32 PixelAddress16SZ(int x, int y, uint32 bp, uint32 bw)
|
||||
{
|
||||
uint32 page = ((bp >> 5) + (y >> 6) * bw + (x >> 6)) % MAX_PAGES;
|
||||
uint32 word = (page << 12) + pageOffset16SZ[bp & 0x1f][y & 0x3f][x & 0x3f];
|
||||
|
||||
return word;
|
||||
return swizzle16SZ.pa(x, y, bp, bw);
|
||||
}
|
||||
|
||||
// pixel R/W
|
||||
@@ -537,9 +778,14 @@ public:
|
||||
m_vm32[addr] = c;
|
||||
}
|
||||
|
||||
__forceinline static void WritePixel24(uint32* addr, uint32 c)
|
||||
{
|
||||
*addr = (*addr & 0xff000000) | (c & 0x00ffffff);
|
||||
}
|
||||
|
||||
__forceinline void WritePixel24(uint32 addr, uint32 c)
|
||||
{
|
||||
m_vm32[addr] = (m_vm32[addr] & 0xff000000) | (c & 0x00ffffff);
|
||||
WritePixel24(m_vm32 + addr, c);
|
||||
}
|
||||
|
||||
__forceinline void WritePixel16(uint32 addr, uint32 c)
|
||||
@@ -560,19 +806,34 @@ public:
|
||||
m_vm8[addr] = (uint8)((m_vm8[addr] & (0xf0 >> shift)) | ((c & 0x0f) << shift));
|
||||
}
|
||||
|
||||
__forceinline static void WritePixel8H(uint32* addr, uint32 c)
|
||||
{
|
||||
*addr = (*addr & 0x00ffffff) | (c << 24);
|
||||
}
|
||||
|
||||
__forceinline void WritePixel8H(uint32 addr, uint32 c)
|
||||
{
|
||||
m_vm32[addr] = (m_vm32[addr] & 0x00ffffff) | (c << 24);
|
||||
WritePixel8H(m_vm32 + addr, c);
|
||||
}
|
||||
|
||||
__forceinline static void WritePixel4HL(uint32* addr, uint32 c)
|
||||
{
|
||||
*addr = (*addr & 0xf0ffffff) | ((c & 0x0f) << 24);
|
||||
}
|
||||
|
||||
__forceinline void WritePixel4HL(uint32 addr, uint32 c)
|
||||
{
|
||||
m_vm32[addr] = (m_vm32[addr] & 0xf0ffffff) | ((c & 0x0f) << 24);
|
||||
WritePixel4HL(m_vm32 + addr, c);
|
||||
}
|
||||
|
||||
__forceinline static void WritePixel4HH(uint32* addr, uint32 c)
|
||||
{
|
||||
*addr = (*addr & 0x0fffffff) | ((c & 0x0f) << 28);
|
||||
}
|
||||
|
||||
__forceinline void WritePixel4HH(uint32 addr, uint32 c)
|
||||
{
|
||||
m_vm32[addr] = (m_vm32[addr] & 0x0fffffff) | ((c & 0x0f) << 28);
|
||||
WritePixel4HH(m_vm32 + addr, c);
|
||||
}
|
||||
|
||||
__forceinline void WriteFrame16(uint32 addr, uint32 c)
|
||||
@@ -668,75 +929,35 @@ public:
|
||||
WriteFrame16(PixelAddress16SZ(x, y, bp, bw), c);
|
||||
}
|
||||
|
||||
__forceinline void WritePixel32(uint8* RESTRICT src, uint32 pitch, GSOffset* off, const GSVector4i& r)
|
||||
void WritePixel32(uint8* RESTRICT src, uint32 pitch, const GSOffset& off, const GSVector4i& r)
|
||||
{
|
||||
src -= r.left * sizeof(uint32);
|
||||
|
||||
for (int y = r.top; y < r.bottom; y++, src += pitch)
|
||||
{
|
||||
uint32* RESTRICT s = (uint32*)src;
|
||||
uint32* RESTRICT d = &m_vm32[off->pixel.row[y]];
|
||||
int* RESTRICT col = off->pixel.col[0];
|
||||
|
||||
for (int x = r.left; x < r.right; x++)
|
||||
{
|
||||
d[col[x]] = s[x];
|
||||
}
|
||||
}
|
||||
off.loopPixels(r, m_vm32, (uint32*)src, pitch, [&](uint32* dst, uint32* src) { *dst = *src; });
|
||||
}
|
||||
|
||||
__forceinline void WritePixel24(uint8* RESTRICT src, uint32 pitch, GSOffset* off, const GSVector4i& r)
|
||||
void WritePixel24(uint8* RESTRICT src, uint32 pitch, const GSOffset& off, const GSVector4i& r)
|
||||
{
|
||||
src -= r.left * sizeof(uint32);
|
||||
|
||||
for (int y = r.top; y < r.bottom; y++, src += pitch)
|
||||
off.loopPixels(r, m_vm32, (uint32*)src, pitch,
|
||||
[&](uint32* dst, uint32* src)
|
||||
{
|
||||
uint32* RESTRICT s = (uint32*)src;
|
||||
uint32* RESTRICT d = &m_vm32[off->pixel.row[y]];
|
||||
int* RESTRICT col = off->pixel.col[0];
|
||||
|
||||
for (int x = r.left; x < r.right; x++)
|
||||
{
|
||||
d[col[x]] = (d[col[x]] & 0xff000000) | (s[x] & 0x00ffffff);
|
||||
}
|
||||
}
|
||||
*dst = (*dst & 0xff000000) | (*src & 0x00ffffff);
|
||||
});
|
||||
}
|
||||
|
||||
__forceinline void WritePixel16(uint8* RESTRICT src, uint32 pitch, GSOffset* off, const GSVector4i& r)
|
||||
void WritePixel16(uint8* RESTRICT src, uint32 pitch, const GSOffset& off, const GSVector4i& r)
|
||||
{
|
||||
src -= r.left * sizeof(uint16);
|
||||
|
||||
for (int y = r.top; y < r.bottom; y++, src += pitch)
|
||||
{
|
||||
uint16* RESTRICT s = (uint16*)src;
|
||||
uint16* RESTRICT d = &m_vm16[off->pixel.row[y]];
|
||||
int* RESTRICT col = off->pixel.col[0];
|
||||
|
||||
for (int x = r.left; x < r.right; x++)
|
||||
{
|
||||
d[col[x]] = s[x];
|
||||
}
|
||||
}
|
||||
off.loopPixels(r, m_vm16, (uint16*)src, pitch, [&](uint16* dst, uint16* src) { *dst = *src; });
|
||||
}
|
||||
|
||||
__forceinline void WriteFrame16(uint8* RESTRICT src, uint32 pitch, GSOffset* off, const GSVector4i& r)
|
||||
void WriteFrame16(uint8* RESTRICT src, uint32 pitch, const GSOffset& off, const GSVector4i& r)
|
||||
{
|
||||
src -= r.left * sizeof(uint32);
|
||||
|
||||
for (int y = r.top; y < r.bottom; y++, src += pitch)
|
||||
off.loopPixels(r, m_vm16, (uint32*)src, pitch,
|
||||
[&](uint16* dst, uint32* src)
|
||||
{
|
||||
uint32* RESTRICT s = (uint32*)src;
|
||||
uint16* RESTRICT d = &m_vm16[off->pixel.row[y]];
|
||||
int* RESTRICT col = off->pixel.col[0];
|
||||
uint32 rb = *src & 0x00f800f8;
|
||||
uint32 ga = *src & 0x8000f800;
|
||||
|
||||
for (int x = r.left; x < r.right; x++)
|
||||
{
|
||||
uint32 rb = s[x] & 0x00f800f8;
|
||||
uint32 ga = s[x] & 0x8000f800;
|
||||
|
||||
d[col[x]] = (uint16)((ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3));
|
||||
}
|
||||
}
|
||||
*dst = (uint16)((ga >> 16) | (rb >> 9) | (ga >> 6) | (rb >> 3));
|
||||
});
|
||||
}
|
||||
|
||||
__forceinline uint32 ReadTexel32(uint32 addr, const GIFRegTEXA& TEXA) const
|
||||
@@ -874,17 +1095,17 @@ public:
|
||||
|
||||
// * => 32
|
||||
|
||||
void ReadTexture32(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTextureGPU24(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture24(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture16(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture8(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture8H(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4HL(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4HH(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture32(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTextureGPU24(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture24(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture16(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture8(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture8H(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4HL(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4HH(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
|
||||
void ReadTexture(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
|
||||
void ReadTextureBlock32(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
|
||||
void ReadTextureBlock24(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
|
||||
@@ -897,11 +1118,11 @@ public:
|
||||
|
||||
// pal ? 8 : 32
|
||||
|
||||
void ReadTexture8P(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4P(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture8HP(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4HLP(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4HHP(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture8P(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4P(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture8HP(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4HLP(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture4HHP(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
|
||||
void ReadTextureBlock8P(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
|
||||
void ReadTextureBlock4P(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const;
|
||||
@@ -912,9 +1133,31 @@ public:
|
||||
//
|
||||
|
||||
template <typename T>
|
||||
void ReadTexture(const GSOffset* RESTRICT off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
void ReadTexture(const GSOffset& off, const GSVector4i& r, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA);
|
||||
|
||||
//
|
||||
|
||||
void SaveBMP(const std::string& fn, uint32 bp, uint32 bw, uint32 psm, int w, int h);
|
||||
};
|
||||
|
||||
constexpr inline GSOffset GSOffset::fromKnownPSM(uint32 bp, uint32 bw, GS_PSM psm)
|
||||
{
|
||||
switch (psm)
|
||||
{
|
||||
case PSM_PSMCT32: return GSOffset(GSLocalMemory::swizzle32, bp, bw, psm);
|
||||
case PSM_PSMCT24: return GSOffset(GSLocalMemory::swizzle32, bp, bw, psm);
|
||||
case PSM_PSMCT16: return GSOffset(GSLocalMemory::swizzle16, bp, bw, psm);
|
||||
case PSM_PSMCT16S: return GSOffset(GSLocalMemory::swizzle16S, bp, bw, psm);
|
||||
case PSM_PSGPU24: return GSOffset(GSLocalMemory::swizzle16, bp, bw, psm);
|
||||
case PSM_PSMT8: return GSOffset(GSLocalMemory::swizzle8, bp, bw, psm);
|
||||
case PSM_PSMT4: return GSOffset(GSLocalMemory::swizzle4, bp, bw, psm);
|
||||
case PSM_PSMT8H: return GSOffset(GSLocalMemory::swizzle32, bp, bw, psm);
|
||||
case PSM_PSMT4HL: return GSOffset(GSLocalMemory::swizzle32, bp, bw, psm);
|
||||
case PSM_PSMT4HH: return GSOffset(GSLocalMemory::swizzle32, bp, bw, psm);
|
||||
case PSM_PSMZ32: return GSOffset(GSLocalMemory::swizzle32Z, bp, bw, psm);
|
||||
case PSM_PSMZ24: return GSOffset(GSLocalMemory::swizzle32Z, bp, bw, psm);
|
||||
case PSM_PSMZ16: return GSOffset(GSLocalMemory::swizzle16Z, bp, bw, psm);
|
||||
case PSM_PSMZ16S: return GSOffset(GSLocalMemory::swizzle16SZ, bp, bw, psm);
|
||||
}
|
||||
return GSOffset(GSLocalMemory::swizzle32, bp, bw, psm);
|
||||
}
|
||||
|
||||
@@ -34,10 +34,12 @@ void GSPerfMon::Put(counter_t c, double val)
|
||||
if (c == Frame)
|
||||
{
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
// clock on linux will return CLOCK_PROCESS_CPUTIME_ID.
|
||||
// CLOCK_THREAD_CPUTIME_ID is much more useful to measure the fps
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
|
||||
# ifdef CLOCK_MONOTONIC_RAW
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
# else
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
# endif
|
||||
uint64 now = (uint64)ts.tv_sec * (uint64)1e6 + (uint64)ts.tv_nsec / (uint64)1e3;
|
||||
#else
|
||||
clock_t now = clock();
|
||||
|
||||
+75
-149
@@ -1650,182 +1650,108 @@ void GSState::Move()
|
||||
|
||||
// TODO: unroll inner loops (width has special size requirement, must be multiples of 1 << n, depending on the format)
|
||||
|
||||
GSOffset* RESTRICT spo = m_mem.GetOffset(m_env.BITBLTBUF.SBP, m_env.BITBLTBUF.SBW, m_env.BITBLTBUF.SPSM);
|
||||
GSOffset* RESTRICT dpo = m_mem.GetOffset(m_env.BITBLTBUF.DBP, m_env.BITBLTBUF.DBW, m_env.BITBLTBUF.DPSM);
|
||||
int sbp = m_env.BITBLTBUF.SBP;
|
||||
int sbw = m_env.BITBLTBUF.SBW;
|
||||
int dbp = m_env.BITBLTBUF.DBP;
|
||||
int dbw = m_env.BITBLTBUF.DBW;
|
||||
GSOffset spo = m_mem.GetOffset(sbp, sbw, m_env.BITBLTBUF.SPSM);
|
||||
GSOffset dpo = m_mem.GetOffset(dbp, dbw, m_env.BITBLTBUF.DPSM);
|
||||
|
||||
auto genericCopy = [=](const GSOffset& dpo, const GSOffset& spo, auto&& getPAHelper, auto&& pxCopyFn)
|
||||
{
|
||||
int _sy = sy, _dy = dy; // Faster with local copied variables, compiler optimizations are dumb
|
||||
if (xinc > 0)
|
||||
{
|
||||
for (int y = 0; y < h; y++, _sy += yinc, _dy += yinc)
|
||||
{
|
||||
auto s = getPAHelper(spo, sx, _sy);
|
||||
auto d = getPAHelper(dpo, dx, _dy);
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
pxCopyFn(d, s, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < h; y++, _sy += yinc, _dy += yinc)
|
||||
{
|
||||
auto s = getPAHelper(spo, sx, _sy);
|
||||
auto d = getPAHelper(dpo, dx, _dy);
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
pxCopyFn(d, s, -x);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto copy = [=](const GSOffset& dpo, const GSOffset& spo, auto&& pxCopyFn)
|
||||
{
|
||||
genericCopy(dpo, spo,
|
||||
[](const GSOffset& o, int x, int y) { return o.paMulti(x, y); },
|
||||
[=](const GSOffset::PAHelper& d, const GSOffset::PAHelper& s, int x)
|
||||
{
|
||||
return pxCopyFn(d.value(x), s.value(x));
|
||||
});
|
||||
};
|
||||
|
||||
auto copyFast = [=](auto* vm, const GSOffset& dpo, const GSOffset& spo, auto&& pxCopyFn)
|
||||
{
|
||||
genericCopy(dpo, spo,
|
||||
[=](const GSOffset& o, int x, int y) { return o.paMulti(vm, x, y); },
|
||||
[=](const auto& d, const auto& s, int x)
|
||||
{
|
||||
return pxCopyFn(d.value(x), s.value(x));
|
||||
});
|
||||
};
|
||||
|
||||
if (spsm.trbpp == dpsm.trbpp && spsm.trbpp >= 16)
|
||||
{
|
||||
int* RESTRICT scol = &spo->pixel.col[0][sx];
|
||||
int* RESTRICT dcol = &dpo->pixel.col[0][dx];
|
||||
|
||||
if (spsm.trbpp == 32)
|
||||
{
|
||||
if (xinc > 0)
|
||||
copyFast(m_mem.m_vm32, dpo.assertSizesMatch(GSLocalMemory::swizzle32), spo.assertSizesMatch(GSLocalMemory::swizzle32), [](uint32* d, uint32* s)
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint32* RESTRICT s = &m_mem.m_vm32[spo->pixel.row[sy]];
|
||||
uint32* RESTRICT d = &m_mem.m_vm32[dpo->pixel.row[dy]];
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
d[dcol[x]] = s[scol[x]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint32* RESTRICT s = &m_mem.m_vm32[spo->pixel.row[sy]];
|
||||
uint32* RESTRICT d = &m_mem.m_vm32[dpo->pixel.row[dy]];
|
||||
|
||||
for (int x = 0; x > -w; x--)
|
||||
d[dcol[x]] = s[scol[x]];
|
||||
}
|
||||
}
|
||||
*d = *s;
|
||||
});
|
||||
}
|
||||
else if (spsm.trbpp == 24)
|
||||
{
|
||||
if (xinc > 0)
|
||||
copyFast(m_mem.m_vm32, dpo.assertSizesMatch(GSLocalMemory::swizzle32), spo.assertSizesMatch(GSLocalMemory::swizzle32), [](uint32* d, uint32* s)
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint32* RESTRICT s = &m_mem.m_vm32[spo->pixel.row[sy]];
|
||||
uint32* RESTRICT d = &m_mem.m_vm32[dpo->pixel.row[dy]];
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
d[dcol[x]] = (d[dcol[x]] & 0xff000000) | (s[scol[x]] & 0x00ffffff);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint32* RESTRICT s = &m_mem.m_vm32[spo->pixel.row[sy]];
|
||||
uint32* RESTRICT d = &m_mem.m_vm32[dpo->pixel.row[dy]];
|
||||
|
||||
for (int x = 0; x > -w; x--)
|
||||
d[dcol[x]] = (d[dcol[x]] & 0xff000000) | (s[scol[x]] & 0x00ffffff);
|
||||
}
|
||||
}
|
||||
*d = (*d & 0xff000000) | (*s & 0x00ffffff);
|
||||
});
|
||||
}
|
||||
else // if(spsm.trbpp == 16)
|
||||
{
|
||||
if (xinc > 0)
|
||||
copyFast(m_mem.m_vm16, dpo.assertSizesMatch(GSLocalMemory::swizzle16), spo.assertSizesMatch(GSLocalMemory::swizzle16), [](uint16* d, uint16* s)
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint16* RESTRICT s = &m_mem.m_vm16[spo->pixel.row[sy]];
|
||||
uint16* RESTRICT d = &m_mem.m_vm16[dpo->pixel.row[dy]];
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
d[dcol[x]] = s[scol[x]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint16* RESTRICT s = &m_mem.m_vm16[spo->pixel.row[sy]];
|
||||
uint16* RESTRICT d = &m_mem.m_vm16[dpo->pixel.row[dy]];
|
||||
|
||||
for (int x = 0; x > -w; x--)
|
||||
d[dcol[x]] = s[scol[x]];
|
||||
}
|
||||
}
|
||||
*d = *s;
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (m_env.BITBLTBUF.SPSM == PSM_PSMT8 && m_env.BITBLTBUF.DPSM == PSM_PSMT8)
|
||||
{
|
||||
if (xinc > 0)
|
||||
copyFast(m_mem.m_vm8, GSOffset::fromKnownPSM(dbp, dbw, PSM_PSMT8), GSOffset::fromKnownPSM(sbp, sbw, PSM_PSMT8), [](uint8* d, uint8* s)
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint8* RESTRICT s = &m_mem.m_vm8[spo->pixel.row[sy]];
|
||||
uint8* RESTRICT d = &m_mem.m_vm8[dpo->pixel.row[dy]];
|
||||
|
||||
int* RESTRICT scol = &spo->pixel.col[sy & 7][sx];
|
||||
int* RESTRICT dcol = &dpo->pixel.col[dy & 7][dx];
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
d[dcol[x]] = s[scol[x]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint8* RESTRICT s = &m_mem.m_vm8[spo->pixel.row[sy]];
|
||||
uint8* RESTRICT d = &m_mem.m_vm8[dpo->pixel.row[dy]];
|
||||
|
||||
int* RESTRICT scol = &spo->pixel.col[sy & 7][sx];
|
||||
int* RESTRICT dcol = &dpo->pixel.col[dy & 7][dx];
|
||||
|
||||
for (int x = 0; x > -w; x--)
|
||||
d[dcol[x]] = s[scol[x]];
|
||||
}
|
||||
}
|
||||
*d = *s;
|
||||
});
|
||||
}
|
||||
else if (m_env.BITBLTBUF.SPSM == PSM_PSMT4 && m_env.BITBLTBUF.DPSM == PSM_PSMT4)
|
||||
{
|
||||
if (xinc > 0)
|
||||
copy(GSOffset::fromKnownPSM(dbp, dbw, PSM_PSMT4), GSOffset::fromKnownPSM(sbp, sbw, PSM_PSMT4), [&](uint32 doff, uint32 soff)
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint32 sbase = spo->pixel.row[sy];
|
||||
uint32 dbase = dpo->pixel.row[dy];
|
||||
|
||||
int* RESTRICT scol = &spo->pixel.col[sy & 7][sx];
|
||||
int* RESTRICT dcol = &dpo->pixel.col[dy & 7][dx];
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
m_mem.WritePixel4(dbase + dcol[x], m_mem.ReadPixel4(sbase + scol[x]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint32 sbase = spo->pixel.row[sy];
|
||||
uint32 dbase = dpo->pixel.row[dy];
|
||||
|
||||
int* RESTRICT scol = &spo->pixel.col[sy & 7][sx];
|
||||
int* RESTRICT dcol = &dpo->pixel.col[dy & 7][dx];
|
||||
|
||||
for (int x = 0; x > -w; x--)
|
||||
m_mem.WritePixel4(dbase + dcol[x], m_mem.ReadPixel4(sbase + scol[x]));
|
||||
}
|
||||
}
|
||||
m_mem.WritePixel4(doff, m_mem.ReadPixel4(soff));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xinc > 0)
|
||||
copy(dpo, spo, [&](uint32 doff, uint32 soff)
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint32 sbase = spo->pixel.row[sy];
|
||||
uint32 dbase = dpo->pixel.row[dy];
|
||||
|
||||
int* RESTRICT scol = &spo->pixel.col[sy & 7][sx];
|
||||
int* RESTRICT dcol = &dpo->pixel.col[dy & 7][dx];
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
(m_mem.*dpsm.wpa)(dbase + dcol[x], (m_mem.*spsm.rpa)(sbase + scol[x]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < h; y++, sy += yinc, dy += yinc)
|
||||
{
|
||||
uint32 sbase = spo->pixel.row[sy];
|
||||
uint32 dbase = dpo->pixel.row[dy];
|
||||
|
||||
int* RESTRICT scol = &spo->pixel.col[sy & 7][sx];
|
||||
int* RESTRICT dcol = &dpo->pixel.col[dy & 7][dx];
|
||||
|
||||
for (int x = 0; x > -w; x--)
|
||||
(m_mem.*dpsm.wpa)(dbase + dcol[x], (m_mem.*spsm.rpa)(sbase + scol[x]));
|
||||
}
|
||||
}
|
||||
(m_mem.*dpsm.wpa)(doff, (m_mem.*spsm.rpa)(soff));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+108
-16
@@ -19,7 +19,18 @@
|
||||
#include "GSTables.h"
|
||||
#include "GS_types.h"
|
||||
|
||||
const uint8 blockTable32[4][8] =
|
||||
template <int Width, int Height>
|
||||
static constexpr GSSizedBlockSwizzleTable<Height, Width> makeSwizzleTable(const uint8 (&arr)[Height][Width]) {
|
||||
GSSizedBlockSwizzleTable<Height, Width> table = {};
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
table.value[y][x] = arr[y % Height][x % Width];
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
static constexpr uint8 _blockTable32[4][8] =
|
||||
{
|
||||
{ 0, 1, 4, 5, 16, 17, 20, 21},
|
||||
{ 2, 3, 6, 7, 18, 19, 22, 23},
|
||||
@@ -27,7 +38,7 @@ const uint8 blockTable32[4][8] =
|
||||
{ 10, 11, 14, 15, 26, 27, 30, 31}
|
||||
};
|
||||
|
||||
const uint8 blockTable32Z[4][8] =
|
||||
static constexpr uint8 _blockTable32Z[4][8] =
|
||||
{
|
||||
{ 24, 25, 28, 29, 8, 9, 12, 13},
|
||||
{ 26, 27, 30, 31, 10, 11, 14, 15},
|
||||
@@ -35,7 +46,7 @@ const uint8 blockTable32Z[4][8] =
|
||||
{ 18, 19, 22, 23, 2, 3, 6, 7}
|
||||
};
|
||||
|
||||
const uint8 blockTable16[8][4] =
|
||||
static constexpr uint8 _blockTable16[8][4] =
|
||||
{
|
||||
{ 0, 2, 8, 10 },
|
||||
{ 1, 3, 9, 11 },
|
||||
@@ -47,7 +58,7 @@ const uint8 blockTable16[8][4] =
|
||||
{ 21, 23, 29, 31 }
|
||||
};
|
||||
|
||||
const uint8 blockTable16S[8][4] =
|
||||
static constexpr uint8 _blockTable16S[8][4] =
|
||||
{
|
||||
{ 0, 2, 16, 18 },
|
||||
{ 1, 3, 17, 19 },
|
||||
@@ -59,7 +70,7 @@ const uint8 blockTable16S[8][4] =
|
||||
{ 13, 15, 29, 31 }
|
||||
};
|
||||
|
||||
const uint8 blockTable16Z[8][4] =
|
||||
static constexpr uint8 _blockTable16Z[8][4] =
|
||||
{
|
||||
{ 24, 26, 16, 18 },
|
||||
{ 25, 27, 17, 19 },
|
||||
@@ -71,7 +82,7 @@ const uint8 blockTable16Z[8][4] =
|
||||
{ 13, 15, 5, 7 }
|
||||
};
|
||||
|
||||
const uint8 blockTable16SZ[8][4] =
|
||||
static constexpr uint8 _blockTable16SZ[8][4] =
|
||||
{
|
||||
{ 24, 26, 8, 10 },
|
||||
{ 25, 27, 9, 11 },
|
||||
@@ -83,7 +94,7 @@ const uint8 blockTable16SZ[8][4] =
|
||||
{ 21, 23, 5, 7 }
|
||||
};
|
||||
|
||||
const uint8 blockTable8[4][8] =
|
||||
static constexpr uint8 _blockTable8[4][8] =
|
||||
{
|
||||
{ 0, 1, 4, 5, 16, 17, 20, 21},
|
||||
{ 2, 3, 6, 7, 18, 19, 22, 23},
|
||||
@@ -91,7 +102,7 @@ const uint8 blockTable8[4][8] =
|
||||
{ 10, 11, 14, 15, 26, 27, 30, 31}
|
||||
};
|
||||
|
||||
const uint8 blockTable4[8][4] =
|
||||
static constexpr uint8 _blockTable4[8][4] =
|
||||
{
|
||||
{ 0, 2, 8, 10 },
|
||||
{ 1, 3, 9, 11 },
|
||||
@@ -103,7 +114,16 @@ const uint8 blockTable4[8][4] =
|
||||
{ 21, 23, 29, 31 }
|
||||
};
|
||||
|
||||
const uint8 columnTable32[8][8] =
|
||||
constexpr GSSizedBlockSwizzleTable<4, 8> blockTable32 = makeSwizzleTable(_blockTable32);
|
||||
constexpr GSSizedBlockSwizzleTable<4, 8> blockTable32Z = makeSwizzleTable(_blockTable32Z);
|
||||
constexpr GSSizedBlockSwizzleTable<8, 4> blockTable16 = makeSwizzleTable(_blockTable16);
|
||||
constexpr GSSizedBlockSwizzleTable<8, 4> blockTable16S = makeSwizzleTable(_blockTable16S);
|
||||
constexpr GSSizedBlockSwizzleTable<8, 4> blockTable16Z = makeSwizzleTable(_blockTable16Z);
|
||||
constexpr GSSizedBlockSwizzleTable<8, 4> blockTable16SZ = makeSwizzleTable(_blockTable16SZ);
|
||||
constexpr GSSizedBlockSwizzleTable<4, 8> blockTable8 = makeSwizzleTable(_blockTable8);
|
||||
constexpr GSSizedBlockSwizzleTable<8, 4> blockTable4 = makeSwizzleTable(_blockTable4);
|
||||
|
||||
constexpr uint8 columnTable32[8][8] =
|
||||
{
|
||||
{ 0, 1, 4, 5, 8, 9, 12, 13 },
|
||||
{ 2, 3, 6, 7, 10, 11, 14, 15 },
|
||||
@@ -115,7 +135,7 @@ const uint8 columnTable32[8][8] =
|
||||
{ 50, 51, 54, 55, 58, 59, 62, 63 },
|
||||
};
|
||||
|
||||
const uint8 columnTable16[8][16] =
|
||||
constexpr uint8 columnTable16[8][16] =
|
||||
{
|
||||
{ 0, 2, 8, 10, 16, 18, 24, 26,
|
||||
1, 3, 9, 11, 17, 19, 25, 27 },
|
||||
@@ -135,7 +155,7 @@ const uint8 columnTable16[8][16] =
|
||||
101, 103, 109, 111, 117, 119, 125, 127 },
|
||||
};
|
||||
|
||||
const uint8 columnTable8[16][16] =
|
||||
constexpr uint8 columnTable8[16][16] =
|
||||
{
|
||||
{ 0, 4, 16, 20, 32, 36, 48, 52, // column 0
|
||||
2, 6, 18, 22, 34, 38, 50, 54 },
|
||||
@@ -171,7 +191,7 @@ const uint8 columnTable8[16][16] =
|
||||
203, 207, 219, 223, 235, 239, 251, 255 },
|
||||
};
|
||||
|
||||
const uint16 columnTable4[16][32] =
|
||||
constexpr uint16 columnTable4[16][32] =
|
||||
{
|
||||
{ 0, 8, 32, 40, 64, 72, 96, 104, // column 0
|
||||
2, 10, 34, 42, 66, 74, 98, 106,
|
||||
@@ -239,7 +259,7 @@ const uint16 columnTable4[16][32] =
|
||||
407, 415, 439, 447, 471, 479, 503, 511 },
|
||||
};
|
||||
|
||||
const uint8 clutTableT32I8[128] =
|
||||
constexpr uint8 clutTableT32I8[128] =
|
||||
{
|
||||
0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15,
|
||||
64, 65, 68, 69, 72, 73, 76, 77, 66, 67, 70, 71, 74, 75, 78, 79,
|
||||
@@ -251,13 +271,13 @@ const uint8 clutTableT32I8[128] =
|
||||
112, 113, 116, 117, 120, 121, 124, 125, 114, 115, 118, 119, 122, 123, 126, 127
|
||||
};
|
||||
|
||||
const uint8 clutTableT32I4[16] =
|
||||
constexpr uint8 clutTableT32I4[16] =
|
||||
{
|
||||
0, 1, 4, 5, 8, 9, 12, 13,
|
||||
2, 3, 6, 7, 10, 11, 14, 15
|
||||
};
|
||||
|
||||
const uint8 clutTableT16I8[32] =
|
||||
constexpr uint8 clutTableT16I8[32] =
|
||||
{
|
||||
0, 2, 8, 10, 16, 18, 24, 26,
|
||||
4, 6, 12, 14, 20, 22, 28, 30,
|
||||
@@ -265,8 +285,80 @@ const uint8 clutTableT16I8[32] =
|
||||
5, 7, 13, 15, 21, 23, 29, 31
|
||||
};
|
||||
|
||||
const uint8 clutTableT16I4[16] =
|
||||
constexpr uint8 clutTableT16I4[16] =
|
||||
{
|
||||
0, 2, 8, 10, 16, 18, 24, 26,
|
||||
4, 6, 12, 14, 20, 22, 28, 30
|
||||
};
|
||||
|
||||
template <int BlocksHigh, int BlocksWide, int ColHeight, int ColWidth, typename Col>
|
||||
constexpr int pxOffset(const uint8 (&blockTable)[BlocksHigh][BlocksWide], Col (&colTable)[ColHeight][ColWidth], int x, int y)
|
||||
{
|
||||
int blockSize = ColHeight * ColWidth;
|
||||
int pageSize = blockSize * BlocksHigh * BlocksWide;
|
||||
int pageWidth = BlocksWide * ColWidth;
|
||||
int pageX = x / pageWidth;
|
||||
int subpageX = x % pageWidth;
|
||||
int blockID = blockTable[y / ColHeight][subpageX / ColWidth];
|
||||
int sublockOffset = colTable[y % ColHeight][subpageX % ColWidth];
|
||||
return pageX * pageSize + blockID * blockSize + sublockOffset;
|
||||
}
|
||||
|
||||
template <int BlocksHigh, int BlocksWide, int ColHeight, int ColWidth, typename Col>
|
||||
constexpr GSPixelColOffsetTable<BlocksHigh * ColHeight> makeColOffsetTable(const uint8 (&blockTable)[BlocksHigh][BlocksWide], Col (&colTable)[ColHeight][ColWidth])
|
||||
{
|
||||
constexpr int size = BlocksHigh * ColHeight;
|
||||
GSPixelColOffsetTable<size> table = {};
|
||||
for (int y = 0; y < size; y++)
|
||||
{
|
||||
table.value[y] = pxOffset(blockTable, colTable, 0, y);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
template <int BlocksHigh, int BlocksWide, int ColHeight, int ColWidth, typename Col>
|
||||
constexpr GSSizedPixelRowOffsetTable<BlocksWide * ColWidth> makeRowOffsetTable(const uint8 (&blockTable)[BlocksHigh][BlocksWide], Col (&colTable)[ColHeight][ColWidth], int y)
|
||||
{
|
||||
int base = pxOffset(blockTable, colTable, 0, y);
|
||||
GSSizedPixelRowOffsetTable<BlocksWide * ColWidth> table = {};
|
||||
for (int x = 0; x < 2048; x++)
|
||||
{
|
||||
table.value[x] = pxOffset(blockTable, colTable, x, y) - base;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
constexpr GSPixelColOffsetTable< 32> pixelColOffset32 = makeColOffsetTable(_blockTable32, columnTable32);
|
||||
constexpr GSPixelColOffsetTable< 32> pixelColOffset32Z = makeColOffsetTable(_blockTable32Z, columnTable32);
|
||||
constexpr GSPixelColOffsetTable< 64> pixelColOffset16 = makeColOffsetTable(_blockTable16, columnTable16);
|
||||
constexpr GSPixelColOffsetTable< 64> pixelColOffset16S = makeColOffsetTable(_blockTable16S, columnTable16);
|
||||
constexpr GSPixelColOffsetTable< 64> pixelColOffset16Z = makeColOffsetTable(_blockTable16Z, columnTable16);
|
||||
constexpr GSPixelColOffsetTable< 64> pixelColOffset16SZ = makeColOffsetTable(_blockTable16SZ, columnTable16);
|
||||
constexpr GSPixelColOffsetTable< 64> pixelColOffset8 = makeColOffsetTable(_blockTable8, columnTable8);
|
||||
constexpr GSPixelColOffsetTable<128> pixelColOffset4 = makeColOffsetTable(_blockTable4, columnTable4);
|
||||
// These can't be constexpr due to a GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99901
|
||||
CONSTINIT const GSSizedPixelRowOffsetTable< 64> GSTables::_pixelRowOffset32 = makeRowOffsetTable(_blockTable32, columnTable32, 0);
|
||||
CONSTINIT const GSSizedPixelRowOffsetTable< 64> GSTables::_pixelRowOffset32Z = makeRowOffsetTable(_blockTable32Z, columnTable32, 0);
|
||||
CONSTINIT const GSSizedPixelRowOffsetTable< 64> GSTables::_pixelRowOffset16 = makeRowOffsetTable(_blockTable16, columnTable16, 0);
|
||||
CONSTINIT const GSSizedPixelRowOffsetTable< 64> GSTables::_pixelRowOffset16S = makeRowOffsetTable(_blockTable16S, columnTable16, 0);
|
||||
CONSTINIT const GSSizedPixelRowOffsetTable< 64> GSTables::_pixelRowOffset16Z = makeRowOffsetTable(_blockTable16Z, columnTable16, 0);
|
||||
CONSTINIT const GSSizedPixelRowOffsetTable< 64> GSTables::_pixelRowOffset16SZ = makeRowOffsetTable(_blockTable16SZ, columnTable16, 0);
|
||||
CONSTINIT const GSSizedPixelRowOffsetTable<128> GSTables::_pixelRowOffset8[2] =
|
||||
{
|
||||
makeRowOffsetTable(_blockTable8, columnTable8, 0),
|
||||
makeRowOffsetTable(_blockTable8, columnTable8, 2),
|
||||
};
|
||||
CONSTINIT const GSSizedPixelRowOffsetTable<128> GSTables::_pixelRowOffset4[2] =
|
||||
{
|
||||
makeRowOffsetTable(_blockTable4, columnTable4, 0),
|
||||
makeRowOffsetTable(_blockTable4, columnTable4, 2),
|
||||
};
|
||||
|
||||
constexpr GSPixelRowOffsetTableList< 64, 0> GSTables::pixelRowOffset32;
|
||||
constexpr GSPixelRowOffsetTableList< 64, 0> GSTables::pixelRowOffset32Z;
|
||||
constexpr GSPixelRowOffsetTableList< 64, 0> GSTables::pixelRowOffset16;
|
||||
constexpr GSPixelRowOffsetTableList< 64, 0> GSTables::pixelRowOffset16S;
|
||||
constexpr GSPixelRowOffsetTableList< 64, 0> GSTables::pixelRowOffset16Z;
|
||||
constexpr GSPixelRowOffsetTableList< 64, 0> GSTables::pixelRowOffset16SZ;
|
||||
constexpr GSPixelRowOffsetTableList<128, 7> GSTables::pixelRowOffset8;
|
||||
constexpr GSPixelRowOffsetTableList<128, 7> GSTables::pixelRowOffset4;
|
||||
|
||||
+148
-8
@@ -17,14 +17,100 @@
|
||||
|
||||
#include "GS_types.h"
|
||||
|
||||
extern const uint8 blockTable32[4][8];
|
||||
extern const uint8 blockTable32Z[4][8];
|
||||
extern const uint8 blockTable16[8][4];
|
||||
extern const uint8 blockTable16S[8][4];
|
||||
extern const uint8 blockTable16Z[8][4];
|
||||
extern const uint8 blockTable16SZ[8][4];
|
||||
extern const uint8 blockTable8[4][8];
|
||||
extern const uint8 blockTable4[8][4];
|
||||
/// Table for storing swizzling of blocks within a page
|
||||
struct alignas(64) GSBlockSwizzleTable
|
||||
{
|
||||
// Some swizzles are 4x8 and others are 8x4. An 8x8 table can store either at the cost of 2x size
|
||||
uint8 value[8][8];
|
||||
|
||||
constexpr uint8 lookup(int x, int y) const
|
||||
{
|
||||
return value[y & 7][x & 7];
|
||||
}
|
||||
};
|
||||
|
||||
/// Adds sizes to GSBlockSwizzleTable for to feel better about not making mistakes
|
||||
template <int Height, int Width>
|
||||
struct GSSizedBlockSwizzleTable : public GSBlockSwizzleTable
|
||||
{
|
||||
};
|
||||
|
||||
/// Table for storing offsets of x = 0 pixels from the beginning of the page
|
||||
/// Add values from a GSPixelRowOffsetTable to get the pixels for x != 0
|
||||
template <int Height>
|
||||
struct alignas(128) GSPixelColOffsetTable
|
||||
{
|
||||
int value[Height] = {};
|
||||
|
||||
int operator[](int y) const
|
||||
{
|
||||
return value[y % Height];
|
||||
}
|
||||
};
|
||||
|
||||
/// Table for storing offsets of x != 0 pixels from the pixel at the same y where x = 0
|
||||
/// Unlike ColOffsets, this table stretches to the maximum size of a texture so no masking is needed
|
||||
struct alignas(128) GSPixelRowOffsetTable
|
||||
{
|
||||
int value[2048] = {};
|
||||
|
||||
int operator[](size_t x) const
|
||||
{
|
||||
ASSERT(x < 2048);
|
||||
return value[x];
|
||||
}
|
||||
};
|
||||
|
||||
/// Adds size to GSPixelRowOffsetTable to feel better about not making mistakes
|
||||
template <int PageWidth>
|
||||
struct GSSizedPixelRowOffsetTable : public GSPixelRowOffsetTable
|
||||
{
|
||||
};
|
||||
|
||||
/// List of row offset tables
|
||||
/// Some swizzlings (PSMT8 and PSMT4) have different row offsets depending on which column they're a part of
|
||||
/// The ones that do use an a a b b b b a a pattern that repeats every 8 rows.
|
||||
/// You can always look up the correct row in this list with y & 7, but if you use y & Mask where Mask is known at compile time, the compiler should be able to optimize better
|
||||
template <int PageWidth, int Mask>
|
||||
struct alignas(sizeof(void*) * 8) GSPixelRowOffsetTableList
|
||||
{
|
||||
const GSPixelRowOffsetTable* rows[8];
|
||||
|
||||
const GSPixelRowOffsetTable& operator[](int y) const
|
||||
{
|
||||
return *rows[y & Mask];
|
||||
}
|
||||
};
|
||||
|
||||
/// Full pixel offset table
|
||||
/// Template values are for objects constructing from one of these tables
|
||||
template <int PageHeight, int PageWidth, int BlockHeight, int BlockWidth, int RowMask>
|
||||
struct GSSwizzleTableList
|
||||
{
|
||||
const GSSizedBlockSwizzleTable<BlockHeight, BlockWidth>& block;
|
||||
const GSPixelColOffsetTable<PageHeight>& col;
|
||||
const GSPixelRowOffsetTableList<PageWidth, RowMask>& row;
|
||||
};
|
||||
|
||||
/// List of all tables for a given swizzle for easy setup
|
||||
template <int PageHeight, int PageWidth, int BlockHeight, int BlockWidth, int RowMask>
|
||||
constexpr GSSwizzleTableList<PageHeight, PageWidth, BlockHeight, BlockWidth, RowMask>
|
||||
makeSwizzleTableList(
|
||||
const GSSizedBlockSwizzleTable<BlockHeight, BlockWidth>& block,
|
||||
const GSPixelColOffsetTable<PageHeight>& col,
|
||||
const GSPixelRowOffsetTableList<PageWidth, RowMask>& row)
|
||||
{
|
||||
return {block, col, row};
|
||||
}
|
||||
|
||||
extern const GSSizedBlockSwizzleTable<4, 8> blockTable32;
|
||||
extern const GSSizedBlockSwizzleTable<4, 8> blockTable32Z;
|
||||
extern const GSSizedBlockSwizzleTable<8, 4> blockTable16;
|
||||
extern const GSSizedBlockSwizzleTable<8, 4> blockTable16S;
|
||||
extern const GSSizedBlockSwizzleTable<8, 4> blockTable16Z;
|
||||
extern const GSSizedBlockSwizzleTable<8, 4> blockTable16SZ;
|
||||
extern const GSSizedBlockSwizzleTable<4, 8> blockTable8;
|
||||
extern const GSSizedBlockSwizzleTable<8, 4> blockTable4;
|
||||
extern const uint8 columnTable32[8][8];
|
||||
extern const uint8 columnTable16[8][16];
|
||||
extern const uint8 columnTable8[16][16];
|
||||
@@ -33,3 +119,57 @@ extern const uint8 clutTableT32I8[128];
|
||||
extern const uint8 clutTableT32I4[16];
|
||||
extern const uint8 clutTableT16I8[32];
|
||||
extern const uint8 clutTableT16I4[16];
|
||||
extern const GSPixelColOffsetTable< 32> pixelColOffset32;
|
||||
extern const GSPixelColOffsetTable< 32> pixelColOffset32Z;
|
||||
extern const GSPixelColOffsetTable< 64> pixelColOffset16;
|
||||
extern const GSPixelColOffsetTable< 64> pixelColOffset16S;
|
||||
extern const GSPixelColOffsetTable< 64> pixelColOffset16Z;
|
||||
extern const GSPixelColOffsetTable< 64> pixelColOffset16SZ;
|
||||
extern const GSPixelColOffsetTable< 64> pixelColOffset8;
|
||||
extern const GSPixelColOffsetTable<128> pixelColOffset4;
|
||||
|
||||
template <int PageWidth>
|
||||
constexpr GSPixelRowOffsetTableList<PageWidth, 0> makeRowOffsetTableList(
|
||||
const GSSizedPixelRowOffsetTable<PageWidth>* a)
|
||||
{
|
||||
return {{a, a, a, a, a, a, a, a}};
|
||||
}
|
||||
|
||||
template <int PageWidth>
|
||||
constexpr GSPixelRowOffsetTableList<PageWidth, 7> makeRowOffsetTableList(
|
||||
const GSSizedPixelRowOffsetTable<PageWidth>* a,
|
||||
const GSSizedPixelRowOffsetTable<PageWidth>* b)
|
||||
{
|
||||
return {{a, a, b, b, b, b, a, a}};
|
||||
}
|
||||
|
||||
/// Just here to force external linkage so we don't end up with multiple copies of pixelRowOffset*
|
||||
struct GSTables
|
||||
{
|
||||
static const GSSizedPixelRowOffsetTable< 64> _pixelRowOffset32;
|
||||
static const GSSizedPixelRowOffsetTable< 64> _pixelRowOffset32Z;
|
||||
static const GSSizedPixelRowOffsetTable< 64> _pixelRowOffset16;
|
||||
static const GSSizedPixelRowOffsetTable< 64> _pixelRowOffset16S;
|
||||
static const GSSizedPixelRowOffsetTable< 64> _pixelRowOffset16Z;
|
||||
static const GSSizedPixelRowOffsetTable< 64> _pixelRowOffset16SZ;
|
||||
static const GSSizedPixelRowOffsetTable<128> _pixelRowOffset8[2];
|
||||
static const GSSizedPixelRowOffsetTable<128> _pixelRowOffset4[2];
|
||||
|
||||
static constexpr auto pixelRowOffset32 = makeRowOffsetTableList(&_pixelRowOffset32);
|
||||
static constexpr auto pixelRowOffset32Z = makeRowOffsetTableList(&_pixelRowOffset32Z);
|
||||
static constexpr auto pixelRowOffset16 = makeRowOffsetTableList(&_pixelRowOffset16);
|
||||
static constexpr auto pixelRowOffset16S = makeRowOffsetTableList(&_pixelRowOffset16S);
|
||||
static constexpr auto pixelRowOffset16Z = makeRowOffsetTableList(&_pixelRowOffset16Z);
|
||||
static constexpr auto pixelRowOffset16SZ = makeRowOffsetTableList(&_pixelRowOffset16SZ);
|
||||
static constexpr auto pixelRowOffset8 = makeRowOffsetTableList(&_pixelRowOffset8[0], &_pixelRowOffset8[1]);
|
||||
static constexpr auto pixelRowOffset4 = makeRowOffsetTableList(&_pixelRowOffset4[0], &_pixelRowOffset4[1]);
|
||||
};
|
||||
|
||||
constexpr auto swizzleTables32 = makeSwizzleTableList(blockTable32, pixelColOffset32, GSTables::pixelRowOffset32 );
|
||||
constexpr auto swizzleTables32Z = makeSwizzleTableList(blockTable32Z, pixelColOffset32Z, GSTables::pixelRowOffset32Z );
|
||||
constexpr auto swizzleTables16 = makeSwizzleTableList(blockTable16, pixelColOffset16, GSTables::pixelRowOffset16 );
|
||||
constexpr auto swizzleTables16Z = makeSwizzleTableList(blockTable16Z, pixelColOffset16Z, GSTables::pixelRowOffset16Z );
|
||||
constexpr auto swizzleTables16S = makeSwizzleTableList(blockTable16S, pixelColOffset16S, GSTables::pixelRowOffset16S );
|
||||
constexpr auto swizzleTables16SZ = makeSwizzleTableList(blockTable16SZ, pixelColOffset16SZ, GSTables::pixelRowOffset16SZ);
|
||||
constexpr auto swizzleTables8 = makeSwizzleTableList(blockTable8, pixelColOffset8, GSTables::pixelRowOffset8 );
|
||||
constexpr auto swizzleTables4 = makeSwizzleTableList(blockTable4, pixelColOffset4, GSTables::pixelRowOffset4 );
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <codecvt>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Renderers/DX11/GSDevice11.h"
|
||||
#include <VersionHelpers.h>
|
||||
#include "svnrev.h"
|
||||
#include <wil/com.h>
|
||||
@@ -186,82 +185,6 @@ CRCHackLevel GSUtil::GetRecommendedCRCHackLevel(GSRendererType type)
|
||||
return type == GSRendererType::OGL_HW ? CRCHackLevel::Partial : CRCHackLevel::Full;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// ---------------------------------------------------------------------------------
|
||||
// DX11 Detection (includes DXGI detection and dynamic library method bindings)
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Code 'Borrowed' from Microsoft's DXGI sources -- Modified to suit our needs. --air
|
||||
// Stripped down because of unnecessary complexity and false positives
|
||||
// e.g. (d3d11_beta.dll would fail at device creation time) --pseudonym
|
||||
|
||||
static int s_DXGI;
|
||||
static int s_D3D11;
|
||||
|
||||
bool GSUtil::CheckDXGI()
|
||||
{
|
||||
if (0 == s_DXGI)
|
||||
{
|
||||
HMODULE hmod = LoadLibrary(L"dxgi.dll");
|
||||
s_DXGI = hmod ? 1 : -1;
|
||||
if (hmod)
|
||||
FreeLibrary(hmod);
|
||||
}
|
||||
|
||||
return s_DXGI > 0;
|
||||
}
|
||||
|
||||
bool GSUtil::CheckD3D11()
|
||||
{
|
||||
if (!CheckDXGI())
|
||||
return false;
|
||||
|
||||
if (0 == s_D3D11)
|
||||
{
|
||||
HMODULE hmod = LoadLibrary(L"d3d11.dll");
|
||||
s_D3D11 = hmod ? 1 : -1;
|
||||
if (hmod)
|
||||
FreeLibrary(hmod);
|
||||
}
|
||||
|
||||
return s_D3D11 > 0;
|
||||
}
|
||||
|
||||
D3D_FEATURE_LEVEL GSUtil::CheckDirect3D11Level(IDXGIAdapter* adapter, D3D_DRIVER_TYPE type)
|
||||
{
|
||||
HRESULT hr;
|
||||
D3D_FEATURE_LEVEL level;
|
||||
|
||||
if (!CheckD3D11())
|
||||
return (D3D_FEATURE_LEVEL)0;
|
||||
|
||||
hr = D3D11CreateDevice(adapter, type, NULL, 0, NULL, 0, D3D11_SDK_VERSION, NULL, &level, NULL);
|
||||
|
||||
return SUCCEEDED(hr) ? level : (D3D_FEATURE_LEVEL)0;
|
||||
}
|
||||
|
||||
GSRendererType GSUtil::GetBestRenderer()
|
||||
{
|
||||
wil::com_ptr_nothrow<IDXGIFactory1> dxgi_factory;
|
||||
if (SUCCEEDED(CreateDXGIFactory1(IID_PPV_ARGS(dxgi_factory.put()))))
|
||||
{
|
||||
wil::com_ptr_nothrow<IDXGIAdapter1> adapter;
|
||||
if (SUCCEEDED(dxgi_factory->EnumAdapters1(0, adapter.put())))
|
||||
{
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
if (SUCCEEDED(adapter->GetDesc1(&desc)))
|
||||
{
|
||||
D3D_FEATURE_LEVEL level = GSUtil::CheckDirect3D11Level();
|
||||
// Check for Nvidia VendorID. Latest OpenGL features need at least DX11 level GPU
|
||||
if (desc.VendorId == 0x10DE && level >= D3D_FEATURE_LEVEL_11_0)
|
||||
return GSRendererType::OGL_HW;
|
||||
}
|
||||
}
|
||||
}
|
||||
return GSRendererType::DX1011_HW;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
void GSmkdir(const wchar_t* dir)
|
||||
{
|
||||
|
||||
@@ -36,13 +36,6 @@ public:
|
||||
|
||||
static bool CheckSSE();
|
||||
static CRCHackLevel GetRecommendedCRCHackLevel(GSRendererType type);
|
||||
|
||||
#ifdef _WIN32
|
||||
static bool CheckDXGI();
|
||||
static bool CheckD3D11();
|
||||
static GSRendererType GetBestRenderer();
|
||||
static D3D_FEATURE_LEVEL CheckDirect3D11Level(IDXGIAdapter* adapter = NULL, D3D_DRIVER_TYPE type = D3D_DRIVER_TYPE_HARDWARE);
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
+6
-12
@@ -53,28 +53,22 @@ public:
|
||||
struct { T v[2]; };
|
||||
};
|
||||
|
||||
GSVector2T()
|
||||
GSVector2T() = default;
|
||||
|
||||
constexpr GSVector2T(T x): x(x), y(x)
|
||||
{
|
||||
}
|
||||
|
||||
GSVector2T(T x)
|
||||
constexpr GSVector2T(T x, T y): x(x), y(y)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = x;
|
||||
}
|
||||
|
||||
GSVector2T(T x, T y)
|
||||
{
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
bool operator==(const GSVector2T& v) const
|
||||
constexpr bool operator==(const GSVector2T& v) const
|
||||
{
|
||||
return x == v.x && y == v.y;
|
||||
}
|
||||
|
||||
bool operator!=(const GSVector2T& v) const
|
||||
constexpr bool operator!=(const GSVector2T& v) const
|
||||
{
|
||||
return x != v.x || y != v.y;
|
||||
}
|
||||
|
||||
+37
-15
@@ -234,13 +234,9 @@ public:
|
||||
return sat_i32(a);
|
||||
}
|
||||
|
||||
template <int mode>
|
||||
__forceinline GSVector4i ralign(const GSVector2i& a) const
|
||||
template <Align_Mode mode>
|
||||
GSVector4i _ralign_helper(const GSVector4i& mask) const
|
||||
{
|
||||
// a must be 1 << n
|
||||
|
||||
GSVector4i mask = GSVector4i(a) - GSVector4i(1, 1);
|
||||
|
||||
GSVector4i v;
|
||||
|
||||
switch (mode)
|
||||
@@ -248,13 +244,28 @@ public:
|
||||
case Align_Inside: v = *this + mask; break;
|
||||
case Align_Outside: v = *this + mask.zwxy(); break;
|
||||
case Align_NegInf: v = *this; break;
|
||||
case Align_PosInf: v = *this + mask.zwzw(); break;
|
||||
case Align_PosInf: v = *this + mask.xyxy(); break;
|
||||
default: pxAssert(0); break;
|
||||
}
|
||||
|
||||
return v.andnot(mask.xyxy());
|
||||
}
|
||||
|
||||
/// Align the rect using mask values that already have one subtracted (1 << n - 1 aligns to 1 << n)
|
||||
template <Align_Mode mode>
|
||||
GSVector4i ralign_presub(const GSVector2i& a) const
|
||||
{
|
||||
return _ralign_helper<mode>(GSVector4i(a));
|
||||
}
|
||||
|
||||
template <Align_Mode mode>
|
||||
GSVector4i ralign(const GSVector2i& a) const
|
||||
{
|
||||
// a must be 1 << n
|
||||
|
||||
return _ralign_helper<mode>(GSVector4i(a) - GSVector4i(1, 1));
|
||||
}
|
||||
|
||||
GSVector4i fit(int arx, int ary) const;
|
||||
|
||||
GSVector4i fit(int preset) const;
|
||||
@@ -426,15 +437,19 @@ public:
|
||||
return GSVector4i(_mm_blend_epi16(m, a, mask));
|
||||
}
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
|
||||
template <int mask>
|
||||
__forceinline GSVector4i blend32(const GSVector4i& v) const
|
||||
{
|
||||
#if _M_SSE >= 0x501
|
||||
return GSVector4i(_mm_blend_epi32(m, v.m, mask));
|
||||
}
|
||||
|
||||
#else
|
||||
constexpr int bit3 = ((mask & 8) * 3) << 3;
|
||||
constexpr int bit2 = ((mask & 4) * 3) << 2;
|
||||
constexpr int bit1 = ((mask & 2) * 3) << 1;
|
||||
constexpr int bit0 = (mask & 1) * 3;
|
||||
return blend16<bit3 | bit2 | bit1 | bit0>(v);
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline GSVector4i blend(const GSVector4i& a, const GSVector4i& mask) const
|
||||
{
|
||||
@@ -698,6 +713,13 @@ public:
|
||||
return GSVector4i(_mm_sra_epi32(m, i));
|
||||
}
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
__forceinline GSVector4i srav32(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(_mm_srav_epi32(m, v.m));
|
||||
}
|
||||
#endif
|
||||
|
||||
__forceinline GSVector4i sll16(int i) const
|
||||
{
|
||||
return GSVector4i(_mm_slli_epi16(m, i));
|
||||
@@ -719,9 +741,9 @@ public:
|
||||
}
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
__forceinline GSVector4i sllv32(__m128i i) const
|
||||
__forceinline GSVector4i sllv32(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(_mm_sllv_epi32(m, i));
|
||||
return GSVector4i(_mm_sllv_epi32(m, v.m));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -756,9 +778,9 @@ public:
|
||||
}
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
__forceinline GSVector4i srlv32(__m128i i) const
|
||||
__forceinline GSVector4i srlv32(const GSVector4i& v) const
|
||||
{
|
||||
return GSVector4i(_mm_srlv_epi32(m, i));
|
||||
return GSVector4i(_mm_srlv_epi32(m, v.m));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+1
-5
@@ -110,11 +110,7 @@ extern void vmfree(void* ptr, size_t size);
|
||||
|
||||
// Convert gcc see define into GS (windows) define
|
||||
#if defined(__AVX2__)
|
||||
#if defined(__x86_64__)
|
||||
#define _M_SSE 0x500 // TODO
|
||||
#else
|
||||
#define _M_SSE 0x501
|
||||
#endif
|
||||
#define _M_SSE 0x501
|
||||
#elif defined(__AVX__)
|
||||
#define _M_SSE 0x500
|
||||
#elif defined(__SSE4_1__)
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GS/Renderers/DX11/D3D.h"
|
||||
#include "GS/GS.h"
|
||||
|
||||
#include <d3d11.h>
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
wil::com_ptr_nothrow<IDXGIFactory2> CreateFactory(bool debug)
|
||||
{
|
||||
UINT flags = 0;
|
||||
if (debug)
|
||||
flags |= DXGI_CREATE_FACTORY_DEBUG;
|
||||
|
||||
// we use CreateDXGIFactory2 because we assume at least windows 8.1 anyway
|
||||
wil::com_ptr_nothrow<IDXGIFactory2> factory;
|
||||
HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(factory.put()));
|
||||
|
||||
// if we failed to create a factory with debug support
|
||||
// try one without
|
||||
if (FAILED(hr) && debug)
|
||||
{
|
||||
fprintf(stderr, "D3D: failed to create debug dxgi factory, trying without debugging\n");
|
||||
hr = CreateDXGIFactory2(0, IID_PPV_ARGS(factory.put()));;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
fprintf(stderr, "D3D: failed to create dxgi factory\n"
|
||||
"check that your system meets our minimum requirements:\n"
|
||||
"https://github.com/PCSX2/pcsx2#system-requirements\n");
|
||||
}
|
||||
|
||||
return factory;
|
||||
}
|
||||
|
||||
std::vector<std::string> GetAdapterList(IDXGIFactory2* factory)
|
||||
{
|
||||
ASSERT(factory);
|
||||
|
||||
UINT index = 0;
|
||||
wil::com_ptr_nothrow<IDXGIAdapter1> adapter;
|
||||
|
||||
std::vector<std::string> adapter_list;
|
||||
while (factory->EnumAdapters1(index, adapter.put()) != DXGI_ERROR_NOT_FOUND)
|
||||
{
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
|
||||
std::string name;
|
||||
if (SUCCEEDED(adapter->GetDesc1(&desc)))
|
||||
name = convert_utf16_to_utf8(desc.Description);
|
||||
|
||||
adapter_list.push_back(std::move(name));
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return adapter_list;
|
||||
}
|
||||
|
||||
wil::com_ptr_nothrow<IDXGIAdapter1> GetAdapterFromIndex(IDXGIFactory2* factory, int index)
|
||||
{
|
||||
ASSERT(factory);
|
||||
|
||||
wil::com_ptr_nothrow<IDXGIAdapter1> adapter;
|
||||
if (factory->EnumAdapters1(index, adapter.put()) == DXGI_ERROR_NOT_FOUND)
|
||||
{
|
||||
// try index 0 (default adapter)
|
||||
fprintf(stderr, "D3D: adapter not found, falling back to the default\n");
|
||||
if (FAILED(factory->EnumAdapters1(0, adapter.put())))
|
||||
{
|
||||
// either there are no adapters connected or something major is wrong with the system
|
||||
fprintf(stderr, "D3D: failed to EnumAdapters\n");
|
||||
}
|
||||
}
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
bool IsNvidia(IDXGIAdapter1* adapter)
|
||||
{
|
||||
ASSERT(adapter);
|
||||
|
||||
DXGI_ADAPTER_DESC1 desc = {};
|
||||
if (FAILED(adapter->GetDesc1(&desc)))
|
||||
{
|
||||
fprintf(stderr, "D3D: failed to get the adapter description\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// NV magic number
|
||||
return desc.VendorId == 0x10DE;
|
||||
}
|
||||
|
||||
bool SupportsFeatureLevel11(IDXGIAdapter1* adapter)
|
||||
{
|
||||
ASSERT(adapter);
|
||||
|
||||
D3D_FEATURE_LEVEL feature_level;
|
||||
|
||||
static const D3D_FEATURE_LEVEL check[] = { D3D_FEATURE_LEVEL_11_0 };
|
||||
const HRESULT hr = D3D11CreateDevice(
|
||||
adapter, D3D_DRIVER_TYPE_UNKNOWN, nullptr, 0,
|
||||
check, std::size(check), D3D11_SDK_VERSION, nullptr, &feature_level, nullptr
|
||||
);
|
||||
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
|
||||
return feature_level == D3D_FEATURE_LEVEL_11_0;
|
||||
}
|
||||
|
||||
bool ShouldPreferD3D()
|
||||
{
|
||||
auto factory = CreateFactory(false);
|
||||
auto adapter = GetAdapterFromIndex(factory.get(), 0);
|
||||
|
||||
return !(IsNvidia(adapter.get()) && SupportsFeatureLevel11(adapter.get()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <dxgi1_3.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <wil/com.h>
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
// create a dxgi factory
|
||||
wil::com_ptr_nothrow<IDXGIFactory2> CreateFactory(bool debug);
|
||||
|
||||
// get a list of adapters
|
||||
std::vector<std::string> GetAdapterList(IDXGIFactory2* factory);
|
||||
|
||||
// get an adapter based on position
|
||||
// assuming no one removes/moves it, it should always have the same id
|
||||
// however in the event that the adapter is not found due to the above, use the default
|
||||
wil::com_ptr_nothrow<IDXGIAdapter1> GetAdapterFromIndex(IDXGIFactory2* factory, int index);
|
||||
|
||||
// this is sort of a legacy thing that doesn't have much to do with d3d (just the easiest way)
|
||||
// checks to see if the adapter at 0 is NV and thus we should prefer OpenGL
|
||||
bool IsNvidia(IDXGIAdapter1* adapter);
|
||||
bool ShouldPreferD3D();
|
||||
};
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GS.h"
|
||||
#include "GSDevice11.h"
|
||||
#include "GS/Renderers/DX11/D3D.h"
|
||||
#include "GS/GSUtil.h"
|
||||
#include "GS/resource.h"
|
||||
#include <fstream>
|
||||
@@ -76,8 +77,6 @@ bool GSDevice11::SetFeatureLevel(D3D_FEATURE_LEVEL level, bool compat_mode)
|
||||
|
||||
bool GSDevice11::Create(const WindowInfo& wi)
|
||||
{
|
||||
bool nvidia_vendor = false;
|
||||
|
||||
if (!__super::Create(wi))
|
||||
{
|
||||
return false;
|
||||
@@ -89,57 +88,35 @@ bool GSDevice11::Create(const WindowInfo& wi)
|
||||
D3D11_RASTERIZER_DESC rd;
|
||||
D3D11_BLEND_DESC bsd;
|
||||
|
||||
// create factory
|
||||
wil::com_ptr_nothrow<IDXGIFactory2> factory;
|
||||
const bool enable_debugging = theApp.GetConfigB("debug_d3d");
|
||||
|
||||
auto factory = D3D::CreateFactory(enable_debugging);
|
||||
if (!factory)
|
||||
return false;
|
||||
|
||||
// select adapter
|
||||
auto adapter = D3D::GetAdapterFromIndex(
|
||||
factory.get(), theApp.GetConfigI("adapter_index")
|
||||
);
|
||||
|
||||
DXGI_ADAPTER_DESC1 adapter_desc = {};
|
||||
if (SUCCEEDED(adapter->GetDesc1(&adapter_desc)))
|
||||
{
|
||||
const HRESULT result = CreateDXGIFactory2(0, IID_PPV_ARGS(factory.put()));
|
||||
if (FAILED(result))
|
||||
{
|
||||
fprintf(stderr, "D3D11: Unable to create DXGIFactory2 (reason: %x)\n", result);
|
||||
return false;
|
||||
}
|
||||
std::string adapter_name = convert_utf16_to_utf8(
|
||||
adapter_desc.Description
|
||||
);
|
||||
|
||||
fprintf(stderr, "Selected DXGI Adapter\n"
|
||||
"\tName: %s\n"
|
||||
"\tVendor: %x\n", adapter_name.c_str(), adapter_desc.VendorId);
|
||||
}
|
||||
|
||||
// enumerate adapters
|
||||
wil::com_ptr_nothrow<IDXGIAdapter1> adapter;
|
||||
D3D_DRIVER_TYPE driver_type = D3D_DRIVER_TYPE_HARDWARE;
|
||||
|
||||
{
|
||||
std::string adapter_id = theApp.GetConfigS("Adapter");
|
||||
|
||||
if (adapter_id == "ref")
|
||||
driver_type = D3D_DRIVER_TYPE_REFERENCE;
|
||||
else
|
||||
{
|
||||
for (int i = 0;; i++)
|
||||
{
|
||||
wil::com_ptr_nothrow<IDXGIAdapter1> enum_adapter;
|
||||
if (FAILED(factory->EnumAdapters1(i, enum_adapter.put())))
|
||||
break;
|
||||
DXGI_ADAPTER_DESC1 desc;
|
||||
const HRESULT hr = enum_adapter->GetDesc1(&desc);
|
||||
if (SUCCEEDED(hr) && (GSAdapter(desc) == adapter_id || adapter_id == "default"))
|
||||
{
|
||||
if (desc.VendorId == 0x10DE)
|
||||
nvidia_vendor = true;
|
||||
|
||||
adapter = std::move(enum_adapter);
|
||||
driver_type = D3D_DRIVER_TYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
D3D_FEATURE_LEVEL level;
|
||||
|
||||
// device creation
|
||||
{
|
||||
uint32 flags = D3D11_CREATE_DEVICE_SINGLETHREADED;
|
||||
|
||||
#ifdef _DEBUG
|
||||
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
#endif
|
||||
if(enable_debugging)
|
||||
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
|
||||
constexpr std::array<D3D_FEATURE_LEVEL, 3> supported_levels = {
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
@@ -147,16 +124,60 @@ bool GSDevice11::Create(const WindowInfo& wi)
|
||||
D3D_FEATURE_LEVEL_10_0,
|
||||
};
|
||||
|
||||
const HRESULT result = D3D11CreateDevice(
|
||||
adapter.get(), driver_type, nullptr, flags,
|
||||
D3D_FEATURE_LEVEL feature_level;
|
||||
HRESULT result = D3D11CreateDevice(
|
||||
adapter.get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, flags,
|
||||
supported_levels.data(), supported_levels.size(),
|
||||
D3D11_SDK_VERSION, m_dev.put(), &level, m_ctx.put());
|
||||
D3D11_SDK_VERSION, m_dev.put(), &feature_level, m_ctx.put()
|
||||
);
|
||||
|
||||
// if a debug device is requested but not supported, fallback to non-debug device
|
||||
if (FAILED(result) && enable_debugging)
|
||||
{
|
||||
fprintf(stderr, "D3D: failed to create debug device, trying without debugging\n");
|
||||
// clear the debug flag
|
||||
flags = D3D11_CREATE_DEVICE_SINGLETHREADED;
|
||||
|
||||
result = D3D11CreateDevice(
|
||||
adapter.get(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, flags,
|
||||
supported_levels.data(), supported_levels.size(),
|
||||
D3D11_SDK_VERSION, m_dev.put(), &feature_level, m_ctx.put()
|
||||
);
|
||||
}
|
||||
|
||||
if (FAILED(result))
|
||||
{
|
||||
fprintf(stderr, "D3D11: Unable to create D3D11 device (reason %x)\n", result);
|
||||
fprintf(stderr, "D3D: unable to create D3D11 device (reason %x)\n"
|
||||
"ensure that your gpu supports our minimum requirements:\n"
|
||||
"https://github.com/PCSX2/pcsx2#system-requirements\n", result);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (enable_debugging)
|
||||
{
|
||||
if (auto info_queue = m_dev.try_query<ID3D11InfoQueue>())
|
||||
{
|
||||
const int break_on = theApp.GetConfigI("dx_break_on_severity");
|
||||
|
||||
info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, break_on & (1 << 0));
|
||||
info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, break_on & (1 << 1));
|
||||
info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, break_on & (1 << 2));
|
||||
info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_INFO, break_on & (1 << 3));
|
||||
}
|
||||
fprintf(stderr, "D3D: debugging enabled\n");
|
||||
}
|
||||
|
||||
if (!SetFeatureLevel(feature_level, true))
|
||||
{
|
||||
fprintf(stderr, "D3D: adapter doesn't have a sufficient feature level\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set maximum texture size limit based on supported feature level.
|
||||
if (feature_level >= D3D_FEATURE_LEVEL_11_0)
|
||||
m_d3d_texsize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
else
|
||||
m_d3d_texsize = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
}
|
||||
|
||||
// swapchain creation
|
||||
@@ -182,40 +203,18 @@ bool GSDevice11::Create(const WindowInfo& wi)
|
||||
|
||||
if (FAILED(result))
|
||||
{
|
||||
fprintf(stderr, "D3D11: Failed to create swapchain (reason: %x)\n", result);
|
||||
fprintf(stderr, "D3D: Failed to create swapchain (reason: %x)\n", result);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SetFeatureLevel(level, true))
|
||||
return false;
|
||||
|
||||
// Set maximum texture size limit based on supported feature level.
|
||||
if (level >= D3D_FEATURE_LEVEL_11_0)
|
||||
m_d3d_texsize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
else
|
||||
m_d3d_texsize = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
|
||||
{
|
||||
// HACK: check nVIDIA
|
||||
// Note: It can cause issues on several games such as SOTC, Fatal Frame, plus it adds border offset.
|
||||
const bool disable_safe_features = theApp.GetConfigB("UserHacks") && theApp.GetConfigB("UserHacks_Disable_Safe_Features");
|
||||
m_hack_topleft_offset = (m_upscale_multiplier != 1 && nvidia_vendor && !disable_safe_features) ? -0.01f : 0.0f;
|
||||
bool disable_safe_features = theApp.GetConfigB("UserHacks") && theApp.GetConfigB("UserHacks_Disable_Safe_Features");
|
||||
m_hack_topleft_offset = (m_upscale_multiplier != 1 && D3D::IsNvidia(adapter.get()) && !disable_safe_features) ? -0.01f : 0.0f;
|
||||
}
|
||||
|
||||
// debug
|
||||
#ifdef _DEBUG
|
||||
if (auto info_queue = m_dev.try_query<ID3D11InfoQueue>())
|
||||
{
|
||||
int break_on = theApp.GetConfigI("dx_break_on_severity");
|
||||
|
||||
info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, break_on & (1 << 0));
|
||||
info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, break_on & (1 << 1));
|
||||
info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, break_on & (1 << 2));
|
||||
info_queue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_INFO, break_on & (1 << 3));
|
||||
}
|
||||
#endif
|
||||
|
||||
// convert
|
||||
|
||||
D3D11_INPUT_ELEMENT_DESC il_convert[] =
|
||||
|
||||
@@ -79,7 +79,7 @@ void GSTextureCache11::Read(Target* t, const GSVector4i& r)
|
||||
{
|
||||
// TODO: block level write
|
||||
|
||||
GSOffset* off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
switch (TEX0.PSM)
|
||||
{
|
||||
@@ -124,7 +124,7 @@ void GSTextureCache11::Read(Source* t, const GSVector4i& r)
|
||||
|
||||
if (offscreen->Map(m, &r_offscreen))
|
||||
{
|
||||
GSOffset* off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
m_renderer->m_mem.WritePixel32(m.bits, m.pitch, off, r);
|
||||
|
||||
|
||||
@@ -885,11 +885,8 @@ void GSRendererHW::SwSpriteRender()
|
||||
InvalidateLocalMem(bitbltbuf, GSVector4i(sx, sy, sx + w, sy + h));
|
||||
InvalidateVideoMem(bitbltbuf, GSVector4i(dx, dy, dx + w, dy + h));
|
||||
|
||||
GSOffset* RESTRICT spo = texture_mapping_enabled ? m_mem.GetOffset(bitbltbuf.SBP, bitbltbuf.SBW, bitbltbuf.SPSM) : nullptr;
|
||||
GSOffset* RESTRICT dpo = m_mem.GetOffset(bitbltbuf.DBP, bitbltbuf.DBW, bitbltbuf.DPSM);
|
||||
|
||||
const int* RESTRICT scol = texture_mapping_enabled ? &spo->pixel.col[0][sx] : nullptr;
|
||||
int* RESTRICT dcol = &dpo->pixel.col[0][dx];
|
||||
GSOffset spo = texture_mapping_enabled ? m_mem.GetOffset(bitbltbuf.SBP, bitbltbuf.SBW, bitbltbuf.SPSM) : GSOffset();
|
||||
GSOffset dpo = m_mem.GetOffset(bitbltbuf.DBP, bitbltbuf.DBW, bitbltbuf.DPSM);
|
||||
|
||||
const bool alpha_blending_enabled = PRIM->ABE;
|
||||
|
||||
@@ -910,19 +907,23 @@ void GSRendererHW::SwSpriteRender()
|
||||
|
||||
for (int y = 0; y < h; y++, ++sy, ++dy)
|
||||
{
|
||||
const uint32* RESTRICT s = texture_mapping_enabled ? &m_mem.m_vm32[spo->pixel.row[sy]] : nullptr;
|
||||
uint32* RESTRICT d = &m_mem.m_vm32[dpo->pixel.row[dy]];
|
||||
auto spa = texture_mapping_enabled ? spo.paMulti(m_mem.m_vm32, sx, sy) : GSOffset::PAPtrHelper<uint32>();
|
||||
auto dpa = dpo.paMulti(m_mem.m_vm32, dx, dy);
|
||||
|
||||
ASSERT(w % 2 == 0);
|
||||
|
||||
for (int x = 0; x < w; x += 2)
|
||||
{
|
||||
uint32* di = dpa.value(x);
|
||||
ASSERT(*di + 1 == *dpa.value(x + 1)); // Destination pixel pair is adjacent in memory
|
||||
|
||||
GSVector4i sc;
|
||||
if (texture_mapping_enabled)
|
||||
{
|
||||
uint32* si = spa.value(x);
|
||||
// Read 2 source pixel colors
|
||||
ASSERT((scol[x] + 1) == scol[x + 1]); // Source pixel pair is adjacent in memory
|
||||
sc = GSVector4i::loadl(&s[scol[x]]).u8to16(); // 0x00AA00BB00GG00RR00aa00bb00gg00rr
|
||||
ASSERT((*si + 1) == *spa.value(x + 1)); // Source pixel pair is adjacent in memory
|
||||
sc = GSVector4i::loadl(si).u8to16(); // 0x00AA00BB00GG00RR00aa00bb00gg00rr
|
||||
|
||||
// Apply TFX
|
||||
ASSERT(tex0_tfx == 0 || tex0_tfx == 1);
|
||||
@@ -943,8 +944,7 @@ void GSRendererHW::SwSpriteRender()
|
||||
if (alpha_blending_enabled || fb_mask_enabled)
|
||||
{
|
||||
// Read 2 destination pixel colors
|
||||
ASSERT((dcol[x] + 1) == dcol[x + 1]); // Destination pixel pair is adjacent in memory
|
||||
dc0 = GSVector4i::loadl(&d[dcol[x]]).u8to16(); // 0x00AA00BB00GG00RR00aa00bb00gg00rr
|
||||
dc0 = GSVector4i::loadl(di).u8to16(); // 0x00AA00BB00GG00RR00aa00bb00gg00rr
|
||||
}
|
||||
|
||||
if (alpha_blending_enabled)
|
||||
@@ -999,8 +999,7 @@ void GSRendererHW::SwSpriteRender()
|
||||
|
||||
// Store 2 pixel colors
|
||||
dc = dc.pu16(GSVector4i::zero()); // 0x0000000000000000AABBGGRRaabbggrr
|
||||
ASSERT((dcol[x] + 1) == dcol[x + 1]); // Destination pixel pair is adjacent in memory
|
||||
GSVector4i::storel(&d[dcol[x]], dc);
|
||||
GSVector4i::storel(di, dc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1806,7 +1805,7 @@ void GSRendererHW::OI_GsMemClear()
|
||||
// Limit it further to a full screen 0 write
|
||||
if ((m_vertex.next == 2) && m_vt.m_min.c.eq(GSVector4i(0)))
|
||||
{
|
||||
GSOffset* off = m_context->offset.fb;
|
||||
const GSOffset& off = m_context->offset.fb;
|
||||
const GSVector4i r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(m_context->scissor.in));
|
||||
// Limit the hack to a single fullscreen clear. Some games might use severals column to clear a screen
|
||||
// but hopefully it will be enough.
|
||||
@@ -1824,12 +1823,11 @@ void GSRendererHW::OI_GsMemClear()
|
||||
// Based on WritePixel32
|
||||
for (int y = r.top; y < r.bottom; y++)
|
||||
{
|
||||
uint32* RESTRICT d = &m_mem.m_vm32[off->pixel.row[y]];
|
||||
int* RESTRICT col = off->pixel.col[0];
|
||||
auto pa = off.assertSizesMatch(GSLocalMemory::swizzle32).paMulti(m_mem.m_vm32, 0, y);
|
||||
|
||||
for (int x = r.left; x < r.right; x++)
|
||||
{
|
||||
d[col[x]] = 0; // Here the constant color
|
||||
*pa.value(x) = 0; // Here the constant color
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1838,12 +1836,11 @@ void GSRendererHW::OI_GsMemClear()
|
||||
// Based on WritePixel24
|
||||
for (int y = r.top; y < r.bottom; y++)
|
||||
{
|
||||
uint32* RESTRICT d = &m_mem.m_vm32[off->pixel.row[y]];
|
||||
int* RESTRICT col = off->pixel.col[0];
|
||||
auto pa = off.assertSizesMatch(GSLocalMemory::swizzle32).paMulti(m_mem.m_vm32, 0, y);
|
||||
|
||||
for (int x = r.left; x < r.right; x++)
|
||||
{
|
||||
d[col[x]] &= 0xff000000; // Clear the color
|
||||
*pa.value(x) &= 0xff000000; // Clear the color
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1854,12 +1851,11 @@ void GSRendererHW::OI_GsMemClear()
|
||||
// Based on WritePixel16
|
||||
for(int y = r.top; y < r.bottom; y++)
|
||||
{
|
||||
uint32* RESTRICT d = &m_mem.m_vm16[off->pixel.row[y]];
|
||||
int* RESTRICT col = off->pixel.col[0];
|
||||
auto pa = off.assertSizesMatch(GSLocalMemory::swizzle16).paMulti(m_mem.m_vm16, 0, y);
|
||||
|
||||
for(int x = r.left; x < r.right; x++)
|
||||
{
|
||||
d[col[x]] = 0; // Here the constant color
|
||||
*pa.value(x) = 0; // Here the constant color
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -276,7 +276,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||
uint32 bw = TEX0.TBW;
|
||||
int tw = 1 << TEX0.TW;
|
||||
int th = 1 << TEX0.TH;
|
||||
uint32 bp_end = psm_s.bn(tw - 1, th - 1, bp, bw); // Valid only for color formats
|
||||
uint32 bp_end = psm_s.info.bn(tw - 1, th - 1, bp, bw); // Valid only for color formats
|
||||
|
||||
// Arc the Lad finds the wrong surface here when looking for a depth stencil.
|
||||
// Since we're currently not caching depth stencils (check ToDo in CreateSource) we should not look for it here.
|
||||
@@ -376,7 +376,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
||||
{
|
||||
if (candidate_x_offset == 0 && candidate_y_offset == 0)
|
||||
continue;
|
||||
uint32 candidate_bp = psm_s.bn(candidate_x_offset, candidate_y_offset, t->m_TEX0.TBP0, bw);
|
||||
uint32 candidate_bp = psm_s.info.bn(candidate_x_offset, candidate_y_offset, t->m_TEX0.TBP0, bw);
|
||||
if (bp == candidate_bp && bp_end <= t->m_end_block)
|
||||
{
|
||||
// SWEEP HIT: <x,y> offset found
|
||||
@@ -797,14 +797,11 @@ void GSTextureCache::InvalidateVideoMemType(int type, uint32 bp)
|
||||
|
||||
// Goal: invalidate data sent to the GPU when the source (GS memory) is modified
|
||||
// Called each time you want to write to the GS memory
|
||||
void GSTextureCache::InvalidateVideoMem(GSOffset* off, const GSVector4i& rect, bool target)
|
||||
void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& rect, bool target)
|
||||
{
|
||||
if (!off)
|
||||
return; // Fixme. Crashes Dual Hearts, maybe others as well. Was fine before r1549.
|
||||
|
||||
uint32 bp = off->bp;
|
||||
uint32 bw = off->bw;
|
||||
uint32 psm = off->psm;
|
||||
uint32 bp = off.bp();
|
||||
uint32 bw = off.bw();
|
||||
uint32 psm = off.psm();
|
||||
|
||||
if (!target)
|
||||
{
|
||||
@@ -847,7 +844,7 @@ void GSTextureCache::InvalidateVideoMem(GSOffset* off, const GSVector4i& rect, b
|
||||
// we are screwed.
|
||||
if (m_renderer->m_game.title == CRC::HauntingGround)
|
||||
{
|
||||
uint32 end_block = GSLocalMemory::m_psm[psm].bn(rect.z - 1, rect.w - 1, bp, bw); // Valid only for color formats
|
||||
uint32 end_block = GSLocalMemory::m_psm[psm].info.bn(rect.z - 1, rect.w - 1, bp, bw); // Valid only for color formats
|
||||
auto type = RenderTarget;
|
||||
|
||||
for (auto t : m_dst[type])
|
||||
@@ -871,18 +868,12 @@ void GSTextureCache::InvalidateVideoMem(GSOffset* off, const GSVector4i& rect, b
|
||||
}
|
||||
}
|
||||
|
||||
GSVector4i r;
|
||||
|
||||
uint32* pages = (uint32*)m_temp;
|
||||
|
||||
off->GetPages(rect, pages, &r);
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (const uint32* p = pages; *p != GSOffset::EOP; p++)
|
||||
{
|
||||
uint32 page = *p;
|
||||
GSVector4i r = rect.ralign<Align_Outside>((bp & 31) == 0 ? GSLocalMemory::m_psm[psm].pgs : GSLocalMemory::m_psm[psm].bs);
|
||||
|
||||
off.loopPages(rect, [&](uint32 page)
|
||||
{
|
||||
auto& list = m_src.m_map[page];
|
||||
for (auto i = list.begin(); i != list.end();)
|
||||
{
|
||||
@@ -937,7 +928,7 @@ void GSTextureCache::InvalidateVideoMem(GSOffset* off, const GSVector4i& rect, b
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!target)
|
||||
return;
|
||||
@@ -1045,10 +1036,10 @@ void GSTextureCache::InvalidateVideoMem(GSOffset* off, const GSVector4i& rect, b
|
||||
|
||||
// Goal: retrive the data from the GPU to the GS memory.
|
||||
// Called each time you want to read from the GS memory
|
||||
void GSTextureCache::InvalidateLocalMem(GSOffset* off, const GSVector4i& r)
|
||||
void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r)
|
||||
{
|
||||
uint32 bp = off->bp;
|
||||
uint32 psm = off->psm;
|
||||
uint32 bp = off.bp();
|
||||
uint32 psm = off.psm();
|
||||
//uint32 bw = off->bw;
|
||||
|
||||
// No depth handling please.
|
||||
@@ -1724,14 +1715,14 @@ void GSTextureCache::Surface::UpdateAge()
|
||||
bool GSTextureCache::Surface::Inside(uint32 bp, uint32 bw, uint32 psm, const GSVector4i& rect)
|
||||
{
|
||||
// Valid only for color formats.
|
||||
uint32 const end_block = GSLocalMemory::m_psm[psm].bn(rect.z - 1, rect.w - 1, bp, bw);
|
||||
uint32 const end_block = GSLocalMemory::m_psm[psm].info.bn(rect.z - 1, rect.w - 1, bp, bw);
|
||||
return bp >= m_TEX0.TBP0 && end_block <= m_end_block;
|
||||
}
|
||||
|
||||
bool GSTextureCache::Surface::Overlaps(uint32 bp, uint32 bw, uint32 psm, const GSVector4i& rect)
|
||||
{
|
||||
// Valid only for color formats.
|
||||
uint32 const end_block = GSLocalMemory::m_psm[psm].bn(rect.z - 1, rect.w - 1, bp, bw);
|
||||
uint32 const end_block = GSLocalMemory::m_psm[psm].info.bn(rect.z - 1, rect.w - 1, bp, bw);
|
||||
return (m_TEX0.TBP0 <= bp && bp <= m_end_block)
|
||||
|| (m_TEX0.TBP0 <= end_block && end_block <= m_end_block);
|
||||
}
|
||||
@@ -1777,8 +1768,7 @@ GSTextureCache::Source::Source(GSRenderer* r, const GIFRegTEX0& TEX0, const GIFR
|
||||
m_p2t = r->m_mem.GetPage2TileMap(m_TEX0);
|
||||
}
|
||||
|
||||
GSOffset* off = m_renderer->m_context->offset.tex;
|
||||
m_pages_as_bit = off->GetPagesAsBits(m_TEX0);
|
||||
m_pages = m_renderer->m_context->offset.tex.pageLooperForRect(GSVector4i(0, 0, 1 << TEX0.TW, 1 << TEX0.TH));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1808,23 +1798,23 @@ void GSTextureCache::Source::Update(const GSVector4i& rect, int layer)
|
||||
m_complete = true; // lame, but better than nothing
|
||||
}
|
||||
|
||||
const GSOffset* off = m_renderer->m_context->offset.tex;
|
||||
const GSOffset& off = m_renderer->m_context->offset.tex;
|
||||
GSOffset::BNHelper bn = off.bnMulti(r.left, r.top);
|
||||
|
||||
uint32 blocks = 0;
|
||||
|
||||
if (m_repeating)
|
||||
{
|
||||
for (int y = r.top; y < r.bottom; y += bs.y)
|
||||
for (int y = r.top; y < r.bottom; y += bs.y, bn.nextBlockY())
|
||||
{
|
||||
uint32 base = off->block.row[y >> 3u];
|
||||
|
||||
for (int x = r.left, i = (y << 7) + x; x < r.right; x += bs.x, i += bs.x)
|
||||
for (int x = r.left; x < r.right; bn.nextBlockX(), x += bs.x)
|
||||
{
|
||||
uint32 block = base + off->block.col[x >> 3u];
|
||||
int i = (bn.blkY() << 7) + bn.blkX();
|
||||
uint32 block = bn.valueNoWrap();
|
||||
|
||||
if (block < MAX_BLOCKS || m_wrap_gs_mem)
|
||||
{
|
||||
uint32 addr = (i >> 3u) % MAX_BLOCKS;
|
||||
uint32 addr = i % MAX_BLOCKS;
|
||||
|
||||
uint32 row = addr >> 5u;
|
||||
uint32 col = 1 << (addr & 31u);
|
||||
@@ -1843,13 +1833,11 @@ void GSTextureCache::Source::Update(const GSVector4i& rect, int layer)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = r.top; y < r.bottom; y += bs.y)
|
||||
for (int y = r.top; y < r.bottom; y += bs.y, bn.nextBlockY())
|
||||
{
|
||||
uint32 base = off->block.row[y >> 3u];
|
||||
|
||||
for (int x = r.left; x < r.right; x += bs.x)
|
||||
for (int x = r.left; x < r.right; x += bs.x, bn.nextBlockX())
|
||||
{
|
||||
uint32 block = base + off->block.col[x >> 3u];
|
||||
uint32 block = bn.valueNoWrap();
|
||||
|
||||
if (block < MAX_BLOCKS || m_wrap_gs_mem)
|
||||
{
|
||||
@@ -1951,7 +1939,7 @@ void GSTextureCache::Source::Flush(uint32 count, int layer)
|
||||
|
||||
GSLocalMemory& mem = m_renderer->m_mem;
|
||||
|
||||
const GSOffset* off = m_renderer->m_context->offset.tex;
|
||||
const GSOffset& off = m_renderer->m_context->offset.tex;
|
||||
|
||||
GSLocalMemory::readTexture rtx = psm.rtx;
|
||||
|
||||
@@ -2079,7 +2067,7 @@ void GSTextureCache::Target::Update()
|
||||
|
||||
GSTexture* t = m_renderer->m_dev->CreateTexture(w, h);
|
||||
|
||||
const GSOffset* off = m_renderer->m_mem.GetOffset(m_TEX0.TBP0, m_TEX0.TBW, m_TEX0.PSM);
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(m_TEX0.TBP0, m_TEX0.TBW, m_TEX0.PSM);
|
||||
|
||||
GSTexture::GSMap m;
|
||||
|
||||
@@ -2123,14 +2111,14 @@ void GSTextureCache::Target::UpdateValidity(const GSVector4i& rect)
|
||||
m_valid = m_valid.runion(rect);
|
||||
|
||||
// Block of the bottom right texel of the validity rectangle, last valid block of the texture
|
||||
m_end_block = GSLocalMemory::m_psm[m_TEX0.PSM].bn(m_valid.z - 1, m_valid.w - 1, m_TEX0.TBP0, m_TEX0.TBW); // Valid only for color formats
|
||||
m_end_block = GSLocalMemory::m_psm[m_TEX0.PSM].info.bn(m_valid.z - 1, m_valid.w - 1, m_TEX0.TBP0, m_TEX0.TBW); // Valid only for color formats
|
||||
|
||||
// GL_CACHE("UpdateValidity (0x%x->0x%x) from R:%d,%d Valid: %d,%d", m_TEX0.TBP0, m_end_block, rect.z, rect.w, m_valid.z, m_valid.w);
|
||||
}
|
||||
|
||||
// GSTextureCache::SourceMap
|
||||
|
||||
void GSTextureCache::SourceMap::Add(Source* s, const GIFRegTEX0& TEX0, GSOffset* off)
|
||||
void GSTextureCache::SourceMap::Add(Source* s, const GIFRegTEX0& TEX0, const GSOffset& off)
|
||||
{
|
||||
m_surfaces.insert(s);
|
||||
|
||||
@@ -2147,26 +2135,10 @@ void GSTextureCache::SourceMap::Add(Source* s, const GIFRegTEX0& TEX0, GSOffset*
|
||||
}
|
||||
|
||||
// The source pointer will be stored/duplicated in all m_map[array of pages]
|
||||
for (size_t i = 0; i < countof(m_pages); i++)
|
||||
s->m_pages.loopPages([this, s](uint32 page)
|
||||
{
|
||||
if (uint32 p = s->m_pages_as_bit[i])
|
||||
{
|
||||
auto* m = &m_map[i << 5];
|
||||
auto* e = &s->m_erase_it[i << 5];
|
||||
|
||||
unsigned long j;
|
||||
|
||||
while (_BitScanForward(&j, p))
|
||||
{
|
||||
// FIXME: this statement could be optimized to a single ASM instruction (instead of 4)
|
||||
// Either BTR (AKA bit test and reset). Depends on the previous instruction.
|
||||
// Or BLSR (AKA Reset Lowest Set Bit). No dependency but require BMI1 (basically a recent CPU)
|
||||
p ^= 1U << j;
|
||||
|
||||
e[j] = m[j].InsertFront(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
s->m_erase_it[page] = m_map[page].InsertFront(s);
|
||||
});
|
||||
}
|
||||
|
||||
void GSTextureCache::SourceMap::RemoveAll()
|
||||
@@ -2197,26 +2169,10 @@ void GSTextureCache::SourceMap::RemoveAt(Source* s)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < countof(m_pages); i++)
|
||||
s->m_pages.loopPages([this, s](uint32 page)
|
||||
{
|
||||
if (uint32 p = s->m_pages_as_bit[i])
|
||||
{
|
||||
auto* m = &m_map[i << 5];
|
||||
const auto* e = &s->m_erase_it[i << 5];
|
||||
|
||||
unsigned long j;
|
||||
|
||||
while (_BitScanForward(&j, p))
|
||||
{
|
||||
// FIXME: this statement could be optimized to a single ASM instruction (instead of 4)
|
||||
// Either BTR (AKA bit test and reset). Depends on the previous instruction.
|
||||
// Or BLSR (AKA Reset Lowest Set Bit). No dependency but require BMI1 (basically a recent CPU)
|
||||
p ^= 1U << j;
|
||||
|
||||
m[j].EraseIndex(e[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_map[page].EraseIndex(s->m_erase_it[page]);
|
||||
});
|
||||
}
|
||||
|
||||
delete s;
|
||||
|
||||
@@ -125,7 +125,7 @@ public:
|
||||
GIFRegTEX0 m_layer_TEX0[7]; // Detect already loaded value
|
||||
// Keep a GSTextureCache::SourceMap::m_map iterator to allow fast erase
|
||||
std::array<uint16, MAX_PAGES> m_erase_it;
|
||||
uint32* m_pages_as_bit;
|
||||
GSOffset::PageLooper m_pages;
|
||||
|
||||
public:
|
||||
Source(GSRenderer* r, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, uint8* temp, bool dummy_container = false);
|
||||
@@ -189,7 +189,7 @@ public:
|
||||
memset(m_pages, 0, sizeof(m_pages));
|
||||
}
|
||||
|
||||
void Add(Source* s, const GIFRegTEX0& TEX0, GSOffset* off);
|
||||
void Add(Source* s, const GIFRegTEX0& TEX0, const GSOffset& off);
|
||||
void RemoveAll();
|
||||
void RemovePartial();
|
||||
void RemoveAt(Source* s);
|
||||
@@ -249,8 +249,8 @@ public:
|
||||
|
||||
void InvalidateVideoMemType(int type, uint32 bp);
|
||||
void InvalidateVideoMemSubTarget(GSTextureCache::Target* rt);
|
||||
void InvalidateVideoMem(GSOffset* off, const GSVector4i& r, bool target = true);
|
||||
void InvalidateLocalMem(GSOffset* off, const GSVector4i& r);
|
||||
void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool target = true);
|
||||
void InvalidateLocalMem(const GSOffset& off, const GSVector4i& r);
|
||||
|
||||
void IncAge();
|
||||
bool UserHacks_HalfPixelOffset;
|
||||
|
||||
@@ -146,7 +146,6 @@ namespace GLLoader
|
||||
|
||||
bool s_first_load = true;
|
||||
|
||||
bool amd_legacy_buggy_driver = false;
|
||||
bool vendor_id_amd = false;
|
||||
bool vendor_id_nvidia = false;
|
||||
bool vendor_id_intel = false;
|
||||
@@ -156,22 +155,19 @@ namespace GLLoader
|
||||
|
||||
bool found_geometry_shader = true; // we require GL3.3 so geometry must be supported by default
|
||||
bool found_GL_ARB_clear_texture = false;
|
||||
bool found_GL_ARB_get_texture_sub_image = false; // Not yet used
|
||||
// DX11 GPU
|
||||
bool found_GL_ARB_gpu_shader5 = false; // Require IvyBridge
|
||||
bool found_GL_ARB_shader_image_load_store = false; // Intel IB. Nvidia/AMD miss Mesa implementation.
|
||||
bool found_GL_ARB_shader_storage_buffer_object = false;
|
||||
bool found_GL_ARB_compute_shader = false;
|
||||
bool found_GL_ARB_texture_view = false; // maybe older gpu can support it ?
|
||||
|
||||
// Mandatory in the future
|
||||
bool found_GL_ARB_multi_bind = false;
|
||||
bool found_GL_ARB_vertex_attrib_binding = false;
|
||||
|
||||
// In case sparse2 isn't supported
|
||||
bool found_compatible_GL_ARB_sparse_texture2 = false;
|
||||
bool found_compatible_sparse_depth = false;
|
||||
|
||||
// Not yet used
|
||||
#ifdef GL_EXT_TEX_SUB_IMAGE
|
||||
bool found_GL_ARB_get_texture_sub_image = false;
|
||||
#endif
|
||||
|
||||
static void mandatory(const std::string& ext)
|
||||
{
|
||||
if (!GLExtension::Has(ext))
|
||||
@@ -211,46 +207,20 @@ namespace GLLoader
|
||||
|
||||
void check_gl_version(int major, int minor)
|
||||
{
|
||||
const GLubyte* s = glGetString(GL_VERSION);
|
||||
if (s == NULL)
|
||||
{
|
||||
fprintf(stderr, "Error: GLLoader failed to get GL version\n");
|
||||
throw GSRecoverableError();
|
||||
}
|
||||
GLuint v = 1;
|
||||
while (s[v] != '\0' && s[v - 1] != ' ')
|
||||
v++;
|
||||
|
||||
const char* vendor = (const char*)glGetString(GL_VENDOR);
|
||||
fprintf_once(stdout, "OpenGL information. GPU: %s. Vendor: %s. Driver: %s\n", glGetString(GL_RENDERER), vendor, &s[v]);
|
||||
|
||||
// Name changed but driver is still bad!
|
||||
if (strstr(vendor, "Advanced Micro Devices") || strstr(vendor, "ATI Technologies Inc.") || strstr(vendor, "ATI"))
|
||||
vendor_id_amd = true;
|
||||
/*if (vendor_id_amd && (
|
||||
strstr((const char*)&s[v], " 10.") || // Blacklist all 2010 AMD drivers.
|
||||
strstr((const char*)&s[v], " 11.") || // Blacklist all 2011 AMD drivers.
|
||||
strstr((const char*)&s[v], " 12.") || // Blacklist all 2012 AMD drivers.
|
||||
strstr((const char*)&s[v], " 13.") || // Blacklist all 2013 AMD drivers.
|
||||
strstr((const char*)&s[v], " 14.") || // Blacklist all 2014 AMD drivers.
|
||||
strstr((const char*)&s[v], " 15.") || // Blacklist all 2015 AMD drivers.
|
||||
strstr((const char*)&s[v], " 16.") || // Blacklist all 2016 AMD drivers.
|
||||
strstr((const char*)&s[v], " 17.") // Blacklist all 2017 AMD drivers for now.
|
||||
))
|
||||
amd_legacy_buggy_driver = true;
|
||||
*/
|
||||
if (strstr(vendor, "NVIDIA Corporation"))
|
||||
else if (strstr(vendor, "NVIDIA Corporation"))
|
||||
vendor_id_nvidia = true;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (strstr(vendor, "Intel"))
|
||||
else if (strstr(vendor, "Intel"))
|
||||
vendor_id_intel = true;
|
||||
#else
|
||||
// On linux assumes the free driver if it isn't nvidia or amd pro driver
|
||||
mesa_driver = !vendor_id_nvidia && !vendor_id_amd;
|
||||
#endif
|
||||
// As of 2019 SSO is still broken on intel (Kaby Lake confirmed).
|
||||
buggy_sso_dual_src = vendor_id_intel || vendor_id_amd /*|| amd_legacy_buggy_driver*/;
|
||||
buggy_sso_dual_src = vendor_id_intel || vendor_id_amd;
|
||||
|
||||
if (theApp.GetConfigI("override_geometry_shader") != -1)
|
||||
{
|
||||
@@ -310,20 +280,17 @@ namespace GLLoader
|
||||
found_GL_ARB_gpu_shader5 = optional("GL_ARB_gpu_shader5");
|
||||
// GL4.2
|
||||
found_GL_ARB_shader_image_load_store = optional("GL_ARB_shader_image_load_store");
|
||||
// GL4.3
|
||||
found_GL_ARB_compute_shader = optional("GL_ARB_compute_shader");
|
||||
found_GL_ARB_shader_storage_buffer_object = optional("GL_ARB_shader_storage_buffer_object");
|
||||
found_GL_ARB_texture_view = optional("GL_ARB_texture_view");
|
||||
found_GL_ARB_vertex_attrib_binding = optional("GL_ARB_vertex_attrib_binding");
|
||||
// GL4.4
|
||||
found_GL_ARB_clear_texture = optional("GL_ARB_clear_texture");
|
||||
found_GL_ARB_multi_bind = optional("GL_ARB_multi_bind");
|
||||
// GL4.5
|
||||
optional("GL_ARB_direct_state_access");
|
||||
// Mandatory for the advance HW renderer effect. Unfortunately Mesa LLVMPIPE/SWR renderers doesn't support this extension.
|
||||
// Rendering might be corrupted but it could be good enough for test/virtual machine.
|
||||
optional("GL_ARB_texture_barrier");
|
||||
// Not yet used
|
||||
#ifdef GL_EXT_TEX_SUB_IMAGE
|
||||
found_GL_ARB_get_texture_sub_image = optional("GL_ARB_get_texture_sub_image");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (vendor_id_amd)
|
||||
|
||||
@@ -35,7 +35,6 @@ namespace GLLoader
|
||||
extern bool vendor_id_amd;
|
||||
extern bool vendor_id_nvidia;
|
||||
extern bool vendor_id_intel;
|
||||
extern bool amd_legacy_buggy_driver;
|
||||
extern bool mesa_driver;
|
||||
extern bool buggy_sso_dual_src;
|
||||
extern bool in_replayer;
|
||||
|
||||
@@ -485,8 +485,6 @@ private:
|
||||
std::unique_ptr<GL::StreamBuffer> m_vertex_stream_buffer;
|
||||
std::unique_ptr<GL::StreamBuffer> m_index_stream_buffer;
|
||||
GLuint m_vertex_array_object = 0;
|
||||
u32 m_vertex_buffer_base_vertex = 0;
|
||||
u32 m_index_buffer_offset = 0;
|
||||
GLenum m_draw_topology = 0;
|
||||
|
||||
std::unique_ptr<GL::StreamBuffer> m_vertex_uniform_stream_buffer;
|
||||
|
||||
@@ -78,7 +78,7 @@ void GSTextureCacheOGL::Read(Target* t, const GSVector4i& r)
|
||||
{
|
||||
// TODO: block level write
|
||||
|
||||
GSOffset* off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
switch (TEX0.PSM)
|
||||
{
|
||||
@@ -125,7 +125,7 @@ void GSTextureCacheOGL::Read(Source* t, const GSVector4i& r)
|
||||
|
||||
if (offscreen->Map(m, &r_offscreen))
|
||||
{
|
||||
GSOffset* off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
GSOffset off = m_renderer->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
m_renderer->m_mem.WritePixel32(m.bits, m.pitch, off, r);
|
||||
|
||||
|
||||
@@ -468,7 +468,7 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
|
||||
// The fastest way will be to use a PBO to read the data asynchronously. Unfortunately GS
|
||||
// architecture is waiting the data right now.
|
||||
|
||||
#if 0
|
||||
#ifdef GL_EXT_TEX_SUB_IMAGE
|
||||
// Maybe it is as good as the code below. I don't know
|
||||
// With openGL 4.5 you can use glGetTextureSubImage
|
||||
|
||||
|
||||
@@ -2811,31 +2811,28 @@ void GSDrawScanline::DrawRect(const GSVector4i& r, const GSVertexSW& v)
|
||||
|
||||
if (m != 0xffffffff)
|
||||
{
|
||||
const int* zbr = m_global.zbr;
|
||||
const int* zbc = m_global.zbc;
|
||||
|
||||
uint32 z = v.t.u32[3]; // (uint32)v.p.z;
|
||||
|
||||
if (m_global.sel.zpsm != 2)
|
||||
{
|
||||
if (m == 0)
|
||||
{
|
||||
DrawRectT<uint32, false>(zbr, zbc, r, z, m);
|
||||
DrawRectT<uint32, false>(m_global.zbo, r, z, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRectT<uint32, true>(zbr, zbc, r, z, m);
|
||||
DrawRectT<uint32, true>(m_global.zbo, r, z, m);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m & 0xffff) == 0)
|
||||
{
|
||||
DrawRectT<uint16, false>(zbr, zbc, r, z, m);
|
||||
DrawRectT<uint16, false>(m_global.zbo, r, z, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRectT<uint16, true>(zbr, zbc, r, z, m);
|
||||
DrawRectT<uint16, true>(m_global.zbo, r, z, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2848,9 +2845,6 @@ void GSDrawScanline::DrawRect(const GSVector4i& r, const GSVertexSW& v)
|
||||
|
||||
if (m != 0xffffffff)
|
||||
{
|
||||
const int* fbr = m_global.fbr;
|
||||
const int* fbc = m_global.fbc;
|
||||
|
||||
uint32 c = (GSVector4i(v.c) >> 7).rgba32();
|
||||
|
||||
if (m_global.sel.fba)
|
||||
@@ -2862,11 +2856,11 @@ void GSDrawScanline::DrawRect(const GSVector4i& r, const GSVertexSW& v)
|
||||
{
|
||||
if (m == 0)
|
||||
{
|
||||
DrawRectT<uint32, false>(fbr, fbc, r, c, m);
|
||||
DrawRectT<uint32, false>(m_global.fbo, r, c, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRectT<uint32, true>(fbr, fbc, r, c, m);
|
||||
DrawRectT<uint32, true>(m_global.fbo, r, c, m);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2875,18 +2869,18 @@ void GSDrawScanline::DrawRect(const GSVector4i& r, const GSVertexSW& v)
|
||||
|
||||
if ((m & 0xffff) == 0)
|
||||
{
|
||||
DrawRectT<uint16, false>(fbr, fbc, r, c, m);
|
||||
DrawRectT<uint16, false>(m_global.fbo, r, c, m);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawRectT<uint16, true>(fbr, fbc, r, c, m);
|
||||
DrawRectT<uint16, true>(m_global.fbo, r, c, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, bool masked>
|
||||
void GSDrawScanline::DrawRectT(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, uint32 c, uint32 m)
|
||||
void GSDrawScanline::DrawRectT(const GSOffset& off, const GSVector4i& r, uint32 c, uint32 m)
|
||||
{
|
||||
if (m == 0xffffffff)
|
||||
return;
|
||||
@@ -2921,25 +2915,25 @@ void GSDrawScanline::DrawRectT(const int* RESTRICT row, const int* RESTRICT col,
|
||||
|
||||
if (!br.rempty())
|
||||
{
|
||||
FillRect<T, masked>(row, col, GSVector4i(r.x, r.y, r.z, br.y), c, m);
|
||||
FillRect<T, masked>(row, col, GSVector4i(r.x, br.w, r.z, r.w), c, m);
|
||||
FillRect<T, masked>(off, GSVector4i(r.x, r.y, r.z, br.y), c, m);
|
||||
FillRect<T, masked>(off, GSVector4i(r.x, br.w, r.z, r.w), c, m);
|
||||
|
||||
if (r.x < br.x || br.z < r.z)
|
||||
{
|
||||
FillRect<T, masked>(row, col, GSVector4i(r.x, br.y, br.x, br.w), c, m);
|
||||
FillRect<T, masked>(row, col, GSVector4i(br.z, br.y, r.z, br.w), c, m);
|
||||
FillRect<T, masked>(off, GSVector4i(r.x, br.y, br.x, br.w), c, m);
|
||||
FillRect<T, masked>(off, GSVector4i(br.z, br.y, r.z, br.w), c, m);
|
||||
}
|
||||
|
||||
FillBlock<T, masked>(row, col, br, color, mask);
|
||||
FillBlock<T, masked>(off, br, color, mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
FillRect<T, masked>(row, col, r, c, m);
|
||||
FillRect<T, masked>(off, r, c, m);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, bool masked>
|
||||
void GSDrawScanline::FillRect(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, uint32 c, uint32 m)
|
||||
void GSDrawScanline::FillRect(const GSOffset& off, const GSVector4i& r, uint32 c, uint32 m)
|
||||
{
|
||||
if (r.x >= r.z)
|
||||
return;
|
||||
@@ -2948,11 +2942,12 @@ void GSDrawScanline::FillRect(const int* RESTRICT row, const int* RESTRICT col,
|
||||
|
||||
for (int y = r.y; y < r.w; y++)
|
||||
{
|
||||
T* RESTRICT d = &vm[row[y]];
|
||||
auto pa = off.paMulti(vm, 0, y);
|
||||
|
||||
for (int x = r.x; x < r.z; x++)
|
||||
{
|
||||
d[col[x]] = (T)(!masked ? c : (c | (d[col[x]] & m)));
|
||||
T& d = *pa.value(x);
|
||||
d = (T)(!masked ? c : (c | (d & m)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2960,7 +2955,7 @@ void GSDrawScanline::FillRect(const int* RESTRICT row, const int* RESTRICT col,
|
||||
#if _M_SSE >= 0x501
|
||||
|
||||
template <class T, bool masked>
|
||||
void GSDrawScanline::FillBlock(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, const GSVector8i& c, const GSVector8i& m)
|
||||
void GSDrawScanline::FillBlock(const GSOffset& off, const GSVector4i& r, const GSVector8i& c, const GSVector8i& m)
|
||||
{
|
||||
if (r.x >= r.z)
|
||||
return;
|
||||
@@ -2969,11 +2964,9 @@ void GSDrawScanline::FillBlock(const int* RESTRICT row, const int* RESTRICT col,
|
||||
|
||||
for (int y = r.y; y < r.w; y += 8)
|
||||
{
|
||||
T* RESTRICT d = &vm[row[y]];
|
||||
|
||||
for (int x = r.x; x < r.z; x += 8 * 4 / sizeof(T))
|
||||
{
|
||||
GSVector8i* RESTRICT p = (GSVector8i*)&d[col[x]];
|
||||
GSVector8i* RESTRICT p = (GSVector8i*)&vm[off.pa(x, y)];
|
||||
|
||||
p[0] = !masked ? c : (c | (p[0] & m));
|
||||
p[1] = !masked ? c : (c | (p[1] & m));
|
||||
@@ -2990,7 +2983,7 @@ void GSDrawScanline::FillBlock(const int* RESTRICT row, const int* RESTRICT col,
|
||||
#else
|
||||
|
||||
template <class T, bool masked>
|
||||
void GSDrawScanline::FillBlock(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m)
|
||||
void GSDrawScanline::FillBlock(const GSOffset& off, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m)
|
||||
{
|
||||
if (r.x >= r.z)
|
||||
return;
|
||||
@@ -2999,11 +2992,11 @@ void GSDrawScanline::FillBlock(const int* RESTRICT row, const int* RESTRICT col,
|
||||
|
||||
for (int y = r.y; y < r.w; y += 8)
|
||||
{
|
||||
T* RESTRICT d = &vm[row[y]];
|
||||
auto pa = off.paMulti(vm, 0, y);
|
||||
|
||||
for (int x = r.x; x < r.z; x += 8 * 4 / sizeof(T))
|
||||
{
|
||||
GSVector4i* RESTRICT p = (GSVector4i*)&d[col[x]];
|
||||
GSVector4i* RESTRICT p = (GSVector4i*)pa.value(x);
|
||||
|
||||
for (int i = 0; i < 16; i += 4)
|
||||
{
|
||||
|
||||
@@ -38,20 +38,20 @@ protected:
|
||||
GSCodeGeneratorFunctionMap<GSDrawScanlineCodeGenerator, uint64, DrawScanlinePtr> m_ds_map;
|
||||
|
||||
template <class T, bool masked>
|
||||
void DrawRectT(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, uint32 c, uint32 m);
|
||||
void DrawRectT(const GSOffset& off, const GSVector4i& r, uint32 c, uint32 m);
|
||||
|
||||
template <class T, bool masked>
|
||||
__forceinline void FillRect(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, uint32 c, uint32 m);
|
||||
__forceinline void FillRect(const GSOffset& off, const GSVector4i& r, uint32 c, uint32 m);
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
|
||||
template <class T, bool masked>
|
||||
__forceinline void FillBlock(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, const GSVector8i& c, const GSVector8i& m);
|
||||
__forceinline void FillBlock(const GSOffset& off, const GSVector4i& r, const GSVector8i& c, const GSVector8i& m);
|
||||
|
||||
#else
|
||||
|
||||
template <class T, bool masked>
|
||||
__forceinline void FillBlock(const int* RESTRICT row, const int* RESTRICT col, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m);
|
||||
__forceinline void FillBlock(const GSOffset& off, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,189 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSScanlineEnvironment.h"
|
||||
#include "GSNewCodeGenerator.h"
|
||||
|
||||
#undef _t // Conflict with wx, hopefully no one needs this
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
#define DRAW_SCANLINE_VECTOR_REGISTER Xbyak::Ymm
|
||||
#define DRAW_SCANLINE_USING_XMM 0
|
||||
#define DRAW_SCANLINE_USING_YMM 1
|
||||
#else
|
||||
#define DRAW_SCANLINE_VECTOR_REGISTER Xbyak::Xmm
|
||||
#define DRAW_SCANLINE_USING_XMM 1
|
||||
#define DRAW_SCANLINE_USING_YMM 0
|
||||
#endif
|
||||
|
||||
class GSDrawScanlineCodeGenerator2 : public GSNewCodeGenerator
|
||||
{
|
||||
using _parent = GSNewCodeGenerator;
|
||||
using XYm = DRAW_SCANLINE_VECTOR_REGISTER;
|
||||
|
||||
/// On x86-64 we reserve a bunch of GPRs for holding addresses of locals that would otherwise be hard to reach
|
||||
/// On x86-32 the same values are just raw 32-bit addresses
|
||||
using LocalAddr = Choose3264<size_t, AddressReg>::type;
|
||||
|
||||
constexpr static bool isXmm = std::is_same<XYm, Xbyak::Xmm>::value;
|
||||
constexpr static bool isYmm = std::is_same<XYm, Xbyak::Ymm>::value;
|
||||
constexpr static int wordsize = is64 ? 8 : 4;
|
||||
constexpr static int vecsize = isXmm ? 16 : 32;
|
||||
constexpr static int vecsizelog = isXmm ? 4 : 5;
|
||||
constexpr static int vecints = vecsize / 4;
|
||||
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
constexpr static int _32_args = 16;
|
||||
constexpr static int _invalid = 0xaaaaaaaa;
|
||||
#ifdef _WIN32
|
||||
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;
|
||||
// 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;
|
||||
#else
|
||||
// System-V has a redzone so stick everything there
|
||||
constexpr static int _64_rz_rbx = -8 * 1;
|
||||
constexpr static int _64_rz_r12 = -8 * 2;
|
||||
constexpr static int _64_rz_r13 = -8 * 3;
|
||||
constexpr static int _64_rz_r14 = -8 * 4;
|
||||
constexpr static int _64_rz_r15 = -8 * 5;
|
||||
constexpr static int _64_top = -8 * 6;
|
||||
#endif
|
||||
constexpr static int _top = is64 ? _64_top : _32_args + 4;
|
||||
constexpr static int _v = is64 ? _invalid : _32_args + 8;
|
||||
|
||||
GSScanlineSelector m_sel;
|
||||
GSScanlineLocalData& m_local;
|
||||
bool m_rip;
|
||||
bool use_lod;
|
||||
|
||||
const XYm xym0{0}, xym1{1}, xym2{2}, xym3{3}, xym4{4}, xym5{5}, xym6{6}, xym7{7}, xym8{8}, xym9{9}, xym10{10}, xym11{11}, xym12{12}, xym13{13}, xym14{14}, xym15{15};
|
||||
/// 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 LocalAddr _g_const, _m_local, _m_local__gd, _m_local__gd__vm;
|
||||
/// Available on both x86 and x64, not always valid
|
||||
const XYm _rb, _ga, _fm, _zm, _fd, _test;
|
||||
/// Always valid if needed, x64 only
|
||||
const XYm _z, _f, _s, _t, _q, _f_rb, _f_ga;
|
||||
|
||||
/// Returns the first arg on 32-bit, second on 64-bit
|
||||
static LocalAddr chooseLocal(const void* addr32, AddressReg reg64)
|
||||
{
|
||||
return choose3264((size_t)addr32, reg64);
|
||||
}
|
||||
|
||||
public:
|
||||
GSDrawScanlineCodeGenerator2(Xbyak::CodeGenerator* base, CPUInfo cpu, void* param, uint64 key);
|
||||
void Generate();
|
||||
|
||||
private:
|
||||
/// Loads the given address into the given register if needed, and returns something that can be used in a `ptr[]`
|
||||
LocalAddr loadAddress(AddressReg reg, const void* addr);
|
||||
/// Broadcast 128 bits of floats from memory to the whole register, whatever size that register might be
|
||||
void broadcastf128(const XYm& reg, const Xbyak::Address& mem);
|
||||
/// Broadcast 128 bits of integers from memory to the whole register, whatever size that register might be
|
||||
void broadcasti128(const XYm& reg, const Xbyak::Address& mem);
|
||||
/// Broadcast a floating-point variable stored in GSScanlineLocalData to the whole register
|
||||
/// On YMM registers this will be a broadcast from a 32-bit value
|
||||
/// On XMM registers this will be a load of a full 128-bit value, with the broadcast happening before storing to the local data
|
||||
void broadcastssLocal(const XYm& reg, const Xbyak::Address& mem);
|
||||
/// Broadcast a qword variable stored in GSScanlineLocalData to the whole register
|
||||
/// On YMM registers this will be a broadcast from a 64-bit value
|
||||
/// On XMM registers this will be a load of a full 128-bit value, with the broadcast happening before storing to the local data
|
||||
void pbroadcastqLocal(const XYm& reg, const Xbyak::Address& mem);
|
||||
/// Broadcast a dword variable stored in GSScanlineLocalData to the whole register
|
||||
/// On YMM registers this will be a broadcast from a 32-bit value
|
||||
/// On XMM registers this will be a load of a full 128-bit value, with the broadcast happening before storing to the local data
|
||||
void pbroadcastdLocal(const XYm& reg, const Xbyak::Address& mem);
|
||||
/// Broadcast a word variable stored in GSScanlineLocalData to the whole register
|
||||
/// On YMM registers this will be a broadcast from a 16-bit value
|
||||
/// On XMM registers this will be a load of a full 128-bit value, with the broadcast happening before storing to the local data
|
||||
void pbroadcastwLocal(const XYm& reg, const Xbyak::Address& mem);
|
||||
/// Broadcast a 32-bit GPR to a vector register
|
||||
void broadcastGPRToVec(const XYm& vec, const Xbyak::Reg32& gpr);
|
||||
void modulate16(const XYm& a, const Xbyak::Operand& f, uint8 shift);
|
||||
void lerp16(const XYm& a, const XYm& b, const XYm& f, uint8 shift);
|
||||
void lerp16_4(const XYm& a, const XYm& b, const XYm& f);
|
||||
void mix16(const XYm& a, const XYm& b, const XYm& temp);
|
||||
void clamp16(const XYm& a, const XYm& temp);
|
||||
void alltrue(const XYm& test);
|
||||
void blend(const XYm& a, const XYm& b, const XYm& mask);
|
||||
void blendr(const XYm& b, const XYm& a, const XYm& mask);
|
||||
void blend8(const XYm& a, const XYm& b);
|
||||
void blend8r(const XYm& b, const XYm& a);
|
||||
void split16_2x8(const XYm& l, const XYm& h, const XYm& src);
|
||||
|
||||
void Init();
|
||||
void Step();
|
||||
void TestZ(const XYm& temp1, const XYm& temp2);
|
||||
void SampleTexture();
|
||||
void SampleTexture_TexelReadHelper(int mip_offset);
|
||||
void Wrap(const XYm& uv);
|
||||
void Wrap(const XYm& uv0, const XYm& uv1);
|
||||
void SampleTextureLOD();
|
||||
void WrapLOD(const XYm& uv);
|
||||
void WrapLOD(const XYm& uv0, const XYm& uv1);
|
||||
void AlphaTFX();
|
||||
void ReadMask();
|
||||
void TestAlpha();
|
||||
void ColorTFX();
|
||||
void Fog();
|
||||
void ReadFrame();
|
||||
void TestDestAlpha();
|
||||
void WriteMask();
|
||||
void WriteZBuf();
|
||||
void AlphaBlend();
|
||||
void WriteFrame();
|
||||
void ReadPixel(const XYm& dst, const XYm& tmp, const AddressReg& addr);
|
||||
#if DRAW_SCANLINE_USING_XMM
|
||||
void WritePixel(const XYm& src_, const AddressReg& addr, const Xbyak::Reg8& mask, bool fast, int psm, int fz);
|
||||
#else
|
||||
void WritePixel(const XYm& src_, const AddressReg& addr, const Xbyak::Reg32& mask, bool fast, int psm, int fz);
|
||||
#endif
|
||||
void WritePixel(const Xmm& src, const AddressReg& addr, uint8 i, uint8 j, int psm);
|
||||
void ReadTexel1(const XYm& dst, const XYm& src, const XYm& tmp1, const XYm& tmp2, int mip_offset);
|
||||
void ReadTexel4(
|
||||
const XYm& d0, const XYm& d1,
|
||||
const XYm& d2s0, const XYm& d3s1,
|
||||
const XYm& s2, const XYm& s3,
|
||||
const XYm& tmp1, const XYm& tmp2,
|
||||
int mip_offset);
|
||||
void ReadTexelImpl(
|
||||
const XYm& d0, const XYm& d1,
|
||||
const XYm& d2s0, const XYm& d3s1,
|
||||
const XYm& s2, const XYm& s3,
|
||||
const XYm& tmp1, const XYm& tmp2,
|
||||
int pixels, int mip_offset);
|
||||
void ReadTexelImplLoadTexLOD(int lod, int mip_offset);
|
||||
void ReadTexelImplYmm(
|
||||
const Ymm& d0, const Ymm& d1,
|
||||
const Ymm& d2s0, const Ymm& d3s1,
|
||||
const Ymm& s2, const Ymm& s3,
|
||||
const Ymm& tmp,
|
||||
int pixels, int mip_offset);
|
||||
void ReadTexelImplSSE4(
|
||||
const Xmm& d0, const Xmm& d1,
|
||||
const Xmm& d2s0, const Xmm& d3s1,
|
||||
const Xmm& s2, const Xmm& s3,
|
||||
int pixels, int mip_offset);
|
||||
void ReadTexelImpl(const Xmm& dst, const Xmm& addr, uint8 i, bool texInA3, bool preserveDst);
|
||||
};
|
||||
@@ -15,17 +15,8 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSDrawScanlineCodeGenerator.h"
|
||||
#include "GSDrawScanlineCodeGenerator.all.h"
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
#else
|
||||
void GSDrawScanlineCodeGenerator::Generate()
|
||||
{
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
Generate_AVX();
|
||||
else
|
||||
Generate_SSE();
|
||||
}
|
||||
#endif
|
||||
|
||||
GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(void* param, uint64 key, void* code, size_t maxsize)
|
||||
: GSCodeGenerator(code, maxsize)
|
||||
@@ -37,227 +28,5 @@ GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(void* param, uint64 key
|
||||
if (m_sel.breakpoint)
|
||||
db(0xCC);
|
||||
|
||||
try
|
||||
{
|
||||
Generate();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fprintf(stderr, "ERR:GSDrawScanlineCodeGenerator %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::modulate16(const Xmm& a, const Operand& f, uint8 shift)
|
||||
{
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
{
|
||||
if (shift == 0)
|
||||
{
|
||||
vpmulhrsw(a, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
vpsllw(a, shift + 1);
|
||||
vpmulhw(a, f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (shift == 0 && m_cpu.has(Xbyak::util::Cpu::tSSSE3))
|
||||
{
|
||||
pmulhrsw(a, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
psllw(a, shift + 1);
|
||||
pmulhw(a, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::lerp16(const Xmm& a, const Xmm& b, const Xmm& f, uint8 shift)
|
||||
{
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
{
|
||||
vpsubw(a, b);
|
||||
modulate16(a, f, shift);
|
||||
vpaddw(a, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
psubw(a, b);
|
||||
modulate16(a, f, shift);
|
||||
paddw(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::lerp16_4(const Xmm& a, const Xmm& b, const Xmm& f)
|
||||
{
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
{
|
||||
vpsubw(a, b);
|
||||
vpmullw(a, f);
|
||||
vpsraw(a, 4);
|
||||
vpaddw(a, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
psubw(a, b);
|
||||
pmullw(a, f);
|
||||
psraw(a, 4);
|
||||
paddw(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::mix16(const Xmm& a, const Xmm& b, const Xmm& temp)
|
||||
{
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
{
|
||||
vpblendw(a, b, 0xaa);
|
||||
}
|
||||
else
|
||||
{
|
||||
pblendw(a, b, 0xaa);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::clamp16(const Xmm& a, const Xmm& temp)
|
||||
{
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
{
|
||||
vpackuswb(a, a);
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
// Greg: why ?
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX2))
|
||||
{
|
||||
ASSERT(a.isYMM());
|
||||
vpermq(Ymm(a.getIdx()), Ymm(a.getIdx()), _MM_SHUFFLE(3, 1, 2, 0)); // this sucks
|
||||
}
|
||||
#endif
|
||||
|
||||
vpmovzxbw(a, a);
|
||||
}
|
||||
else
|
||||
{
|
||||
packuswb(a, a);
|
||||
pmovzxbw(a, a);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::alltrue(const Xmm& test)
|
||||
{
|
||||
uint32 mask = test.isYMM() ? 0xffffffff : 0xffff;
|
||||
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
{
|
||||
vpmovmskb(eax, test);
|
||||
cmp(eax, mask);
|
||||
je("step", T_NEAR);
|
||||
}
|
||||
else
|
||||
{
|
||||
pmovmskb(eax, test);
|
||||
cmp(eax, mask);
|
||||
je("step", T_NEAR);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::blend(const Xmm& a, const Xmm& b, const Xmm& mask)
|
||||
{
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
{
|
||||
vpand(b, mask);
|
||||
vpandn(mask, a);
|
||||
vpor(a, b, mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
pand(b, mask);
|
||||
pandn(mask, a);
|
||||
por(b, mask);
|
||||
movdqa(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::blendr(const Xmm& b, const Xmm& a, const Xmm& mask)
|
||||
{
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
{
|
||||
vpand(b, mask);
|
||||
vpandn(mask, a);
|
||||
vpor(b, mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
pand(b, mask);
|
||||
pandn(mask, a);
|
||||
por(b, mask);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::blend8(const Xmm& a, const Xmm& b)
|
||||
{
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
vpblendvb(a, a, b, xmm0);
|
||||
else
|
||||
pblendvb(a, b);
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::blend8r(const Xmm& b, const Xmm& a)
|
||||
{
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
{
|
||||
vpblendvb(b, a, b, xmm0);
|
||||
}
|
||||
else
|
||||
{
|
||||
pblendvb(a, b);
|
||||
movdqa(b, a);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::split16_2x8(const Xmm& l, const Xmm& h, const Xmm& src)
|
||||
{
|
||||
// l = src & 0xFF; (1 left shift + 1 right shift)
|
||||
// h = (src >> 8) & 0xFF; (1 right shift)
|
||||
|
||||
if (m_cpu.has(Xbyak::util::Cpu::tAVX))
|
||||
{
|
||||
if (src == h)
|
||||
{
|
||||
vpsllw(l, src, 8);
|
||||
vpsrlw(h, 8);
|
||||
}
|
||||
else if (src == l)
|
||||
{
|
||||
vpsrlw(h, src, 8);
|
||||
vpsllw(l, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
vpsllw(l, src, 8);
|
||||
vpsrlw(h, src, 8);
|
||||
}
|
||||
vpsrlw(l, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (src == h)
|
||||
{
|
||||
movdqa(l, src);
|
||||
}
|
||||
else if (src == l)
|
||||
{
|
||||
movdqa(h, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
movdqa(l, src);
|
||||
movdqa(h, src);
|
||||
}
|
||||
psllw(l, 8);
|
||||
psrlw(l, 8);
|
||||
psrlw(h, 8);
|
||||
}
|
||||
GSDrawScanlineCodeGenerator2(this, CPUInfo(m_cpu), (void*)&m_local, m_sel.key).Generate();
|
||||
}
|
||||
|
||||
@@ -27,117 +27,12 @@
|
||||
|
||||
class GSDrawScanlineCodeGenerator : public GSCodeGenerator
|
||||
{
|
||||
typedef Xbyak::Ymm Ymm;
|
||||
typedef Xbyak::Xmm Xmm;
|
||||
typedef Xbyak::Reg8 Reg8;
|
||||
typedef Xbyak::Operand Operand;
|
||||
|
||||
void operator=(const GSDrawScanlineCodeGenerator&);
|
||||
|
||||
GSScanlineSelector m_sel;
|
||||
GSScanlineLocalData& m_local;
|
||||
bool m_rip;
|
||||
|
||||
void Generate();
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
|
||||
void Init();
|
||||
void Step();
|
||||
void TestZ(const Ymm& temp1, const Ymm& temp2);
|
||||
void SampleTexture();
|
||||
void Wrap(const Ymm& uv0);
|
||||
void Wrap(const Ymm& uv0, const Ymm& uv1);
|
||||
void SampleTextureLOD();
|
||||
void WrapLOD(const Ymm& uv0);
|
||||
void WrapLOD(const Ymm& uv0, const Ymm& uv1);
|
||||
void AlphaTFX();
|
||||
void ReadMask();
|
||||
void TestAlpha();
|
||||
void ColorTFX();
|
||||
void Fog();
|
||||
void ReadFrame();
|
||||
void TestDestAlpha();
|
||||
void WriteMask();
|
||||
void WriteZBuf();
|
||||
void AlphaBlend();
|
||||
void WriteFrame();
|
||||
void ReadPixel(const Ymm& dst, const Ymm& temp, const RegLong& addr);
|
||||
void WritePixel(const Ymm& src, const Ymm& temp, const RegLong& addr, const Xbyak::Reg32& mask, bool fast, int psm, int fz);
|
||||
void WritePixel(const Xmm& src, const RegLong& addr, uint8 i, uint8 j, int psm);
|
||||
void ReadTexel(int pixels, int mip_offset = 0);
|
||||
void ReadTexel(const Ymm& dst, const Ymm& addr, uint8 i);
|
||||
|
||||
#else
|
||||
|
||||
void Generate_SSE();
|
||||
void Init_SSE();
|
||||
void Step_SSE();
|
||||
void TestZ_SSE(const Xmm& temp1, const Xmm& temp2);
|
||||
void SampleTexture_SSE();
|
||||
void Wrap_SSE(const Xmm& uv0);
|
||||
void Wrap_SSE(const Xmm& uv0, const Xmm& uv1);
|
||||
void SampleTextureLOD_SSE();
|
||||
void WrapLOD_SSE(const Xmm& uv0);
|
||||
void WrapLOD_SSE(const Xmm& uv0, const Xmm& uv1);
|
||||
void AlphaTFX_SSE();
|
||||
void ReadMask_SSE();
|
||||
void TestAlpha_SSE();
|
||||
void ColorTFX_SSE();
|
||||
void Fog_SSE();
|
||||
void ReadFrame_SSE();
|
||||
void TestDestAlpha_SSE();
|
||||
void WriteMask_SSE();
|
||||
void WriteZBuf_SSE();
|
||||
void AlphaBlend_SSE();
|
||||
void WriteFrame_SSE();
|
||||
void ReadPixel_SSE(const Xmm& dst, const RegLong& addr);
|
||||
void WritePixel_SSE(const Xmm& src, const RegLong& addr, const Reg8& mask, bool fast, int psm, int fz);
|
||||
void WritePixel_SSE(const Xmm& src, const RegLong& addr, uint8 i, int psm);
|
||||
void ReadTexel_SSE(int pixels, int mip_offset = 0);
|
||||
void ReadTexel_SSE(const Xmm& dst, const Xmm& addr, uint8 i);
|
||||
|
||||
void Generate_AVX();
|
||||
void Init_AVX();
|
||||
void Step_AVX();
|
||||
void TestZ_AVX(const Xmm& temp1, const Xmm& temp2);
|
||||
void SampleTexture_AVX();
|
||||
void Wrap_AVX(const Xmm& uv0);
|
||||
void Wrap_AVX(const Xmm& uv0, const Xmm& uv1);
|
||||
void SampleTextureLOD_AVX();
|
||||
void WrapLOD_AVX(const Xmm& uv0);
|
||||
void WrapLOD_AVX(const Xmm& uv0, const Xmm& uv1);
|
||||
void AlphaTFX_AVX();
|
||||
void ReadMask_AVX();
|
||||
void TestAlpha_AVX();
|
||||
void ColorTFX_AVX();
|
||||
void Fog_AVX();
|
||||
void ReadFrame_AVX();
|
||||
void TestDestAlpha_AVX();
|
||||
void WriteMask_AVX();
|
||||
void WriteZBuf_AVX();
|
||||
void AlphaBlend_AVX();
|
||||
void WriteFrame_AVX();
|
||||
void ReadPixel_AVX(const Xmm& dst, const RegLong& addr);
|
||||
void WritePixel_AVX(const Xmm& src, const RegLong& addr, const Reg8& mask, bool fast, int psm, int fz);
|
||||
void WritePixel_AVX(const Xmm& src, const RegLong& addr, uint8 i, int psm);
|
||||
void ReadTexel_AVX(int pixels, int mip_offset = 0);
|
||||
void ReadTexel_AVX(const Xmm& dst, const Xmm& addr, uint8 i);
|
||||
|
||||
#endif
|
||||
|
||||
void modulate16(const Xmm& a, const Operand& f, uint8 shift);
|
||||
void lerp16(const Xmm& a, const Xmm& b, const Xmm& f, uint8 shift);
|
||||
void lerp16_4(const Xmm& a, const Xmm& b, const Xmm& f);
|
||||
void mix16(const Xmm& a, const Xmm& b, const Xmm& temp);
|
||||
void clamp16(const Xmm& a, const Xmm& temp);
|
||||
void alltrue(const Xmm& test);
|
||||
void blend(const Xmm& a, const Xmm& b, const Xmm& mask);
|
||||
void blendr(const Xmm& b, const Xmm& a, const Xmm& mask);
|
||||
void blend8(const Xmm& a, const Xmm& b);
|
||||
void blend8r(const Xmm& b, const Xmm& a);
|
||||
void split16_2x8(const Xmm& l, const Xmm& h, const Xmm& src);
|
||||
|
||||
public:
|
||||
GSDrawScanlineCodeGenerator(void* param, uint64 key, void* code, size_t maxsize);
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,118 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSDrawScanlineCodeGenerator.h"
|
||||
|
||||
#if _M_SSE < 0x501 && (defined(_M_AMD64) || defined(_WIN64))
|
||||
|
||||
// It is useless to port the code to SSEx, better use the faster 32 bits version instead
|
||||
void GSDrawScanlineCodeGenerator::Generate_SSE()
|
||||
{
|
||||
// Avoid a crash if someone want to use it
|
||||
ret();
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::Init_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::Step_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::TestZ_SSE(const Xmm& temp1, const Xmm& temp2)
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::SampleTexture_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::Wrap_SSE(const Xmm& uv)
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::Wrap_SSE(const Xmm& uv0, const Xmm& uv1)
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::AlphaTFX_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::ReadMask_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::TestAlpha_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::ColorTFX_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::Fog_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::ReadFrame_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::TestDestAlpha_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::WriteMask_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::WriteZBuf_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::AlphaBlend_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::WriteFrame_SSE()
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::ReadPixel_SSE(const Xmm& dst, const RegLong& addr)
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::WritePixel_SSE(const Xmm& src, const RegLong& addr, const Reg8& mask, bool fast, int psm, int fz)
|
||||
{
|
||||
}
|
||||
|
||||
//static const int s_offsets[4] = {0, 2, 8, 10};
|
||||
|
||||
void GSDrawScanlineCodeGenerator::WritePixel_SSE(const Xmm& src, const RegLong& addr, uint8 i, int psm)
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::ReadTexel_SSE(int pixels, int mip_offset)
|
||||
{
|
||||
}
|
||||
|
||||
void GSDrawScanlineCodeGenerator::ReadTexel_SSE(const Xmm& dst, const Xmm& addr, uint8 i)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -13,26 +13,5 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
using namespace Xbyak;
|
||||
|
||||
#ifdef _M_AMD64
|
||||
// Yeah let use mips naming ;)
|
||||
#ifdef _WIN64
|
||||
#define a0 rcx
|
||||
#define a1 rdx
|
||||
#define a2 r8
|
||||
#define a3 r9
|
||||
#define t0 rdi
|
||||
#define t1 rsi
|
||||
#else
|
||||
#define a0 rdi
|
||||
#define a1 rsi
|
||||
#define a2 rdx
|
||||
#define a3 rcx
|
||||
#define t0 r8
|
||||
#define t1 r9
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSNewCodeGenerator.h"
|
||||
@@ -0,0 +1,489 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS/GS_types.h"
|
||||
#include "xbyak/xbyak.h"
|
||||
#include "xbyak/xbyak_util.h"
|
||||
|
||||
namespace SSEVersion
|
||||
{
|
||||
enum SSEVersion
|
||||
{
|
||||
AVX2 = 0x501,
|
||||
AVX = 0x500,
|
||||
SSE41 = 0x401,
|
||||
};
|
||||
}
|
||||
|
||||
/// Similar to Xbyak::util::cpu but more open to us putting in extra flags (e.g. "vpgatherdd is fast"), as well as making it easier to test other configurations by artifically limiting features
|
||||
struct CPUInfo
|
||||
{
|
||||
bool hasFMA = false;
|
||||
SSEVersion::SSEVersion sseVersion = SSEVersion::SSE41;
|
||||
|
||||
CPUInfo() = default;
|
||||
CPUInfo(const Xbyak::util::Cpu& cpu)
|
||||
{
|
||||
auto version = SSEVersion::SSE41;
|
||||
if (cpu.has(cpu.tAVX))
|
||||
version = SSEVersion::AVX;
|
||||
if (cpu.has(cpu.tAVX2))
|
||||
version = SSEVersion::AVX2;
|
||||
|
||||
hasFMA = cpu.has(cpu.tFMA);
|
||||
sseVersion = version;
|
||||
}
|
||||
};
|
||||
|
||||
/// Code generator that automatically selects between SSE and AVX, x86 and x64 so you don't have to
|
||||
/// Should make combined SSE and AVX codegen much easier
|
||||
class GSNewCodeGenerator
|
||||
{
|
||||
public:
|
||||
using Address = Xbyak::Address;
|
||||
using Label = Xbyak::Label;
|
||||
using Operand = Xbyak::Operand;
|
||||
using Reg32e = Xbyak::Reg32e;
|
||||
using Reg32 = Xbyak::Reg32;
|
||||
using Reg16 = Xbyak::Reg16;
|
||||
using Reg8 = Xbyak::Reg8;
|
||||
using Reg = Xbyak::Reg;
|
||||
using Xmm = Xbyak::Xmm;
|
||||
using Ymm = Xbyak::Ymm;
|
||||
using Zmm = Xbyak::Zmm;
|
||||
|
||||
class Error : public std::exception
|
||||
{
|
||||
public:
|
||||
enum Value
|
||||
{
|
||||
ERR_64_BIT_REG_IN_32,
|
||||
ERR_64_INSTR_IN_32,
|
||||
ERR_SSE_INSTR_IN_AVX,
|
||||
ERR_AVX_INSTR_IN_SSE,
|
||||
};
|
||||
|
||||
Value value;
|
||||
|
||||
Error(Value value) : value(value) {}
|
||||
|
||||
const char* what() const noexcept
|
||||
{
|
||||
static const char* tbl[] = {
|
||||
"used 64-bit register in 32-bit code",
|
||||
"used 64-bit only instruction in 32-bit code",
|
||||
"used SSE instruction in AVX code",
|
||||
"used AVX instruction in SSE code",
|
||||
};
|
||||
if (static_cast<uint32>(value) < (sizeof(tbl) / sizeof(*tbl)))
|
||||
{
|
||||
return tbl[value];
|
||||
}
|
||||
else
|
||||
{
|
||||
return "GSNewCodeGenerator Unknown Error";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/// Make sure the register is okay to use
|
||||
void validateRegister(const Operand& op)
|
||||
{
|
||||
if (is64)
|
||||
return;
|
||||
if (op.isREG() && (op.isExtIdx() || op.isExt8bit()))
|
||||
throw Error(Error::ERR_64_BIT_REG_IN_32);
|
||||
if (op.isMEM())
|
||||
{
|
||||
auto e = static_cast<const Address&>(op).getRegExp();
|
||||
validateRegister(e.getIndex());
|
||||
validateRegister(e.getBase());
|
||||
}
|
||||
}
|
||||
/// For easier macro-ing
|
||||
void validateRegister(int imm)
|
||||
{
|
||||
}
|
||||
|
||||
void require64()
|
||||
{
|
||||
if (!is64)
|
||||
throw Error(Error::ERR_64_INSTR_IN_32);
|
||||
}
|
||||
void requireAVX()
|
||||
{
|
||||
if (!hasAVX)
|
||||
throw Error(Error::ERR_AVX_INSTR_IN_SSE);
|
||||
}
|
||||
|
||||
public:
|
||||
Xbyak::CodeGenerator& actual;
|
||||
|
||||
#if defined(_M_X86_64)
|
||||
constexpr static bool is32 = false;
|
||||
constexpr static bool is64 = true;
|
||||
using AddressReg = Xbyak::Reg64;
|
||||
using RipType = Xbyak::RegRip;
|
||||
|
||||
template <typename T32, typename T64>
|
||||
struct Choose3264 { using type = T64; };
|
||||
|
||||
template <typename T32, typename T64>
|
||||
static T64 choose3264(T32 t32, T64 t64) { return t64; }
|
||||
#else
|
||||
constexpr static bool is32 = true;
|
||||
constexpr static bool is64 = false;
|
||||
using AddressReg = Xbyak::Reg32;
|
||||
using RipType = int;
|
||||
|
||||
template <typename T32, typename T64>
|
||||
struct Choose3264 { using type = T32; };
|
||||
|
||||
template <typename T32, typename T64>
|
||||
static T32 choose3264(T32 t32, T64 t64) { return t32; }
|
||||
#endif
|
||||
|
||||
const bool hasAVX, hasAVX2, hasFMA;
|
||||
|
||||
const Xmm xmm0{0}, xmm1{1}, xmm2{2}, xmm3{3}, xmm4{4}, xmm5{5}, xmm6{6}, xmm7{7}, xmm8{8}, xmm9{9}, xmm10{10}, xmm11{11}, xmm12{12}, xmm13{13}, xmm14{14}, xmm15{15};
|
||||
const Ymm ymm0{0}, ymm1{1}, ymm2{2}, ymm3{3}, ymm4{4}, ymm5{5}, ymm6{6}, ymm7{7}, ymm8{8}, ymm9{9}, ymm10{10}, ymm11{11}, ymm12{12}, ymm13{13}, ymm14{14}, ymm15{15};
|
||||
const AddressReg rax{0}, rcx{1}, rdx{2}, rbx{3}, rsp{4}, rbp{5}, rsi{6}, rdi{7}, r8{8}, r9{9}, r10{10}, r11{11}, r12{12}, r13{13}, r14{14}, r15{15};
|
||||
const Reg32 eax{0}, ecx{1}, edx{2}, ebx{3}, esp{4}, ebp{5}, esi{6}, edi{7}, r8d{8}, r9d{9}, r10d{10}, r11d{11}, r12d{12}, r13d{13}, r14d{14}, r15d{15};
|
||||
const Reg16 ax{0}, cx{1}, dx{2}, bx{3}, sp{4}, bp{5}, si{6}, di{7};
|
||||
const Reg8 al{0}, cl{1}, dl{2}, bl{3}, ah{4}, ch{5}, dh{6}, bh{7};
|
||||
|
||||
const RipType rip{};
|
||||
const Xbyak::AddressFrame ptr{0}, byte{8}, word{16}, dword{32}, qword{64}, xword{128}, yword{256}, zword{512};
|
||||
|
||||
GSNewCodeGenerator(Xbyak::CodeGenerator* actual, CPUInfo cpu)
|
||||
: actual(*actual)
|
||||
, hasAVX(cpu.sseVersion >= SSEVersion::AVX)
|
||||
, hasAVX2(cpu.sseVersion >= SSEVersion::AVX2)
|
||||
, hasFMA(cpu.hasFMA)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// ------------ Forwarding instructions ------------
|
||||
// Note: Only instructions used by codegen were added here, so if you're modifying codegen, you may need to add instructions here
|
||||
|
||||
// For instructions available in SSE and AVX, functions with the SSE name and arguments that forward to SSE or AVX depending on the target, as well as functions with the AVX name and arguments that forward to the AVX version or assert on SSE
|
||||
|
||||
// ARGS_* macros are provided for shorter argument lists. The following single-letter abbreviations are used: X=Xmm, Y=Ymm, O=Operand, A=Address, I=Immediate
|
||||
// FORWARD(argcount, category, instrname, argtypes...) forwards an instruction. The following categories are available:
|
||||
// BASE: non-SSE
|
||||
// SSE: available on SSE and v-prefixed on AVX
|
||||
// SSEONLY: available only on SSE (exception on AVX)
|
||||
// AVX: available only on AVX (exception on SSE)
|
||||
// AVX2: available only on AVX2 (exception on AVX/SSE)
|
||||
// FMA: available only with FMA
|
||||
// SFORWARD forwards an SSE-AVX pair where the AVX variant takes the same number of registers (e.g. pshufd dst, src + vpshufd dst, src)
|
||||
// AFORWARD forwards an SSE-AVX pair where the AVX variant takes an extra destination register (e.g. shufps dst, src + vshufps dst, src, src)
|
||||
|
||||
// Implementation details:
|
||||
// ACTUAL_FORWARD_*: Actually forward the function of the given type
|
||||
// FORWARD#: First validates the arguments (e.g. make sure you're not passing registers over 7 on x86), then forwards to an ACTUAL_FORWARD_*
|
||||
|
||||
// Big thanks to https://stackoverflow.com/a/24028231 for helping me figure out how to work around MSVC's terrible macro expander
|
||||
// Of course GCC/Clang don't like the workaround so enjoy the ifdefs
|
||||
#define EXPAND_ARGS(macro, args) macro args
|
||||
|
||||
#define ACTUAL_FORWARD_BASE(name, ...) \
|
||||
actual.name(__VA_ARGS__);
|
||||
|
||||
#define ACTUAL_FORWARD_SSE(name, ...) \
|
||||
if (hasAVX) \
|
||||
actual.v##name(__VA_ARGS__); \
|
||||
else \
|
||||
actual.name(__VA_ARGS__);
|
||||
|
||||
#define ACTUAL_FORWARD_SSEONLY(name, ...) \
|
||||
if (hasAVX) \
|
||||
throw Error(Error::ERR_SSE_INSTR_IN_AVX); \
|
||||
else \
|
||||
actual.name(__VA_ARGS__);
|
||||
|
||||
#define ACTUAL_FORWARD_AVX(name, ...) \
|
||||
if (hasAVX) \
|
||||
actual.name(__VA_ARGS__); \
|
||||
else \
|
||||
throw Error(Error::ERR_AVX_INSTR_IN_SSE);
|
||||
|
||||
#define ACTUAL_FORWARD_AVX2(name, ...) \
|
||||
if (hasAVX2) \
|
||||
actual.name(__VA_ARGS__); \
|
||||
else \
|
||||
throw Error(Error::ERR_AVX_INSTR_IN_SSE);
|
||||
|
||||
#define ACTUAL_FORWARD_FMA(name, ...) \
|
||||
if (hasFMA) \
|
||||
actual.name(__VA_ARGS__); \
|
||||
else \
|
||||
throw Error(Error::ERR_AVX_INSTR_IN_SSE);
|
||||
|
||||
#define FORWARD1(category, name, type) \
|
||||
void name(type a) \
|
||||
{ \
|
||||
validateRegister(a); \
|
||||
ACTUAL_FORWARD_##category(name, a) \
|
||||
}
|
||||
|
||||
#define FORWARD2(category, name, type1, type2) \
|
||||
void name(type1 a, type2 b) \
|
||||
{ \
|
||||
validateRegister(a); \
|
||||
validateRegister(b); \
|
||||
ACTUAL_FORWARD_##category(name, a, b) \
|
||||
}
|
||||
|
||||
#define FORWARD3(category, name, type1, type2, type3) \
|
||||
void name(type1 a, type2 b, type3 c) \
|
||||
{ \
|
||||
validateRegister(a); \
|
||||
validateRegister(b); \
|
||||
validateRegister(c); \
|
||||
ACTUAL_FORWARD_##category(name, a, b, c) \
|
||||
}
|
||||
|
||||
#define FORWARD4(category, name, type1, type2, type3, type4) \
|
||||
void name(type1 a, type2 b, type3 c, type4 d) \
|
||||
{ \
|
||||
validateRegister(a); \
|
||||
validateRegister(b); \
|
||||
validateRegister(c); \
|
||||
validateRegister(d); \
|
||||
ACTUAL_FORWARD_##category(name, a, b, c, d) \
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define FORWARD_(argcount, ...) FORWARD##argcount(__VA_ARGS__)
|
||||
// Gets the macro evaluator to evaluate in the right order
|
||||
#define FORWARD(...) FORWARD_(__VA_ARGS__)
|
||||
#else
|
||||
#define FORWARD_(argcount, ...) EXPAND_ARGS(FORWARD##argcount, (__VA_ARGS__))
|
||||
// Gets the macro evaluator to evaluate in the right order
|
||||
#define FORWARD(...) EXPAND_ARGS(FORWARD_, (__VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#define FORWARD_SSE_XMM0(name) \
|
||||
void name(const Xmm& a, const Operand& b) \
|
||||
{ \
|
||||
validateRegister(a); \
|
||||
validateRegister(b); \
|
||||
if (hasAVX) \
|
||||
actual.v##name(a, b, Xmm(0)); \
|
||||
else \
|
||||
actual.name(a, b); \
|
||||
} \
|
||||
FORWARD(4, AVX, v##name, const Xmm&, const Xmm&, const Operand&, const Xmm&)
|
||||
|
||||
#define FORWARD_JUMP(name) \
|
||||
void name(const void *addr) { actual.name(addr); } \
|
||||
void name(const Label& label, Xbyak::CodeGenerator::LabelType type = Xbyak::CodeGenerator::T_AUTO) { actual.name(label, type); } \
|
||||
void name(const char *label, Xbyak::CodeGenerator::LabelType type = Xbyak::CodeGenerator::T_AUTO) { actual.name(label, type); }
|
||||
|
||||
#define ADD_ONE_2 3
|
||||
#define ADD_ONE_3 4
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define SFORWARD(argcount, name, ...) FORWARD(argcount, SSE, name, __VA_ARGS__)
|
||||
#define AFORWARD_(argcount, name, arg1, ...) \
|
||||
SFORWARD(argcount, name, arg1, __VA_ARGS__) \
|
||||
FORWARD(ADD_ONE_##argcount, AVX, v##name, arg1, arg1, __VA_ARGS__)
|
||||
// Gets the macro evaluator to evaluate in the right order
|
||||
#define AFORWARD(...) EXPAND_ARGS(AFORWARD_, (__VA_ARGS__))
|
||||
#else
|
||||
#define SFORWARD(argcount, name, ...) EXPAND_ARGS(FORWARD, (argcount, SSE, name, __VA_ARGS__))
|
||||
#define AFORWARD_(argcount, name, arg1, ...) \
|
||||
EXPAND_ARGS(SFORWARD, (argcount, name, arg1, __VA_ARGS__)) \
|
||||
EXPAND_ARGS(FORWARD, (ADD_ONE_##argcount, AVX, v##name, arg1, arg1, __VA_ARGS__))
|
||||
// Gets the macro evaluator to evaluate in the right order
|
||||
#define AFORWARD(...) EXPAND_ARGS(AFORWARD_, (__VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#define FORWARD_OO_OI(name) \
|
||||
FORWARD(2, BASE, name, ARGS_OO) \
|
||||
FORWARD(2, BASE, name, ARGS_OI)
|
||||
|
||||
#define ARGS_OI const Operand&, uint32
|
||||
#define ARGS_OO const Operand&, const Operand&
|
||||
#define ARGS_XI const Xmm&, int
|
||||
#define ARGS_XO const Xmm&, const Operand&
|
||||
#define ARGS_XOI const Xmm&, const Operand&, uint8
|
||||
#define ARGS_XXO const Xmm&, const Xmm&, const Operand&
|
||||
|
||||
// For instructions that are ifdef'd out without XBYAK64
|
||||
#ifdef XBYAK64
|
||||
#define REQUIRE64(action) require64(); action
|
||||
#else
|
||||
#define REQUIRE64(action) require64()
|
||||
#endif
|
||||
|
||||
const uint8 *getCurr() { return actual.getCurr(); }
|
||||
void align(int x = 16) { return actual.align(x); }
|
||||
void db(int code) { actual.db(code); }
|
||||
void L(const std::string& label) { actual.L(label); }
|
||||
|
||||
void cdqe() { REQUIRE64(actual.cdqe()); }
|
||||
void ret(int imm = 0) { actual.ret(imm); }
|
||||
void vzeroupper() { requireAVX(); actual.vzeroupper(); }
|
||||
void vzeroall() { requireAVX(); actual.vzeroall(); }
|
||||
|
||||
FORWARD_OO_OI(add)
|
||||
FORWARD_OO_OI(and)
|
||||
FORWARD_OO_OI(cmp)
|
||||
FORWARD_OO_OI(or)
|
||||
FORWARD_OO_OI(sub)
|
||||
FORWARD_OO_OI(xor)
|
||||
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, not, const Operand&)
|
||||
FORWARD(1, BASE, pop, const Operand&)
|
||||
FORWARD(1, BASE, push, const Operand&)
|
||||
FORWARD(2, BASE, sar, const Operand&, const Reg8&)
|
||||
FORWARD(2, BASE, sar, ARGS_OI)
|
||||
FORWARD(2, BASE, shl, const Operand&, const Reg8&)
|
||||
FORWARD(2, BASE, shl, ARGS_OI)
|
||||
FORWARD(2, BASE, shr, const Operand&, const Reg8&)
|
||||
FORWARD(2, BASE, shr, ARGS_OI)
|
||||
FORWARD(2, BASE, test, const Operand&, const Reg&);
|
||||
FORWARD(2, BASE, test, ARGS_OI);
|
||||
|
||||
FORWARD_JUMP(je)
|
||||
FORWARD_JUMP(jle)
|
||||
FORWARD_JUMP(jmp)
|
||||
|
||||
AFORWARD(2, addps, ARGS_XO)
|
||||
SFORWARD(2, cvtdq2ps, ARGS_XO)
|
||||
SFORWARD(2, cvtps2dq, ARGS_XO)
|
||||
SFORWARD(2, cvttps2dq, ARGS_XO)
|
||||
SFORWARD(3, extractps, const Operand&, const Xmm&, uint8)
|
||||
AFORWARD(2, maxps, ARGS_XO)
|
||||
AFORWARD(2, minps, ARGS_XO)
|
||||
SFORWARD(2, movaps, ARGS_XO)
|
||||
SFORWARD(2, movaps, 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&)
|
||||
SFORWARD(2, movd, const Xmm&, const Reg32&)
|
||||
SFORWARD(2, movdqa, ARGS_XO)
|
||||
SFORWARD(2, movdqa, const Address&, const Xmm&)
|
||||
SFORWARD(2, movhps, ARGS_XO)
|
||||
SFORWARD(2, movhps, const Address&, const Xmm&)
|
||||
SFORWARD(2, movq, const Address&, const Xmm&)
|
||||
SFORWARD(2, movq, const Xmm&, const Address&)
|
||||
AFORWARD(2, mulps, ARGS_XO)
|
||||
AFORWARD(2, orps, ARGS_XO)
|
||||
AFORWARD(2, packssdw, ARGS_XO)
|
||||
AFORWARD(2, packusdw, ARGS_XO)
|
||||
AFORWARD(2, packuswb, ARGS_XO)
|
||||
AFORWARD(2, paddd, ARGS_XO)
|
||||
AFORWARD(2, paddusb, ARGS_XO)
|
||||
AFORWARD(2, paddw, ARGS_XO)
|
||||
AFORWARD(2, pand, ARGS_XO)
|
||||
AFORWARD(2, pandn, ARGS_XO)
|
||||
AFORWARD(3, pblendw, ARGS_XOI)
|
||||
AFORWARD(2, pcmpeqd, ARGS_XO)
|
||||
AFORWARD(2, pcmpeqw, ARGS_XO)
|
||||
AFORWARD(2, pcmpgtd, ARGS_XO)
|
||||
SFORWARD(3, pextrd, const Operand&, const Xmm&, uint8)
|
||||
SFORWARD(3, pextrw, const Operand&, const Xmm&, uint8)
|
||||
AFORWARD(3, pinsrd, ARGS_XOI)
|
||||
AFORWARD(2, pmaxsw, ARGS_XO)
|
||||
AFORWARD(2, pminsd, ARGS_XO)
|
||||
AFORWARD(2, pminsw, ARGS_XO)
|
||||
SFORWARD(2, pmovsxbd, ARGS_XO)
|
||||
SFORWARD(2, pmovmskb, const Reg32e&, const Xmm&)
|
||||
SFORWARD(2, pmovzxbw, ARGS_XO)
|
||||
AFORWARD(2, pmulhrsw, ARGS_XO)
|
||||
AFORWARD(2, pmulhw, ARGS_XO)
|
||||
AFORWARD(2, pmullw, ARGS_XO)
|
||||
AFORWARD(2, por, ARGS_XO)
|
||||
SFORWARD(3, pshufd, ARGS_XOI)
|
||||
SFORWARD(3, pshufhw, ARGS_XOI)
|
||||
SFORWARD(3, pshuflw, ARGS_XOI)
|
||||
AFORWARD(2, pslld, ARGS_XI)
|
||||
AFORWARD(2, psllw, ARGS_XI)
|
||||
AFORWARD(2, psrad, ARGS_XI)
|
||||
AFORWARD(2, psrad, ARGS_XO)
|
||||
AFORWARD(2, psraw, ARGS_XI)
|
||||
AFORWARD(2, psrld, ARGS_XI)
|
||||
AFORWARD(2, psrldq, ARGS_XI)
|
||||
AFORWARD(2, psrlw, ARGS_XI)
|
||||
AFORWARD(2, psrlw, ARGS_XO)
|
||||
AFORWARD(2, psubd, ARGS_XO)
|
||||
AFORWARD(2, psubw, ARGS_XO)
|
||||
AFORWARD(2, punpckhdq, ARGS_XO)
|
||||
AFORWARD(2, punpckhwd, ARGS_XO)
|
||||
AFORWARD(2, punpcklbw, ARGS_XO)
|
||||
AFORWARD(2, punpckldq, ARGS_XO)
|
||||
AFORWARD(2, punpcklqdq,ARGS_XO)
|
||||
AFORWARD(2, punpcklwd, ARGS_XO)
|
||||
AFORWARD(2, pxor, ARGS_XO)
|
||||
SFORWARD(2, rcpps, ARGS_XO)
|
||||
AFORWARD(3, shufps, ARGS_XOI)
|
||||
AFORWARD(2, subps, ARGS_XO)
|
||||
AFORWARD(2, xorps, ARGS_XO)
|
||||
|
||||
FORWARD_SSE_XMM0(pblendvb)
|
||||
|
||||
FORWARD(2, AVX, vbroadcastss, ARGS_XO)
|
||||
FORWARD(2, AVX2, vbroadcasti128, const Ymm&, const Address&)
|
||||
FORWARD(2, AVX, vbroadcastf128, const Ymm&, const Address&)
|
||||
FORWARD(3, FMA, vfmadd213ps, ARGS_XXO)
|
||||
FORWARD(3, AVX2, vextracti128, const Operand&, const Ymm&, uint8)
|
||||
FORWARD(4, AVX2, vinserti128, const Ymm&, const Ymm&, const Operand&, uint8);
|
||||
FORWARD(2, AVX2, vpbroadcastd, ARGS_XO)
|
||||
FORWARD(2, AVX2, vpbroadcastq, ARGS_XO)
|
||||
FORWARD(2, AVX2, vpbroadcastw, ARGS_XO)
|
||||
FORWARD(3, AVX2, vpermq, const Ymm&, const Operand&, uint8)
|
||||
FORWARD(3, AVX2, vpgatherdd, const Xmm&, const Address&, const Xmm&);
|
||||
FORWARD(3, AVX2, vpsravd, ARGS_XXO)
|
||||
FORWARD(3, AVX2, vpsrlvd, ARGS_XXO)
|
||||
|
||||
#undef REQUIRE64
|
||||
#undef ARGS_OI
|
||||
#undef ARGS_OO
|
||||
#undef ARGS_XI
|
||||
#undef ARGS_XO
|
||||
#undef ARGS_XOI
|
||||
#undef ARGS_XXO
|
||||
#undef FORWARD_OO_OI
|
||||
#undef AFORWARD
|
||||
#undef AFORWARD_
|
||||
#undef SFORWARD
|
||||
#undef ADD_ONE_2
|
||||
#undef ADD_ONE_3
|
||||
#undef FORWARD_SSE_XMM0
|
||||
#undef FORWARD_JUMP
|
||||
#undef FORWARD
|
||||
#undef FORWARD_
|
||||
#undef FORWARD4
|
||||
#undef FORWARD3
|
||||
#undef FORWARD2
|
||||
#undef FORWARD1
|
||||
#undef ACTUAL_FORWARD_FMA
|
||||
#undef ACTUAL_FORWARD_AVX2
|
||||
#undef ACTUAL_FORWARD_AVX
|
||||
#undef ACTUAL_FORWARD_SSE
|
||||
#undef ACTUAL_FORWARD_SSEONLY
|
||||
#undef ACTUAL_FORWARD_BASE
|
||||
#undef EXPAND_ARGS
|
||||
};
|
||||
@@ -409,17 +409,20 @@ void GSRendererSW::Draw()
|
||||
|
||||
// GSScanlineGlobalData& gd = sd->global;
|
||||
|
||||
uint32* fb_pages = NULL;
|
||||
uint32* zb_pages = NULL;
|
||||
GSOffset::PageLooper* fb_pages = NULL;
|
||||
GSOffset::PageLooper* zb_pages = NULL;
|
||||
GSOffset::PageLooper _fb_pages, _zb_pages;
|
||||
|
||||
if (sd->global.sel.fb)
|
||||
{
|
||||
fb_pages = m_context->offset.fb->GetPages(r);
|
||||
_fb_pages = m_context->offset.fb.pageLooperForRect(r);
|
||||
fb_pages = &_fb_pages;
|
||||
}
|
||||
|
||||
if (sd->global.sel.zb)
|
||||
{
|
||||
zb_pages = m_context->offset.zb->GetPages(r);
|
||||
_zb_pages = m_context->offset.zb.pageLooperForRect(r);
|
||||
zb_pages = &_zb_pages;
|
||||
}
|
||||
|
||||
// check if there is an overlap between this and previous targets
|
||||
@@ -438,7 +441,7 @@ void GSRendererSW::Draw()
|
||||
|
||||
// addref source and target pages
|
||||
|
||||
sd->UsePages(fb_pages, m_context->offset.fb->psm, zb_pages, m_context->offset.zb->psm);
|
||||
sd->UsePages(fb_pages, m_context->offset.fb.psm(), zb_pages, m_context->offset.zb.psm());
|
||||
|
||||
//
|
||||
|
||||
@@ -641,26 +644,26 @@ void GSRendererSW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GS
|
||||
fflush(s_fp);
|
||||
}
|
||||
|
||||
GSOffset* off = m_mem.GetOffset(BITBLTBUF.DBP, BITBLTBUF.DBW, BITBLTBUF.DPSM);
|
||||
|
||||
off->GetPages(r, m_tmp_pages);
|
||||
GSOffset off = m_mem.GetOffset(BITBLTBUF.DBP, BITBLTBUF.DBW, BITBLTBUF.DPSM);
|
||||
GSOffset::PageLooper pages = off.pageLooperForRect(r);
|
||||
|
||||
// check if the changing pages either used as a texture or a target
|
||||
|
||||
if (!m_rl->IsSynced())
|
||||
{
|
||||
for (uint32* RESTRICT p = m_tmp_pages; *p != GSOffset::EOP; p++)
|
||||
pages.loopPagesWithBreak([&](uint32 page)
|
||||
{
|
||||
if (m_fzb_pages[*p] | m_tex_pages[*p])
|
||||
if (m_fzb_pages[page] | m_tex_pages[page])
|
||||
{
|
||||
Sync(6);
|
||||
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
m_tc->InvalidatePages(m_tmp_pages, off->psm); // if texture update runs on a thread and Sync(5) happens then this must come later
|
||||
m_tc->InvalidatePages(pages, off.psm()); // if texture update runs on a thread and Sync(5) happens then this must come later
|
||||
}
|
||||
|
||||
void GSRendererSW::InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut)
|
||||
@@ -673,77 +676,92 @@ void GSRendererSW::InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GS
|
||||
|
||||
if (!m_rl->IsSynced())
|
||||
{
|
||||
GSOffset* off = m_mem.GetOffset(BITBLTBUF.SBP, BITBLTBUF.SBW, BITBLTBUF.SPSM);
|
||||
GSOffset off = m_mem.GetOffset(BITBLTBUF.SBP, BITBLTBUF.SBW, BITBLTBUF.SPSM);
|
||||
GSOffset::PageLooper pages = off.pageLooperForRect(r);
|
||||
|
||||
off->GetPages(r, m_tmp_pages);
|
||||
|
||||
for (uint32* RESTRICT p = m_tmp_pages; *p != GSOffset::EOP; p++)
|
||||
pages.loopPagesWithBreak([&](uint32 page)
|
||||
{
|
||||
if (m_fzb_pages[*p])
|
||||
if (m_fzb_pages[page])
|
||||
{
|
||||
Sync(7);
|
||||
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void GSRendererSW::UsePages(const uint32* pages, const int type)
|
||||
void GSRendererSW::UsePages(const GSOffset::PageLooper& pages, const int type)
|
||||
{
|
||||
for (const uint32* p = pages; *p != GSOffset::EOP; p++)
|
||||
pages.loopPages([=](uint32 page)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
ASSERT((m_fzb_pages[*p] & 0xFFFF) < USHRT_MAX);
|
||||
m_fzb_pages[*p] += 1;
|
||||
ASSERT((m_fzb_pages[page] & 0xFFFF) < USHRT_MAX);
|
||||
m_fzb_pages[page] += 1;
|
||||
break;
|
||||
case 1:
|
||||
ASSERT((m_fzb_pages[*p] >> 16) < USHRT_MAX);
|
||||
m_fzb_pages[*p] += 0x10000;
|
||||
ASSERT((m_fzb_pages[page] >> 16) < USHRT_MAX);
|
||||
m_fzb_pages[page] += 0x10000;
|
||||
break;
|
||||
case 2:
|
||||
ASSERT(m_tex_pages[*p] < USHRT_MAX);
|
||||
m_tex_pages[*p] += 1;
|
||||
ASSERT(m_tex_pages[page] < USHRT_MAX);
|
||||
m_tex_pages[page] += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void GSRendererSW::ReleasePages(const uint32* pages, const int type)
|
||||
void GSRendererSW::ReleasePages(const GSOffset::PageLooper& pages, const int type)
|
||||
{
|
||||
for (const uint32* p = pages; *p != GSOffset::EOP; p++)
|
||||
pages.loopPages([=](uint32 page)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
ASSERT((m_fzb_pages[*p] & 0xFFFF) > 0);
|
||||
m_fzb_pages[*p] -= 1;
|
||||
ASSERT((m_fzb_pages[page] & 0xFFFF) > 0);
|
||||
m_fzb_pages[page] -= 1;
|
||||
break;
|
||||
case 1:
|
||||
ASSERT((m_fzb_pages[*p] >> 16) > 0);
|
||||
m_fzb_pages[*p] -= 0x10000;
|
||||
ASSERT((m_fzb_pages[page] >> 16) > 0);
|
||||
m_fzb_pages[page] -= 0x10000;
|
||||
break;
|
||||
case 2:
|
||||
ASSERT(m_tex_pages[*p] > 0);
|
||||
m_tex_pages[*p] -= 1;
|
||||
ASSERT(m_tex_pages[page] > 0);
|
||||
m_tex_pages[page] -= 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pages, const GSVector4i& r)
|
||||
bool GSRendererSW::CheckTargetPages(const GSOffset::PageLooper* fb_pages, const GSOffset::PageLooper* zb_pages, const GSVector4i& r)
|
||||
{
|
||||
bool synced = m_rl->IsSynced();
|
||||
|
||||
bool fb = fb_pages != NULL;
|
||||
bool zb = zb_pages != NULL;
|
||||
|
||||
GSOffset::PageLooper _fb_pages, _zb_pages;
|
||||
auto requirePages = [&]
|
||||
{
|
||||
if (fb_pages == NULL)
|
||||
{
|
||||
_fb_pages = m_context->offset.fb.pageLooperForRect(r);
|
||||
fb_pages = &_fb_pages;
|
||||
}
|
||||
if (zb_pages == NULL)
|
||||
{
|
||||
_zb_pages = m_context->offset.zb.pageLooperForRect(r);
|
||||
zb_pages = &_zb_pages;
|
||||
}
|
||||
};
|
||||
|
||||
bool res = false;
|
||||
|
||||
if (m_fzb != m_context->offset.fzb4)
|
||||
@@ -753,17 +771,14 @@ bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pag
|
||||
m_fzb = m_context->offset.fzb4;
|
||||
m_fzb_bbox = r;
|
||||
|
||||
if (fb_pages == NULL) fb_pages = m_context->offset.fb->GetPages(r);
|
||||
if (zb_pages == NULL) zb_pages = m_context->offset.zb->GetPages(r);
|
||||
|
||||
memset(m_fzb_cur_pages, 0, sizeof(m_fzb_cur_pages));
|
||||
|
||||
uint32 used = 0;
|
||||
|
||||
for (const uint32* p = fb_pages; *p != GSOffset::EOP; p++)
|
||||
{
|
||||
uint32 i = *p;
|
||||
requirePages();
|
||||
|
||||
fb_pages->loopPages([&](uint32 i)
|
||||
{
|
||||
uint32 row = i >> 5;
|
||||
uint32 col = 1 << (i & 31);
|
||||
|
||||
@@ -771,12 +786,10 @@ bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pag
|
||||
|
||||
used |= m_fzb_pages[i];
|
||||
used |= m_tex_pages[i];
|
||||
}
|
||||
});
|
||||
|
||||
for (const uint32* p = zb_pages; *p != GSOffset::EOP; p++)
|
||||
zb_pages->loopPages([&](uint32 i)
|
||||
{
|
||||
uint32 i = *p;
|
||||
|
||||
uint32 row = i >> 5;
|
||||
uint32 col = 1 << (i & 31);
|
||||
|
||||
@@ -784,7 +797,7 @@ bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pag
|
||||
|
||||
used |= m_fzb_pages[i];
|
||||
used |= m_tex_pages[i];
|
||||
}
|
||||
});
|
||||
|
||||
if (!synced)
|
||||
{
|
||||
@@ -816,15 +829,12 @@ bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pag
|
||||
{
|
||||
// drawing area is larger than previous time, check new parts only to avoid false positives (m_fzb_cur_pages guards)
|
||||
|
||||
if (fb_pages == NULL) fb_pages = m_context->offset.fb->GetPages(r);
|
||||
if (zb_pages == NULL) zb_pages = m_context->offset.zb->GetPages(r);
|
||||
requirePages();
|
||||
|
||||
uint32 used = 0;
|
||||
|
||||
for (const uint32* p = fb_pages; *p != GSOffset::EOP; p++)
|
||||
fb_pages->loopPages([&](uint32 i)
|
||||
{
|
||||
uint32 i = *p;
|
||||
|
||||
uint32 row = i >> 5;
|
||||
uint32 col = 1 << (i & 31);
|
||||
|
||||
@@ -834,12 +844,10 @@ bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pag
|
||||
|
||||
used |= m_fzb_pages[i];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const uint32* p = zb_pages; *p != GSOffset::EOP; p++)
|
||||
zb_pages->loopPages([&](uint32 i)
|
||||
{
|
||||
uint32 i = *p;
|
||||
|
||||
uint32 row = i >> 5;
|
||||
uint32 col = 1 << (i & 31);
|
||||
|
||||
@@ -849,7 +857,7 @@ bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pag
|
||||
|
||||
used |= m_fzb_pages[i];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!synced)
|
||||
{
|
||||
@@ -873,9 +881,9 @@ bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pag
|
||||
|
||||
if (fb && !res)
|
||||
{
|
||||
for (const uint32* p = fb_pages; *p != GSOffset::EOP; p++)
|
||||
fb_pages->loopPagesWithBreak([&](uint32 page)
|
||||
{
|
||||
if (m_fzb_pages[*p] & 0xffff0000)
|
||||
if (m_fzb_pages[page] & 0xffff0000)
|
||||
{
|
||||
if (LOG)
|
||||
{
|
||||
@@ -885,16 +893,17 @@ bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pag
|
||||
|
||||
res = true;
|
||||
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (zb && !res)
|
||||
{
|
||||
for (const uint32* p = zb_pages; *p != GSOffset::EOP; p++)
|
||||
zb_pages->loopPagesWithBreak([&](uint32 page)
|
||||
{
|
||||
if (m_fzb_pages[*p] & 0x0000ffff)
|
||||
if (m_fzb_pages[page] & 0x0000ffff)
|
||||
{
|
||||
if (LOG)
|
||||
{
|
||||
@@ -904,16 +913,14 @@ bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pag
|
||||
|
||||
res = true;
|
||||
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fb && fb_pages != NULL) delete[] fb_pages;
|
||||
if (!zb && zb_pages != NULL) delete[] zb_pages;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -923,19 +930,22 @@ bool GSRendererSW::CheckSourcePages(SharedData* sd)
|
||||
{
|
||||
for (size_t i = 0; sd->m_tex[i].t != NULL; i++)
|
||||
{
|
||||
sd->m_tex[i].t->m_offset->GetPages(sd->m_tex[i].r, m_tmp_pages);
|
||||
GSOffset::PageLooper pages = sd->m_tex[i].t->m_offset.pageLooperForRect(sd->m_tex[i].r);
|
||||
|
||||
uint32* pages = m_tmp_pages; // sd->m_tex[i].t->m_pages.n;
|
||||
|
||||
for (const uint32* p = pages; *p != GSOffset::EOP; p++)
|
||||
bool ret = false;
|
||||
pages.loopPagesWithBreak([&](uint32 pages)
|
||||
{
|
||||
// TODO: 8H 4HL 4HH texture at the same place as the render target (24 bit, or 32-bit where the alpha channel is masked, Valkyrie Profile 2)
|
||||
|
||||
if (m_fzb_pages[*p]) // currently being drawn to? => sync
|
||||
if (m_fzb_pages[pages]) // currently being drawn to? => sync
|
||||
{
|
||||
return true;
|
||||
ret = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (ret)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -954,10 +964,8 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
|
||||
|
||||
gd.vm = m_mem.m_vm8;
|
||||
|
||||
gd.fbr = context->offset.fb->pixel.row;
|
||||
gd.zbr = context->offset.zb->pixel.row;
|
||||
gd.fbc = context->offset.fb->pixel.col[0];
|
||||
gd.zbc = context->offset.zb->pixel.col[0];
|
||||
gd.fbo = context->offset.fb;
|
||||
gd.zbo = context->offset.zb;
|
||||
gd.fzbr = context->offset.fzb4->row;
|
||||
gd.fzbc = context->offset.fzb4->col;
|
||||
|
||||
@@ -1423,8 +1431,6 @@ bool GSRendererSW::GetScanlineGlobalData(SharedData* data)
|
||||
|
||||
GSRendererSW::SharedData::SharedData(GSRendererSW* parent)
|
||||
: m_parent(parent)
|
||||
, m_fb_pages(NULL)
|
||||
, m_zb_pages(NULL)
|
||||
, m_fpsm(0)
|
||||
, m_zpsm(0)
|
||||
, m_using_pages(false)
|
||||
@@ -1460,7 +1466,7 @@ GSRendererSW::SharedData::~SharedData()
|
||||
|
||||
//static TransactionScope::Lock s_lock;
|
||||
|
||||
void GSRendererSW::SharedData::UsePages(const uint32* fb_pages, int fpsm, const uint32* zb_pages, int zpsm)
|
||||
void GSRendererSW::SharedData::UsePages(const GSOffset::PageLooper* fb_pages, int fpsm, const GSOffset::PageLooper* zb_pages, int zpsm)
|
||||
{
|
||||
if (m_using_pages)
|
||||
return;
|
||||
@@ -1468,24 +1474,26 @@ void GSRendererSW::SharedData::UsePages(const uint32* fb_pages, int fpsm, const
|
||||
{
|
||||
//TransactionScope scope(s_lock);
|
||||
|
||||
if (global.sel.fb && fb_pages != NULL)
|
||||
if (global.sel.fb)
|
||||
{
|
||||
m_parent->UsePages(fb_pages, 0);
|
||||
m_parent->UsePages(*fb_pages, 0);
|
||||
}
|
||||
|
||||
if (global.sel.zb && zb_pages != NULL)
|
||||
if (global.sel.zb)
|
||||
{
|
||||
m_parent->UsePages(zb_pages, 1);
|
||||
m_parent->UsePages(*zb_pages, 1);
|
||||
}
|
||||
|
||||
for (size_t i = 0; m_tex[i].t != NULL; i++)
|
||||
{
|
||||
m_parent->UsePages(m_tex[i].t->m_pages.n, 2);
|
||||
m_parent->UsePages(m_tex[i].t->m_pages, 2);
|
||||
}
|
||||
}
|
||||
|
||||
m_fb_pages = fb_pages;
|
||||
m_zb_pages = zb_pages;
|
||||
if (fb_pages)
|
||||
m_fb_pages = *fb_pages;
|
||||
if (zb_pages)
|
||||
m_zb_pages = *zb_pages;
|
||||
m_fpsm = fpsm;
|
||||
m_zpsm = zpsm;
|
||||
|
||||
@@ -1512,16 +1520,10 @@ void GSRendererSW::SharedData::ReleasePages()
|
||||
|
||||
for (size_t i = 0; m_tex[i].t != NULL; i++)
|
||||
{
|
||||
m_parent->ReleasePages(m_tex[i].t->m_pages.n, 2);
|
||||
m_parent->ReleasePages(m_tex[i].t->m_pages, 2);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] m_fb_pages;
|
||||
delete[] m_zb_pages;
|
||||
|
||||
m_fb_pages = NULL;
|
||||
m_zb_pages = NULL;
|
||||
|
||||
m_using_pages = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,8 @@ class GSRendererSW : public GSRenderer
|
||||
|
||||
public:
|
||||
GSRendererSW* m_parent;
|
||||
const uint32* m_fb_pages;
|
||||
const uint32* m_zb_pages;
|
||||
GSOffset::PageLooper m_fb_pages;
|
||||
GSOffset::PageLooper m_zb_pages;
|
||||
int m_fpsm;
|
||||
int m_zpsm;
|
||||
bool m_using_pages;
|
||||
@@ -52,7 +52,7 @@ class GSRendererSW : public GSRenderer
|
||||
SharedData(GSRendererSW* parent);
|
||||
virtual ~SharedData();
|
||||
|
||||
void UsePages(const uint32* fb_pages, int fpsm, const uint32* zb_pages, int zpsm);
|
||||
void UsePages(const GSOffset::PageLooper* fb_pages, int fpsm, const GSOffset::PageLooper* zb_pages, int zpsm);
|
||||
void ReleasePages();
|
||||
|
||||
void SetSource(GSTextureCacheSW::Texture* t, const GSVector4i& r, int level);
|
||||
@@ -76,7 +76,6 @@ protected:
|
||||
uint32 m_fzb_cur_pages[16];
|
||||
std::atomic<uint32> m_fzb_pages[512]; // uint16 frame/zbuf pages interleaved
|
||||
std::atomic<uint16> m_tex_pages[512];
|
||||
uint32 m_tmp_pages[512 + 1];
|
||||
|
||||
void Reset();
|
||||
void VSync(int field);
|
||||
@@ -90,10 +89,10 @@ protected:
|
||||
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r);
|
||||
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut = false);
|
||||
|
||||
void UsePages(const uint32* pages, const int type);
|
||||
void ReleasePages(const uint32* pages, const int type);
|
||||
void UsePages(const GSOffset::PageLooper& pages, const int type);
|
||||
void ReleasePages(const GSOffset::PageLooper& pages, const int type);
|
||||
|
||||
bool CheckTargetPages(const uint32* fb_pages, const uint32* zb_pages, const GSVector4i& r);
|
||||
bool CheckTargetPages(const GSOffset::PageLooper* fb_pages, const GSOffset::PageLooper* zb_pages, const GSVector4i& r);
|
||||
bool CheckSourcePages(SharedData* sd);
|
||||
|
||||
bool GetScanlineGlobalData(SharedData* data);
|
||||
|
||||
@@ -127,10 +127,8 @@ struct alignas(32) GSScanlineGlobalData // per batch variables, this is like a p
|
||||
uint32* clut;
|
||||
GSVector4i* dimx;
|
||||
|
||||
const int* fbr;
|
||||
const int* zbr;
|
||||
const int* fbc;
|
||||
const int* zbc;
|
||||
GSOffset fbo;
|
||||
GSOffset zbo;
|
||||
const GSVector2i* fzbr;
|
||||
const GSVector2i* fzbc;
|
||||
|
||||
|
||||
@@ -0,0 +1,566 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GS/GS_types.h"
|
||||
#include "GSSetupPrimCodeGenerator.all.h"
|
||||
#include "GSVertexSW.h"
|
||||
|
||||
using namespace Xbyak;
|
||||
|
||||
#define _rip_local(field) ((is32 || m_rip) ? ptr[rip + (char*)&m_local.field] : ptr[_m_local + OFFSETOF(GSScanlineLocalData, field)])
|
||||
|
||||
#define _64_m_local _64_t0
|
||||
|
||||
/// On AVX, does a v-prefixed separate destination operation
|
||||
/// On SSE, moves src1 into dst using movdqa, then does the operation
|
||||
#define THREEARG(operation, dst, src1, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (hasAVX) \
|
||||
{ \
|
||||
v##operation(dst, src1, __VA_ARGS__); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
movdqa(dst, src1); \
|
||||
operation(dst, __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
#define _rip_local_d(x) _rip_local(d8.x)
|
||||
#define _rip_local_d_p(x) _rip_local_d(p.x)
|
||||
#else
|
||||
#define _rip_local_d(x) _rip_local(d4.x)
|
||||
#define _rip_local_d_p(x) _rip_local_d(x)
|
||||
#endif
|
||||
|
||||
GSSetupPrimCodeGenerator2::GSSetupPrimCodeGenerator2(Xbyak::CodeGenerator* base, CPUInfo cpu, void* param, uint64 key)
|
||||
: _parent(base, cpu)
|
||||
, m_local(*(GSScanlineLocalData*)param)
|
||||
, m_rip(false), many_regs(false)
|
||||
// On x86 arg registers are very temporary but on x64 they aren't, so on x86 some registers overlap
|
||||
#ifdef _WIN32
|
||||
, _64_vertex(is64 ? rcx : r8)
|
||||
, _index(is64 ? rdx : rcx)
|
||||
, _dscan(is64 ? r8 : rdx)
|
||||
, _64_t0(r9), t1(is64 ? r10 : rcx)
|
||||
#else
|
||||
, _64_vertex(is64 ? rdi : r8)
|
||||
, _index(is64 ? rsi : rcx)
|
||||
, _dscan(rdx)
|
||||
, _64_t0(is64 ? rcx : r8), t1(is64 ? r8 : rcx)
|
||||
#endif
|
||||
, _m_local(chooseLocal(&m_local, _64_m_local))
|
||||
{
|
||||
m_sel.key = key;
|
||||
|
||||
m_en.z = m_sel.zb ? 1 : 0;
|
||||
m_en.f = m_sel.fb && m_sel.fge ? 1 : 0;
|
||||
m_en.t = m_sel.fb && m_sel.tfx != TFX_NONE ? 1 : 0;
|
||||
m_en.c = m_sel.fb && !(m_sel.tfx == TFX_DECAL && m_sel.tcc) ? 1 : 0;
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator2::broadcastf128(const XYm& reg, const Address& mem)
|
||||
{
|
||||
#if SETUP_PRIM_USING_YMM
|
||||
vbroadcastf128(reg, mem);
|
||||
#else
|
||||
movaps(reg, mem);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator2::Generate()
|
||||
{
|
||||
// Technically we just need the delta < 2GB
|
||||
m_rip = (size_t)&m_local < 0x80000000 && (size_t)getCurr() < 0x80000000;
|
||||
|
||||
bool needs_shift = (m_en.z || m_en.f) && m_sel.prim != GS_SPRITE_CLASS || m_en.t || m_en.c && m_sel.iip;
|
||||
many_regs = is64 && isYmm && !m_sel.notest && needs_shift;
|
||||
|
||||
#ifdef _WIN64
|
||||
int needs_saving = many_regs ? 6 : m_sel.notest ? 0 : 2;
|
||||
if (needs_saving)
|
||||
{
|
||||
sub(rsp, 8 + 16 * needs_saving);
|
||||
for (int i = 0; i < needs_saving; i++)
|
||||
{
|
||||
movdqa(ptr[rsp + i * 16], Xmm(i + 6));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (is64 && !m_rip)
|
||||
mov(_64_m_local, (size_t)&m_local);
|
||||
|
||||
if (needs_shift)
|
||||
{
|
||||
if (is32)
|
||||
mov(_dscan, ptr[rsp + _32_dscan]);
|
||||
|
||||
if (isXmm)
|
||||
mov(rax, (size_t)g_const->m_shift_128b);
|
||||
else
|
||||
mov(rax, (size_t)g_const->m_shift_256b);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 2 : many_regs ? 9 : 5); i++)
|
||||
{
|
||||
movaps(XYm(3 + i), ptr[rax + i * vecsize]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isXmm)
|
||||
Depth_XMM();
|
||||
else
|
||||
Depth_YMM();
|
||||
|
||||
Texture();
|
||||
|
||||
Color();
|
||||
|
||||
#ifdef _WIN64
|
||||
if (needs_saving)
|
||||
{
|
||||
for (int i = 0; i < needs_saving; i++)
|
||||
{
|
||||
movdqa(Xmm(i + 6), ptr[rsp + i * 16]);
|
||||
}
|
||||
add(rsp, 8 + 16 * needs_saving);
|
||||
}
|
||||
#endif
|
||||
if (isYmm)
|
||||
vzeroupper();
|
||||
ret();
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator2::Depth_XMM()
|
||||
{
|
||||
if (!m_en.z && !m_en.f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
// GSVector4 p = dscan.p;
|
||||
|
||||
|
||||
movaps(xmm0, ptr[_dscan + offsetof(GSVertexSW, p)]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// GSVector4 df = p.wwww();
|
||||
|
||||
THREEARG(shufps, xmm1, xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
// m_local.d4.f = GSVector4i(df * 4.0f).xxzzlh();
|
||||
|
||||
THREEARG(mulps, xmm2, xmm1, xmm3);
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
pshuflw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
movdqa(_rip_local_d_p(f), xmm2);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// m_local.d[i].f = GSVector4i(df * m_shift[i]).xxzzlh();
|
||||
|
||||
THREEARG(mulps, xmm2, xmm1, XYm(4 + i));
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
pshuflw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
movdqa(_rip_local(d[i].f), xmm2);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// GSVector4 dz = p.zzzz();
|
||||
|
||||
shufps(xmm0, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
// m_local.d4.z = dz * 4.0f;
|
||||
|
||||
THREEARG(mulps, xmm1, xmm0, xmm3);
|
||||
movdqa(_rip_local_d_p(z), xmm1);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// m_local.d[i].z = dz * m_shift[i];
|
||||
|
||||
THREEARG(mulps, xmm1, xmm0, XYm(4 + i));
|
||||
movdqa(_rip_local(d[i].z), xmm1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
if (is32)
|
||||
mov(_index, ptr[rsp + _32_index]);
|
||||
mov(eax, ptr[_index + sizeof(uint32) * 1]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
if (is64)
|
||||
add(rax, _64_vertex);
|
||||
else
|
||||
add(rax, ptr[rsp + _32_vertex]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.p.f = GSVector4i(p).zzzzh().zzzz();
|
||||
movaps(xmm0, ptr[rax + offsetof(GSVertexSW, p)]);
|
||||
|
||||
cvttps2dq(xmm1, xmm0);
|
||||
pshufhw(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
pshufd(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
movdqa(_rip_local(p.f), xmm1);
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// uint32 z is bypassed in t.w
|
||||
|
||||
movdqa(xmm0, ptr[rax + offsetof(GSVertexSW, t)]);
|
||||
pshufd(xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
movdqa(_rip_local(p.z), xmm0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator2::Depth_YMM()
|
||||
{
|
||||
if (!m_en.z && !m_en.f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
// GSVector4 dp8 = dscan.p * GSVector4::broadcast32(&shift[0]);
|
||||
|
||||
broadcastf128(xym0, ptr[_dscan + offsetof(GSVertexSW, p)]);
|
||||
|
||||
vmulps(ymm1, ymm0, ymm3);
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// m_local.d8.p.z = dp8.extract32<2>();
|
||||
|
||||
extractps(_rip_local_d_p(z), xmm1, 2);
|
||||
|
||||
// GSVector8 dz = GSVector8(dscan.p).zzzz();
|
||||
|
||||
vshufps(ymm2, ymm0, ymm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
}
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.d8.p.f = GSVector4i(dp8).extract32<3>();
|
||||
|
||||
cvtps2dq(ymm1, ymm1);
|
||||
pextrd(_rip_local_d_p(f), xmm1, 3);
|
||||
|
||||
// GSVector8 df = GSVector8(dscan.p).wwww();
|
||||
|
||||
vshufps(ymm1, ymm0, ymm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
}
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : dsize); i++)
|
||||
{
|
||||
if (m_en.z)
|
||||
{
|
||||
// m_local.d[i].z = dz * shift[1 + i];
|
||||
|
||||
// Save a byte in the encoding for ymm8-11 by swapping with ymm2 (multiplication is communative)
|
||||
if (i < 4 || many_regs)
|
||||
vmulps(ymm0, Ymm(4 + i), ymm2);
|
||||
else
|
||||
vmulps(ymm0, ymm2, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
movaps(_rip_local(d[i].z), ymm0);
|
||||
}
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.d[i].f = GSVector8i(df * m_shift[i]).xxzzlh();
|
||||
|
||||
if (i < 4 || many_regs)
|
||||
vmulps(ymm0, Ymm(4 + i), ymm1);
|
||||
else
|
||||
vmulps(ymm0, ymm1, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
cvttps2dq(ymm0, ymm0);
|
||||
pshuflw(ymm0, ymm0, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(ymm0, ymm0, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
movdqa(_rip_local(d[i].f), ymm0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
if (is32)
|
||||
mov(_index, ptr[rsp + _32_index]);
|
||||
mov(eax, ptr[_index + sizeof(uint32) * 1]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
if (is64)
|
||||
add(rax, _64_vertex);
|
||||
else
|
||||
add(rax, ptr[rsp + _32_vertex]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.p.f = GSVector4i(vertex[index[1]].p).extract32<3>();
|
||||
|
||||
movaps(xmm0, ptr[rax + offsetof(GSVertexSW, p)]);
|
||||
cvttps2dq(xmm0, xmm0);
|
||||
pextrd(_rip_local(p.f), xmm0, 3);
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// m_local.p.z = vertex[index[1]].t.u32[3]; // uint32 z is bypassed in t.w
|
||||
|
||||
mov(t1.cvt32(), ptr[rax + offsetof(GSVertexSW, t.w)]);
|
||||
mov(_rip_local(p.z), t1.cvt32());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator2::Texture()
|
||||
{
|
||||
if (!m_en.t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// GSVector4 t = dscan.t;
|
||||
|
||||
broadcastf128(xym0, ptr[_dscan + offsetof(GSVertexSW, t)]);
|
||||
|
||||
THREEARG(mulps, xmm1, xmm0, xmm3);
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d4.stq = GSVector4i(t * 4.0f);
|
||||
|
||||
cvttps2dq(xmm1, xmm1);
|
||||
|
||||
movdqa(_rip_local_d(stq), xmm1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d4.stq = t * 4.0f;
|
||||
|
||||
movaps(_rip_local_d(stq), xmm1);
|
||||
}
|
||||
|
||||
for (int j = 0, k = m_sel.fst ? 2 : 3; j < k; j++)
|
||||
{
|
||||
// GSVector4 ds = t.xxxx();
|
||||
// GSVector4 dt = t.yyyy();
|
||||
// GSVector4 dq = t.zzzz();
|
||||
|
||||
THREEARG(shufps, xym1, xym0, xym0, _MM_SHUFFLE(j, j, j, j));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : dsize); i++)
|
||||
{
|
||||
// GSVector4 v = ds/dt * m_shift[i];
|
||||
|
||||
if (i < 4 || many_regs)
|
||||
THREEARG(mulps, xym2, XYm(4 + i), xym1);
|
||||
else
|
||||
vmulps(ymm2, ymm1, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d[i].s/t = GSVector4i(v);
|
||||
|
||||
cvttps2dq(xym2, xym2);
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: movdqa(_rip_local(d[i].s), xym2); break;
|
||||
case 1: movdqa(_rip_local(d[i].t), xym2); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d[i].s/t/q = v;
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: movaps(_rip_local(d[i].s), xym2); break;
|
||||
case 1: movaps(_rip_local(d[i].t), xym2); break;
|
||||
case 2: movaps(_rip_local(d[i].q), xym2); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator2::Color()
|
||||
{
|
||||
if (!m_en.c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.iip)
|
||||
{
|
||||
// GSVector4 c = dscan.c;
|
||||
|
||||
broadcastf128(xym0, ptr[_dscan + offsetof(GSVertexSW, c)]);
|
||||
|
||||
// m_local.d4.c = GSVector4i(c * 4.0f).xzyw().ps32();
|
||||
|
||||
THREEARG(mulps, xmm1, xmm0, xmm3);
|
||||
cvttps2dq(xmm1, xmm1);
|
||||
pshufd(xmm1, xmm1, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
packssdw(xmm1, xmm1);
|
||||
if (isXmm)
|
||||
movdqa(_rip_local_d(c), xmm1);
|
||||
else
|
||||
movq(_rip_local_d(c), xmm1);
|
||||
|
||||
// xym3 is not needed anymore
|
||||
|
||||
// GSVector4 dr = c.xxxx();
|
||||
// GSVector4 db = c.zzzz();
|
||||
|
||||
THREEARG(shufps, xym2, xym0, xym0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
THREEARG(shufps, xym3, xym0, xym0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : dsize); i++)
|
||||
{
|
||||
// GSVector4i r = GSVector4i(dr * m_shift[i]).ps32();
|
||||
|
||||
if (i < 4 || many_regs)
|
||||
THREEARG(mulps, xym0, XYm(4 + i), xym2);
|
||||
else
|
||||
vmulps(ymm0, ymm2, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
cvttps2dq(xym0, xym0);
|
||||
packssdw(xym0, xym0);
|
||||
|
||||
// GSVector4i b = GSVector4i(db * m_shift[i]).ps32();
|
||||
|
||||
if (i < 4 || many_regs)
|
||||
THREEARG(mulps, xym1, XYm(4 + i), xym3);
|
||||
else
|
||||
vmulps(ymm1, ymm3, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
cvttps2dq(xym1, xym1);
|
||||
packssdw(xym1, xym1);
|
||||
|
||||
// m_local.d[i].rb = r.upl16(b);
|
||||
|
||||
punpcklwd(xym0, xym1);
|
||||
movdqa(_rip_local(d[i].rb), xym0);
|
||||
}
|
||||
|
||||
// GSVector4 c = dscan.c;
|
||||
|
||||
broadcastf128(xym0, ptr[_dscan + offsetof(GSVertexSW, c)]); // not enough regs, have to reload it
|
||||
|
||||
// GSVector4 dg = c.yyyy();
|
||||
// GSVector4 da = c.wwww();
|
||||
|
||||
THREEARG(shufps, xym2, xym0, xym0, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
THREEARG(shufps, xym3, xym0, xym0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : dsize); i++)
|
||||
{
|
||||
// GSVector4i g = GSVector4i(dg * m_shift[i]).ps32();
|
||||
|
||||
if (i < 4 || many_regs)
|
||||
THREEARG(mulps, xym0, XYm(4 + i), xym2);
|
||||
else
|
||||
vmulps(ymm0, ymm2, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
cvttps2dq(xym0, xym0);
|
||||
packssdw(xym0, xym0);
|
||||
|
||||
// GSVector4i a = GSVector4i(da * m_shift[i]).ps32();
|
||||
|
||||
if (i < 4 || many_regs)
|
||||
THREEARG(mulps, xym1, XYm(4 + i), xym3);
|
||||
else
|
||||
vmulps(ymm1, ymm3, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
cvttps2dq(xym1, xym1);
|
||||
packssdw(xym1, xym1);
|
||||
|
||||
// m_local.d[i].ga = g.upl16(a);
|
||||
|
||||
punpcklwd(xym0, xym1);
|
||||
movdqa(_rip_local(d[i].ga), xym0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4i c = GSVector4i(vertex[index[last].c);
|
||||
|
||||
int last = 0;
|
||||
|
||||
switch (m_sel.prim)
|
||||
{
|
||||
case GS_POINT_CLASS: last = 0; break;
|
||||
case GS_LINE_CLASS: last = 1; break;
|
||||
case GS_TRIANGLE_CLASS: last = 2; break;
|
||||
case GS_SPRITE_CLASS: last = 1; break;
|
||||
}
|
||||
|
||||
if (!(m_sel.prim == GS_SPRITE_CLASS && (m_en.z || m_en.f))) // if this is a sprite, the last vertex was already loaded in Depth()
|
||||
{
|
||||
if (is32)
|
||||
mov(_index, ptr[rsp + _32_index]);
|
||||
mov(eax, ptr[_index + sizeof(uint32) * last]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
if (is64)
|
||||
add(rax, _64_vertex);
|
||||
else
|
||||
add(rax, ptr[rsp + _32_vertex]);
|
||||
}
|
||||
|
||||
if (isXmm)
|
||||
{
|
||||
cvttps2dq(xmm0, ptr[rax + offsetof(GSVertexSW, c)]);
|
||||
}
|
||||
else
|
||||
{
|
||||
vbroadcasti128(ymm0, ptr[rax + offsetof(GSVertexSW, c)]);
|
||||
cvttps2dq(ymm0, ymm0);
|
||||
}
|
||||
|
||||
// c = c.upl16(c.zwxy());
|
||||
|
||||
pshufd(xym1, xym0, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
punpcklwd(xym0, xym1);
|
||||
|
||||
// if(!tme) c = c.srl16(7);
|
||||
|
||||
if (m_sel.tfx == TFX_NONE)
|
||||
{
|
||||
psrlw(xym0, 7);
|
||||
}
|
||||
|
||||
// m_local.c.rb = c.xxxx();
|
||||
// m_local.c.ga = c.zzzz();
|
||||
|
||||
pshufd(xym1, xym0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
pshufd(xym2, xym0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
movdqa(_rip_local(c.rb), xym1);
|
||||
movdqa(_rip_local(c.ga), xym2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSScanlineEnvironment.h"
|
||||
#include "GSNewCodeGenerator.h"
|
||||
|
||||
#if _M_SSE >= 0x501
|
||||
#define SETUP_PRIM_VECTOR_REGISTER Xbyak::Ymm
|
||||
#define SETUP_PRIM_USING_XMM 0
|
||||
#define SETUP_PRIM_USING_YMM 1
|
||||
#else
|
||||
#define SETUP_PRIM_VECTOR_REGISTER Xbyak::Xmm
|
||||
#define SETUP_PRIM_USING_XMM 1
|
||||
#define SETUP_PRIM_USING_YMM 0
|
||||
#endif
|
||||
|
||||
class GSSetupPrimCodeGenerator2 : public GSNewCodeGenerator
|
||||
{
|
||||
using _parent = GSNewCodeGenerator;
|
||||
using XYm = SETUP_PRIM_VECTOR_REGISTER;
|
||||
|
||||
using Xmm = Xbyak::Xmm;
|
||||
using Ymm = Xbyak::Ymm;
|
||||
|
||||
/// On x86-64 we reserve a bunch of GPRs for holding addresses of locals that would otherwise be hard to reach
|
||||
/// On x86-32 the same values are just raw 32-bit addresses
|
||||
using LocalAddr = Choose3264<size_t, AddressReg>::type;
|
||||
|
||||
constexpr static bool isXmm = std::is_same<XYm, Xbyak::Xmm>::value;
|
||||
constexpr static bool isYmm = std::is_same<XYm, Xbyak::Ymm>::value;
|
||||
constexpr static int vecsize = isXmm ? 16 : 32;
|
||||
|
||||
constexpr static int dsize = isXmm ? 4 : 8;
|
||||
|
||||
constexpr static int _32_args = 0;
|
||||
constexpr static int _invalid = 0xaaaaaaaa;
|
||||
constexpr static int _32_vertex = is64 ? _invalid : _32_args + 4;
|
||||
constexpr static int _32_index = is64 ? _invalid : _32_args + 8;
|
||||
constexpr static int _32_dscan = is64 ? _invalid : _32_args + 12;
|
||||
|
||||
GSScanlineSelector m_sel;
|
||||
GSScanlineLocalData& m_local;
|
||||
bool m_rip;
|
||||
bool many_regs;
|
||||
|
||||
struct {uint32 z:1, f:1, t:1, c:1;} m_en;
|
||||
|
||||
const XYm xym0{0}, xym1{1}, xym2{2}, xym3{3}, xym4{4}, xym5{5}, xym6{6}, xym7{7}, xym8{8}, xym9{9}, xym10{10}, xym11{11}, xym12{12}, xym13{13}, xym14{14}, xym15{15};
|
||||
const AddressReg _64_vertex, _index, _dscan, _64_t0, t1;
|
||||
const LocalAddr _m_local;
|
||||
/// Returns the first arg on 32-bit, second on 64-bit
|
||||
static LocalAddr chooseLocal(const void* addr32, AddressReg reg64)
|
||||
{
|
||||
return choose3264((size_t)addr32, reg64);
|
||||
}
|
||||
|
||||
public:
|
||||
GSSetupPrimCodeGenerator2(Xbyak::CodeGenerator* base, CPUInfo cpu, void* param, uint64 key);
|
||||
void Generate();
|
||||
|
||||
private:
|
||||
/// Broadcast 128 bits of floats from memory to the whole register, whatever size that register might be
|
||||
void broadcastf128(const XYm& reg, const Xbyak::Address& mem);
|
||||
|
||||
void Depth_XMM();
|
||||
void Depth_YMM();
|
||||
void Texture();
|
||||
void Color();
|
||||
};
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSSetupPrimCodeGenerator.h"
|
||||
#include "GSSetupPrimCodeGenerator.all.h"
|
||||
|
||||
using namespace Xbyak;
|
||||
|
||||
@@ -30,19 +31,5 @@ GSSetupPrimCodeGenerator::GSSetupPrimCodeGenerator(void* param, uint64 key, void
|
||||
m_en.t = m_sel.fb && m_sel.tfx != TFX_NONE ? 1 : 0;
|
||||
m_en.c = m_sel.fb && !(m_sel.tfx == TFX_DECAL && m_sel.tcc) ? 1 : 0;
|
||||
|
||||
try
|
||||
{
|
||||
#if _M_SSE >= 0x501
|
||||
Generate_AVX2();
|
||||
#else
|
||||
if (m_cpu.has(util::Cpu::tAVX))
|
||||
Generate_AVX();
|
||||
else
|
||||
Generate_SSE();
|
||||
#endif
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fprintf(stderr, "ERR:GSSetupPrimCodeGenerator %s\n", e.what());
|
||||
}
|
||||
GSSetupPrimCodeGenerator2(this, CPUInfo(m_cpu), param, key).Generate();
|
||||
}
|
||||
|
||||
@@ -32,23 +32,6 @@ class GSSetupPrimCodeGenerator : public GSCodeGenerator
|
||||
uint32 z : 1, f : 1, t : 1, c : 1;
|
||||
} m_en;
|
||||
|
||||
#if _M_SSE < 0x501
|
||||
void Generate_SSE();
|
||||
void Depth_SSE();
|
||||
void Texture_SSE();
|
||||
void Color_SSE();
|
||||
|
||||
void Generate_AVX();
|
||||
void Depth_AVX();
|
||||
void Texture_AVX();
|
||||
void Color_AVX();
|
||||
#else
|
||||
void Generate_AVX2();
|
||||
void Depth_AVX2();
|
||||
void Texture_AVX2();
|
||||
void Color_AVX2();
|
||||
#endif
|
||||
|
||||
public:
|
||||
GSSetupPrimCodeGenerator(void* param, uint64 key, void* code, size_t maxsize);
|
||||
};
|
||||
|
||||
@@ -1,365 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSSetupPrimCodeGenerator.h"
|
||||
#include "GSVertexSW.h"
|
||||
#include "GS/GS_codegen.h"
|
||||
|
||||
#if _M_SSE < 0x501 && (defined(_M_AMD64) || defined(_WIN64))
|
||||
|
||||
#define _rip_local(field) (m_rip ? ptr[rip + &m_local.field] : ptr[t0 + offsetof(GSScanlineLocalData, field)])
|
||||
#define _rip_local_v(field, offset) (m_rip ? ptr[rip + &m_local.field] : ptr[t0 + offset])
|
||||
|
||||
void GSSetupPrimCodeGenerator::Generate_AVX()
|
||||
{
|
||||
// Technically we just need the delta < 2GB
|
||||
m_rip = (size_t)&m_local < 0x80000000 && (size_t)getCurr() < 0x80000000;
|
||||
|
||||
#ifdef _WIN64
|
||||
sub(rsp, 8 + 2 * 16);
|
||||
|
||||
vmovdqa(ptr[rsp + 0], xmm6);
|
||||
vmovdqa(ptr[rsp + 16], xmm7);
|
||||
#endif
|
||||
|
||||
if (!m_rip)
|
||||
mov(t0, (size_t)&m_local);
|
||||
|
||||
if ((m_en.z || m_en.f) && m_sel.prim != GS_SPRITE_CLASS || m_en.t || m_en.c && m_sel.iip)
|
||||
{
|
||||
mov(rax, (size_t)g_const->m_shift_128b);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 2 : 5); i++)
|
||||
{
|
||||
vmovaps(Xmm(3 + i), ptr[rax + i * 16]);
|
||||
}
|
||||
}
|
||||
|
||||
Depth_AVX();
|
||||
|
||||
Texture_AVX();
|
||||
|
||||
Color_AVX();
|
||||
|
||||
#ifdef _WIN64
|
||||
vmovdqa(xmm6, ptr[rsp + 0]);
|
||||
vmovdqa(xmm7, ptr[rsp + 16]);
|
||||
|
||||
add(rsp, 8 + 2 * 16);
|
||||
#endif
|
||||
|
||||
ret();
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Depth_AVX()
|
||||
{
|
||||
if (!m_en.z && !m_en.f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
// GSVector4 p = dscan.p;
|
||||
|
||||
vmovaps(xmm0, ptr[a2 + offsetof(GSVertexSW, p)]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// GSVector4 df = p.wwww();
|
||||
|
||||
vshufps(xmm1, xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
// m_local.d4.f = GSVector4i(df * 4.0f).xxzzlh();
|
||||
|
||||
vmulps(xmm2, xmm1, xmm3);
|
||||
vcvttps2dq(xmm2, xmm2);
|
||||
vpshuflw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
vpshufhw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
vmovdqa(_rip_local(d4.f), xmm2);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// m_local.d[i].f = GSVector4i(df * m_shift[i]).xxzzlh();
|
||||
|
||||
vmulps(xmm2, xmm1, Xmm(4 + i));
|
||||
vcvttps2dq(xmm2, xmm2);
|
||||
vpshuflw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
vpshufhw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].f) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
vmovdqa(_rip_local_v(d[i].f, variableOffset), xmm2);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// GSVector4 dz = p.zzzz();
|
||||
|
||||
vshufps(xmm0, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
// m_local.d4.z = dz * 4.0f;
|
||||
|
||||
vmulps(xmm1, xmm0, xmm3);
|
||||
vmovdqa(_rip_local(d4.z), xmm1);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// m_local.d[i].z = dz * m_shift[i];
|
||||
|
||||
vmulps(xmm1, xmm0, Xmm(4 + i));
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].z) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
vmovdqa(_rip_local_v(d[i].z, variableOffset), xmm1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
mov(eax, ptr[a1 + sizeof(uint32) * 1]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
add(rax, a0);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.p.f = GSVector4i(p).zzzzh().zzzz();
|
||||
vmovaps(xmm0, ptr[rax + offsetof(GSVertexSW, p)]);
|
||||
|
||||
vcvttps2dq(xmm1, xmm0);
|
||||
vpshufhw(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
vpshufd(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
vmovdqa(_rip_local(p.f), xmm1);
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// uint32 z is bypassed in t.w
|
||||
|
||||
vmovdqa(xmm0, ptr[rax + offsetof(GSVertexSW, t)]);
|
||||
vpshufd(xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
vmovdqa(_rip_local(p.z), xmm0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Texture_AVX()
|
||||
{
|
||||
if (!m_en.t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// GSVector4 t = dscan.t;
|
||||
|
||||
vmovaps(xmm0, ptr[a2 + offsetof(GSVertexSW, t)]);
|
||||
|
||||
vmulps(xmm1, xmm0, xmm3);
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d4.stq = GSVector4i(t * 4.0f);
|
||||
|
||||
vcvttps2dq(xmm1, xmm1);
|
||||
|
||||
vmovdqa(_rip_local(d4.stq), xmm1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d4.stq = t * 4.0f;
|
||||
|
||||
vmovaps(_rip_local(d4.stq), xmm1);
|
||||
}
|
||||
|
||||
for (int j = 0, k = m_sel.fst ? 2 : 3; j < k; j++)
|
||||
{
|
||||
// GSVector4 ds = t.xxxx();
|
||||
// GSVector4 dt = t.yyyy();
|
||||
// GSVector4 dq = t.zzzz();
|
||||
|
||||
vshufps(xmm1, xmm0, xmm0, (uint8)_MM_SHUFFLE(j, j, j, j));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4 v = ds/dt * m_shift[i];
|
||||
|
||||
vmulps(xmm2, xmm1, Xmm(4 + i));
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d[i].s/t = GSVector4i(v);
|
||||
|
||||
vcvttps2dq(xmm2, xmm2);
|
||||
|
||||
const size_t variableOffsetS = offsetof(GSScanlineLocalData, d[0].s) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
const size_t variableOffsetT = offsetof(GSScanlineLocalData, d[0].t) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: vmovdqa(_rip_local_v(d[i].s, variableOffsetS), xmm2); break;
|
||||
case 1: vmovdqa(_rip_local_v(d[i].t, variableOffsetT), xmm2); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d[i].s/t/q = v;
|
||||
|
||||
const size_t variableOffsetS = offsetof(GSScanlineLocalData, d[0].s) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
const size_t variableOffsetT = offsetof(GSScanlineLocalData, d[0].t) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
const size_t variableOffsetQ = offsetof(GSScanlineLocalData, d[0].q) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: vmovaps(_rip_local_v(d[i].s, variableOffsetS), xmm2); break;
|
||||
case 1: vmovaps(_rip_local_v(d[i].t, variableOffsetT), xmm2); break;
|
||||
case 2: vmovaps(_rip_local_v(d[i].q, variableOffsetQ), xmm2); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Color_AVX()
|
||||
{
|
||||
if (!m_en.c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.iip)
|
||||
{
|
||||
// GSVector4 c = dscan.c;
|
||||
|
||||
vmovaps(xmm0, ptr[a2 + offsetof(GSVertexSW, c)]);
|
||||
|
||||
// m_local.d4.c = GSVector4i(c * 4.0f).xzyw().ps32();
|
||||
|
||||
vmulps(xmm1, xmm0, xmm3);
|
||||
vcvttps2dq(xmm1, xmm1);
|
||||
vpshufd(xmm1, xmm1, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
vpackssdw(xmm1, xmm1);
|
||||
vmovdqa(_rip_local(d4.c), xmm1);
|
||||
|
||||
// xmm3 is not needed anymore
|
||||
|
||||
// GSVector4 dr = c.xxxx();
|
||||
// GSVector4 db = c.zzzz();
|
||||
|
||||
vshufps(xmm2, xmm0, xmm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
vshufps(xmm3, xmm0, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4i r = GSVector4i(dr * m_shift[i]).ps32();
|
||||
|
||||
vmulps(xmm0, xmm2, Xmm(4 + i));
|
||||
vcvttps2dq(xmm0, xmm0);
|
||||
vpackssdw(xmm0, xmm0);
|
||||
|
||||
// GSVector4i b = GSVector4i(db * m_shift[i]).ps32();
|
||||
|
||||
vmulps(xmm1, xmm3, Xmm(4 + i));
|
||||
vcvttps2dq(xmm1, xmm1);
|
||||
vpackssdw(xmm1, xmm1);
|
||||
|
||||
// m_local.d[i].rb = r.upl16(b);
|
||||
|
||||
vpunpcklwd(xmm0, xmm1);
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].rb) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
vmovdqa(_rip_local_v(d[i].rb, variableOffset), xmm0);
|
||||
}
|
||||
|
||||
// GSVector4 c = dscan.c;
|
||||
|
||||
vmovaps(xmm0, ptr[a2 + offsetof(GSVertexSW, c)]); // not enough regs, have to reload it
|
||||
|
||||
// GSVector4 dg = c.yyyy();
|
||||
// GSVector4 da = c.wwww();
|
||||
|
||||
vshufps(xmm2, xmm0, xmm0, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
vshufps(xmm3, xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4i g = GSVector4i(dg * m_shift[i]).ps32();
|
||||
|
||||
vmulps(xmm0, xmm2, Xmm(4 + i));
|
||||
vcvttps2dq(xmm0, xmm0);
|
||||
vpackssdw(xmm0, xmm0);
|
||||
|
||||
// GSVector4i a = GSVector4i(da * m_shift[i]).ps32();
|
||||
|
||||
vmulps(xmm1, xmm3, Xmm(4 + i));
|
||||
vcvttps2dq(xmm1, xmm1);
|
||||
vpackssdw(xmm1, xmm1);
|
||||
|
||||
// m_local.d[i].ga = g.upl16(a);
|
||||
|
||||
vpunpcklwd(xmm0, xmm1);
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].ga) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
vmovdqa(_rip_local_v(d[i].ga, variableOffset), xmm0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4i c = GSVector4i(vertex[index[last].c);
|
||||
|
||||
int last = 0;
|
||||
|
||||
switch (m_sel.prim)
|
||||
{
|
||||
case GS_POINT_CLASS: last = 0; break;
|
||||
case GS_LINE_CLASS: last = 1; break;
|
||||
case GS_TRIANGLE_CLASS: last = 2; break;
|
||||
case GS_SPRITE_CLASS: last = 1; break;
|
||||
}
|
||||
|
||||
if (!(m_sel.prim == GS_SPRITE_CLASS && (m_en.z || m_en.f))) // if this is a sprite, the last vertex was already loaded in Depth()
|
||||
{
|
||||
mov(eax, ptr[a1 + sizeof(uint32) * last]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
add(rax, a0);
|
||||
}
|
||||
|
||||
vcvttps2dq(xmm0, ptr[rax + offsetof(GSVertexSW, c)]);
|
||||
|
||||
// c = c.upl16(c.zwxy());
|
||||
|
||||
vpshufd(xmm1, xmm0, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
vpunpcklwd(xmm0, xmm1);
|
||||
|
||||
// if(!tme) c = c.srl16(7);
|
||||
|
||||
if (m_sel.tfx == TFX_NONE)
|
||||
{
|
||||
vpsrlw(xmm0, 7);
|
||||
}
|
||||
|
||||
// m_local.c.rb = c.xxxx();
|
||||
// m_local.c.ga = c.zzzz();
|
||||
|
||||
vpshufd(xmm1, xmm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
vpshufd(xmm2, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
vmovdqa(_rip_local(c.rb), xmm1);
|
||||
vmovdqa(_rip_local(c.ga), xmm2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,368 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSSetupPrimCodeGenerator.h"
|
||||
#include "GSVertexSW.h"
|
||||
#include "GS/GS_codegen.h"
|
||||
|
||||
#if _M_SSE >= 0x501 && (defined(_M_AMD64) || defined(_WIN64))
|
||||
|
||||
#define _rip_local(field) (m_rip ? ptr[rip + &m_local.field] : ptr[t0 + offsetof(GSScanlineLocalData, field)])
|
||||
#define _rip_local_v(field, offset) (m_rip ? ptr[rip + &m_local.field] : ptr[t0 + offset])
|
||||
|
||||
#define _m_shift(i) (Ymm(7 + i))
|
||||
|
||||
// FIXME windows ?
|
||||
#define _vertex rcx
|
||||
|
||||
void GSSetupPrimCodeGenerator::Generate_AVX2()
|
||||
{
|
||||
// Technically we just need the delta < 2GB
|
||||
m_rip = (size_t)&m_local < 0x80000000 && (size_t)getCurr() < 0x80000000;
|
||||
|
||||
#ifdef _WIN64
|
||||
sub(rsp, 8 + 2 * 16);
|
||||
|
||||
vmovdqa(ptr[rsp + 0], ymm6);
|
||||
vmovdqa(ptr[rsp + 16], ymm7);
|
||||
#endif
|
||||
|
||||
if (!m_rip)
|
||||
mov(t0, (size_t)&m_local);
|
||||
|
||||
if ((m_en.z || m_en.f) && m_sel.prim != GS_SPRITE_CLASS || m_en.t || m_en.c && m_sel.iip)
|
||||
{
|
||||
mov(rax, (size_t)g_const->m_shift_256b);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 2 : 9); i++)
|
||||
{
|
||||
vmovaps(_m_shift(i), ptr[rax + i * 32]);
|
||||
}
|
||||
}
|
||||
// ymm7 to ymm 15 = m_shift[i]
|
||||
|
||||
Depth_AVX2();
|
||||
|
||||
Texture_AVX2();
|
||||
|
||||
Color_AVX2();
|
||||
|
||||
#ifdef _WIN64
|
||||
vmovdqa(ymm6, ptr[rsp + 0]);
|
||||
vmovdqa(ymm7, ptr[rsp + 16]);
|
||||
|
||||
add(rsp, 8 + 2 * 16);
|
||||
#endif
|
||||
|
||||
ret();
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Depth_AVX2()
|
||||
{
|
||||
if (!m_en.z && !m_en.f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
const Ymm& dscan_p = ymm6;
|
||||
|
||||
// GSVector4 dp8 = dscan.p * GSVector4::broadcast32(&shift[0]);
|
||||
|
||||
vbroadcastf128(dscan_p, ptr[a2 + offsetof(GSVertexSW, p)]);
|
||||
|
||||
vmulps(ymm1, dscan_p, _m_shift(0));
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// m_local.d8.p.z = dp8.extract32<2>();
|
||||
|
||||
vextractps(_rip_local(d8.p.z), xmm1, 2);
|
||||
|
||||
// GSVector8 dz = GSVector8(dscan.p).zzzz();
|
||||
|
||||
vshufps(ymm2, dscan_p, dscan_p, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 8); i++)
|
||||
{
|
||||
// m_local.d[i].z = dz * shift[1 + i];
|
||||
|
||||
vmulps(ymm0, ymm2, _m_shift(1 + i));
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].z) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
vmovaps(_rip_local_v(d[i].z, variableOffset), ymm0);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.d8.p.f = GSVector4i(dp8).extract32<3>();
|
||||
|
||||
// FIXME no truncate ? why ? vcvttps2dq ?
|
||||
//vcvtps2dq(ymm2, ymm1); // let's guess a typo
|
||||
vcvttps2dq(ymm2, ymm1);
|
||||
vpextrd(_rip_local(d8.p.f), xmm2, 3);
|
||||
|
||||
// GSVector8 df = GSVector8(dscan.p).wwww();
|
||||
|
||||
vshufps(ymm3, dscan_p, dscan_p, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 8); i++)
|
||||
{
|
||||
// m_local.d[i].f = GSVector8i(df * m_shift[i]).xxzzlh();
|
||||
|
||||
vmulps(ymm0, ymm3, _m_shift(1 + i));
|
||||
vcvttps2dq(ymm0, ymm0);
|
||||
|
||||
vpshuflw(ymm0, ymm0, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
vpshufhw(ymm0, ymm0, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].f) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
vmovdqa(_rip_local_v(d[i].f, variableOffset), ymm0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
mov(_vertex.cvt32(), ptr[a1 + sizeof(uint32) * 1]);
|
||||
shl(_vertex.cvt32(), 6); // * sizeof(GSVertexSW)
|
||||
add(_vertex, a0);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.p.f = GSVector4i(vertex[index[1]].p).extract32<3>();
|
||||
|
||||
vmovaps(xmm0, ptr[_vertex + offsetof(GSVertexSW, p)]);
|
||||
vcvttps2dq(xmm0, xmm0);
|
||||
vpextrd(_rip_local(p.f), xmm0, 3);
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// m_local.p.z = vertex[index[1]].t.u32[3]; // uint32 z is bypassed in t.w
|
||||
|
||||
mov(eax, ptr[ecx + offsetof(GSVertexSW, t.w)]);
|
||||
mov(_rip_local(p.z), eax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Texture_AVX2()
|
||||
{
|
||||
if (!m_en.t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// GSVector8 dt(dscan.t);
|
||||
|
||||
vbroadcastf128(ymm0, ptr[a2 + offsetof(GSVertexSW, t)]);
|
||||
|
||||
// GSVector8 dt8 = dt * shift[0];
|
||||
|
||||
vmulps(ymm1, ymm0, _m_shift(0));
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.84.stq = GSVector4i(t * 4.0f);
|
||||
|
||||
vcvttps2dq(ymm1, ymm1);
|
||||
|
||||
vmovdqa(_rip_local(d8.stq), xmm1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d8.stq = t * 4.0f;
|
||||
|
||||
vmovaps(_rip_local(d8.stq), xmm1);
|
||||
}
|
||||
|
||||
for (int j = 0, k = m_sel.fst ? 2 : 3; j < k; j++)
|
||||
{
|
||||
// GSVector8 dstq = dt.xxxx/yyyy/zzzz();
|
||||
|
||||
vshufps(ymm1, ymm0, ymm0, (uint8)_MM_SHUFFLE(j, j, j, j));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 8); i++)
|
||||
{
|
||||
// GSVector8 v = dstq * shift[1 + i];
|
||||
|
||||
vmulps(ymm2, ymm1, _m_shift(1 + i));
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d[i].s/t = GSVector8::cast(GSVector8i(v));
|
||||
|
||||
vcvttps2dq(ymm2, ymm2);
|
||||
|
||||
const size_t variableOffsetS = offsetof(GSScanlineLocalData, d[0].s) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
const size_t variableOffsetT = offsetof(GSScanlineLocalData, d[0].t) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: vmovdqa(_rip_local_v(d[i].s, variableOffsetS), ymm2); break;
|
||||
case 1: vmovdqa(_rip_local_v(d[i].t, variableOffsetT), ymm2); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d[i].s/t/q = v;
|
||||
|
||||
const size_t variableOffsetS = offsetof(GSScanlineLocalData, d[0].s) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
const size_t variableOffsetT = offsetof(GSScanlineLocalData, d[0].t) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
const size_t variableOffsetQ = offsetof(GSScanlineLocalData, d[0].q) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: vmovaps(_rip_local_v(d[i].s, variableOffsetS), ymm2); break;
|
||||
case 1: vmovaps(_rip_local_v(d[i].t, variableOffsetT), ymm2); break;
|
||||
case 2: vmovaps(_rip_local_v(d[i].q, variableOffsetQ), ymm2); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Color_AVX2()
|
||||
{
|
||||
if (!m_en.c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.iip)
|
||||
{
|
||||
const Ymm& dscan_c = ymm6;
|
||||
|
||||
// GSVector8 dc(dscan.c);
|
||||
|
||||
vbroadcastf128(dscan_c, ptr[a2 + offsetof(GSVertexSW, c)]);
|
||||
|
||||
// m_local.d8.c = GSVector4i(c * 4.0f).xzyw().ps32();
|
||||
|
||||
vmulps(ymm1, dscan_c, ymm3);
|
||||
vcvttps2dq(ymm1, ymm1);
|
||||
vpshufd(ymm1, ymm1, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
vpackssdw(ymm1, ymm1);
|
||||
vmovq(_rip_local(d8.c), xmm1);
|
||||
|
||||
// GSVector8 dr = dc.xxxx();
|
||||
// GSVector8 db = dc.zzzz();
|
||||
|
||||
vshufps(ymm2, dscan_c, dscan_c, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
vshufps(ymm3, dscan_c, dscan_c, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 8); i++)
|
||||
{
|
||||
// GSVector8i r = GSVector8i(dr * shift[1 + i]).ps32();
|
||||
|
||||
vmulps(ymm0, ymm2, _m_shift(1 + i));
|
||||
vcvttps2dq(ymm0, ymm0);
|
||||
vpackssdw(ymm0, ymm0);
|
||||
|
||||
// GSVector4i b = GSVector8i(db * shift[1 + i]).ps32();
|
||||
|
||||
vmulps(ymm1, ymm3, _m_shift(1 + i));
|
||||
vcvttps2dq(ymm1, ymm1);
|
||||
vpackssdw(ymm1, ymm1);
|
||||
|
||||
// m_local.d[i].rb = r.upl16(b);
|
||||
|
||||
vpunpcklwd(ymm0, ymm1);
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].rb) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
vmovdqa(_rip_local_v(d[i].rb, variableOffset), ymm0);
|
||||
}
|
||||
|
||||
// GSVector8 dg = dc.yyyy();
|
||||
// GSVector8 da = dc.wwww();
|
||||
|
||||
vshufps(ymm2, dscan_c, dscan_c, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
vshufps(ymm3, dscan_c, dscan_c, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 8); i++)
|
||||
{
|
||||
// GSVector8i g = GSVector8i(dg * shift[1 + i]).ps32();
|
||||
|
||||
vmulps(ymm0, ymm2, _m_shift(1 + i));
|
||||
vcvttps2dq(ymm0, ymm0);
|
||||
vpackssdw(ymm0, ymm0);
|
||||
|
||||
// GSVector8i a = GSVector8i(da * shift[1 + i]).ps32();
|
||||
|
||||
vmulps(ymm1, ymm3, _m_shift(1 + i));
|
||||
vcvttps2dq(ymm1, ymm1);
|
||||
vpackssdw(ymm1, ymm1);
|
||||
|
||||
// m_local.d[i].ga = g.upl16(a);
|
||||
|
||||
vpunpcklwd(ymm0, ymm1);
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].ga) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
vmovdqa(_rip_local_v(d[i].ga, variableOffset), ymm0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4i c = GSVector4i(vertex[index[last].c);
|
||||
|
||||
int last = 0;
|
||||
|
||||
switch (m_sel.prim)
|
||||
{
|
||||
case GS_POINT_CLASS: last = 0; break;
|
||||
case GS_LINE_CLASS: last = 1; break;
|
||||
case GS_TRIANGLE_CLASS: last = 2; break;
|
||||
case GS_SPRITE_CLASS: last = 1; break;
|
||||
}
|
||||
|
||||
if (!(m_sel.prim == GS_SPRITE_CLASS && (m_en.z || m_en.f))) // if this is a sprite, the last vertex was already loaded in Depth()
|
||||
{
|
||||
mov(_vertex.cvt32(), ptr[a1 + sizeof(uint32) * last]);
|
||||
shl(_vertex.cvt32(), 6); // * sizeof(GSVertexSW)
|
||||
add(_vertex, a0);
|
||||
}
|
||||
|
||||
vbroadcasti128(ymm0, ptr[_vertex + offsetof(GSVertexSW, c)]);
|
||||
vcvttps2dq(ymm0, ymm0);
|
||||
|
||||
// c = c.upl16(c.zwxy());
|
||||
|
||||
vpshufd(ymm1, ymm0, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
vpunpcklwd(ymm0, ymm1);
|
||||
|
||||
// if(!tme) c = c.srl16(7);
|
||||
|
||||
if (m_sel.tfx == TFX_NONE)
|
||||
{
|
||||
vpsrlw(ymm0, 7);
|
||||
}
|
||||
|
||||
// m_local.c.rb = c.xxxx();
|
||||
// m_local.c.ga = c.zzzz();
|
||||
|
||||
vpshufd(ymm1, ymm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
vpshufd(ymm2, ymm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
vmovdqa(_rip_local(c.rb), ymm1);
|
||||
vmovdqa(_rip_local(c.ga), ymm2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,374 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSSetupPrimCodeGenerator.h"
|
||||
#include "GSVertexSW.h"
|
||||
#include "GS/GS_codegen.h"
|
||||
|
||||
#if _M_SSE < 0x501 && (defined(_M_AMD64) || defined(_WIN64))
|
||||
|
||||
void GSSetupPrimCodeGenerator::Generate_SSE()
|
||||
{
|
||||
#ifdef _WIN64
|
||||
sub(rsp, 8 + 2 * 16);
|
||||
|
||||
vmovdqa(ptr[rsp + 0], xmm6);
|
||||
vmovdqa(ptr[rsp + 16], xmm7);
|
||||
#endif
|
||||
|
||||
mov(t0, (size_t)&m_local);
|
||||
|
||||
if ((m_en.z || m_en.f) && m_sel.prim != GS_SPRITE_CLASS || m_en.t || m_en.c && m_sel.iip)
|
||||
{
|
||||
mov(rax, (size_t)g_const->m_shift_128b[0]);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 2 : 5); i++)
|
||||
{
|
||||
movaps(Xmm(3 + i), ptr[rax + i * 16]);
|
||||
}
|
||||
}
|
||||
|
||||
Depth_SSE();
|
||||
|
||||
Texture_SSE();
|
||||
|
||||
Color_SSE();
|
||||
|
||||
#ifdef _WIN64
|
||||
vmovdqa(xmm6, ptr[rsp + 0]);
|
||||
vmovdqa(xmm7, ptr[rsp + 16]);
|
||||
|
||||
add(rsp, 8 + 2 * 16);
|
||||
#endif
|
||||
|
||||
ret();
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Depth_SSE()
|
||||
{
|
||||
if (!m_en.z && !m_en.f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
// GSVector4 p = dscan.p;
|
||||
|
||||
movaps(xmm0, ptr[a2 + offsetof(GSVertexSW, p)]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// GSVector4 df = p.wwww();
|
||||
|
||||
movaps(xmm1, xmm0);
|
||||
shufps(xmm1, xmm1, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
// m_local.d4.f = GSVector4i(df * 4.0f).xxzzlh();
|
||||
|
||||
movaps(xmm2, xmm1);
|
||||
mulps(xmm2, xmm3);
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
pshuflw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
movdqa(ptr[t0 + offsetof(GSScanlineLocalData, d4.f)], xmm2);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// m_local.d[i].f = GSVector4i(df * m_shift[i]).xxzzlh();
|
||||
|
||||
movaps(xmm2, xmm1);
|
||||
mulps(xmm2, Xmm(4 + i));
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
pshuflw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].f) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
movdqa(ptr[t0 + variableOffset], xmm2);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// GSVector4 dz = p.zzzz();
|
||||
|
||||
shufps(xmm0, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
// m_local.d4.z = dz * 4.0f;
|
||||
|
||||
movaps(xmm1, xmm0);
|
||||
mulps(xmm1, xmm3);
|
||||
movdqa(ptr[t0 + offsetof(GSScanlineLocalData, d4.z)], xmm1);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// m_local.d[i].z = dz * m_shift[i];
|
||||
|
||||
movaps(xmm1, xmm0);
|
||||
mulps(xmm1, Xmm(4 + i));
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].z) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
movdqa(ptr[t0 + variableOffset], xmm1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
mov(eax, ptr[a1 + sizeof(uint32) * 1]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
add(rax, a0);
|
||||
|
||||
movaps(xmm0, ptr[rax + offsetof(GSVertexSW, p)]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.p.f = GSVector4i(p).zzzzh().zzzz();
|
||||
|
||||
cvttps2dq(xmm1, xmm0);
|
||||
pshufhw(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
pshufd(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
movdqa(ptr[t0 + offsetof(GSScanlineLocalData, p.f)], xmm1);
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// uint32 z is bypassed in t.w
|
||||
|
||||
vmovdqa(xmm0, ptr[rax + offsetof(GSVertexSW, t)]);
|
||||
vpshufd(xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
vmovdqa(ptr[t0 + offsetof(GSScanlineLocalData, p.z)], xmm0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Texture_SSE()
|
||||
{
|
||||
if (!m_en.t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// GSVector4 t = dscan.t;
|
||||
|
||||
movaps(xmm0, ptr[a2 + offsetof(GSVertexSW, t)]);
|
||||
|
||||
movaps(xmm1, xmm0);
|
||||
mulps(xmm1, xmm3);
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d4.stq = GSVector4i(t * 4.0f);
|
||||
|
||||
cvttps2dq(xmm1, xmm1);
|
||||
|
||||
movdqa(ptr[t0 + offsetof(GSScanlineLocalData, d4.stq)], xmm1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d4.stq = t * 4.0f;
|
||||
|
||||
movaps(ptr[t0 + offsetof(GSScanlineLocalData, d4.stq)], xmm1);
|
||||
}
|
||||
|
||||
for (int j = 0, k = m_sel.fst ? 2 : 3; j < k; j++)
|
||||
{
|
||||
// GSVector4 ds = t.xxxx();
|
||||
// GSVector4 dt = t.yyyy();
|
||||
// GSVector4 dq = t.zzzz();
|
||||
|
||||
movaps(xmm1, xmm0);
|
||||
shufps(xmm1, xmm1, (uint8)_MM_SHUFFLE(j, j, j, j));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4 v = ds/dt * m_shift[i];
|
||||
|
||||
movaps(xmm2, xmm1);
|
||||
mulps(xmm2, Xmm(4 + i));
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d[i].s/t = GSVector4i(v);
|
||||
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
|
||||
const size_t variableOffsetS = offsetof(GSScanlineLocalData, d[0].s) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
const size_t variableOffsetT = offsetof(GSScanlineLocalData, d[0].t) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: movdqa(ptr[t0 + variableOffsetS], xmm2); break;
|
||||
case 1: movdqa(ptr[t0 + variableOffsetT], xmm2); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d[i].s/t/q = v;
|
||||
|
||||
const size_t variableOffsetS = offsetof(GSScanlineLocalData, d[0].s) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
const size_t variableOffsetT = offsetof(GSScanlineLocalData, d[0].t) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
const size_t variableOffsetQ = offsetof(GSScanlineLocalData, d[0].q) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: movaps(ptr[t0 + variableOffsetS], xmm2); break;
|
||||
case 1: movaps(ptr[t0 + variableOffsetT], xmm2); break;
|
||||
case 2: movaps(ptr[t0 + variableOffsetQ], xmm2); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Color_SSE()
|
||||
{
|
||||
if (!m_en.c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.iip)
|
||||
{
|
||||
// GSVector4 c = dscan.c;
|
||||
|
||||
movaps(xmm0, ptr[a2 + offsetof(GSVertexSW, c)]);
|
||||
movaps(xmm1, xmm0);
|
||||
|
||||
// m_local.d4.c = GSVector4i(c * 4.0f).xzyw().ps32();
|
||||
|
||||
movaps(xmm2, xmm0);
|
||||
mulps(xmm2, xmm3);
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
pshufd(xmm2, xmm2, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
packssdw(xmm2, xmm2);
|
||||
movdqa(ptr[t0 + offsetof(GSScanlineLocalData, d4.c)], xmm2);
|
||||
|
||||
// xmm3 is not needed anymore
|
||||
|
||||
// GSVector4 dr = c.xxxx();
|
||||
// GSVector4 db = c.zzzz();
|
||||
|
||||
shufps(xmm0, xmm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
shufps(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4i r = GSVector4i(dr * m_shift[i]).ps32();
|
||||
|
||||
movaps(xmm2, xmm0);
|
||||
mulps(xmm2, Xmm(4 + i));
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
packssdw(xmm2, xmm2);
|
||||
|
||||
// GSVector4i b = GSVector4i(db * m_shift[i]).ps32();
|
||||
|
||||
movaps(xmm3, xmm1);
|
||||
mulps(xmm3, Xmm(4 + i));
|
||||
cvttps2dq(xmm3, xmm3);
|
||||
packssdw(xmm3, xmm3);
|
||||
|
||||
// m_local.d[i].rb = r.upl16(b);
|
||||
|
||||
punpcklwd(xmm2, xmm3);
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].rb) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
movdqa(ptr[t0 + variableOffset], xmm2);
|
||||
}
|
||||
|
||||
// GSVector4 c = dscan.c;
|
||||
|
||||
movaps(xmm0, ptr[a2 + offsetof(GSVertexSW, c)]); // not enough regs, have to reload it
|
||||
movaps(xmm1, xmm0);
|
||||
|
||||
// GSVector4 dg = c.yyyy();
|
||||
// GSVector4 da = c.wwww();
|
||||
|
||||
shufps(xmm0, xmm0, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
shufps(xmm1, xmm1, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4i g = GSVector4i(dg * m_shift[i]).ps32();
|
||||
|
||||
movaps(xmm2, xmm0);
|
||||
mulps(xmm2, Xmm(4 + i));
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
packssdw(xmm2, xmm2);
|
||||
|
||||
// GSVector4i a = GSVector4i(da * m_shift[i]).ps32();
|
||||
|
||||
movaps(xmm3, xmm1);
|
||||
mulps(xmm3, Xmm(4 + i));
|
||||
cvttps2dq(xmm3, xmm3);
|
||||
packssdw(xmm3, xmm3);
|
||||
|
||||
// m_local.d[i].ga = g.upl16(a);
|
||||
|
||||
punpcklwd(xmm2, xmm3);
|
||||
|
||||
const size_t variableOffset = offsetof(GSScanlineLocalData, d[0].ga) + (i * sizeof(GSScanlineLocalData::d[0]));
|
||||
movdqa(ptr[t0 + variableOffset], xmm2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4i c = GSVector4i(vertex[index[last].c);
|
||||
|
||||
int last = 0;
|
||||
|
||||
switch (m_sel.prim)
|
||||
{
|
||||
case GS_POINT_CLASS: last = 0; break;
|
||||
case GS_LINE_CLASS: last = 1; break;
|
||||
case GS_TRIANGLE_CLASS: last = 2; break;
|
||||
case GS_SPRITE_CLASS: last = 1; break;
|
||||
}
|
||||
|
||||
if (!(m_sel.prim == GS_SPRITE_CLASS && (m_en.z || m_en.f))) // if this is a sprite, the last vertex was already loaded in Depth()
|
||||
{
|
||||
mov(eax, ptr[a1 + sizeof(uint32) * last]);
|
||||
shl(eax, 6); // * sizeof(GSVertexSW)
|
||||
add(rax, a0);
|
||||
}
|
||||
|
||||
cvttps2dq(xmm0, ptr[rax + offsetof(GSVertexSW, c)]);
|
||||
|
||||
// c = c.upl16(c.zwxy());
|
||||
|
||||
pshufd(xmm1, xmm0, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
punpcklwd(xmm0, xmm1);
|
||||
|
||||
// if(!tme) c = c.srl16(7);
|
||||
|
||||
if (m_sel.tfx == TFX_NONE)
|
||||
{
|
||||
psrlw(xmm0, 7);
|
||||
}
|
||||
|
||||
// m_local.c.rb = c.xxxx();
|
||||
// m_local.c.ga = c.zzzz();
|
||||
|
||||
pshufd(xmm1, xmm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
pshufd(xmm2, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
movdqa(ptr[t0 + offsetof(GSScanlineLocalData, c.rb)], xmm1);
|
||||
movdqa(ptr[t0 + offsetof(GSScanlineLocalData, c.ga)], xmm2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,335 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSSetupPrimCodeGenerator.h"
|
||||
#include "GSVertexSW.h"
|
||||
#include "GS/GS_codegen.h"
|
||||
|
||||
#if _M_SSE < 0x501 && !(defined(_M_AMD64) || defined(_WIN64))
|
||||
|
||||
static const int _args = 0;
|
||||
static const int _vertex = _args + 4;
|
||||
static const int _index = _args + 8;
|
||||
static const int _dscan = _args + 12;
|
||||
|
||||
void GSSetupPrimCodeGenerator::Generate_AVX()
|
||||
{
|
||||
if ((m_en.z || m_en.f) && m_sel.prim != GS_SPRITE_CLASS || m_en.t || m_en.c && m_sel.iip)
|
||||
{
|
||||
mov(edx, dword[esp + _dscan]);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 2 : 5); i++)
|
||||
{
|
||||
vmovaps(Xmm(3 + i), ptr[g_const->m_shift_128b[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
Depth_AVX();
|
||||
|
||||
Texture_AVX();
|
||||
|
||||
Color_AVX();
|
||||
|
||||
ret();
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Depth_AVX()
|
||||
{
|
||||
if (!m_en.z && !m_en.f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
// GSVector4 p = dscan.p;
|
||||
|
||||
vmovaps(xmm0, ptr[edx + offsetof(GSVertexSW, p)]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// GSVector4 df = p.wwww();
|
||||
|
||||
vshufps(xmm1, xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
// m_local.d4.f = GSVector4i(df * 4.0f).xxzzlh();
|
||||
|
||||
vmulps(xmm2, xmm1, xmm3);
|
||||
vcvttps2dq(xmm2, xmm2);
|
||||
vpshuflw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
vpshufhw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
vmovdqa(ptr[&m_local.d4.f], xmm2);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// m_local.d[i].f = GSVector4i(df * m_shift[i]).xxzzlh();
|
||||
|
||||
vmulps(xmm2, xmm1, Xmm(4 + i));
|
||||
vcvttps2dq(xmm2, xmm2);
|
||||
vpshuflw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
vpshufhw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
vmovdqa(ptr[&m_local.d[i].f], xmm2);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// GSVector4 dz = p.zzzz();
|
||||
|
||||
vshufps(xmm0, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
// m_local.d4.z = dz * 4.0f;
|
||||
|
||||
vmulps(xmm1, xmm0, xmm3);
|
||||
vmovdqa(ptr[&m_local.d4.z], xmm1);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// m_local.d[i].z = dz * m_shift[i];
|
||||
|
||||
vmulps(xmm1, xmm0, Xmm(4 + i));
|
||||
vmovdqa(ptr[&m_local.d[i].z], xmm1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
mov(ecx, ptr[esp + _index]);
|
||||
mov(ecx, ptr[ecx + sizeof(uint32) * 1]);
|
||||
shl(ecx, 6); // * sizeof(GSVertexSW)
|
||||
add(ecx, ptr[esp + _vertex]);
|
||||
|
||||
vmovaps(xmm0, ptr[ecx + offsetof(GSVertexSW, p)]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.p.f = GSVector4i(p).zzzzh().zzzz();
|
||||
|
||||
vcvttps2dq(xmm1, xmm0);
|
||||
vpshufhw(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
vpshufd(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
vmovdqa(ptr[&m_local.p.f], xmm1);
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// uint32 z is bypassed in t.w
|
||||
|
||||
vmovdqa(xmm0, ptr[ecx + offsetof(GSVertexSW, t)]);
|
||||
vpshufd(xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
vmovdqa(ptr[&m_local.p.z], xmm0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Texture_AVX()
|
||||
{
|
||||
if (!m_en.t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// GSVector4 t = dscan.t;
|
||||
|
||||
vmovaps(xmm0, ptr[edx + offsetof(GSVertexSW, t)]);
|
||||
|
||||
vmulps(xmm1, xmm0, xmm3);
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d4.stq = GSVector4i(t * 4.0f);
|
||||
|
||||
vcvttps2dq(xmm1, xmm1);
|
||||
|
||||
vmovdqa(ptr[&m_local.d4.stq], xmm1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d4.stq = t * 4.0f;
|
||||
|
||||
vmovaps(ptr[&m_local.d4.stq], xmm1);
|
||||
}
|
||||
|
||||
for (int j = 0, k = m_sel.fst ? 2 : 3; j < k; j++)
|
||||
{
|
||||
// GSVector4 ds = t.xxxx();
|
||||
// GSVector4 dt = t.yyyy();
|
||||
// GSVector4 dq = t.zzzz();
|
||||
|
||||
vshufps(xmm1, xmm0, xmm0, (uint8)_MM_SHUFFLE(j, j, j, j));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4 v = ds/dt * m_shift[i];
|
||||
|
||||
vmulps(xmm2, xmm1, Xmm(4 + i));
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d[i].s/t = GSVector4i(v);
|
||||
|
||||
vcvttps2dq(xmm2, xmm2);
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: vmovdqa(ptr[&m_local.d[i].s], xmm2); break;
|
||||
case 1: vmovdqa(ptr[&m_local.d[i].t], xmm2); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d[i].s/t/q = v;
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: vmovaps(ptr[&m_local.d[i].s], xmm2); break;
|
||||
case 1: vmovaps(ptr[&m_local.d[i].t], xmm2); break;
|
||||
case 2: vmovaps(ptr[&m_local.d[i].q], xmm2); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Color_AVX()
|
||||
{
|
||||
if (!m_en.c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.iip)
|
||||
{
|
||||
// GSVector4 c = dscan.c;
|
||||
|
||||
vmovaps(xmm0, ptr[edx + offsetof(GSVertexSW, c)]);
|
||||
|
||||
// m_local.d4.c = GSVector4i(c * 4.0f).xzyw().ps32();
|
||||
|
||||
vmulps(xmm1, xmm0, xmm3);
|
||||
vcvttps2dq(xmm1, xmm1);
|
||||
vpshufd(xmm1, xmm1, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
vpackssdw(xmm1, xmm1);
|
||||
vmovdqa(ptr[&m_local.d4.c], xmm1);
|
||||
|
||||
// xmm3 is not needed anymore
|
||||
|
||||
// GSVector4 dr = c.xxxx();
|
||||
// GSVector4 db = c.zzzz();
|
||||
|
||||
vshufps(xmm2, xmm0, xmm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
vshufps(xmm3, xmm0, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4i r = GSVector4i(dr * m_shift[i]).ps32();
|
||||
|
||||
vmulps(xmm0, xmm2, Xmm(4 + i));
|
||||
vcvttps2dq(xmm0, xmm0);
|
||||
vpackssdw(xmm0, xmm0);
|
||||
|
||||
// GSVector4i b = GSVector4i(db * m_shift[i]).ps32();
|
||||
|
||||
vmulps(xmm1, xmm3, Xmm(4 + i));
|
||||
vcvttps2dq(xmm1, xmm1);
|
||||
vpackssdw(xmm1, xmm1);
|
||||
|
||||
// m_local.d[i].rb = r.upl16(b);
|
||||
|
||||
vpunpcklwd(xmm0, xmm1);
|
||||
vmovdqa(ptr[&m_local.d[i].rb], xmm0);
|
||||
}
|
||||
|
||||
// GSVector4 c = dscan.c;
|
||||
|
||||
vmovaps(xmm0, ptr[edx + offsetof(GSVertexSW, c)]); // not enough regs, have to reload it
|
||||
|
||||
// GSVector4 dg = c.yyyy();
|
||||
// GSVector4 da = c.wwww();
|
||||
|
||||
vshufps(xmm2, xmm0, xmm0, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
vshufps(xmm3, xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4i g = GSVector4i(dg * m_shift[i]).ps32();
|
||||
|
||||
vmulps(xmm0, xmm2, Xmm(4 + i));
|
||||
vcvttps2dq(xmm0, xmm0);
|
||||
vpackssdw(xmm0, xmm0);
|
||||
|
||||
// GSVector4i a = GSVector4i(da * m_shift[i]).ps32();
|
||||
|
||||
vmulps(xmm1, xmm3, Xmm(4 + i));
|
||||
vcvttps2dq(xmm1, xmm1);
|
||||
vpackssdw(xmm1, xmm1);
|
||||
|
||||
// m_local.d[i].ga = g.upl16(a);
|
||||
|
||||
vpunpcklwd(xmm0, xmm1);
|
||||
vmovdqa(ptr[&m_local.d[i].ga], xmm0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4i c = GSVector4i(vertex[index[last].c);
|
||||
|
||||
int last = 0;
|
||||
|
||||
switch (m_sel.prim)
|
||||
{
|
||||
case GS_POINT_CLASS: last = 0; break;
|
||||
case GS_LINE_CLASS: last = 1; break;
|
||||
case GS_TRIANGLE_CLASS: last = 2; break;
|
||||
case GS_SPRITE_CLASS: last = 1; break;
|
||||
}
|
||||
|
||||
if (!(m_sel.prim == GS_SPRITE_CLASS && (m_en.z || m_en.f))) // if this is a sprite, the last vertex was already loaded in Depth()
|
||||
{
|
||||
mov(ecx, ptr[esp + _index]);
|
||||
mov(ecx, ptr[ecx + sizeof(uint32) * last]);
|
||||
shl(ecx, 6); // * sizeof(GSVertexSW)
|
||||
add(ecx, ptr[esp + _vertex]);
|
||||
}
|
||||
|
||||
vcvttps2dq(xmm0, ptr[ecx + offsetof(GSVertexSW, c)]);
|
||||
|
||||
// c = c.upl16(c.zwxy());
|
||||
|
||||
vpshufd(xmm1, xmm0, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
vpunpcklwd(xmm0, xmm1);
|
||||
|
||||
// if(!tme) c = c.srl16(7);
|
||||
|
||||
if (m_sel.tfx == TFX_NONE)
|
||||
{
|
||||
vpsrlw(xmm0, 7);
|
||||
}
|
||||
|
||||
// m_local.c.rb = c.xxxx();
|
||||
// m_local.c.ga = c.zzzz();
|
||||
|
||||
vpshufd(xmm1, xmm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
vpshufd(xmm2, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
vmovdqa(ptr[&m_local.c.rb], xmm1);
|
||||
vmovdqa(ptr[&m_local.c.ga], xmm2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,360 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSSetupPrimCodeGenerator.h"
|
||||
#include "GSVertexSW.h"
|
||||
#include "GS/GS_codegen.h"
|
||||
|
||||
#if _M_SSE >= 0x501 && !(defined(_M_AMD64) || defined(_WIN64))
|
||||
|
||||
static const int _args = 0;
|
||||
static const int _vertex = _args + 4;
|
||||
static const int _index = _args + 8;
|
||||
static const int _dscan = _args + 12;
|
||||
|
||||
void GSSetupPrimCodeGenerator::Generate_AVX2()
|
||||
{
|
||||
if ((m_en.z || m_en.f) && m_sel.prim != GS_SPRITE_CLASS || m_en.t || m_en.c && m_sel.iip)
|
||||
{
|
||||
mov(edx, dword[esp + _dscan]);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 2 : 5); i++)
|
||||
{
|
||||
vmovaps(Ymm(3 + i), ptr[g_const->m_shift_256b[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
Depth_AVX2();
|
||||
|
||||
Texture_AVX2();
|
||||
|
||||
Color_AVX2();
|
||||
|
||||
ret();
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Depth_AVX2()
|
||||
{
|
||||
if (!m_en.z && !m_en.f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
// GSVector4 dp8 = dscan.p * GSVector4::broadcast32(&shift[0]);
|
||||
|
||||
vbroadcastf128(ymm0, ptr[edx + offsetof(GSVertexSW, p)]);
|
||||
|
||||
vmulps(ymm1, ymm0, ymm3);
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// m_local.d8.p.z = dp8.extract32<2>();
|
||||
|
||||
vextractps(ptr[&m_local.d8.p.z], xmm1, 2);
|
||||
}
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.d8.p.f = GSVector4i(dp8).extract32<3>();
|
||||
|
||||
vcvtps2dq(ymm2, ymm1);
|
||||
vpextrd(ptr[&m_local.d8.p.f], xmm2, 3);
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// GSVector8 dz = GSVector8(dscan.p).zzzz();
|
||||
|
||||
vshufps(ymm2, ymm0, ymm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
}
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// GSVector8 df = GSVector8(dscan.p).wwww();
|
||||
|
||||
vshufps(ymm1, ymm0, ymm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
}
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 8); i++)
|
||||
{
|
||||
if (m_en.z)
|
||||
{
|
||||
// m_local.d[i].z = dz * shift[1 + i];
|
||||
|
||||
if (i < 4)
|
||||
vmulps(ymm0, ymm2, Ymm(4 + i));
|
||||
else
|
||||
vmulps(ymm0, ymm2, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
vmovaps(ptr[&m_local.d[i].z], ymm0);
|
||||
}
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.d[i].f = GSVector8i(df * m_shift[i]).xxzzlh();
|
||||
|
||||
if (i < 4)
|
||||
vmulps(ymm0, ymm1, Ymm(4 + i));
|
||||
else
|
||||
vmulps(ymm0, ymm1, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
vcvttps2dq(ymm0, ymm0);
|
||||
vpshuflw(ymm0, ymm0, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
vpshufhw(ymm0, ymm0, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
vmovdqa(ptr[&m_local.d[i].f], ymm0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
mov(ecx, ptr[esp + _index]);
|
||||
mov(ecx, ptr[ecx + sizeof(uint32) * 1]);
|
||||
shl(ecx, 6); // * sizeof(GSVertexSW)
|
||||
add(ecx, ptr[esp + _vertex]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.p.f = GSVector4i(vertex[index[1]].p).extract32<3>();
|
||||
|
||||
vmovaps(xmm0, ptr[ecx + offsetof(GSVertexSW, p)]);
|
||||
vcvttps2dq(xmm0, xmm0);
|
||||
vpextrd(ptr[&m_local.p.f], xmm0, 3);
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// m_local.p.z = vertex[index[1]].t.u32[3]; // uint32 z is bypassed in t.w
|
||||
|
||||
mov(eax, ptr[ecx + offsetof(GSVertexSW, t.w)]);
|
||||
mov(ptr[&m_local.p.z], eax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Texture_AVX2()
|
||||
{
|
||||
if (!m_en.t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// GSVector8 dt(dscan.t);
|
||||
|
||||
vbroadcastf128(ymm0, ptr[edx + offsetof(GSVertexSW, t)]);
|
||||
|
||||
// GSVector8 dt8 = dt * shift[0];
|
||||
|
||||
vmulps(ymm1, ymm0, ymm3);
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d8.stq = GSVector8::cast(GSVector8i(dt8));
|
||||
|
||||
vcvttps2dq(ymm1, ymm1);
|
||||
|
||||
vmovdqa(ptr[&m_local.d8.stq], xmm1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d8.stq = dt8;
|
||||
|
||||
vmovaps(ptr[&m_local.d8.stq], xmm1);
|
||||
}
|
||||
|
||||
for (int j = 0, k = m_sel.fst ? 2 : 3; j < k; j++)
|
||||
{
|
||||
// GSVector8 dstq = dt.xxxx/yyyy/zzzz();
|
||||
|
||||
vshufps(ymm1, ymm0, ymm0, (uint8)_MM_SHUFFLE(j, j, j, j));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 8); i++)
|
||||
{
|
||||
// GSVector8 v = dstq * shift[1 + i];
|
||||
|
||||
if (i < 4)
|
||||
vmulps(ymm2, ymm1, Ymm(4 + i));
|
||||
else
|
||||
vmulps(ymm2, ymm1, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d[i].s/t = GSVector8::cast(GSVector8i(v));
|
||||
|
||||
vcvttps2dq(ymm2, ymm2);
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: vmovdqa(ptr[&m_local.d[i].s], ymm2); break;
|
||||
case 1: vmovdqa(ptr[&m_local.d[i].t], ymm2); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d[i].s/t/q = v;
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: vmovaps(ptr[&m_local.d[i].s], ymm2); break;
|
||||
case 1: vmovaps(ptr[&m_local.d[i].t], ymm2); break;
|
||||
case 2: vmovaps(ptr[&m_local.d[i].q], ymm2); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Color_AVX2()
|
||||
{
|
||||
if (!m_en.c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.iip)
|
||||
{
|
||||
// GSVector8 dc(dscan.c);
|
||||
|
||||
vbroadcastf128(ymm0, ptr[edx + offsetof(GSVertexSW, c)]);
|
||||
|
||||
// m_local.d8.c = GSVector8i(dc * shift[0]).xzyw().ps32();
|
||||
|
||||
vmulps(ymm1, ymm0, ymm3);
|
||||
vcvttps2dq(ymm1, ymm1);
|
||||
vpshufd(ymm1, ymm1, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
vpackssdw(ymm1, ymm1);
|
||||
vmovq(ptr[&m_local.d8.c], xmm1);
|
||||
|
||||
// ymm3 is not needed anymore
|
||||
|
||||
// GSVector8 dr = dc.xxxx();
|
||||
// GSVector8 db = dc.zzzz();
|
||||
|
||||
vshufps(ymm2, ymm0, ymm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
vshufps(ymm3, ymm0, ymm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 8); i++)
|
||||
{
|
||||
// GSVector8i r = GSVector8i(dr * shift[1 + i]).ps32();
|
||||
|
||||
if (i < 4)
|
||||
vmulps(ymm0, ymm2, Ymm(4 + i));
|
||||
else
|
||||
vmulps(ymm0, ymm2, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
vcvttps2dq(ymm0, ymm0);
|
||||
vpackssdw(ymm0, ymm0);
|
||||
|
||||
// GSVector4i b = GSVector8i(db * shift[1 + i]).ps32();
|
||||
|
||||
if (i < 4)
|
||||
vmulps(ymm1, ymm3, Ymm(4 + i));
|
||||
else
|
||||
vmulps(ymm1, ymm3, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
vcvttps2dq(ymm1, ymm1);
|
||||
vpackssdw(ymm1, ymm1);
|
||||
|
||||
// m_local.d[i].rb = r.upl16(b);
|
||||
|
||||
vpunpcklwd(ymm0, ymm1);
|
||||
vmovdqa(ptr[&m_local.d[i].rb], ymm0);
|
||||
}
|
||||
|
||||
// GSVector8 dc(dscan.c);
|
||||
|
||||
vbroadcastf128(ymm0, ptr[edx + offsetof(GSVertexSW, c)]); // not enough regs, have to reload it
|
||||
|
||||
// GSVector8 dg = dc.yyyy();
|
||||
// GSVector8 da = dc.wwww();
|
||||
|
||||
vshufps(ymm2, ymm0, ymm0, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
vshufps(ymm3, ymm0, ymm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 8); i++)
|
||||
{
|
||||
// GSVector8i g = GSVector8i(dg * shift[1 + i]).ps32();
|
||||
|
||||
if (i < 4)
|
||||
vmulps(ymm0, ymm2, Ymm(4 + i));
|
||||
else
|
||||
vmulps(ymm0, ymm2, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
vcvttps2dq(ymm0, ymm0);
|
||||
vpackssdw(ymm0, ymm0);
|
||||
|
||||
// GSVector8i a = GSVector8i(da * shift[1 + i]).ps32();
|
||||
|
||||
if (i < 4)
|
||||
vmulps(ymm1, ymm3, Ymm(4 + i));
|
||||
else
|
||||
vmulps(ymm1, ymm3, ptr[g_const->m_shift_256b[i + 1]]);
|
||||
vcvttps2dq(ymm1, ymm1);
|
||||
vpackssdw(ymm1, ymm1);
|
||||
|
||||
// m_local.d[i].ga = g.upl16(a);
|
||||
|
||||
vpunpcklwd(ymm0, ymm1);
|
||||
vmovdqa(ptr[&m_local.d[i].ga], ymm0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector8i c = GSVector8i(GSVector8(vertex[index[last]].c));
|
||||
|
||||
int last = 0;
|
||||
|
||||
switch (m_sel.prim)
|
||||
{
|
||||
case GS_POINT_CLASS: last = 0; break;
|
||||
case GS_LINE_CLASS: last = 1; break;
|
||||
case GS_TRIANGLE_CLASS: last = 2; break;
|
||||
case GS_SPRITE_CLASS: last = 1; break;
|
||||
}
|
||||
|
||||
if (!(m_sel.prim == GS_SPRITE_CLASS && (m_en.z || m_en.f))) // if this is a sprite, the last vertex was already loaded in Depth()
|
||||
{
|
||||
mov(ecx, ptr[esp + _index]);
|
||||
mov(ecx, ptr[ecx + sizeof(uint32) * last]);
|
||||
shl(ecx, 6); // * sizeof(GSVertexSW)
|
||||
add(ecx, ptr[esp + _vertex]);
|
||||
}
|
||||
|
||||
vbroadcasti128(ymm0, ptr[ecx + offsetof(GSVertexSW, c)]);
|
||||
vcvttps2dq(ymm0, ymm0);
|
||||
|
||||
// c = c.upl16(c.zwxy());
|
||||
|
||||
vpshufd(ymm1, ymm0, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
vpunpcklwd(ymm0, ymm1);
|
||||
|
||||
// if(!tme) c = c.srl16(7);
|
||||
|
||||
if (m_sel.tfx == TFX_NONE)
|
||||
{
|
||||
vpsrlw(ymm0, 7);
|
||||
}
|
||||
|
||||
// m_local.c.rb = c.xxxx();
|
||||
// m_local.c.ga = c.zzzz();
|
||||
|
||||
vpshufd(ymm1, ymm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
vpshufd(ymm2, ymm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
vmovdqa(ptr[&m_local.c.rb], ymm1);
|
||||
vmovdqa(ptr[&m_local.c.ga], ymm2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,350 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSSetupPrimCodeGenerator.h"
|
||||
#include "GSVertexSW.h"
|
||||
#include "GS/GS_codegen.h"
|
||||
|
||||
#if _M_SSE < 0x501 && !(defined(_M_AMD64) || defined(_WIN64))
|
||||
|
||||
static const int _args = 0;
|
||||
static const int _vertex = _args + 4;
|
||||
static const int _index = _args + 8;
|
||||
static const int _dscan = _args + 12;
|
||||
|
||||
void GSSetupPrimCodeGenerator::Generate_SSE()
|
||||
{
|
||||
if ((m_en.z || m_en.f) && m_sel.prim != GS_SPRITE_CLASS || m_en.t || m_en.c && m_sel.iip)
|
||||
{
|
||||
mov(edx, dword[esp + _dscan]);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 2 : 5); i++)
|
||||
{
|
||||
movaps(Xmm(3 + i), ptr[g_const->m_shift_128b[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
Depth_SSE();
|
||||
|
||||
Texture_SSE();
|
||||
|
||||
Color_SSE();
|
||||
|
||||
ret();
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Depth_SSE()
|
||||
{
|
||||
if (!m_en.z && !m_en.f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.prim != GS_SPRITE_CLASS)
|
||||
{
|
||||
// GSVector4 p = dscan.p;
|
||||
|
||||
movaps(xmm0, ptr[edx + offsetof(GSVertexSW, p)]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// GSVector4 df = p.wwww();
|
||||
|
||||
movaps(xmm1, xmm0);
|
||||
shufps(xmm1, xmm1, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
// m_local.d4.f = GSVector4i(df * 4.0f).xxzzlh();
|
||||
|
||||
movaps(xmm2, xmm1);
|
||||
mulps(xmm2, xmm3);
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
pshuflw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
movdqa(ptr[&m_local.d4.f], xmm2);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// m_local.d[i].f = GSVector4i(df * m_shift[i]).xxzzlh();
|
||||
|
||||
movaps(xmm2, xmm1);
|
||||
mulps(xmm2, Xmm(4 + i));
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
pshuflw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
pshufhw(xmm2, xmm2, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
movdqa(ptr[&m_local.d[i].f], xmm2);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// GSVector4 dz = p.zzzz();
|
||||
|
||||
shufps(xmm0, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
// m_local.d4.z = dz * 4.0f;
|
||||
|
||||
movaps(xmm1, xmm0);
|
||||
mulps(xmm1, xmm3);
|
||||
movdqa(ptr[&m_local.d4.z], xmm1);
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// m_local.d[i].z = dz * m_shift[i];
|
||||
|
||||
movaps(xmm1, xmm0);
|
||||
mulps(xmm1, Xmm(4 + i));
|
||||
movdqa(ptr[&m_local.d[i].z], xmm1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4 p = vertex[index[1]].p;
|
||||
|
||||
mov(ecx, ptr[esp + _index]);
|
||||
mov(ecx, ptr[ecx + sizeof(uint32) * 1]);
|
||||
shl(ecx, 6); // * sizeof(GSVertexSW)
|
||||
add(ecx, ptr[esp + _vertex]);
|
||||
|
||||
movaps(xmm0, ptr[ecx + offsetof(GSVertexSW, p)]);
|
||||
|
||||
if (m_en.f)
|
||||
{
|
||||
// m_local.p.f = GSVector4i(p).zzzzh().zzzz();
|
||||
|
||||
cvttps2dq(xmm1, xmm0);
|
||||
pshufhw(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
pshufd(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
movdqa(ptr[&m_local.p.f], xmm1);
|
||||
}
|
||||
|
||||
if (m_en.z)
|
||||
{
|
||||
// uint32 z is bypassed in t.w
|
||||
|
||||
movdqa(xmm0, ptr[ecx + offsetof(GSVertexSW, t)]);
|
||||
pshufd(xmm0, xmm0, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
movdqa(ptr[&m_local.p.z], xmm0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Texture_SSE()
|
||||
{
|
||||
if (!m_en.t)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// GSVector4 t = dscan.t;
|
||||
|
||||
movaps(xmm0, ptr[edx + offsetof(GSVertexSW, t)]);
|
||||
|
||||
movaps(xmm1, xmm0);
|
||||
mulps(xmm1, xmm3);
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d4.stq = GSVector4i(t * 4.0f);
|
||||
|
||||
cvttps2dq(xmm1, xmm1);
|
||||
|
||||
movdqa(ptr[&m_local.d4.stq], xmm1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d4.stq = t * 4.0f;
|
||||
|
||||
movaps(ptr[&m_local.d4.stq], xmm1);
|
||||
}
|
||||
|
||||
for (int j = 0, k = m_sel.fst ? 2 : 3; j < k; j++)
|
||||
{
|
||||
// GSVector4 ds = t.xxxx();
|
||||
// GSVector4 dt = t.yyyy();
|
||||
// GSVector4 dq = t.zzzz();
|
||||
|
||||
movaps(xmm1, xmm0);
|
||||
shufps(xmm1, xmm1, (uint8)_MM_SHUFFLE(j, j, j, j));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4 v = ds/dt * m_shift[i];
|
||||
|
||||
movaps(xmm2, xmm1);
|
||||
mulps(xmm2, Xmm(4 + i));
|
||||
|
||||
if (m_sel.fst)
|
||||
{
|
||||
// m_local.d[i].s/t = GSVector4i(v);
|
||||
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: movdqa(ptr[&m_local.d[i].s], xmm2); break;
|
||||
case 1: movdqa(ptr[&m_local.d[i].t], xmm2); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_local.d[i].s/t/q = v;
|
||||
|
||||
switch (j)
|
||||
{
|
||||
case 0: movaps(ptr[&m_local.d[i].s], xmm2); break;
|
||||
case 1: movaps(ptr[&m_local.d[i].t], xmm2); break;
|
||||
case 2: movaps(ptr[&m_local.d[i].q], xmm2); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSSetupPrimCodeGenerator::Color_SSE()
|
||||
{
|
||||
if (!m_en.c)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_sel.iip)
|
||||
{
|
||||
// GSVector4 c = dscan.c;
|
||||
|
||||
movaps(xmm0, ptr[edx + offsetof(GSVertexSW, c)]);
|
||||
movaps(xmm1, xmm0);
|
||||
|
||||
// m_local.d4.c = GSVector4i(c * 4.0f).xzyw().ps32();
|
||||
|
||||
movaps(xmm2, xmm0);
|
||||
mulps(xmm2, xmm3);
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
pshufd(xmm2, xmm2, _MM_SHUFFLE(3, 1, 2, 0));
|
||||
packssdw(xmm2, xmm2);
|
||||
movdqa(ptr[&m_local.d4.c], xmm2);
|
||||
|
||||
// xmm3 is not needed anymore
|
||||
|
||||
// GSVector4 dr = c.xxxx();
|
||||
// GSVector4 db = c.zzzz();
|
||||
|
||||
shufps(xmm0, xmm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
shufps(xmm1, xmm1, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4i r = GSVector4i(dr * m_shift[i]).ps32();
|
||||
|
||||
movaps(xmm2, xmm0);
|
||||
mulps(xmm2, Xmm(4 + i));
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
packssdw(xmm2, xmm2);
|
||||
|
||||
// GSVector4i b = GSVector4i(db * m_shift[i]).ps32();
|
||||
|
||||
movaps(xmm3, xmm1);
|
||||
mulps(xmm3, Xmm(4 + i));
|
||||
cvttps2dq(xmm3, xmm3);
|
||||
packssdw(xmm3, xmm3);
|
||||
|
||||
// m_local.d[i].rb = r.upl16(b);
|
||||
|
||||
punpcklwd(xmm2, xmm3);
|
||||
movdqa(ptr[&m_local.d[i].rb], xmm2);
|
||||
}
|
||||
|
||||
// GSVector4 c = dscan.c;
|
||||
|
||||
movaps(xmm0, ptr[edx + offsetof(GSVertexSW, c)]); // not enough regs, have to reload it
|
||||
movaps(xmm1, xmm0);
|
||||
|
||||
// GSVector4 dg = c.yyyy();
|
||||
// GSVector4 da = c.wwww();
|
||||
|
||||
shufps(xmm0, xmm0, _MM_SHUFFLE(1, 1, 1, 1));
|
||||
shufps(xmm1, xmm1, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
|
||||
for (int i = 0; i < (m_sel.notest ? 1 : 4); i++)
|
||||
{
|
||||
// GSVector4i g = GSVector4i(dg * m_shift[i]).ps32();
|
||||
|
||||
movaps(xmm2, xmm0);
|
||||
mulps(xmm2, Xmm(4 + i));
|
||||
cvttps2dq(xmm2, xmm2);
|
||||
packssdw(xmm2, xmm2);
|
||||
|
||||
// GSVector4i a = GSVector4i(da * m_shift[i]).ps32();
|
||||
|
||||
movaps(xmm3, xmm1);
|
||||
mulps(xmm3, Xmm(4 + i));
|
||||
cvttps2dq(xmm3, xmm3);
|
||||
packssdw(xmm3, xmm3);
|
||||
|
||||
// m_local.d[i].ga = g.upl16(a);
|
||||
|
||||
punpcklwd(xmm2, xmm3);
|
||||
movdqa(ptr[&m_local.d[i].ga], xmm2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// GSVector4i c = GSVector4i(vertex[index[last].c);
|
||||
|
||||
int last = 0;
|
||||
|
||||
switch (m_sel.prim)
|
||||
{
|
||||
case GS_POINT_CLASS: last = 0; break;
|
||||
case GS_LINE_CLASS: last = 1; break;
|
||||
case GS_TRIANGLE_CLASS: last = 2; break;
|
||||
case GS_SPRITE_CLASS: last = 1; break;
|
||||
}
|
||||
|
||||
if (!(m_sel.prim == GS_SPRITE_CLASS && (m_en.z || m_en.f))) // if this is a sprite, the last vertex was already loaded in Depth()
|
||||
{
|
||||
mov(ecx, ptr[esp + _index]);
|
||||
mov(ecx, ptr[ecx + sizeof(uint32) * last]);
|
||||
shl(ecx, 6); // * sizeof(GSVertexSW)
|
||||
add(ecx, ptr[esp + _vertex]);
|
||||
}
|
||||
|
||||
cvttps2dq(xmm0, ptr[ecx + offsetof(GSVertexSW, c)]);
|
||||
|
||||
// c = c.upl16(c.zwxy());
|
||||
|
||||
pshufd(xmm1, xmm0, _MM_SHUFFLE(1, 0, 3, 2));
|
||||
punpcklwd(xmm0, xmm1);
|
||||
|
||||
// if(!tme) c = c.srl16(7);
|
||||
|
||||
if (m_sel.tfx == TFX_NONE)
|
||||
{
|
||||
psrlw(xmm0, 7);
|
||||
}
|
||||
|
||||
// m_local.c.rb = c.xxxx();
|
||||
// m_local.c.ga = c.zzzz();
|
||||
|
||||
pshufd(xmm1, xmm0, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
pshufd(xmm2, xmm0, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
|
||||
movdqa(ptr[&m_local.c.rb], xmm1);
|
||||
movdqa(ptr[&m_local.c.ga], xmm2);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -62,21 +62,18 @@ GSTextureCacheSW::Texture* GSTextureCacheSW::Lookup(const GIFRegTEX0& TEX0, cons
|
||||
|
||||
m_textures.insert(t);
|
||||
|
||||
for (const uint32* p = t->m_pages.n; *p != GSOffset::EOP; p++)
|
||||
t->m_pages.loopPages([&](uint32 page)
|
||||
{
|
||||
const uint32 page = *p;
|
||||
t->m_erase_it[page] = m_map[page].InsertFront(t);
|
||||
}
|
||||
});
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void GSTextureCacheSW::InvalidatePages(const uint32* pages, uint32 psm)
|
||||
void GSTextureCacheSW::InvalidatePages(const GSOffset::PageLooper& pages, uint32 psm)
|
||||
{
|
||||
for (const uint32* p = pages; *p != GSOffset::EOP; p++)
|
||||
pages.loopPages([&](uint32 page)
|
||||
{
|
||||
const uint32 page = *p;
|
||||
|
||||
for (Texture* t : m_map[page])
|
||||
{
|
||||
if (GSUtil::HasSharedBits(psm, t->m_sharedbits))
|
||||
@@ -98,7 +95,7 @@ void GSTextureCacheSW::InvalidatePages(const uint32* pages, uint32 psm)
|
||||
t->m_complete = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void GSTextureCacheSW::RemoveAll()
|
||||
@@ -124,11 +121,10 @@ void GSTextureCacheSW::IncAge()
|
||||
{
|
||||
i = m_textures.erase(i);
|
||||
|
||||
for (const uint32* p = t->m_pages.n; *p != GSOffset::EOP; p++)
|
||||
t->m_pages.loopPages([&](uint32 page)
|
||||
{
|
||||
const uint32 page = *p;
|
||||
m_map[page].EraseIndex(t->m_erase_it[page]);
|
||||
}
|
||||
});
|
||||
|
||||
delete t;
|
||||
}
|
||||
@@ -162,9 +158,7 @@ GSTextureCacheSW::Texture::Texture(GSState* state, uint32 tw0, const GIFRegTEX0&
|
||||
m_sharedbits = GSUtil::HasSharedBitsPtr(m_TEX0.PSM);
|
||||
|
||||
m_offset = m_state->m_mem.GetOffset(TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
|
||||
m_pages.n = m_offset->GetPages(GSVector4i(0, 0, 1 << TEX0.TW, 1 << TEX0.TH));
|
||||
memcpy(m_pages.bm, m_offset->GetPagesAsBits(TEX0), sizeof(m_pages.bm));
|
||||
m_pages = m_offset.pageLooperForRect(GSVector4i(0, 0, 1 << TEX0.TW, 1 << TEX0.TH));
|
||||
|
||||
m_repeating = m_TEX0.IsRepeating(); // repeating mode always works, it is just slightly slower
|
||||
|
||||
@@ -176,8 +170,6 @@ GSTextureCacheSW::Texture::Texture(GSState* state, uint32 tw0, const GIFRegTEX0&
|
||||
|
||||
GSTextureCacheSW::Texture::~Texture()
|
||||
{
|
||||
delete[] m_pages.n;
|
||||
|
||||
if (m_buff)
|
||||
{
|
||||
_aligned_free(m_buff);
|
||||
@@ -223,7 +215,7 @@ bool GSTextureCacheSW::Texture::Update(const GSVector4i& rect)
|
||||
|
||||
GSLocalMemory& mem = m_state->m_mem;
|
||||
|
||||
const GSOffset* RESTRICT off = m_offset;
|
||||
GSOffset off = m_offset;
|
||||
|
||||
uint32 blocks = 0;
|
||||
|
||||
@@ -235,22 +227,20 @@ bool GSTextureCacheSW::Texture::Update(const GSVector4i& rect)
|
||||
|
||||
int block_pitch = pitch * bs.y;
|
||||
|
||||
r = r.srl32(3);
|
||||
shift += off.blockShiftX();
|
||||
int bottom = r.bottom >> off.blockShiftY();
|
||||
int right = r.right >> off.blockShiftX();
|
||||
|
||||
bs.x >>= 3;
|
||||
bs.y >>= 3;
|
||||
|
||||
shift += 3;
|
||||
GSOffset::BNHelper bn = off.bnMulti(r.left, r.top);
|
||||
|
||||
if (m_repeating)
|
||||
{
|
||||
for (int y = r.top; y < r.bottom; y += bs.y, dst += block_pitch)
|
||||
for (; bn.blkY() < bottom; bn.nextBlockY(), dst += block_pitch)
|
||||
{
|
||||
uint32 base = off->block.row[y];
|
||||
|
||||
for (int x = r.left, i = (y << 7) + x; x < r.right; x += bs.x, i += bs.x)
|
||||
for (; bn.blkX() < right; bn.nextBlockX())
|
||||
{
|
||||
uint32 block = (base + off->block.col[x]) % MAX_BLOCKS;
|
||||
int i = (bn.blkY() << 7) + bn.blkX();
|
||||
uint32 block = bn.value();
|
||||
|
||||
uint32 row = i >> 5;
|
||||
uint32 col = 1 << (i & 31);
|
||||
@@ -259,7 +249,7 @@ bool GSTextureCacheSW::Texture::Update(const GSVector4i& rect)
|
||||
{
|
||||
m_valid[row] |= col;
|
||||
|
||||
(mem.*rtxbP)(block, &dst[x << shift], pitch, m_TEXA);
|
||||
(mem.*rtxbP)(block, &dst[bn.blkX() << shift], pitch, m_TEXA);
|
||||
|
||||
blocks++;
|
||||
}
|
||||
@@ -268,13 +258,11 @@ bool GSTextureCacheSW::Texture::Update(const GSVector4i& rect)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = r.top; y < r.bottom; y += bs.y, dst += block_pitch)
|
||||
for (; bn.blkY() < bottom; bn.nextBlockY(), dst += block_pitch)
|
||||
{
|
||||
uint32 base = off->block.row[y];
|
||||
|
||||
for (int x = r.left; x < r.right; x += bs.x)
|
||||
for (; bn.blkX() < right; bn.nextBlockX())
|
||||
{
|
||||
uint32 block = (base + off->block.col[x]) % MAX_BLOCKS;
|
||||
uint32 block = bn.value();
|
||||
|
||||
uint32 row = block >> 5;
|
||||
uint32 col = 1 << (block & 31);
|
||||
@@ -283,7 +271,7 @@ bool GSTextureCacheSW::Texture::Update(const GSVector4i& rect)
|
||||
{
|
||||
m_valid[row] |= col;
|
||||
|
||||
(mem.*rtxbP)(block, &dst[x << shift], pitch, m_TEXA);
|
||||
(mem.*rtxbP)(block, &dst[bn.blkX() << shift], pitch, m_TEXA);
|
||||
|
||||
blocks++;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ public:
|
||||
{
|
||||
public:
|
||||
GSState* m_state;
|
||||
GSOffset* m_offset;
|
||||
GSOffset m_offset;
|
||||
GSOffset::PageLooper m_pages;
|
||||
GIFRegTEX0 m_TEX0;
|
||||
GIFRegTEXA m_TEXA;
|
||||
void* m_buff;
|
||||
@@ -36,7 +37,6 @@ public:
|
||||
std::vector<GSVector2i>* m_p2t;
|
||||
uint32 m_valid[MAX_PAGES];
|
||||
std::array<uint16, MAX_PAGES> m_erase_it;
|
||||
struct { uint32 bm[16]; const uint32* n; } m_pages;
|
||||
const uint32* RESTRICT m_sharedbits;
|
||||
|
||||
// m_valid
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
|
||||
Texture* Lookup(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, uint32 tw0 = 0);
|
||||
|
||||
void InvalidatePages(const uint32* pages, uint32 psm);
|
||||
void InvalidatePages(const GSOffset::PageLooper& pages, uint32 psm);
|
||||
|
||||
void RemoveAll();
|
||||
void IncAge();
|
||||
|
||||
@@ -1,722 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include <gtk/gtk.h>
|
||||
#include "GS.h"
|
||||
#include "GS_res.h"
|
||||
#include "GSSetting.h"
|
||||
|
||||
// Port of deprecated GTK2 API to recent GTK3. Those defines
|
||||
// could prove handy for testing
|
||||
#define GTK3_MONITOR_API GTK_CHECK_VERSION(3, 22, 0)
|
||||
#define GTK3_GRID_API GTK_CHECK_VERSION(3, 12, 0)
|
||||
|
||||
static GtkWidget* s_hack_frame;
|
||||
|
||||
bool BigEnough()
|
||||
{
|
||||
#if GTK3_MONITOR_API
|
||||
GdkDisplay* display = gdk_display_get_default();
|
||||
GdkSeat* seat = gdk_display_get_default_seat(display);
|
||||
GdkDevice* pointer = gdk_seat_get_pointer(seat);
|
||||
int x;
|
||||
int y;
|
||||
gdk_device_get_position(pointer, nullptr, &x, &y);
|
||||
GdkMonitor* monitor = gdk_display_get_monitor_at_point(display, x, y);
|
||||
GdkRectangle my_geometry{};
|
||||
gdk_monitor_get_geometry(monitor, &my_geometry);
|
||||
return my_geometry.height > 1000;
|
||||
#else
|
||||
return (gdk_screen_get_height(gdk_screen_get_default()) > 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AddTooltip(GtkWidget* w, int idc)
|
||||
{
|
||||
gtk_widget_set_tooltip_text(w, dialog_message(idc));
|
||||
}
|
||||
|
||||
void AddTooltip(GtkWidget* w1, GtkWidget* w2, int idc)
|
||||
{
|
||||
AddTooltip(w1, idc);
|
||||
AddTooltip(w2, idc);
|
||||
}
|
||||
|
||||
GtkWidget* CreateVbox()
|
||||
{
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
return gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
|
||||
#else
|
||||
return gtk_vbox_new(false, 5);
|
||||
#endif
|
||||
}
|
||||
|
||||
GtkWidget* left_label(const char* lbl)
|
||||
{
|
||||
GtkWidget* w = gtk_label_new(lbl);
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
gtk_widget_set_halign(w, GTK_ALIGN_START);
|
||||
#else
|
||||
gtk_misc_set_alignment(GTK_MISC(w), 0.0, 0.5);
|
||||
#endif
|
||||
return w;
|
||||
}
|
||||
|
||||
void CB_ChangedComboBox(GtkComboBox* combo, gpointer user_data)
|
||||
{
|
||||
int p = gtk_combo_box_get_active(combo);
|
||||
auto s = reinterpret_cast<std::vector<GSSetting>*>(g_object_get_data(G_OBJECT(combo), "Settings"));
|
||||
|
||||
try
|
||||
{
|
||||
theApp.SetConfig((char*)user_data, s->at(p).value);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget* CreateComboBoxFromVector(const std::vector<GSSetting>& s, const char* opt_name)
|
||||
{
|
||||
GtkWidget* combo_box = gtk_combo_box_text_new();
|
||||
int32_t opt_value = theApp.GetConfigI(opt_name);
|
||||
int opt_position = 0;
|
||||
|
||||
for (size_t i = 0; i < s.size(); i++)
|
||||
{
|
||||
std::string label = s[i].name;
|
||||
|
||||
if (!s[i].note.empty())
|
||||
label += format(" (%s)", s[i].note.c_str());
|
||||
|
||||
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo_box), label.c_str());
|
||||
|
||||
if (s[i].value == opt_value)
|
||||
opt_position = i;
|
||||
}
|
||||
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), opt_position);
|
||||
|
||||
g_signal_connect(combo_box, "changed", G_CALLBACK(CB_ChangedComboBox), const_cast<char*>(opt_name));
|
||||
g_object_set_data(G_OBJECT(combo_box), "Settings", (void*)&s);
|
||||
|
||||
return combo_box;
|
||||
}
|
||||
|
||||
void CB_EntryActived(GtkEntry* entry, gpointer user_data)
|
||||
{
|
||||
int hex_value = 0;
|
||||
const gchar* data = gtk_entry_get_text(entry);
|
||||
|
||||
if (sscanf(data, "%X", &hex_value) == 1)
|
||||
theApp.SetConfig((char*)user_data, hex_value);
|
||||
}
|
||||
|
||||
GtkWidget* CreateTextBox(const char* opt_name)
|
||||
{
|
||||
GtkWidget* entry = gtk_entry_new();
|
||||
|
||||
int hex_value = theApp.GetConfigI(opt_name);
|
||||
|
||||
gchar* data = (gchar*)g_malloc(sizeof(gchar) * 40);
|
||||
sprintf(data, "%X", hex_value);
|
||||
gtk_entry_set_text(GTK_ENTRY(entry), data);
|
||||
g_free(data);
|
||||
|
||||
g_signal_connect(entry, "activate", G_CALLBACK(CB_EntryActived), const_cast<char*>(opt_name));
|
||||
g_signal_connect(entry, "changed", G_CALLBACK(CB_EntryActived), const_cast<char*>(opt_name));
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void CB_ToggleCheckBox(GtkToggleButton* togglebutton, gpointer user_data)
|
||||
{
|
||||
char* opt = (char*)user_data;
|
||||
theApp.SetConfig(opt, (int)gtk_toggle_button_get_active(togglebutton));
|
||||
if (strcmp(opt, "UserHacks") == 0)
|
||||
{
|
||||
gtk_widget_set_sensitive(s_hack_frame, gtk_toggle_button_get_active(togglebutton));
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget* CreateCheckBox(const char* label, const char* opt_name)
|
||||
{
|
||||
GtkWidget* check = gtk_check_button_new_with_label(label);
|
||||
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), theApp.GetConfigB(opt_name));
|
||||
|
||||
g_signal_connect(check, "toggled", G_CALLBACK(CB_ToggleCheckBox), const_cast<char*>(opt_name));
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
void CB_SpinButton(GtkSpinButton* spin, gpointer user_data)
|
||||
{
|
||||
theApp.SetConfig((char*)user_data, (int)gtk_spin_button_get_value(spin));
|
||||
}
|
||||
|
||||
GtkWidget* CreateSpinButton(double min, double max, const char* opt_name)
|
||||
{
|
||||
GtkWidget* spin = gtk_spin_button_new_with_range(min, max, 1);
|
||||
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), theApp.GetConfigI(opt_name));
|
||||
|
||||
g_signal_connect(spin, "value-changed", G_CALLBACK(CB_SpinButton), const_cast<char*>(opt_name));
|
||||
|
||||
return spin;
|
||||
}
|
||||
|
||||
void CB_RangeChanged(GtkRange* range, gpointer user_data)
|
||||
{
|
||||
theApp.SetConfig((char*)user_data, (int)gtk_range_get_value(range));
|
||||
}
|
||||
|
||||
GtkWidget* CreateScale(const char* opt_name, int scale_min = 0, int scale_max = 100, int scale_range = 10)
|
||||
{
|
||||
#if GTK_CHECK_VERSION(3, 0, 0)
|
||||
GtkWidget* scale = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, scale_min, scale_max, scale_range);
|
||||
#else
|
||||
GtkWidget* scale = gtk_hscale_new_with_range(scale_min, scale_max, scale_range);
|
||||
#endif
|
||||
|
||||
gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT);
|
||||
gtk_range_set_value(GTK_RANGE(scale), theApp.GetConfigI(opt_name));
|
||||
|
||||
g_signal_connect(scale, "value-changed", G_CALLBACK(CB_RangeChanged), const_cast<char*>(opt_name));
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
void CB_PickFile(GtkFileChooserButton* chooser, gpointer user_data)
|
||||
{
|
||||
theApp.SetConfig((char*)user_data, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser)));
|
||||
}
|
||||
|
||||
GtkWidget* CreateFileChooser(GtkFileChooserAction action, const char* label, const char* opt_name)
|
||||
{
|
||||
GtkWidget* chooser = gtk_file_chooser_button_new(label, action);
|
||||
|
||||
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(chooser), theApp.GetConfigS(opt_name).c_str());
|
||||
|
||||
g_signal_connect(chooser, "file-set", G_CALLBACK(CB_PickFile), const_cast<char*>(opt_name));
|
||||
|
||||
return chooser;
|
||||
}
|
||||
|
||||
static int s_table_line = 0;
|
||||
|
||||
void AttachInTable(GtkWidget* table, GtkWidget* w, int pos, int pad = 0, int size = 1)
|
||||
{
|
||||
#if GTK3_GRID_API
|
||||
gtk_widget_set_margin_start(w, pad);
|
||||
gtk_widget_set_hexpand(w, false);
|
||||
gtk_grid_attach(GTK_GRID(table), w, pos, s_table_line, size, 1);
|
||||
#else
|
||||
GtkAttachOptions opt = (GtkAttachOptions)(/*GTK_EXPAND | */ GTK_FILL); // default
|
||||
gtk_table_attach(GTK_TABLE(table), w, pos, pos + size, s_table_line, s_table_line + 1, opt, opt, pad, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void InsertWidgetInTable(GtkWidget* table, GtkWidget* left, GtkWidget* right = NULL, GtkWidget* third = NULL)
|
||||
{
|
||||
guint l_xpad = GTK_IS_CHECK_BUTTON(left) ? 0 : 22;
|
||||
|
||||
if (!left)
|
||||
{
|
||||
AttachInTable(table, right, 1);
|
||||
}
|
||||
else if (!right)
|
||||
{
|
||||
AttachInTable(table, left, 0, l_xpad);
|
||||
}
|
||||
else if (right == left)
|
||||
{
|
||||
AttachInTable(table, right, 0, 0, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
AttachInTable(table, left, 0, l_xpad);
|
||||
AttachInTable(table, right, 1);
|
||||
}
|
||||
if (third)
|
||||
{
|
||||
AttachInTable(table, third, 2);
|
||||
}
|
||||
|
||||
s_table_line++;
|
||||
}
|
||||
|
||||
GtkWidget* CreateTableInBox(GtkWidget* parent_box, const char* frame_title, int row, int col)
|
||||
{
|
||||
#if GTK3_GRID_API
|
||||
GtkWidget* table = gtk_grid_new();
|
||||
gtk_widget_set_hexpand(table, true);
|
||||
#else
|
||||
GtkWidget* table = gtk_table_new(row, col, false);
|
||||
#endif
|
||||
GtkWidget* container = (frame_title) ? gtk_frame_new(frame_title) : CreateVbox();
|
||||
gtk_container_add(GTK_CONTAINER(container), table);
|
||||
gtk_container_add(GTK_CONTAINER(parent_box), container);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
void populate_hw_table(GtkWidget* hw_table)
|
||||
{
|
||||
GtkWidget* hack_enable_check = CreateCheckBox("Enable User Hacks", "UserHacks");
|
||||
GtkWidget* acc_date_check = CreateCheckBox("Accurate DATE", "accurate_date");
|
||||
GtkWidget* paltex_check = CreateCheckBox("GPU Palette Conversion", "paltex");
|
||||
GtkWidget* conservative_fb_check = CreateCheckBox("Conservative Buffer Allocation", "conservative_framebuffer");
|
||||
|
||||
GtkWidget* fsaa_label = left_label("Internal Resolution:");
|
||||
GtkWidget* fsaa_combo_box = CreateComboBoxFromVector(theApp.m_gs_upscale_multiplier, "upscale_multiplier");
|
||||
|
||||
GtkWidget* af_label = left_label("Anisotropic Filtering:");
|
||||
GtkWidget* af_combo_box = CreateComboBoxFromVector(theApp.m_gs_max_anisotropy, "MaxAnisotropy");
|
||||
|
||||
GtkWidget* dither_label = left_label("Dithering (PgDn):");
|
||||
GtkWidget* dither_combo_box = CreateComboBoxFromVector(theApp.m_gs_dithering, "dithering_ps2");
|
||||
|
||||
GtkWidget* mipmap_label = left_label("Mipmapping (Insert):");
|
||||
GtkWidget* mipmap_combo_box = CreateComboBoxFromVector(theApp.m_gs_hw_mipmapping, "mipmap_hw");
|
||||
|
||||
GtkWidget* crc_label = left_label("CRC Hack Level:");
|
||||
GtkWidget* crc_combo_box = CreateComboBoxFromVector(theApp.m_gs_crc_level, "crc_hack_level");
|
||||
|
||||
GtkWidget* acc_bld_label = left_label("Blending Accuracy:");
|
||||
GtkWidget* acc_bld_combo_box = CreateComboBoxFromVector(theApp.m_gs_acc_blend_level, "accurate_blending_unit");
|
||||
|
||||
// Some helper string
|
||||
gtk_widget_set_tooltip_text(hack_enable_check, "Enable the HW hack option panel");
|
||||
AddTooltip(acc_date_check, IDC_ACCURATE_DATE);
|
||||
AddTooltip(paltex_check, IDC_PALTEX);
|
||||
AddTooltip(conservative_fb_check, IDC_CONSERVATIVE_FB);
|
||||
AddTooltip(crc_label, crc_combo_box, IDC_CRC_LEVEL);
|
||||
AddTooltip(af_label, af_combo_box, IDC_AFCOMBO);
|
||||
AddTooltip(mipmap_label, IDC_MIPMAP_HW);
|
||||
AddTooltip(mipmap_combo_box, IDC_MIPMAP_HW);
|
||||
AddTooltip(acc_bld_label, acc_bld_combo_box, IDC_ACCURATE_BLEND_UNIT);
|
||||
AddTooltip(dither_label, dither_combo_box, IDC_DITHERING);
|
||||
|
||||
s_table_line = 0;
|
||||
InsertWidgetInTable(hw_table, hack_enable_check, acc_date_check);
|
||||
InsertWidgetInTable(hw_table, paltex_check, conservative_fb_check);
|
||||
InsertWidgetInTable(hw_table, fsaa_label, fsaa_combo_box);
|
||||
InsertWidgetInTable(hw_table, af_label, af_combo_box);
|
||||
InsertWidgetInTable(hw_table, dither_label, dither_combo_box);
|
||||
InsertWidgetInTable(hw_table, mipmap_label, mipmap_combo_box);
|
||||
InsertWidgetInTable(hw_table, crc_label, crc_combo_box);
|
||||
InsertWidgetInTable(hw_table, acc_bld_label, acc_bld_combo_box);
|
||||
}
|
||||
|
||||
void populate_gl_table(GtkWidget* gl_table)
|
||||
{
|
||||
GtkWidget* gl_gs_label = left_label("Geometry Shader:");
|
||||
GtkWidget* gl_gs_combo = CreateComboBoxFromVector(theApp.m_gs_generic_list, "override_geometry_shader");
|
||||
GtkWidget* gl_ils_label = left_label("Image Load Store:");
|
||||
GtkWidget* gl_ils_combo = CreateComboBoxFromVector(theApp.m_gs_generic_list, "override_GL_ARB_shader_image_load_store");
|
||||
GtkWidget* gl_sps_label = left_label("Sparse Texture:");
|
||||
GtkWidget* gl_sps_combo = CreateComboBoxFromVector(theApp.m_gs_generic_list, "override_GL_ARB_sparse_texture");
|
||||
|
||||
AddTooltip(gl_gs_label, gl_gs_combo, IDC_GEOMETRY_SHADER_OVERRIDE);
|
||||
AddTooltip(gl_ils_label, gl_ils_combo, IDC_IMAGE_LOAD_STORE);
|
||||
AddTooltip(gl_sps_label, gl_sps_combo, IDC_SPARSE_TEXTURE);
|
||||
|
||||
s_table_line = 0;
|
||||
InsertWidgetInTable(gl_table, gl_gs_label, gl_gs_combo);
|
||||
InsertWidgetInTable(gl_table, gl_ils_label, gl_ils_combo);
|
||||
InsertWidgetInTable(gl_table, gl_sps_label, gl_sps_combo);
|
||||
}
|
||||
|
||||
void populate_sw_table(GtkWidget* sw_table)
|
||||
{
|
||||
GtkWidget* threads_label = left_label("Extra rendering threads:");
|
||||
GtkWidget* threads_spin = CreateSpinButton(0, 32, "extrathreads");
|
||||
|
||||
GtkWidget* aa_check = CreateCheckBox("Edge Anti-aliasing (Del)", "aa1");
|
||||
GtkWidget* mipmap_check = CreateCheckBox("Mipmapping", "mipmap");
|
||||
GtkWidget* autoflush_sw_check = CreateCheckBox("Auto Flush", "autoflush_sw");
|
||||
|
||||
AddTooltip(aa_check, IDC_AA1);
|
||||
AddTooltip(mipmap_check, IDC_MIPMAP_SW);
|
||||
AddTooltip(autoflush_sw_check, IDC_AUTO_FLUSH_SW);
|
||||
AddTooltip(threads_label, threads_spin, IDC_SWTHREADS);
|
||||
|
||||
s_table_line = 0;
|
||||
InsertWidgetInTable(sw_table, threads_label, threads_spin);
|
||||
InsertWidgetInTable(sw_table, autoflush_sw_check, aa_check);
|
||||
InsertWidgetInTable(sw_table, mipmap_check);
|
||||
}
|
||||
|
||||
void populate_shader_table(GtkWidget* shader_table)
|
||||
{
|
||||
GtkWidget* shader = CreateFileChooser(GTK_FILE_CHOOSER_ACTION_OPEN, "Select an external shader", "shaderfx_glsl");
|
||||
GtkWidget* shader_conf = CreateFileChooser(GTK_FILE_CHOOSER_ACTION_OPEN, "Then select a config", "shaderfx_conf");
|
||||
GtkWidget* shader_label = left_label("External shader glsl");
|
||||
GtkWidget* shader_conf_label = left_label("External shader conf");
|
||||
|
||||
GtkWidget* shadeboost_check = CreateCheckBox("Shade Boost", "ShadeBoost");
|
||||
GtkWidget* fxaa_check = CreateCheckBox("Fxaa Shader (PgUp)", "fxaa");
|
||||
GtkWidget* shaderfx_check = CreateCheckBox("External Shader (Home)", "shaderfx");
|
||||
|
||||
GtkWidget* tv_shader_label = left_label("TV Shader:");
|
||||
GtkWidget* tv_shader = CreateComboBoxFromVector(theApp.m_gs_tv_shaders, "TVShader");
|
||||
|
||||
GtkWidget* linear_check = CreateCheckBox("Texture Filtering of Display", "linear_present");
|
||||
|
||||
// Shadeboost scale
|
||||
GtkWidget* sb_brightness = CreateScale("ShadeBoost_Brightness");
|
||||
GtkWidget* sb_brightness_label = left_label("Shade Boost Brightness:");
|
||||
|
||||
GtkWidget* sb_contrast = CreateScale("ShadeBoost_Contrast");
|
||||
GtkWidget* sb_contrast_label = left_label("Shade Boost Contrast:");
|
||||
|
||||
GtkWidget* sb_saturation = CreateScale("ShadeBoost_Saturation");
|
||||
GtkWidget* sb_saturation_label = left_label("Shade Boost Saturation:");
|
||||
|
||||
AddTooltip(shadeboost_check, IDC_SHADEBOOST);
|
||||
AddTooltip(shaderfx_check, IDC_SHADER_FX);
|
||||
AddTooltip(fxaa_check, IDC_FXAA);
|
||||
AddTooltip(linear_check, IDC_LINEAR_PRESENT);
|
||||
|
||||
s_table_line = 0;
|
||||
InsertWidgetInTable(shader_table, linear_check);
|
||||
InsertWidgetInTable(shader_table, fxaa_check);
|
||||
InsertWidgetInTable(shader_table, shadeboost_check);
|
||||
InsertWidgetInTable(shader_table, sb_brightness_label, sb_brightness);
|
||||
InsertWidgetInTable(shader_table, sb_contrast_label, sb_contrast);
|
||||
InsertWidgetInTable(shader_table, sb_saturation_label, sb_saturation);
|
||||
InsertWidgetInTable(shader_table, shaderfx_check);
|
||||
InsertWidgetInTable(shader_table, shader_label, shader);
|
||||
InsertWidgetInTable(shader_table, shader_conf_label, shader_conf);
|
||||
InsertWidgetInTable(shader_table, tv_shader_label, tv_shader);
|
||||
}
|
||||
|
||||
static GtkWidget* s_hack_skipdraw_offset_spin;
|
||||
static GtkWidget* s_hack_skipdraw_spin;
|
||||
|
||||
static void CB_SkipdrawRange(GtkSpinButton*, gpointer)
|
||||
{
|
||||
int skipdraw_offset = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(s_hack_skipdraw_offset_spin));
|
||||
int skipdraw = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(s_hack_skipdraw_spin));
|
||||
|
||||
bool skipdraw_offset_changed = skipdraw_offset != theApp.GetConfigI("UserHacks_SkipDraw_Offset");
|
||||
bool skipdraw_changed = skipdraw != theApp.GetConfigI("UserHacks_SkipDraw");
|
||||
|
||||
if (skipdraw_offset == 0 && skipdraw_offset_changed || skipdraw == 0 && skipdraw_changed)
|
||||
{
|
||||
skipdraw_offset = 0;
|
||||
skipdraw = 0;
|
||||
}
|
||||
else if (skipdraw_offset > skipdraw)
|
||||
{
|
||||
if (skipdraw_offset_changed)
|
||||
skipdraw = skipdraw_offset;
|
||||
if (skipdraw_changed)
|
||||
skipdraw_offset = skipdraw;
|
||||
}
|
||||
else if (skipdraw > 0 && skipdraw_offset == 0)
|
||||
{
|
||||
skipdraw_offset = 1;
|
||||
}
|
||||
|
||||
theApp.SetConfig("UserHacks_SkipDraw_Offset", skipdraw_offset);
|
||||
theApp.SetConfig("UserHacks_SkipDraw", skipdraw);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s_hack_skipdraw_offset_spin), skipdraw_offset);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s_hack_skipdraw_spin), skipdraw);
|
||||
}
|
||||
|
||||
static void CreateSkipdrawSpinButtons(double min, double max)
|
||||
{
|
||||
s_hack_skipdraw_offset_spin = gtk_spin_button_new_with_range(min, max, 1);
|
||||
s_hack_skipdraw_spin = gtk_spin_button_new_with_range(min, max, 1);
|
||||
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s_hack_skipdraw_offset_spin), theApp.GetConfigI("UserHacks_SkipDraw_Offset"));
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(s_hack_skipdraw_spin), theApp.GetConfigI("UserHacks_SkipDraw"));
|
||||
|
||||
g_signal_connect(s_hack_skipdraw_offset_spin, "value-changed", G_CALLBACK(CB_SkipdrawRange), nullptr);
|
||||
g_signal_connect(s_hack_skipdraw_spin, "value-changed", G_CALLBACK(CB_SkipdrawRange), nullptr);
|
||||
}
|
||||
|
||||
void populate_hack_table(GtkWidget* hack_table)
|
||||
{
|
||||
GtkWidget* hack_offset_label = left_label("Half-pixel Offset:");
|
||||
GtkWidget* hack_offset_box = CreateComboBoxFromVector(theApp.m_gs_offset_hack, "UserHacks_HalfPixelOffset");
|
||||
GtkWidget* hack_skipdraw_label = left_label("Skipdraw Range:");
|
||||
CreateSkipdrawSpinButtons(0, 10000);
|
||||
GtkWidget* hack_wild_check = CreateCheckBox("Wild Arms Hack", "UserHacks_WildHack");
|
||||
GtkWidget* hack_tco_label = left_label("Texture Offsets:");
|
||||
GtkWidget* hack_tco_x_spin = CreateSpinButton(0, 10000, "UserHacks_TCOffsetX");
|
||||
GtkWidget* hack_tco_y_spin = CreateSpinButton(0, 10000, "UserHacks_TCOffsetY");
|
||||
GtkWidget* align_sprite_check = CreateCheckBox("Align Sprite", "UserHacks_align_sprite_X");
|
||||
GtkWidget* preload_gs_check = CreateCheckBox("Preload Frame Data", "preload_frame_with_gs_data");
|
||||
GtkWidget* hack_fast_inv = CreateCheckBox("Fast Texture Invalidation", "UserHacks_DisablePartialInvalidation");
|
||||
GtkWidget* hack_depth_check = CreateCheckBox("Disable Depth Emulation", "UserHacks_DisableDepthSupport");
|
||||
GtkWidget* hack_safe_features = CreateCheckBox("Disable Safe Features", "UserHacks_Disable_Safe_Features");
|
||||
GtkWidget* hack_cpu_fbcv = CreateCheckBox("Frame Buffer Conversion", "UserHacks_CPU_FB_Conversion");
|
||||
GtkWidget* hack_auto_flush = CreateCheckBox("Auto Flush", "UserHacks_AutoFlush");
|
||||
GtkWidget* hack_merge_sprite = CreateCheckBox("Merge Sprite", "UserHacks_merge_pp_sprite");
|
||||
GtkWidget* hack_wrap_mem = CreateCheckBox("Memory Wrapping", "wrap_gs_mem");
|
||||
|
||||
GtkWidget* stretch_hack_box = CreateComboBoxFromVector(theApp.m_gs_hack, "UserHacks_round_sprite_offset");
|
||||
GtkWidget* stretch_hack_label = left_label("Round Sprite:");
|
||||
GtkWidget* trilinear_box = CreateComboBoxFromVector(theApp.m_gs_trifilter, "UserHacks_TriFilter");
|
||||
GtkWidget* trilinear_label = left_label("Trilinear Filtering:");
|
||||
GtkWidget* half_screen_ts_box = CreateComboBoxFromVector(theApp.m_gs_generic_list, "UserHacks_Half_Bottom_Override");
|
||||
GtkWidget* half_screen_ts_label = left_label("Half-screen Fix:");
|
||||
|
||||
// Reuse windows helper string :)
|
||||
AddTooltip(hack_offset_label, IDC_OFFSETHACK);
|
||||
AddTooltip(hack_offset_box, IDC_OFFSETHACK);
|
||||
AddTooltip(hack_skipdraw_label, IDC_SKIPDRAWHACK);
|
||||
AddTooltip(s_hack_skipdraw_offset_spin, IDC_SKIPDRAWHACK);
|
||||
AddTooltip(s_hack_skipdraw_spin, IDC_SKIPDRAWHACK);
|
||||
AddTooltip(hack_wild_check, IDC_WILDHACK);
|
||||
AddTooltip(hack_tco_label, IDC_TCOFFSETX);
|
||||
AddTooltip(hack_tco_x_spin, IDC_TCOFFSETX);
|
||||
AddTooltip(hack_tco_y_spin, IDC_TCOFFSETX);
|
||||
AddTooltip(align_sprite_check, IDC_ALIGN_SPRITE);
|
||||
AddTooltip(stretch_hack_label, stretch_hack_box, IDC_ROUND_SPRITE);
|
||||
AddTooltip(preload_gs_check, IDC_PRELOAD_GS);
|
||||
AddTooltip(hack_fast_inv, IDC_FAST_TC_INV);
|
||||
AddTooltip(hack_depth_check, IDC_TC_DEPTH);
|
||||
AddTooltip(hack_cpu_fbcv, IDC_CPU_FB_CONVERSION);
|
||||
AddTooltip(hack_auto_flush, IDC_AUTO_FLUSH_HW);
|
||||
AddTooltip(hack_safe_features, IDC_SAFE_FEATURES);
|
||||
AddTooltip(hack_merge_sprite, IDC_MERGE_PP_SPRITE);
|
||||
AddTooltip(hack_wrap_mem, IDC_MEMORY_WRAPPING);
|
||||
AddTooltip(trilinear_box, IDC_TRI_FILTER);
|
||||
AddTooltip(trilinear_label, IDC_TRI_FILTER);
|
||||
AddTooltip(half_screen_ts_box, IDC_HALF_SCREEN_TS);
|
||||
AddTooltip(half_screen_ts_label, IDC_HALF_SCREEN_TS);
|
||||
|
||||
|
||||
s_table_line = 0;
|
||||
// Hacks
|
||||
// Column one and two HW Hacks
|
||||
InsertWidgetInTable(hack_table, align_sprite_check, hack_cpu_fbcv);
|
||||
InsertWidgetInTable(hack_table, hack_auto_flush, hack_wrap_mem);
|
||||
InsertWidgetInTable(hack_table, hack_depth_check, hack_merge_sprite);
|
||||
InsertWidgetInTable(hack_table, hack_safe_features, preload_gs_check);
|
||||
InsertWidgetInTable(hack_table, hack_fast_inv, hack_wild_check);
|
||||
// Other hacks
|
||||
InsertWidgetInTable(hack_table, half_screen_ts_label, half_screen_ts_box);
|
||||
InsertWidgetInTable(hack_table, trilinear_label, trilinear_box);
|
||||
InsertWidgetInTable(hack_table, hack_offset_label, hack_offset_box);
|
||||
InsertWidgetInTable(hack_table, stretch_hack_label, stretch_hack_box);
|
||||
InsertWidgetInTable(hack_table, hack_skipdraw_label, s_hack_skipdraw_offset_spin, s_hack_skipdraw_spin);
|
||||
InsertWidgetInTable(hack_table, hack_tco_label, hack_tco_x_spin, hack_tco_y_spin);
|
||||
}
|
||||
|
||||
void populate_main_table(GtkWidget* main_table)
|
||||
{
|
||||
GtkWidget* render_label = left_label("Renderer:");
|
||||
GtkWidget* render_combo_box = CreateComboBoxFromVector(theApp.m_gs_renderers, "Renderer");
|
||||
GtkWidget* interlace_label = left_label("Interlacing (F5):");
|
||||
GtkWidget* interlace_combo_box = CreateComboBoxFromVector(theApp.m_gs_interlace, "interlace");
|
||||
GtkWidget* filter_label = left_label("Texture Filtering:");
|
||||
GtkWidget* filter_combo_box = CreateComboBoxFromVector(theApp.m_gs_bifilter, "filter");
|
||||
|
||||
AddTooltip(filter_label, filter_combo_box, IDC_FILTER);
|
||||
|
||||
s_table_line = 0;
|
||||
InsertWidgetInTable(main_table, render_label, render_combo_box);
|
||||
InsertWidgetInTable(main_table, interlace_label, interlace_combo_box);
|
||||
InsertWidgetInTable(main_table, filter_label, filter_combo_box);
|
||||
}
|
||||
|
||||
void populate_debug_table(GtkWidget* debug_table)
|
||||
{
|
||||
GtkWidget* glsl_debug_check = CreateCheckBox("GLSL compilation", "debug_glsl_shader");
|
||||
GtkWidget* gl_debug_check = CreateCheckBox("Print GL error", "debug_opengl");
|
||||
GtkWidget* gs_dump_check = CreateCheckBox("Dump GS data", "dump");
|
||||
GtkWidget* gs_save_check = CreateCheckBox("Save RT", "save");
|
||||
GtkWidget* gs_savef_check = CreateCheckBox("Save Frame", "savef");
|
||||
GtkWidget* gs_savet_check = CreateCheckBox("Save Texture", "savet");
|
||||
GtkWidget* gs_savez_check = CreateCheckBox("Save Depth", "savez");
|
||||
|
||||
GtkWidget* gs_saven_label = left_label("Start of Dump");
|
||||
GtkWidget* gs_saven_spin = CreateSpinButton(0, pow(10, 9), "saven");
|
||||
GtkWidget* gs_savel_label = left_label("Length of Dump");
|
||||
GtkWidget* gs_savel_spin = CreateSpinButton(0, pow(10, 5), "savel");
|
||||
|
||||
s_table_line = 0;
|
||||
InsertWidgetInTable(debug_table, gl_debug_check, glsl_debug_check);
|
||||
InsertWidgetInTable(debug_table, gs_dump_check);
|
||||
InsertWidgetInTable(debug_table, gs_save_check, gs_savef_check);
|
||||
InsertWidgetInTable(debug_table, gs_savet_check, gs_savez_check);
|
||||
InsertWidgetInTable(debug_table, gs_saven_label, gs_saven_spin);
|
||||
InsertWidgetInTable(debug_table, gs_savel_label, gs_savel_spin);
|
||||
}
|
||||
|
||||
void populate_record_table(GtkWidget* record_table)
|
||||
{
|
||||
GtkWidget* capture_check = CreateCheckBox("Enable Recording (with F12)", "capture_enabled");
|
||||
GtkWidget* resxy_label = left_label("Resolution:");
|
||||
GtkWidget* resx_spin = CreateSpinButton(256, 8192, "CaptureWidth");
|
||||
GtkWidget* resy_spin = CreateSpinButton(256, 8192, "CaptureHeight");
|
||||
GtkWidget* threads_label = left_label("Saving Threads:");
|
||||
GtkWidget* threads_spin = CreateSpinButton(1, 32, "capture_threads");
|
||||
GtkWidget* out_dir_label = left_label("Output Directory:");
|
||||
GtkWidget* out_dir = CreateFileChooser(GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, "Select a directory", "capture_out_dir");
|
||||
GtkWidget* png_label = left_label("PNG Compression Level:");
|
||||
GtkWidget* png_level = CreateSpinButton(1, 9, "png_compression_level");
|
||||
|
||||
InsertWidgetInTable(record_table, capture_check);
|
||||
InsertWidgetInTable(record_table, resxy_label, resx_spin, resy_spin);
|
||||
InsertWidgetInTable(record_table, threads_label, threads_spin);
|
||||
InsertWidgetInTable(record_table, png_label, png_level);
|
||||
InsertWidgetInTable(record_table, out_dir_label, out_dir);
|
||||
}
|
||||
|
||||
void populate_osd_table(GtkWidget* osd_table)
|
||||
{
|
||||
GtkWidget* monitor_check = CreateCheckBox("Enable Monitor", "osd_monitor_enabled");
|
||||
GtkWidget* log_check = CreateCheckBox("Enable Log", "osd_log_enabled");
|
||||
GtkWidget* fontsize_label = left_label("Size:");
|
||||
GtkWidget* fontsize_text = CreateSpinButton(1, 100, "osd_fontsize");
|
||||
GtkWidget* osd_red_label = left_label("Red:");
|
||||
GtkWidget* osd_red_spin = CreateScale("osd_color_r", 0, 255, 1);
|
||||
GtkWidget* osd_green_label = left_label("Green:");
|
||||
GtkWidget* osd_green_spin = CreateScale("osd_color_g", 0, 255, 1);
|
||||
GtkWidget* osd_blue_label = left_label("Blue:");
|
||||
GtkWidget* osd_blue_spin = CreateScale("osd_color_b", 0, 255, 1);
|
||||
GtkWidget* opacity_label = left_label("Opacity:");
|
||||
GtkWidget* opacity_slide = CreateScale("osd_color_opacity");
|
||||
GtkWidget* log_timeout_label = left_label("Timeout (seconds):");
|
||||
GtkWidget* log_timeout_text = CreateSpinButton(2, 10, "osd_log_timeout");
|
||||
GtkWidget* max_messages_label = left_label("Maximum Onscreen Log Messages:");
|
||||
GtkWidget* max_messages_spin = CreateSpinButton(1, 20, "osd_max_log_messages");
|
||||
|
||||
AddTooltip(log_check, IDC_OSD_LOG);
|
||||
AddTooltip(monitor_check, IDC_OSD_MONITOR);
|
||||
AddTooltip(max_messages_label, max_messages_spin, IDC_OSD_MAX_LOG);
|
||||
|
||||
InsertWidgetInTable(osd_table, monitor_check, log_check);
|
||||
InsertWidgetInTable(osd_table, fontsize_label, fontsize_text);
|
||||
InsertWidgetInTable(osd_table, osd_red_label, osd_red_spin);
|
||||
InsertWidgetInTable(osd_table, osd_green_label, osd_green_spin);
|
||||
InsertWidgetInTable(osd_table, osd_blue_label, osd_blue_spin);
|
||||
InsertWidgetInTable(osd_table, opacity_label, opacity_slide);
|
||||
InsertWidgetInTable(osd_table, log_timeout_label, log_timeout_text);
|
||||
InsertWidgetInTable(osd_table, max_messages_label, max_messages_spin);
|
||||
}
|
||||
|
||||
GtkWidget* ScrollMe(GtkWidget* w)
|
||||
{
|
||||
// the scrolled window add an ugly outline/border even when the scroll bar is off.
|
||||
if (BigEnough())
|
||||
return w;
|
||||
|
||||
GtkWidget* scrollbar = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollbar), GTK_SHADOW_NONE);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbar), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
#if GTK_CHECK_VERSION(3, 22, 0)
|
||||
gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(scrollbar), true);
|
||||
#endif
|
||||
|
||||
#if GTK_CHECK_VERSION(3, 8, 0)
|
||||
gtk_container_add(GTK_CONTAINER(scrollbar), w);
|
||||
#else
|
||||
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollbar), w);
|
||||
#endif
|
||||
|
||||
return scrollbar;
|
||||
}
|
||||
|
||||
bool RunLinuxDialog()
|
||||
{
|
||||
GtkWidget* dialog;
|
||||
int return_value;
|
||||
|
||||
/* Create the widgets */
|
||||
dialog = gtk_dialog_new_with_buttons(
|
||||
"Graphics Settings",
|
||||
NULL, /* parent window*/
|
||||
(GtkDialogFlags)(GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
|
||||
"OK", GTK_RESPONSE_ACCEPT,
|
||||
// "Cancel", GTK_RESPONSE_REJECT, // Drop because it is too annoying to support call back this way
|
||||
NULL);
|
||||
|
||||
// The main area for the whole dialog box.
|
||||
GtkWidget* main_box = CreateVbox();
|
||||
GtkWidget* central_box = CreateVbox();
|
||||
GtkWidget* advanced_box = CreateVbox();
|
||||
GtkWidget* debug_box = CreateVbox();
|
||||
GtkWidget* shader_box = CreateVbox();
|
||||
GtkWidget* osd_box = CreateVbox();
|
||||
|
||||
|
||||
GtkWidget* main_table = CreateTableInBox(main_box, NULL, 2, 2);
|
||||
|
||||
GtkWidget* hw_table = CreateTableInBox(central_box, "Hardware Mode Settings", 7, 2);
|
||||
GtkWidget* sw_table = CreateTableInBox(central_box, "Software Mode Settings", 2, 2);
|
||||
|
||||
GtkWidget* hack_table = CreateTableInBox(advanced_box, "Hacks", 7, 2);
|
||||
GtkWidget* gl_table = CreateTableInBox(advanced_box, "OpenGL Very Advanced Custom Settings", 6, 2);
|
||||
|
||||
GtkWidget* record_table = CreateTableInBox(debug_box, "Recording Settings", 4, 3);
|
||||
GtkWidget* debug_table = CreateTableInBox(debug_box, "OpenGL / GS Debug Settings", 6, 3);
|
||||
|
||||
GtkWidget* shader_table = CreateTableInBox(shader_box, "Custom Shader Settings", 9, 2);
|
||||
GtkWidget* osd_table = CreateTableInBox(osd_box, "OSD", 6, 2);
|
||||
|
||||
// Populate all the tables
|
||||
populate_main_table(main_table);
|
||||
|
||||
populate_shader_table(shader_table);
|
||||
populate_hw_table(hw_table);
|
||||
populate_sw_table(sw_table);
|
||||
|
||||
populate_hack_table(hack_table);
|
||||
populate_gl_table(gl_table);
|
||||
|
||||
populate_debug_table(debug_table);
|
||||
populate_record_table(record_table);
|
||||
|
||||
populate_osd_table(osd_table);
|
||||
|
||||
// Handle some nice tabs
|
||||
GtkWidget* notebook = gtk_notebook_new();
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), ScrollMe(central_box), gtk_label_new("Renderer Settings"));
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), ScrollMe(advanced_box), gtk_label_new("Advanced Settings"));
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), ScrollMe(debug_box), gtk_label_new("Debug/Recording"));
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), ScrollMe(shader_box), gtk_label_new("Post-Processing"));
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), ScrollMe(osd_box), gtk_label_new("OSD"));
|
||||
|
||||
// Put everything in the big box.
|
||||
gtk_container_add(GTK_CONTAINER(main_box), notebook);
|
||||
|
||||
// Enable/disable hack frame based on enable option
|
||||
s_hack_frame = hack_table;
|
||||
gtk_widget_set_sensitive(s_hack_frame, theApp.GetConfigB("UserHacks"));
|
||||
|
||||
// Put the box in the dialog and show it to the world.
|
||||
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), main_box);
|
||||
gtk_widget_show_all(dialog);
|
||||
return_value = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
|
||||
// Compatibility & not supported option
|
||||
int mode_width = theApp.GetConfigI("ModeWidth");
|
||||
int mode_height = theApp.GetConfigI("ModeHeight");
|
||||
theApp.SetConfig("ModeHeight", mode_height);
|
||||
theApp.SetConfig("ModeWidth", mode_width);
|
||||
theApp.SetConfig("windowed", 1);
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
return (return_value == GTK_RESPONSE_ACCEPT);
|
||||
}
|
||||
@@ -15,9 +15,6 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSSetting.h"
|
||||
#ifdef _WIN32
|
||||
#include "GS/resource.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define cvtString(s) L##s
|
||||
|
||||
@@ -38,7 +38,6 @@ const wchar_t* dialog_message(int ID, bool* updateText = NULL);
|
||||
const char* dialog_message(int ID, bool* updateText = NULL);
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
enum
|
||||
{
|
||||
// Renderer
|
||||
@@ -52,6 +51,9 @@ enum
|
||||
IDC_MIPMAP_HW,
|
||||
IDC_CRC_LEVEL,
|
||||
IDC_ACCURATE_BLEND_UNIT,
|
||||
#ifdef _WIN32
|
||||
IDC_ACCURATE_BLEND_UNIT_D3D11,
|
||||
#endif
|
||||
// Rendering Hacks
|
||||
IDC_AUTO_FLUSH_HW,
|
||||
IDC_TC_DEPTH,
|
||||
@@ -91,6 +93,12 @@ enum
|
||||
IDC_OSD_MONITOR,
|
||||
IDC_OSD_MAX_LOG,
|
||||
IDC_OSD_MAX_LOG_EDIT,
|
||||
// Shader Configuration
|
||||
IDC_SHADEBOOST,
|
||||
IDC_SHADER_FX,
|
||||
IDC_FXAA,
|
||||
IDC_LINEAR_PRESENT,
|
||||
#ifndef _WIN32
|
||||
// Shader
|
||||
IDR_CONVERT_GLSL,
|
||||
IDR_FXAA_FX,
|
||||
@@ -101,12 +109,7 @@ enum
|
||||
IDR_TFX_VGS_GLSL,
|
||||
IDR_TFX_FS_GLSL,
|
||||
IDR_TFX_CL,
|
||||
// Shader Configuration
|
||||
IDC_SHADEBOOST,
|
||||
IDC_SHADER_FX,
|
||||
IDC_FXAA,
|
||||
IDC_LINEAR_PRESENT,
|
||||
// Fonts
|
||||
IDR_FONT_ROBOTO,
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,104 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GSDialog.h"
|
||||
#include "GSSetting.h"
|
||||
|
||||
class GSShaderDlg : public GSDialog
|
||||
{
|
||||
int m_saturation;
|
||||
int m_brightness;
|
||||
int m_contrast;
|
||||
|
||||
void UpdateControls();
|
||||
|
||||
protected:
|
||||
void OnInit();
|
||||
bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
public:
|
||||
GSShaderDlg();
|
||||
};
|
||||
|
||||
class GSHacksDlg : public GSDialog
|
||||
{
|
||||
int m_old_skipdraw_offset;
|
||||
int m_old_skipdraw;
|
||||
|
||||
void UpdateControls();
|
||||
|
||||
protected:
|
||||
void OnInit();
|
||||
bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
public:
|
||||
GSHacksDlg();
|
||||
};
|
||||
|
||||
class GSOSDDlg : public GSDialog
|
||||
{
|
||||
struct
|
||||
{
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
int a;
|
||||
} m_color;
|
||||
|
||||
void UpdateControls();
|
||||
|
||||
protected:
|
||||
void OnInit();
|
||||
bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
public:
|
||||
GSOSDDlg();
|
||||
};
|
||||
|
||||
class GSSettingsDlg : public GSDialog
|
||||
{
|
||||
|
||||
struct Adapter
|
||||
{
|
||||
std::string name;
|
||||
std::string id;
|
||||
D3D_FEATURE_LEVEL level;
|
||||
Adapter(const std::string& n, const std::string& i, const D3D_FEATURE_LEVEL& l)
|
||||
: name(n)
|
||||
, id(i)
|
||||
, level(l)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<GSSetting> m_renderers;
|
||||
std::vector<Adapter> m_d3d11_adapters;
|
||||
std::vector<Adapter>* m_current_adapters;
|
||||
std::string m_last_selected_adapter_id;
|
||||
|
||||
std::vector<Adapter> EnumerateD3D11Adapters();
|
||||
|
||||
void UpdateAdapters();
|
||||
void UpdateControls();
|
||||
|
||||
protected:
|
||||
void OnInit();
|
||||
bool OnCommand(HWND hWnd, UINT id, UINT code);
|
||||
|
||||
public:
|
||||
GSSettingsDlg();
|
||||
};
|
||||
@@ -0,0 +1,806 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "GSwxDialog.h"
|
||||
#include "gui/AppConfig.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "GS/Renderers/DX11/D3D.h"
|
||||
#endif
|
||||
|
||||
using namespace GSSettingsDialog;
|
||||
|
||||
namespace
|
||||
{
|
||||
void add_tooltip(wxWindow* widget, int tooltip)
|
||||
{
|
||||
if (tooltip != -1)
|
||||
widget->SetToolTip(dialog_message(tooltip));
|
||||
}
|
||||
|
||||
void add_settings_to_array_string(const std::vector<GSSetting>& s, wxArrayString& arr)
|
||||
{
|
||||
for (const GSSetting& setting : s)
|
||||
{
|
||||
if (!setting.note.empty())
|
||||
arr.Add(setting.name + " (" + setting.note + ")");
|
||||
else
|
||||
arr.Add(setting.name);
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_config_index(const std::vector<GSSetting>& s, int value)
|
||||
{
|
||||
for (size_t i = 0; i < s.size(); i++)
|
||||
{
|
||||
if (s[i].value == value)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_config_from_choice(const wxChoice* choice, const std::vector<GSSetting>& s, const char* str)
|
||||
{
|
||||
int idx = choice->GetSelection();
|
||||
|
||||
if (idx == wxNOT_FOUND)
|
||||
return;
|
||||
|
||||
theApp.SetConfig(str, s[idx].value);
|
||||
}
|
||||
|
||||
void add_label(wxWindow* parent, wxSizer* sizer, const char* str, int tooltip = -1, wxSizerFlags flags = wxSizerFlags().Centre().Right(), long style = wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL)
|
||||
{
|
||||
auto* temp_text = new wxStaticText(parent, wxID_ANY, str, wxDefaultPosition, wxDefaultSize, style);
|
||||
add_tooltip(temp_text, tooltip);
|
||||
sizer->Add(temp_text, flags);
|
||||
}
|
||||
|
||||
/// wxBoxSizer with padding
|
||||
template <typename OuterSizer>
|
||||
struct PaddedBoxSizer
|
||||
{
|
||||
OuterSizer* outer;
|
||||
wxBoxSizer* inner;
|
||||
|
||||
// Make static analyzers happy (memory management is handled by WX)
|
||||
// (There's no actual reason we couldn't use the default copy constructor, except cppcheck screams when you do and it's easier to delete than implement one)
|
||||
PaddedBoxSizer(const PaddedBoxSizer&) = delete;
|
||||
|
||||
template <typename... Args>
|
||||
PaddedBoxSizer(wxOrientation orientation, Args&&... args)
|
||||
: outer(new OuterSizer(orientation, std::forward<Args>(args)...))
|
||||
, inner(new wxBoxSizer(orientation))
|
||||
{
|
||||
wxSizerFlags flags = wxSizerFlags().Expand();
|
||||
#ifdef __APPLE__
|
||||
if (!std::is_same<OuterSizer, wxStaticBoxSizer>::value) // wxMac already adds padding to static box sizers
|
||||
#endif
|
||||
flags.Border();
|
||||
outer->Add(inner, flags);
|
||||
}
|
||||
|
||||
wxBoxSizer* operator->() { return inner; }
|
||||
};
|
||||
|
||||
struct CheckboxPrereq
|
||||
{
|
||||
wxCheckBox* box;
|
||||
explicit CheckboxPrereq(wxCheckBox* box)
|
||||
: box(box)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()()
|
||||
{
|
||||
return box->GetValue();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
GSUIElementHolder::GSUIElementHolder(wxWindow* window)
|
||||
: m_window(window)
|
||||
{
|
||||
}
|
||||
|
||||
wxStaticText* GSUIElementHolder::addWithLabel(wxControl* control, UIElem::Type type, wxSizer* sizer, const char* label, const char* config_name, int tooltip, std::function<bool()> prereq, wxSizerFlags flags)
|
||||
{
|
||||
add_tooltip(control, tooltip);
|
||||
wxStaticText* text = new wxStaticText(m_window, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
|
||||
add_tooltip(text, tooltip);
|
||||
sizer->Add(text, wxSizerFlags().Centre().Right());
|
||||
sizer->Add(control, flags);
|
||||
m_elems.emplace_back(type, control, config_name, prereq);
|
||||
return text;
|
||||
}
|
||||
|
||||
wxCheckBox* GSUIElementHolder::addCheckBox(wxSizer* sizer, const char* label, const char* config_name, int tooltip, std::function<bool()> prereq)
|
||||
{
|
||||
wxCheckBox* box = new wxCheckBox(m_window, wxID_ANY, label);
|
||||
add_tooltip(box, tooltip);
|
||||
if (sizer)
|
||||
sizer->Add(box);
|
||||
m_elems.emplace_back(UIElem::Type::CheckBox, box, config_name, prereq);
|
||||
return box;
|
||||
}
|
||||
|
||||
std::pair<wxChoice*, wxStaticText*> GSUIElementHolder::addComboBoxAndLabel(wxSizer* sizer, const char* label, const char* config_name, const std::vector<GSSetting>* settings, int tooltip, std::function<bool()> prereq)
|
||||
{
|
||||
wxArrayString temp;
|
||||
add_settings_to_array_string(*settings, temp);
|
||||
wxChoice* choice = new GSwxChoice(m_window, wxID_ANY, wxDefaultPosition, wxDefaultSize, temp, settings);
|
||||
return std::make_pair(choice, addWithLabel(choice, UIElem::Type::Choice, sizer, label, config_name, tooltip, prereq));
|
||||
}
|
||||
|
||||
wxSpinCtrl* GSUIElementHolder::addSpin(wxSizer* sizer, const char* config_name, int min, int max, int initial, int tooltip, std::function<bool()> prereq)
|
||||
{
|
||||
wxSpinCtrl* spin = new wxSpinCtrl(m_window, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, initial);
|
||||
add_tooltip(spin, tooltip);
|
||||
if (sizer)
|
||||
sizer->Add(spin, wxSizerFlags(1));
|
||||
m_elems.emplace_back(UIElem::Type::Spin, spin, config_name, prereq);
|
||||
return spin;
|
||||
}
|
||||
|
||||
std::pair<wxSpinCtrl*, wxStaticText*> GSUIElementHolder::addSpinAndLabel(wxSizer* sizer, const char* label, const char* config_name, int min, int max, int initial, int tooltip, std::function<bool()> prereq)
|
||||
{
|
||||
wxSpinCtrl* spin = new wxSpinCtrl(m_window, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, initial);
|
||||
return std::make_pair(spin, addWithLabel(spin, UIElem::Type::Spin, sizer, label, config_name, tooltip, prereq, wxSizerFlags().Centre().Left().Expand()));
|
||||
}
|
||||
|
||||
std::pair<wxSlider*, wxStaticText*> GSUIElementHolder::addSliderAndLabel(wxSizer* sizer, const char* label, const char* config_name, int min, int max, int initial, int tooltip, std::function<bool()> prereq)
|
||||
{
|
||||
wxSlider* slider = new wxSlider(m_window, wxID_ANY, initial, min, max, wxDefaultPosition, wxDefaultSize, wxSL_HORIZONTAL | wxSL_VALUE_LABEL);
|
||||
return std::make_pair(slider, addWithLabel(slider, UIElem::Type::Slider, sizer, label, config_name, tooltip, prereq));
|
||||
}
|
||||
|
||||
std::pair<wxFilePickerCtrl*, wxStaticText*> GSUIElementHolder::addFilePickerAndLabel(wxSizer* sizer, const char* label, const char* config_name, int tooltip, std::function<bool()> prereq)
|
||||
{
|
||||
wxFilePickerCtrl* picker = new wxFilePickerCtrl(m_window, wxID_ANY);
|
||||
return std::make_pair(picker, addWithLabel(picker, UIElem::Type::File, sizer, label, config_name, tooltip, prereq));
|
||||
}
|
||||
|
||||
std::pair<wxDirPickerCtrl*, wxStaticText*> GSUIElementHolder::addDirPickerAndLabel(wxSizer* sizer, const char* label, const char* config_name, int tooltip, std::function<bool()> prereq)
|
||||
{
|
||||
wxDirPickerCtrl* picker = new wxDirPickerCtrl(m_window, wxID_ANY);
|
||||
return std::make_pair(picker, addWithLabel(picker, UIElem::Type::Directory, sizer, label, config_name, tooltip, prereq));
|
||||
}
|
||||
|
||||
void GSUIElementHolder::Load()
|
||||
{
|
||||
for (const UIElem& elem : m_elems)
|
||||
{
|
||||
switch (elem.type)
|
||||
{
|
||||
case UIElem::Type::CheckBox:
|
||||
static_cast<wxCheckBox*>(elem.control)->SetValue(theApp.GetConfigB(elem.config));
|
||||
break;
|
||||
case UIElem::Type::Choice:
|
||||
{
|
||||
GSwxChoice* choice = static_cast<GSwxChoice*>(elem.control);
|
||||
choice->SetSelection(get_config_index(choice->settings, theApp.GetConfigI(elem.config)));
|
||||
break;
|
||||
}
|
||||
case UIElem::Type::Spin:
|
||||
static_cast<wxSpinCtrl*>(elem.control)->SetValue(theApp.GetConfigI(elem.config));
|
||||
break;
|
||||
case UIElem::Type::Slider:
|
||||
static_cast<wxSlider*>(elem.control)->SetValue(theApp.GetConfigI(elem.config));
|
||||
break;
|
||||
case UIElem::Type::File:
|
||||
case UIElem::Type::Directory:
|
||||
{
|
||||
auto* picker = static_cast<wxFileDirPickerCtrlBase*>(elem.control);
|
||||
picker->SetInitialDirectory(theApp.GetConfigS(elem.config));
|
||||
picker->SetPath(theApp.GetConfigS(elem.config));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSUIElementHolder::Save()
|
||||
{
|
||||
for (const UIElem& elem : m_elems)
|
||||
{
|
||||
switch (elem.type)
|
||||
{
|
||||
case UIElem::Type::CheckBox:
|
||||
theApp.SetConfig(elem.config, static_cast<wxCheckBox*>(elem.control)->GetValue());
|
||||
break;
|
||||
case UIElem::Type::Choice:
|
||||
{
|
||||
GSwxChoice* choice = static_cast<GSwxChoice*>(elem.control);
|
||||
set_config_from_choice(choice, choice->settings, elem.config);
|
||||
break;
|
||||
}
|
||||
case UIElem::Type::Spin:
|
||||
theApp.SetConfig(elem.config, static_cast<wxSpinCtrl*>(elem.control)->GetValue());
|
||||
break;
|
||||
case UIElem::Type::Slider:
|
||||
theApp.SetConfig(elem.config, static_cast<wxSlider*>(elem.control)->GetValue());
|
||||
break;
|
||||
case UIElem::Type::File:
|
||||
case UIElem::Type::Directory:
|
||||
theApp.SetConfig(elem.config, static_cast<wxFileDirPickerCtrlBase*>(elem.control)->GetPath());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSUIElementHolder::Update()
|
||||
{
|
||||
for (const UIElem& elem : m_elems)
|
||||
{
|
||||
if (elem.prereq)
|
||||
elem.control->Enable(elem.prereq());
|
||||
}
|
||||
}
|
||||
|
||||
void GSUIElementHolder::DisableAll()
|
||||
{
|
||||
for (const UIElem& elem : m_elems)
|
||||
{
|
||||
if (elem.prereq)
|
||||
elem.control->Enable(false);
|
||||
}
|
||||
}
|
||||
|
||||
RendererTab::RendererTab(wxWindow* parent)
|
||||
: wxPanel(parent, wxID_ANY)
|
||||
, m_ui(this)
|
||||
{
|
||||
const int space = wxSizerFlags().Border().GetBorderInPixels();
|
||||
auto hw_prereq = [this]{ return m_is_hardware; };
|
||||
auto sw_prereq = [this]{ return !m_is_hardware; };
|
||||
|
||||
PaddedBoxSizer<wxBoxSizer> tab_box(wxVERTICAL);
|
||||
PaddedBoxSizer<wxStaticBoxSizer> hardware_box(wxVERTICAL, this, "Hardware Mode");
|
||||
PaddedBoxSizer<wxStaticBoxSizer> software_box(wxVERTICAL, this, "Software Mode");
|
||||
|
||||
auto* hw_checks_box = new wxWrapSizer(wxHORIZONTAL);
|
||||
|
||||
m_ui.addCheckBox(hw_checks_box, "GPU Palette Conversion", "paltex", IDC_PALTEX, hw_prereq);
|
||||
m_ui.addCheckBox(hw_checks_box, "Conservative Buffer Allocation", "conservative_framebuffer", IDC_CONSERVATIVE_FB, hw_prereq);
|
||||
m_ui.addCheckBox(hw_checks_box, "Accurate Destination Alpha Test", "accurate_date", IDC_ACCURATE_DATE, hw_prereq);
|
||||
|
||||
auto* hw_choice_grid = new wxFlexGridSizer(2, space, space);
|
||||
|
||||
m_internal_resolution = m_ui.addComboBoxAndLabel(hw_choice_grid, "Internal Resolution:", "upscale_multiplier", &theApp.m_gs_upscale_multiplier, -1, hw_prereq).first;
|
||||
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Anisotropic Filtering:", "MaxAnisotropy", &theApp.m_gs_max_anisotropy, IDC_AFCOMBO, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Dithering (PgDn):", "dithering_ps2", &theApp.m_gs_dithering, IDC_DITHERING, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "Mipmapping (Insert):", "mipmap_hw", &theApp.m_gs_hw_mipmapping, IDC_MIPMAP_HW, hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(hw_choice_grid, "CRC Hack Level:", "crc_hack_level", &theApp.m_gs_crc_level, IDC_CRC_LEVEL, hw_prereq);
|
||||
|
||||
m_blend_mode = m_ui.addComboBoxAndLabel(hw_choice_grid, "Blending Accuracy:", "accurate_blending_unit", &theApp.m_gs_acc_blend_level, IDC_ACCURATE_BLEND_UNIT, hw_prereq);
|
||||
#ifdef _WIN32
|
||||
m_blend_mode_d3d11 = m_ui.addComboBoxAndLabel(hw_choice_grid, "Blending Accuracy:", "accurate_blending_unit_d3d11", &theApp.m_gs_acc_blend_level_d3d11, IDC_ACCURATE_BLEND_UNIT_D3D11, hw_prereq);
|
||||
#endif
|
||||
|
||||
hardware_box->Add(hw_checks_box, wxSizerFlags().Centre());
|
||||
hardware_box->AddSpacer(space);
|
||||
hardware_box->Add(hw_choice_grid, wxSizerFlags().Centre());
|
||||
|
||||
auto* sw_checks_box = new wxWrapSizer(wxHORIZONTAL);
|
||||
m_ui.addCheckBox(sw_checks_box, "Auto Flush", "autoflush_sw", IDC_AUTO_FLUSH_SW, sw_prereq);
|
||||
m_ui.addCheckBox(sw_checks_box, "Edge Antialiasing (Del)", "aa1", IDC_AA1, sw_prereq);
|
||||
m_ui.addCheckBox(sw_checks_box, "Mipmapping", "mipmap", IDC_MIPMAP_SW, sw_prereq);
|
||||
|
||||
software_box->Add(sw_checks_box, wxSizerFlags().Centre());
|
||||
software_box->AddSpacer(space);
|
||||
|
||||
// Rendering threads
|
||||
auto* thread_box = new wxFlexGridSizer(2, space, space);
|
||||
m_ui.addSpinAndLabel(thread_box, "Extra Rendering threads:", "extrathreads", 0, 32, 2, IDC_SWTHREADS, sw_prereq);
|
||||
software_box->Add(thread_box, wxSizerFlags().Centre());
|
||||
|
||||
tab_box->Add(hardware_box.outer, wxSizerFlags().Expand());
|
||||
tab_box->Add(software_box.outer, wxSizerFlags().Expand());
|
||||
|
||||
SetSizerAndFit(tab_box.outer);
|
||||
}
|
||||
|
||||
void RendererTab::UpdateBlendMode(GSRendererType renderer)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (renderer == GSRendererType::DX1011_HW)
|
||||
{
|
||||
m_blend_mode_d3d11.first ->Show();
|
||||
m_blend_mode_d3d11.second->Show();
|
||||
m_blend_mode.first ->Hide();
|
||||
m_blend_mode.second->Hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_blend_mode_d3d11.first ->Hide();
|
||||
m_blend_mode_d3d11.second->Hide();
|
||||
m_blend_mode.first ->Show();
|
||||
m_blend_mode.second->Show();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
HacksTab::HacksTab(wxWindow* parent)
|
||||
: wxPanel(parent, wxID_ANY)
|
||||
, m_ui(this)
|
||||
{
|
||||
const int space = wxSizerFlags().Border().GetBorderInPixels();
|
||||
PaddedBoxSizer<wxBoxSizer> tab_box(wxVERTICAL);
|
||||
|
||||
auto* hacks_check_box = m_ui.addCheckBox(tab_box.inner, "Enable User Hacks", "UserHacks");
|
||||
CheckboxPrereq hacks_check(hacks_check_box);
|
||||
auto upscale_hacks_prereq = [this, hacks_check_box]{ return !m_is_native_res && hacks_check_box->GetValue(); };
|
||||
|
||||
PaddedBoxSizer<wxStaticBoxSizer> rend_hacks_box (wxVERTICAL, this, "Renderer Hacks");
|
||||
PaddedBoxSizer<wxStaticBoxSizer> upscale_hacks_box(wxVERTICAL, this, "Upscale Hacks");
|
||||
|
||||
auto* rend_hacks_grid = new wxFlexGridSizer(2, space, space);
|
||||
auto* upscale_hacks_grid = new wxFlexGridSizer(3, space, space);
|
||||
|
||||
// Renderer Hacks
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Auto Flush", "UserHacks_AutoFlush", IDC_AUTO_FLUSH_HW, hacks_check);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Fast Texture Invalidation", "UserHacks_DisablePartialInvalidation", IDC_FAST_TC_INV, hacks_check);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Disable Depth Emulation", "UserHacks_DisableDepthSupport", IDC_TC_DEPTH, hacks_check);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Frame Buffer Conversion", "UserHacks_CPU_FB_Conversion", IDC_CPU_FB_CONVERSION, hacks_check);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Disable Safe Features", "UserHacks_Disable_Safe_Features", IDC_SAFE_FEATURES, hacks_check);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Memory Wrapping", "wrap_gs_mem", IDC_MEMORY_WRAPPING, hacks_check);
|
||||
m_ui.addCheckBox(rend_hacks_grid, "Preload Frame Data", "preload_frame_with_gs_data", IDC_PRELOAD_GS, hacks_check);
|
||||
|
||||
// Upscale
|
||||
m_ui.addCheckBox(upscale_hacks_grid, "Align Sprite", "UserHacks_align_sprite_X", IDC_ALIGN_SPRITE, upscale_hacks_prereq);
|
||||
m_ui.addCheckBox(upscale_hacks_grid, "Merge Sprite", "UserHacks_merge_pp_sprite", IDC_MERGE_PP_SPRITE, upscale_hacks_prereq);
|
||||
m_ui.addCheckBox(upscale_hacks_grid, "Wild Arms Hack", "UserHacks_WildHack", IDC_WILDHACK, upscale_hacks_prereq);
|
||||
|
||||
auto* rend_hack_choice_grid = new wxFlexGridSizer(2, space, space);
|
||||
auto* upscale_hack_choice_grid = new wxFlexGridSizer(2, space, space);
|
||||
rend_hack_choice_grid ->AddGrowableCol(1);
|
||||
upscale_hack_choice_grid->AddGrowableCol(1);
|
||||
|
||||
// Renderer Hacks:
|
||||
m_ui.addComboBoxAndLabel(rend_hack_choice_grid, "Half Screen Fix:", "UserHacks_HalfPixelOffset", &theApp.m_gs_generic_list, IDC_HALF_SCREEN_TS, hacks_check);
|
||||
m_ui.addComboBoxAndLabel(rend_hack_choice_grid, "Trilinear Filtering:", "UserHacks_TriFilter", &theApp.m_gs_trifilter, IDC_TRI_FILTER, hacks_check);
|
||||
|
||||
// Skipdraw Range
|
||||
add_label(this, rend_hack_choice_grid, "Skipdraw Range:", IDC_SKIPDRAWHACK);
|
||||
auto* skip_box = new wxBoxSizer(wxHORIZONTAL);
|
||||
skip_x_spin = m_ui.addSpin(skip_box, "UserHacks_SkipDraw_Offset", 0, 10000, 0, IDC_SKIPDRAWOFFSET, hacks_check);
|
||||
skip_y_spin = m_ui.addSpin(skip_box, "UserHacks_SkipDraw", 0, 10000, 0, IDC_SKIPDRAWHACK, hacks_check);
|
||||
|
||||
rend_hack_choice_grid->Add(skip_box, wxSizerFlags().Expand());
|
||||
|
||||
// Upscale Hacks:
|
||||
m_ui.addComboBoxAndLabel(upscale_hack_choice_grid, "Half-Pixel Offset:", "UserHacks_Half_Bottom_Override", &theApp.m_gs_offset_hack, IDC_OFFSETHACK, upscale_hacks_prereq);
|
||||
m_ui.addComboBoxAndLabel(upscale_hack_choice_grid, "Round Sprite:", "UserHacks_round_sprite_offset", &theApp.m_gs_hack, IDC_ROUND_SPRITE, upscale_hacks_prereq);
|
||||
|
||||
// Texture Offsets
|
||||
add_label(this, upscale_hack_choice_grid, "Texture Offsets:", IDC_TCOFFSETX);
|
||||
auto* tex_off_box = new wxBoxSizer(wxHORIZONTAL);
|
||||
add_label(this, tex_off_box, "X:", IDC_TCOFFSETX, wxSizerFlags().Centre());
|
||||
tex_off_box->AddSpacer(space);
|
||||
m_ui.addSpin(tex_off_box, "UserHacks_TCOffsetX", 0, 10000, 0, IDC_TCOFFSETX, hacks_check);
|
||||
tex_off_box->AddSpacer(space);
|
||||
add_label(this, tex_off_box, "Y:", IDC_TCOFFSETY, wxSizerFlags().Centre());
|
||||
tex_off_box->AddSpacer(space);
|
||||
m_ui.addSpin(tex_off_box, "UserHacks_TCOffsetY", 0, 10000, 0, IDC_TCOFFSETY, hacks_check);
|
||||
|
||||
upscale_hack_choice_grid->Add(tex_off_box, wxSizerFlags().Expand());
|
||||
|
||||
rend_hacks_box->Add(rend_hacks_grid, wxSizerFlags().Centre());
|
||||
rend_hacks_box->AddSpacer(space);
|
||||
rend_hacks_box->Add(rend_hack_choice_grid, wxSizerFlags().Expand());
|
||||
|
||||
upscale_hacks_box->Add(upscale_hacks_grid, wxSizerFlags().Centre());
|
||||
upscale_hacks_box->AddSpacer(space);
|
||||
upscale_hacks_box->Add(upscale_hack_choice_grid, wxSizerFlags().Expand());
|
||||
|
||||
tab_box->Add(rend_hacks_box.outer, wxSizerFlags().Expand());
|
||||
tab_box->Add(upscale_hacks_box.outer, wxSizerFlags().Expand());
|
||||
|
||||
SetSizerAndFit(tab_box.outer);
|
||||
}
|
||||
|
||||
void HacksTab::DoUpdate()
|
||||
{
|
||||
m_ui.Update();
|
||||
|
||||
if (skip_x_spin->GetValue() == 0)
|
||||
skip_y_spin->SetValue(0);
|
||||
if (skip_y_spin->GetValue() < skip_x_spin->GetValue())
|
||||
skip_y_spin->SetValue(skip_x_spin->GetValue());
|
||||
}
|
||||
|
||||
RecTab::RecTab(wxWindow* parent)
|
||||
: wxPanel(parent, wxID_ANY)
|
||||
, m_ui(this)
|
||||
{
|
||||
const int space = wxSizerFlags().Border().GetBorderInPixels();
|
||||
PaddedBoxSizer<wxBoxSizer> tab_box(wxVERTICAL);
|
||||
|
||||
auto* record_check = m_ui.addCheckBox(tab_box.inner, "Enable Recording (F12)", "capture_enabled");
|
||||
CheckboxPrereq record_prereq(record_check);
|
||||
PaddedBoxSizer<wxStaticBoxSizer> record_box(wxVERTICAL, this, "Recording");
|
||||
auto* record_grid_box = new wxFlexGridSizer(2, space, space);
|
||||
record_grid_box->AddGrowableCol(1);
|
||||
|
||||
// Resolution
|
||||
add_label(this, record_grid_box, "Resolution:");
|
||||
auto* res_box = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_ui.addSpin(res_box, "CaptureWidth", 256, 8192, 640, -1, record_prereq);
|
||||
m_ui.addSpin(res_box, "CaptureHeight", 256, 8192, 480, -1, record_prereq);
|
||||
|
||||
record_grid_box->Add(res_box, wxSizerFlags().Expand());
|
||||
|
||||
m_ui.addSpinAndLabel(record_grid_box, "Saving Threads:", "capture_threads", 1, 32, 4, -1, record_prereq);
|
||||
m_ui.addSpinAndLabel(record_grid_box, "PNG Compression Level:", "png_compression_level", 1, 9, 1, -1, record_prereq);
|
||||
|
||||
m_ui.addDirPickerAndLabel(record_grid_box, "Output Directory:", "capture_out_dir", -1, record_prereq);
|
||||
|
||||
record_box->Add(record_grid_box, wxSizerFlags().Expand());
|
||||
|
||||
tab_box->Add(record_box.outer, wxSizerFlags().Expand());
|
||||
SetSizerAndFit(tab_box.outer);
|
||||
}
|
||||
|
||||
PostTab::PostTab(wxWindow* parent)
|
||||
: wxPanel(parent, wxID_ANY)
|
||||
, m_ui(this)
|
||||
{
|
||||
const int space = wxSizerFlags().Border().GetBorderInPixels();
|
||||
PaddedBoxSizer<wxBoxSizer> tab_box(wxVERTICAL);
|
||||
PaddedBoxSizer<wxStaticBoxSizer> shader_box(wxVERTICAL, this, "Custom Shader");
|
||||
|
||||
m_ui.addCheckBox(shader_box.inner, "Texture Filtering of Display", "linear_present", IDC_LINEAR_PRESENT);
|
||||
m_ui.addCheckBox(shader_box.inner, "FXAA Shader (PgUp)", "fxaa", IDC_FXAA);
|
||||
|
||||
CheckboxPrereq shade_boost_check(m_ui.addCheckBox(shader_box.inner, "Enable Shade Boost", "ShadeBoost", IDC_SHADEBOOST));
|
||||
|
||||
PaddedBoxSizer<wxStaticBoxSizer> shade_boost_box(wxVERTICAL, this, "Shade Boost");
|
||||
auto* shader_boost_grid = new wxFlexGridSizer(2, space, space);
|
||||
shader_boost_grid->AddGrowableCol(1);
|
||||
|
||||
m_ui.addSliderAndLabel(shader_boost_grid, "Brightness:", "ShadeBoost_Brightness", 0, 100, 50, -1, shade_boost_check);
|
||||
m_ui.addSliderAndLabel(shader_boost_grid, "Contrast:", "ShadeBoost_Contrast", 0, 100, 50, -1, shade_boost_check);
|
||||
m_ui.addSliderAndLabel(shader_boost_grid, "Saturation:", "ShadeBoost_Saturation", 0, 100, 50, -1, shade_boost_check);
|
||||
|
||||
shade_boost_box->Add(shader_boost_grid, wxSizerFlags().Expand());
|
||||
shader_box->Add(shade_boost_box.outer, wxSizerFlags().Expand());
|
||||
|
||||
CheckboxPrereq ext_shader_check(m_ui.addCheckBox(shader_box.inner, "Enable External Shader", "shaderfx", IDC_SHADER_FX));
|
||||
|
||||
PaddedBoxSizer<wxStaticBoxSizer> ext_shader_box(wxVERTICAL, this, "External Shader (Home)");
|
||||
auto* ext_shader_grid = new wxFlexGridSizer(2, space, space);
|
||||
ext_shader_grid->AddGrowableCol(1);
|
||||
|
||||
m_ui.addFilePickerAndLabel(ext_shader_grid, "GLSL fx File:", "shaderfx_glsl", -1, ext_shader_check);
|
||||
m_ui.addFilePickerAndLabel(ext_shader_grid, "Config File:", "shaderfx_conf", -1, ext_shader_check);
|
||||
|
||||
ext_shader_box->Add(ext_shader_grid, wxSizerFlags().Expand());
|
||||
shader_box->Add(ext_shader_box.outer, wxSizerFlags().Expand());
|
||||
|
||||
// TV Shader
|
||||
auto* tv_box = new wxFlexGridSizer(2, space, space);
|
||||
tv_box->AddGrowableCol(1);
|
||||
m_ui.addComboBoxAndLabel(tv_box, "TV Shader:", "TVShader", &theApp.m_gs_tv_shaders);
|
||||
shader_box->Add(tv_box, wxSizerFlags().Expand());
|
||||
|
||||
tab_box->Add(shader_box.outer, wxSizerFlags().Expand());
|
||||
SetSizerAndFit(tab_box.outer);
|
||||
}
|
||||
|
||||
OSDTab::OSDTab(wxWindow* parent)
|
||||
: wxPanel(parent, wxID_ANY)
|
||||
, m_ui(this)
|
||||
{
|
||||
const int space = wxSizerFlags().Border().GetBorderInPixels();
|
||||
PaddedBoxSizer<wxBoxSizer> tab_box(wxVERTICAL);
|
||||
|
||||
CheckboxPrereq monitor_check(m_ui.addCheckBox(tab_box.inner, "Enable Monitor", "osd_monitor_enabled", IDC_OSD_MONITOR));
|
||||
|
||||
PaddedBoxSizer<wxStaticBoxSizer> font_box(wxVERTICAL, this, "Font");
|
||||
auto* font_grid = new wxFlexGridSizer(2, space, space);
|
||||
font_grid->AddGrowableCol(1);
|
||||
|
||||
m_ui.addSpinAndLabel(font_grid, "Size:", "osd_fontsize", 1, 100, 25, -1, monitor_check);
|
||||
|
||||
m_ui.addSliderAndLabel(font_grid, "Red:", "osd_color_r", 0, 255, 0, -1, monitor_check);
|
||||
m_ui.addSliderAndLabel(font_grid, "Green:", "osd_color_g", 0, 255, 0, -1, monitor_check);
|
||||
m_ui.addSliderAndLabel(font_grid, "Blue:", "osd_color_b", 0, 255, 0, -1, monitor_check);
|
||||
m_ui.addSliderAndLabel(font_grid, "Opacity:", "osd_color_opacity", 0, 100, 100, -1, monitor_check);
|
||||
|
||||
font_box->Add(font_grid, wxSizerFlags().Expand());
|
||||
tab_box->Add(font_box.outer, wxSizerFlags().Expand());
|
||||
|
||||
CheckboxPrereq log_check(m_ui.addCheckBox(tab_box.inner, "Enable Log", "osd_log_enabled", IDC_OSD_LOG));
|
||||
|
||||
PaddedBoxSizer<wxStaticBoxSizer> log_box(wxVERTICAL, this, "Log Messages");
|
||||
auto* log_grid = new wxFlexGridSizer(2, space, space);
|
||||
log_grid->AddGrowableCol(1);
|
||||
|
||||
m_ui.addSpinAndLabel(log_grid, "Timeout (seconds):", "osd_log_timeout", 2, 10, 4, -1, log_check);
|
||||
m_ui.addSpinAndLabel(log_grid, "Max On-Screen Messages:", "osd_max_log_messages", 1, 10, 2, IDC_OSD_MAX_LOG, log_check);
|
||||
|
||||
log_box->Add(log_grid, wxSizerFlags().Expand());
|
||||
tab_box->Add(log_box.outer, wxSizerFlags().Expand());
|
||||
|
||||
SetSizerAndFit(tab_box.outer);
|
||||
}
|
||||
|
||||
DebugTab::DebugTab(wxWindow* parent)
|
||||
: wxPanel(parent, wxID_ANY)
|
||||
, m_ui(this)
|
||||
{
|
||||
const int space = wxSizerFlags().Border().GetBorderInPixels();
|
||||
PaddedBoxSizer<wxBoxSizer> tab_box(wxVERTICAL);
|
||||
|
||||
auto ogl_hw_prereq = [this]{ return m_is_ogl_hw; };
|
||||
|
||||
if (g_Conf->DevMode || IsDevBuild)
|
||||
{
|
||||
PaddedBoxSizer<wxStaticBoxSizer> debug_box(wxVERTICAL, this, "Debug");
|
||||
auto* debug_check_box = new wxWrapSizer(wxHORIZONTAL);
|
||||
m_ui.addCheckBox(debug_check_box, "GLSL compilation", "debug_glsl_shader");
|
||||
m_ui.addCheckBox(debug_check_box, "Print GL error", "debug_opengl");
|
||||
#ifdef _WIN32
|
||||
m_ui.addCheckBox(debug_check_box, "D3D Debug Layer", "debug_d3d");
|
||||
#endif
|
||||
m_ui.addCheckBox(debug_check_box, "Dump GS data", "dump");
|
||||
|
||||
auto* debug_save_check_box = new wxWrapSizer(wxHORIZONTAL);
|
||||
m_ui.addCheckBox(debug_save_check_box, "Save RT", "save");
|
||||
m_ui.addCheckBox(debug_save_check_box, "Save Frame", "savef");
|
||||
m_ui.addCheckBox(debug_save_check_box, "Save Texture", "savet");
|
||||
m_ui.addCheckBox(debug_save_check_box, "Save Depth", "savez");
|
||||
|
||||
debug_box->Add(debug_check_box);
|
||||
debug_box->Add(debug_save_check_box);
|
||||
|
||||
auto* dump_grid = new wxFlexGridSizer(2, space, space);
|
||||
|
||||
start_dump_spin = m_ui.addSpinAndLabel(dump_grid, "Start of Dump:", "saven", 0, pow(10, 9), 0).first;
|
||||
end_dump_spin = m_ui.addSpinAndLabel(dump_grid, "End of Dump:", "savel", 0, pow(10, 5), 5000).first;
|
||||
|
||||
debug_box->AddSpacer(space);
|
||||
debug_box->Add(dump_grid);
|
||||
|
||||
tab_box->Add(debug_box.outer, wxSizerFlags().Expand());
|
||||
}
|
||||
|
||||
PaddedBoxSizer<wxStaticBoxSizer> ogl_box(wxVERTICAL, this, "OpenGL");
|
||||
auto* ogl_grid = new wxFlexGridSizer(2, space, space);
|
||||
m_ui.addComboBoxAndLabel(ogl_grid, "Geometry Shader:", "override_geometry_shader", &theApp.m_gs_generic_list, IDC_GEOMETRY_SHADER_OVERRIDE, ogl_hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(ogl_grid, "Image Load Store:", "override_GL_ARB_shader_image_load_store", &theApp.m_gs_generic_list, IDC_IMAGE_LOAD_STORE, ogl_hw_prereq);
|
||||
m_ui.addComboBoxAndLabel(ogl_grid, "Sparse Texture:", "override_GL_ARB_sparse_texture", &theApp.m_gs_generic_list, IDC_SPARSE_TEXTURE, ogl_hw_prereq);
|
||||
ogl_box->Add(ogl_grid);
|
||||
|
||||
tab_box->Add(ogl_box.outer, wxSizerFlags().Expand());
|
||||
|
||||
SetSizerAndFit(tab_box.outer);
|
||||
}
|
||||
|
||||
void DebugTab::DoUpdate()
|
||||
{
|
||||
m_ui.Update();
|
||||
if (!end_dump_spin || !start_dump_spin)
|
||||
return;
|
||||
if (end_dump_spin->GetValue() < start_dump_spin->GetValue())
|
||||
end_dump_spin->SetValue(start_dump_spin->GetValue());
|
||||
}
|
||||
|
||||
Dialog::Dialog()
|
||||
: wxDialog(nullptr, wxID_ANY, "Graphics Settings", wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX | wxRESIZE_BORDER)
|
||||
, m_ui(this)
|
||||
{
|
||||
const int space = wxSizerFlags().Border().GetBorderInPixels();
|
||||
auto* padding = new wxBoxSizer(wxVERTICAL);
|
||||
m_top_box = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
auto* top_grid = new wxFlexGridSizer(2, space, space);
|
||||
top_grid->SetFlexibleDirection(wxHORIZONTAL);
|
||||
|
||||
m_renderer_select = m_ui.addComboBoxAndLabel(top_grid, "Renderer:", "Renderer", &theApp.m_gs_renderers).first;
|
||||
m_renderer_select->Bind(wxEVT_CHOICE, &Dialog::OnRendererChange, this);
|
||||
|
||||
#ifdef _WIN32
|
||||
add_label(this, top_grid, "Adapter:");
|
||||
m_adapter_select = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, {});
|
||||
top_grid->Add(m_adapter_select, wxSizerFlags().Expand());
|
||||
#endif
|
||||
|
||||
m_ui.addComboBoxAndLabel(top_grid, "Interlacing (F5):", "interlace", &theApp.m_gs_interlace);
|
||||
m_ui.addComboBoxAndLabel(top_grid, "Texture Filtering:", "filter", &theApp.m_gs_bifilter, IDC_FILTER);
|
||||
|
||||
auto* book = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
||||
|
||||
m_renderer_panel = new RendererTab(book);
|
||||
m_hacks_panel = new HacksTab(book);
|
||||
m_rec_panel = new RecTab(book);
|
||||
m_post_panel = new PostTab(book);
|
||||
m_osd_panel = new OSDTab(book);
|
||||
m_debug_panel = new DebugTab(book);
|
||||
|
||||
book->AddPage(m_renderer_panel, "Renderer", true);
|
||||
book->AddPage(m_hacks_panel, "Hacks");
|
||||
book->AddPage(m_post_panel, "Shader");
|
||||
book->AddPage(m_osd_panel, "OSD");
|
||||
book->AddPage(m_rec_panel, "Recording");
|
||||
book->AddPage(m_debug_panel, "Advanced");
|
||||
|
||||
m_top_box->Add(top_grid, wxSizerFlags().Centre());
|
||||
m_top_box->Add(book, wxSizerFlags().Expand());
|
||||
|
||||
padding->Add(m_top_box, wxSizerFlags().Expand().Border());
|
||||
|
||||
m_top_box->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), wxSizerFlags().Right());
|
||||
|
||||
SetSizerAndFit(padding);
|
||||
Bind(wxEVT_CHECKBOX, &Dialog::CallUpdate, this);
|
||||
Bind(wxEVT_SPINCTRL, &Dialog::CallUpdate, this);
|
||||
Bind(wxEVT_CHOICE, &Dialog::CallUpdate, this);
|
||||
}
|
||||
|
||||
Dialog::~Dialog()
|
||||
{
|
||||
}
|
||||
|
||||
void Dialog::CallUpdate(wxCommandEvent&)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
void Dialog::OnRendererChange(wxCommandEvent&)
|
||||
{
|
||||
RendererChange();
|
||||
Update();
|
||||
}
|
||||
|
||||
GSRendererType Dialog::GetSelectedRendererType()
|
||||
{
|
||||
int index = m_renderer_select->GetSelection();
|
||||
|
||||
// there is no currently selected renderer or the combo box has more entries than the renderer list or the current selection is negative
|
||||
// make sure you haven't made a mistake initializing everything
|
||||
ASSERT(index < static_cast<int>(theApp.m_gs_renderers.size()) || index >= 0);
|
||||
|
||||
const GSRendererType type = static_cast<GSRendererType>(
|
||||
theApp.m_gs_renderers[index].value
|
||||
);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
void Dialog::RendererChange()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
GSRendererType renderer = GetSelectedRendererType();
|
||||
m_adapter_select->Clear();
|
||||
|
||||
if (renderer == GSRendererType::DX1011_HW)
|
||||
{
|
||||
auto factory = D3D::CreateFactory(false);
|
||||
auto adapter_list = D3D::GetAdapterList(factory.get());
|
||||
|
||||
wxArrayString adapter_arr_string;
|
||||
for (const auto name : adapter_list)
|
||||
{
|
||||
adapter_arr_string.push_back(
|
||||
convert_utf8_to_utf16(name)
|
||||
);
|
||||
}
|
||||
|
||||
m_adapter_select->Insert(adapter_arr_string, 0);
|
||||
m_adapter_select->Enable();
|
||||
m_adapter_select->SetSelection(
|
||||
theApp.GetConfigI("adapter_index")
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_adapter_select->Disable();
|
||||
}
|
||||
m_renderer_panel->UpdateBlendMode(renderer);
|
||||
|
||||
m_renderer_panel->Layout(); // The version of wx we use on Windows is dumb and something prevents relayout from happening to notebook pages
|
||||
#endif
|
||||
}
|
||||
|
||||
void Dialog::Load()
|
||||
{
|
||||
m_ui.Load();
|
||||
#ifdef _WIN32
|
||||
GSRendererType renderer = GSRendererType(theApp.GetConfigI("Renderer"));
|
||||
if (renderer == GSRendererType::Undefined)
|
||||
renderer = D3D::ShouldPreferD3D() ? GSRendererType::DX1011_HW : GSRendererType::OGL_HW;
|
||||
m_renderer_select->SetSelection(get_config_index(theApp.m_gs_renderers, static_cast<int>(renderer)));
|
||||
#endif
|
||||
|
||||
RendererChange();
|
||||
|
||||
m_hacks_panel->Load();
|
||||
m_renderer_panel->Load();
|
||||
m_rec_panel->Load();
|
||||
m_post_panel->Load();
|
||||
m_osd_panel->Load();
|
||||
m_debug_panel->Load();
|
||||
}
|
||||
|
||||
void Dialog::Save()
|
||||
{
|
||||
m_ui.Save();
|
||||
#ifdef _WIN32
|
||||
// only save the adapter when it makes sense to
|
||||
// prevents changing the adapter, switching to another renderer and saving
|
||||
if (GetSelectedRendererType() == GSRendererType::DX1011_HW)
|
||||
{
|
||||
const int current_adapter =
|
||||
m_adapter_select->GetSelection();
|
||||
|
||||
theApp.SetConfig("adapter_index", current_adapter);
|
||||
}
|
||||
#endif
|
||||
|
||||
m_hacks_panel->Save();
|
||||
m_renderer_panel->Save();
|
||||
m_rec_panel->Save();
|
||||
m_post_panel->Save();
|
||||
m_osd_panel->Save();
|
||||
m_debug_panel->Save();
|
||||
}
|
||||
|
||||
void Dialog::Update()
|
||||
{
|
||||
GSRendererType renderer = GetSelectedRendererType();
|
||||
if (renderer == GSRendererType::Null)
|
||||
{
|
||||
m_ui.DisableAll();
|
||||
m_renderer_select->Enable();
|
||||
m_hacks_panel->m_ui.DisableAll();
|
||||
m_renderer_panel->m_ui.DisableAll();
|
||||
m_rec_panel->m_ui.DisableAll();
|
||||
m_post_panel->m_ui.DisableAll();
|
||||
m_osd_panel->m_ui.DisableAll();
|
||||
m_debug_panel->m_ui.DisableAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
// cross-tab dependencies yay
|
||||
bool is_hw = renderer == GSRendererType::OGL_HW || renderer == GSRendererType::DX1011_HW;
|
||||
bool is_upscale = m_renderer_panel->m_internal_resolution->GetSelection() != 0;
|
||||
m_hacks_panel->m_is_native_res = !is_hw || !is_upscale;
|
||||
m_renderer_panel->m_is_hardware = is_hw;
|
||||
m_debug_panel->m_is_ogl_hw = renderer == GSRendererType::OGL_HW;
|
||||
|
||||
m_ui.Update();
|
||||
m_hacks_panel->DoUpdate();
|
||||
m_renderer_panel->DoUpdate();
|
||||
m_rec_panel->DoUpdate();
|
||||
m_post_panel->DoUpdate();
|
||||
m_osd_panel->DoUpdate();
|
||||
m_debug_panel->DoUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
bool RunwxDialog()
|
||||
{
|
||||
Dialog GSSettingsDialog;
|
||||
|
||||
GSSettingsDialog.Load();
|
||||
GSSettingsDialog.Update();
|
||||
if (GSSettingsDialog.ShowModal() == wxID_OK)
|
||||
GSSettingsDialog.Save();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GS.h"
|
||||
#include "GSSetting.h"
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/wrapsizer.h>
|
||||
#include <wx/statline.h>
|
||||
#include <wx/filepicker.h>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
class GSUIElementHolder
|
||||
{
|
||||
class GSwxChoice : public wxChoice
|
||||
{
|
||||
public:
|
||||
const std::vector<GSSetting>& settings;
|
||||
|
||||
GSwxChoice(
|
||||
wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
const wxArrayString& choices,
|
||||
const std::vector<GSSetting>* settings,
|
||||
long style = 0,
|
||||
const wxValidator& validator = wxDefaultValidator,
|
||||
const wxString& name = wxChoiceNameStr)
|
||||
: wxChoice(parent, id, pos, size, choices, style, validator, name)
|
||||
, settings(*settings)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct UIElem
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
CheckBox,
|
||||
Choice,
|
||||
Spin,
|
||||
Slider,
|
||||
File,
|
||||
Directory,
|
||||
};
|
||||
|
||||
Type type;
|
||||
wxControl* control;
|
||||
const char* config;
|
||||
std::function<bool()> prereq;
|
||||
|
||||
UIElem(Type type, wxControl* control, const char* config, std::function<bool()> prereq)
|
||||
: type(type), control(control), config(config), prereq(prereq)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static bool noPrereq() { return true; }
|
||||
|
||||
wxWindow* m_window;
|
||||
std::vector<UIElem> m_elems;
|
||||
|
||||
wxStaticText* addWithLabel(wxControl* control, UIElem::Type type, wxSizer* sizer, const char* label, const char* config_name, int tooltip, std::function<bool()> prereq, wxSizerFlags flags = wxSizerFlags().Centre().Expand().Left());
|
||||
|
||||
public:
|
||||
GSUIElementHolder(wxWindow* window);
|
||||
wxCheckBox* addCheckBox(wxSizer* sizer, const char* label, const char* config_name, int tooltip = -1, std::function<bool()> prereq = noPrereq);
|
||||
std::pair<wxChoice*, wxStaticText*> addComboBoxAndLabel(wxSizer* sizer, const char* label, const char* config_name, const std::vector<GSSetting>* settings, int tooltip = -1, std::function<bool()> prereq = noPrereq);
|
||||
wxSpinCtrl* addSpin(wxSizer* sizer, const char* config_name, int min, int max, int initial, int tooltip = -1, std::function<bool()> prereq = noPrereq);
|
||||
std::pair<wxSpinCtrl*, wxStaticText*> addSpinAndLabel(wxSizer* sizer, const char* label, const char* config_name, int min, int max, int initial, int tooltip = -1, std::function<bool()> prereq = noPrereq);
|
||||
std::pair<wxSlider*, wxStaticText*> addSliderAndLabel(wxSizer* sizer, const char* label, const char* config_name, int min, int max, int initial, int tooltip = -1, std::function<bool()> prereq = noPrereq);
|
||||
std::pair<wxFilePickerCtrl*, wxStaticText*> addFilePickerAndLabel(wxSizer* sizer, const char* label, const char* config_name, int tooltip = -1, std::function<bool()> prereq = noPrereq);
|
||||
std::pair<wxDirPickerCtrl*, wxStaticText*> addDirPickerAndLabel(wxSizer* sizer, const char* label, const char* config_name, int tooltip = -1, std::function<bool()> prereq = noPrereq);
|
||||
|
||||
void Load();
|
||||
void Save();
|
||||
void Update();
|
||||
void DisableAll();
|
||||
};
|
||||
|
||||
namespace GSSettingsDialog
|
||||
{
|
||||
|
||||
class RendererTab : public wxPanel
|
||||
{
|
||||
public:
|
||||
GSUIElementHolder m_ui;
|
||||
wxChoice* m_internal_resolution;
|
||||
std::pair<wxChoice*, wxStaticText*> m_blend_mode;
|
||||
#ifdef _WIN32
|
||||
std::pair<wxChoice*, wxStaticText*> m_blend_mode_d3d11;
|
||||
#endif
|
||||
bool m_is_hardware = false;
|
||||
|
||||
RendererTab(wxWindow* parent);
|
||||
void Load() { m_ui.Load(); }
|
||||
void Save() { m_ui.Save(); }
|
||||
void UpdateBlendMode(GSRendererType renderer);
|
||||
void DoUpdate() { m_ui.Update(); }
|
||||
};
|
||||
|
||||
class HacksTab : public wxPanel
|
||||
{
|
||||
public:
|
||||
GSUIElementHolder m_ui;
|
||||
wxSpinCtrl *skip_x_spin, *skip_y_spin;
|
||||
bool m_is_native_res = false;
|
||||
|
||||
HacksTab(wxWindow* parent);
|
||||
void Load() { m_ui.Load(); }
|
||||
void Save() { m_ui.Save(); }
|
||||
void DoUpdate();
|
||||
};
|
||||
|
||||
class DebugTab : public wxPanel
|
||||
{
|
||||
public:
|
||||
GSUIElementHolder m_ui;
|
||||
wxSpinCtrl* start_dump_spin = nullptr;
|
||||
wxSpinCtrl* end_dump_spin = nullptr;
|
||||
bool m_is_ogl_hw = false;
|
||||
|
||||
DebugTab(wxWindow* parent);
|
||||
void Load() { m_ui.Load(); }
|
||||
void Save() { m_ui.Save(); }
|
||||
void DoUpdate();
|
||||
};
|
||||
|
||||
class RecTab : public wxPanel
|
||||
{
|
||||
public:
|
||||
GSUIElementHolder m_ui;
|
||||
|
||||
RecTab(wxWindow* parent);
|
||||
void Load() { m_ui.Load(); }
|
||||
void Save() { m_ui.Save(); }
|
||||
void DoUpdate() { m_ui.Update(); }
|
||||
};
|
||||
|
||||
class PostTab : public wxPanel
|
||||
{
|
||||
public:
|
||||
GSUIElementHolder m_ui;
|
||||
|
||||
PostTab(wxWindow* parent);
|
||||
void Load() { m_ui.Load(); }
|
||||
void Save() { m_ui.Save(); }
|
||||
void DoUpdate() { m_ui.Update(); }
|
||||
};
|
||||
|
||||
class OSDTab : public wxPanel
|
||||
{
|
||||
public:
|
||||
GSUIElementHolder m_ui;
|
||||
|
||||
OSDTab(wxWindow* parent);
|
||||
void Load() { m_ui.Load(); }
|
||||
void Save() { m_ui.Save(); }
|
||||
void DoUpdate() { m_ui.Update(); }
|
||||
};
|
||||
|
||||
class Dialog : public wxDialog
|
||||
{
|
||||
GSUIElementHolder m_ui;
|
||||
|
||||
wxBoxSizer* m_top_box;
|
||||
wxChoice* m_renderer_select;
|
||||
#ifdef _WIN32
|
||||
wxChoice* m_adapter_select;
|
||||
#endif
|
||||
wxArrayString m_adapter_arr_string;
|
||||
RendererTab* m_renderer_panel;
|
||||
HacksTab* m_hacks_panel;
|
||||
DebugTab* m_debug_panel;
|
||||
RecTab* m_rec_panel;
|
||||
PostTab* m_post_panel;
|
||||
OSDTab* m_osd_panel;
|
||||
|
||||
public:
|
||||
Dialog();
|
||||
~Dialog();
|
||||
void Load();
|
||||
void Save();
|
||||
void Update();
|
||||
void CallUpdate(wxCommandEvent& event);
|
||||
void OnRendererChange(wxCommandEvent& event);
|
||||
void RendererChange();
|
||||
GSRendererType GetSelectedRendererType();
|
||||
};
|
||||
|
||||
} // namespace GSSettingsDialog
|
||||
|
||||
extern bool RunwxDialog();
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
//#define DISABLE_DATE
|
||||
|
||||
// Not yet used/experimental OpenGL extensions
|
||||
//#define GL_EXT_TEX_SUB_IMAGE
|
||||
|
||||
#if !defined(NDEBUG) || defined(_DEBUG) || defined(_DEVEL)
|
||||
#define ENABLE_OGL_DEBUG // Create a debug context and check opengl command status. Allow also to dump various textures/states.
|
||||
|
||||
+2
-127
@@ -4,49 +4,6 @@
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by GS.rc
|
||||
//
|
||||
// General Dialog:
|
||||
#define IDD_CONFIG 2001
|
||||
#define IDB_NULL 2002
|
||||
#define IDB_LOGO11 2003
|
||||
#define IDB_LOGOGL 2004
|
||||
#define IDC_NULL 2005
|
||||
#define IDC_LOGO11 2006
|
||||
#define IDC_LOGOGL 2007
|
||||
#define IDC_ADAPTER_TEXT 2008
|
||||
#define IDC_ADAPTER 2009
|
||||
#define IDC_RENDERER 2010
|
||||
#define IDC_FILTER_TEXT 2011
|
||||
#define IDC_FILTER 2012
|
||||
#define IDC_INTERLACE_TEXT 2013
|
||||
#define IDC_INTERLACE 2014
|
||||
#define IDC_HACKSBUTTON 2015
|
||||
#define IDC_OSDBUTTON 2016
|
||||
#define IDC_SHADEBUTTON 2017
|
||||
// Hardware Renderer Settings:
|
||||
#define IDC_PALTEX 2030
|
||||
#define IDC_CONSERVATIVE_FB 2031
|
||||
#define IDC_UPSCALE_MULTIPLIER 2032
|
||||
#define IDC_UPSCALE_MULTIPLIER_TEXT 2033
|
||||
#define IDC_AFCOMBO_TEXT 2034
|
||||
#define IDC_AFCOMBO 2035
|
||||
#define IDC_MIPMAP_HW 2036
|
||||
#define IDC_MIPMAP_HW_TEXT 2037
|
||||
#define IDC_CRC_LEVEL 2038
|
||||
#define IDC_CRC_LEVEL_TEXT 2039
|
||||
#define IDC_HACKS_ENABLED 2040
|
||||
#define IDC_ACCURATE_DATE 2041
|
||||
#define IDC_ACCURATE_BLEND_UNIT 2042
|
||||
#define IDC_ACCURATE_BLEND_UNIT_D3D11 2043
|
||||
#define IDC_ACCURATE_BLEND_UNIT_TEXT 2044
|
||||
#define IDC_DITHERING 2045
|
||||
#define IDC_DITHERING_TEXT 2046
|
||||
// Software Renderer Settings:
|
||||
#define IDC_MIPMAP_SW 2060
|
||||
#define IDC_AA1 2061
|
||||
#define IDC_SWTHREADS_TEXT 2062
|
||||
#define IDC_SWTHREADS 2063
|
||||
#define IDC_SWTHREADS_EDIT 2064
|
||||
#define IDC_AUTO_FLUSH_SW 2065
|
||||
// Capture:
|
||||
#define IDD_CAPTURE 2090
|
||||
#define IDC_FILENAME 2091
|
||||
@@ -56,89 +13,7 @@
|
||||
#define IDC_HEIGHT 2095
|
||||
#define IDC_CONFIGURE 2096
|
||||
#define IDC_COLORSPACE 2097
|
||||
// Hardware Hacks:
|
||||
#define IDC_WILDHACK 2100
|
||||
#define IDC_OFFSETHACK 2101
|
||||
#define IDC_OFFSETHACK_TEXT 2102
|
||||
#define IDC_TCOFFSETX 2103
|
||||
#define IDC_TCOFFSETX2 2104
|
||||
#define IDC_TCOFFSETX_TEXT 2105
|
||||
#define IDC_TCOFFSETY 2106
|
||||
#define IDC_TCOFFSETY2 2107
|
||||
#define IDC_TCOFFSETY_TEXT 2108
|
||||
#define IDC_TCOFFSET_TEXT 2109
|
||||
#define IDC_ROUND_SPRITE 2110
|
||||
#define IDC_ROUND_SPRITE_TEXT 2111
|
||||
#define IDC_ALIGN_SPRITE 2112
|
||||
#define IDC_TC_DEPTH 2113
|
||||
#define IDC_PRELOAD_GS 2114
|
||||
#define IDC_FAST_TC_INV 2115
|
||||
#define IDC_AUTO_FLUSH_HW 2116
|
||||
#define IDC_MEMORY_WRAPPING 2117
|
||||
#define IDC_TRI_FILTER 2118
|
||||
#define IDC_TRI_FILTER_TEXT 2119
|
||||
#define IDC_SAFE_FEATURES 2120
|
||||
#define IDC_MERGE_PP_SPRITE 2121
|
||||
#define IDC_CPU_FB_CONVERSION 2122
|
||||
#define IDC_SKIPDRAWHACK 2123
|
||||
#define IDC_SKIPDRAWHACK_TEXT 2124
|
||||
#define IDC_SKIPDRAWHACKEDIT 2125
|
||||
#define IDC_SKIPDRAWOFFSET 2126
|
||||
#define IDC_SKIPDRAWOFFSETEDIT 2127
|
||||
#define IDC_HALF_SCREEN_TS 2128
|
||||
#define IDC_HALF_SCREEN_TS_TEXT 2129
|
||||
// Shader:
|
||||
#define IDC_SHADEBOOST 2140
|
||||
#define IDC_FXAA 2141
|
||||
#define IDC_SATURATION_SLIDER 2142
|
||||
#define IDC_BRIGHTNESS_SLIDER 2143
|
||||
#define IDC_CONTRAST_SLIDER 2144
|
||||
#define IDC_SATURATION_TEXT 2145
|
||||
#define IDC_BRIGHTNESS_TEXT 2146
|
||||
#define IDC_CONTRAST_TEXT 2147
|
||||
#define IDC_SATURATION_VALUE 2148
|
||||
#define IDC_CONTRAST_VALUE 2149
|
||||
#define IDC_BRIGHTNESS_VALUE 2150
|
||||
#define IDC_SHADER_FX 2151
|
||||
#define IDC_SHADER_FX_EDIT 2152
|
||||
#define IDC_SHADER_FX_CONF_EDIT 2153
|
||||
#define IDC_SHADER_FX_BUTTON 2154
|
||||
#define IDC_SHADER_FX_CONF_BUTTON 2155
|
||||
#define IDC_SHADER_FX_TEXT 2156
|
||||
#define IDC_SHADER_FX_CONF_TEXT 2157
|
||||
#define IDC_TVSHADER 2158
|
||||
#define IDC_LINEAR_PRESENT 2159
|
||||
// OSD:
|
||||
#define IDC_OSD_LOG 2170
|
||||
#define IDC_OSD_MONITOR 2171
|
||||
#define IDC_OSD_COLOR_RED_SLIDER 2172
|
||||
#define IDC_OSD_COLOR_RED_TEXT 2173
|
||||
#define IDC_OSD_COLOR_RED_AMOUNT 2174
|
||||
#define IDC_OSD_COLOR_BLUE_SLIDER 2175
|
||||
#define IDC_OSD_COLOR_BLUE_TEXT 2176
|
||||
#define IDC_OSD_COLOR_BLUE_AMOUNT 2177
|
||||
#define IDC_OSD_COLOR_GREEN_SLIDER 2178
|
||||
#define IDC_OSD_COLOR_GREEN_TEXT 2179
|
||||
#define IDC_OSD_COLOR_GREEN_AMOUNT 2180
|
||||
#define IDC_OSD_TIMEOUT 2181
|
||||
#define IDC_OSD_TIMEOUT_EDIT 2182
|
||||
#define IDC_OSD_TIMEOUT_TEXT 2183
|
||||
#define IDC_OSD_SIZE 2184
|
||||
#define IDC_OSD_SIZE_EDIT 2185
|
||||
#define IDC_OSD_OPACITY_SLIDER 2186
|
||||
#define IDC_OSD_OPACITY_AMOUNT 2187
|
||||
#define IDC_OSD_MAX_LOG 2188
|
||||
#define IDC_OSD_MAX_LOG_EDIT 2189
|
||||
#define IDC_OSD_MAX_LOG_TEXT 2190
|
||||
#define IDC_OSD_SIZE_TEXT 2191
|
||||
#define IDC_OSD_OPACITY_TEXT 2192
|
||||
// OpenGL Advanced Settings:
|
||||
#define IDC_GEOMETRY_SHADER_OVERRIDE 2200
|
||||
#define IDC_GEOMETRY_SHADER_TEXT 2201
|
||||
#define IDC_IMAGE_LOAD_STORE 2202
|
||||
#define IDC_IMAGE_LOAD_STORE_TEXT 2203
|
||||
#define IDC_SPARSE_TEXTURE 2204
|
||||
#define IDC_SPARSE_TEXTURE_TEXT 2205
|
||||
|
||||
#define IDR_CONVERT_FX 10000
|
||||
#define IDR_TFX_FX 10001
|
||||
#define IDR_MERGE_FX 10002
|
||||
@@ -165,7 +40,7 @@
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 10019
|
||||
#define _APS_NEXT_COMMAND_VALUE 32771
|
||||
#define _APS_NEXT_CONTROL_VALUE 2194
|
||||
#define _APS_NEXT_CONTROL_VALUE 2098
|
||||
#define _APS_NEXT_SYMED_VALUE 5000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# Mac OS, Linux - from # https://github.com/gabomdq/
|
||||
# Game Controller DB for SDL in 2.0.16 format
|
||||
# Source: https://github.com/gabomdq/SDL_GameControllerDB
|
||||
|
||||
# Mac OS X
|
||||
030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
@@ -264,7 +266,7 @@
|
||||
03000000341a000005f7000010010000,HuiJia GameCube Controller Adpater,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000ac0500002d0200001b010000,Gamesir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000bc2000005656000011010000,Gamesir T4w,a:b0,b:b1,y:,x:b3,start:,guide:b12,back:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,leftstick:b10,rightstick:b11,rightx:a2,righty:a3,platform:Linux,
|
||||
03000000bc2000005656000011010000,Gamesir T4w,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,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,
|
||||
030000006f0e00000104000000010000,Gamestop 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,
|
||||
030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
@@ -372,7 +374,7 @@
|
||||
030000005e0400008902000021010000,Microsoft Xbox pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
|
||||
030000005e040000000b000008040000,Microsoft Xbox One Elite 2 pad,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,
|
||||
030000005e040000ea02000008040000,Microsoft Xbox One S pad,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,
|
||||
03000000c62400001a53000000010000,Mini PE,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,
|
||||
03000000c62400001a53000000010000,PowerA Mini Pro Ex,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,
|
||||
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
|
||||
05000000d6200000e589000001000000,Moga 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
|
||||
05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
|
||||
@@ -423,6 +425,7 @@
|
||||
030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,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,
|
||||
030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,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,
|
||||
0500000049190000030400001b010000,Ipega PG9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
@@ -606,3 +609,4 @@
|
||||
xinput,XInput 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,
|
||||
03000000120c0000100e000011010000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000120c0000101e000011010000,Zeroplus P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
|
||||
|
||||
@@ -472,12 +472,12 @@ void PADDialog::InitDialog()
|
||||
|
||||
void PADDialog::OnButtonClicked(wxCommandEvent& event)
|
||||
{
|
||||
// Affichage d'un message à chaque clic sur le bouton
|
||||
// Display a message each time the button is clicked
|
||||
wxButton* bt_tmp = (wxButton*)event.GetEventObject(); // get the button object
|
||||
int bt_id = bt_tmp->GetId() - wxID_HIGHEST - 1; // get the real ID
|
||||
int gamepad_id = m_tab_gamepad->GetSelection(); // get the tab ID (equivalent to the gamepad id)
|
||||
if (bt_id >= 0 && bt_id <= PAD_R_LEFT)
|
||||
{ // if the button ID is a gamepad button
|
||||
{ // if the button ID is a gamepad button
|
||||
bt_tmp->Disable(); // switch the button state to "Disable"
|
||||
config_key(gamepad_id, bt_id);
|
||||
bt_tmp->Enable(); // switch the button state to "Enable"
|
||||
@@ -540,7 +540,7 @@ void PADDialog::OnButtonClicked(wxCommandEvent& event)
|
||||
}
|
||||
m_pan_tabs[gamepad_id]->Refresh();
|
||||
m_pan_tabs[gamepad_id]->Update();
|
||||
config_key(gamepad_id, i);
|
||||
bool key_captured = config_key(gamepad_id, i);
|
||||
switch (i)
|
||||
{
|
||||
case PAD_L_UP: // Left joystick (Up) ↑
|
||||
@@ -573,20 +573,24 @@ void PADDialog::OnButtonClicked(wxCommandEvent& event)
|
||||
}
|
||||
m_pan_tabs[gamepad_id]->Refresh();
|
||||
m_pan_tabs[gamepad_id]->Update();
|
||||
if (!key_captured)
|
||||
{ // if ESC is hit, abort Set_all and return user control
|
||||
break;
|
||||
}
|
||||
usleep(500000); // give enough time to the user to release the button
|
||||
}
|
||||
}
|
||||
else if (bt_id == Ok)
|
||||
{ // If the button ID is equals to the Ok button ID
|
||||
{ // If the button ID is equals to the Ok button ID
|
||||
PADSaveConfig(); // Save the configuration
|
||||
Close(); // Close the window
|
||||
}
|
||||
else if (bt_id == Apply)
|
||||
{ // If the button ID is equals to the Apply button ID
|
||||
{ // If the button ID is equals to the Apply button ID
|
||||
PADSaveConfig(); // Save the configuration
|
||||
}
|
||||
else if (bt_id == Cancel)
|
||||
{ // If the button ID is equals to the cancel button ID
|
||||
{ // If the button ID is equals to the cancel button ID
|
||||
Close(); // Close the window
|
||||
}
|
||||
}
|
||||
@@ -595,7 +599,7 @@ void PADDialog::OnButtonClicked(wxCommandEvent& event)
|
||||
/*********** Methods functions **********/
|
||||
/****************************************/
|
||||
|
||||
void PADDialog::config_key(int pad, int key)
|
||||
bool PADDialog::config_key(int pad, int key)
|
||||
{
|
||||
bool captured = false;
|
||||
u32 key_pressed = 0;
|
||||
@@ -612,11 +616,17 @@ void PADDialog::config_key(int pad, int key)
|
||||
set_keyboard_key(pad, key_pressed, key);
|
||||
m_simulatedKeys[pad][key] = key_pressed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return captured;
|
||||
}
|
||||
captured = true;
|
||||
}
|
||||
}
|
||||
m_bt_gamepad[pad][key]->SetLabel(
|
||||
KeyName(pad, key, m_simulatedKeys[pad][key]).c_str());
|
||||
|
||||
return captured;
|
||||
}
|
||||
|
||||
void PADDialog::clear_key(int pad, int key)
|
||||
@@ -655,7 +665,8 @@ void DisplayDialog()
|
||||
if (g_conf.ftw)
|
||||
{
|
||||
wxString info("The PAD GUI is provided to map the keyboard/mouse to the virtual PS2 pad.\n\n"
|
||||
"Gamepads/Joysticks are plug and play. The active gamepad can be selected in the 'Gamepad Configuration' panel.\n\n");
|
||||
"Gamepads/Joysticks are plug and play. Re-mapping of Gamepads/Joysticks is currently not supported in the PAD GUI.\n\n"
|
||||
"The active gamepad can be selected in the 'Gamepad Configuration' panel.\n\n");
|
||||
|
||||
wxMessageDialog ftw(nullptr, info);
|
||||
ftw.ShowModal();
|
||||
|
||||
@@ -54,7 +54,7 @@ enum gui_buttons
|
||||
#define BUTTONS_LENGHT 32 // numbers of buttons on the gamepad
|
||||
#define UPDATE_TIME 5
|
||||
#define DEFAULT_WIDTH 1000
|
||||
#define DEFAULT_HEIGHT 740
|
||||
#define DEFAULT_HEIGHT 760
|
||||
|
||||
class PADDialog : public wxDialog
|
||||
{
|
||||
@@ -72,7 +72,7 @@ class PADDialog : public wxDialog
|
||||
bool m_pressed[GAMEPAD_NUMBER][NB_IMG];
|
||||
|
||||
// methods
|
||||
void config_key(int, int);
|
||||
bool config_key(int, int);
|
||||
void clear_key(int, int);
|
||||
void repopulate();
|
||||
|
||||
|
||||
+30
-30
@@ -13,7 +13,7 @@
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Anglais (�tats-Unis) resources
|
||||
// English (United States) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
@@ -444,34 +444,35 @@ IDD_GENERAL DIALOGEX 0, 0, 424, 283
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x1
|
||||
BEGIN
|
||||
GROUPBOX "Input APIs",IDC_STATIC,7,6,410,133
|
||||
GROUPBOX "Keyboard API",IDC_STATIC,16,16,192,51
|
||||
GROUPBOX "Input APIs",IDC_STATIC,7,0,410,133
|
||||
GROUPBOX "Keyboard API",IDC_STATIC,16,16,192,39
|
||||
CONTROL "Windows messaging (Recommended)",IDC_KB_WM,"Button",BS_AUTORADIOBUTTON | WS_GROUP,22,28,137,10
|
||||
CONTROL "Raw input",IDC_KB_RAW,"Button",BS_AUTORADIOBUTTON,22,40,112,10
|
||||
GROUPBOX "Game Device APIs",IDC_STATIC,16,70,191,62
|
||||
CONTROL "DirectInput (Legacy)",IDC_G_DI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,82,100,10
|
||||
CONTROL "XInput (Modern)",IDC_G_XI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,94,100,10
|
||||
CONTROL "DualShock 3 native mode (Requires libusb)",IDC_G_DS3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,106,155,10
|
||||
CONTROL "Monitor when in background",IDC_BACKGROUND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,118,107,10
|
||||
GROUPBOX "Mouse API", IDC_STATIC, 216, 16, 192, 58
|
||||
CONTROL "Windows messaging (Recommended)", IDC_M_WM, "Button", BS_AUTORADIOBUTTON | WS_GROUP, 223, 27, 137, 10
|
||||
CONTROL "Raw input", IDC_M_RAW, "Button", BS_AUTORADIOBUTTON, 223, 39, 112, 10
|
||||
CONTROL "Disable", IDC_M_DISABLE, "Button", BS_AUTORADIOBUTTON, 223, 51, 39, 10
|
||||
CONTROL "Start without mouse focus", IDC_MOUSE_UNFOCUS, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 223, 63, 98, 10
|
||||
GROUPBOX "Pads", IDC_STATIC, 7, 142, 410, 62
|
||||
CONTROL "Port 1 Multitap", IDC_MULTITAP1, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 14, 152, 63, 10
|
||||
CONTROL "Port 2 Multitap", IDC_MULTITAP2, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 14, 164, 63, 10
|
||||
CONTROL "Multiple bindings", IDC_MULTIPLE_BINDING, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 14, 176, 66, 10
|
||||
CONTROL "", IDC_PAD_LIST, "SysListView32", LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_TABSTOP, 81, 151, 183, 48, WS_EX_CLIENTEDGE
|
||||
COMBOBOX IDC_PAD_TYPE, 270, 151, 140, 118, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
GROUPBOX "Device Diagnostics", IDC_STATIC, 78, 206, 264, 74
|
||||
CONTROL "", IDC_DIAG_LIST, "SysListView32", LVS_LIST | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_VSCROLL | WS_TABSTOP, 84, 217, 252, 57, WS_EX_CLIENTEDGE
|
||||
GROUPBOX "Hacks and advanced features", IDC_STATIC, 216, 75, 192, 57
|
||||
CONTROL "Enable logging", IDC_DEBUG_FILE, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 223, 88, 79, 10
|
||||
CONTROL "Guitar Hero 2 Hack", IDC_GH2_HACK, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 223, 100, 79, 10
|
||||
PUSHBUTTON "Restore Defaults", ID_RESTORE_DEFAULTS, 306, 168, 62, 15
|
||||
PUSHBUTTON "Load Bindings", ID_LOAD, 271, 186, 62, 15
|
||||
PUSHBUTTON "Save Bindings", ID_SAVE, 345, 186, 62, 15
|
||||
GROUPBOX "Game Device APIs",IDC_STATIC,16,59,191,62
|
||||
CONTROL "DirectInput (Legacy)",IDC_G_DI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,71,100,10
|
||||
CONTROL "XInput (Modern)",IDC_G_XI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,82,100,10
|
||||
CONTROL "DualShock 3 native mode (Requires libusb)",IDC_G_DS3,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,94,155,10
|
||||
CONTROL "Monitor when in background",IDC_BACKGROUND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,22,105,107,10
|
||||
GROUPBOX "Mouse API",IDC_STATIC,216,16,192,61
|
||||
CONTROL "Windows messaging (Recommended)",IDC_M_WM,"Button",BS_AUTORADIOBUTTON | WS_GROUP,223,27,137,10
|
||||
CONTROL "Raw input",IDC_M_RAW,"Button",BS_AUTORADIOBUTTON,223,39,112,10
|
||||
CONTROL "Disable",IDC_M_DISABLE,"Button",BS_AUTORADIOBUTTON,223,51,39,10
|
||||
CONTROL "Start without mouse focus",IDC_MOUSE_UNFOCUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,63,98,10
|
||||
GROUPBOX "Pads",IDC_STATIC,7,142,410,62
|
||||
CONTROL "Port 1 Multitap",IDC_MULTITAP1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,152,63,10
|
||||
CONTROL "Port 2 Multitap",IDC_MULTITAP2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,164,63,10
|
||||
CONTROL "Multiple bindings",IDC_MULTIPLE_BINDING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,176,66,10
|
||||
CONTROL "",IDC_PAD_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_TABSTOP,81,151,183,48,WS_EX_CLIENTEDGE
|
||||
COMBOBOX IDC_PAD_TYPE,270,151,140,118,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
GROUPBOX "Device Diagnostics",IDC_STATIC,78,206,264,74
|
||||
CONTROL "",IDC_DIAG_LIST,"SysListView32",LVS_LIST | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_VSCROLL | WS_TABSTOP,84,217,252,57,WS_EX_CLIENTEDGE
|
||||
GROUPBOX "Hacks and advanced features",IDC_STATIC,216,82,192,39
|
||||
CONTROL "Enable logging",IDC_DEBUG_FILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,94,79,10
|
||||
CONTROL "Guitar Hero 2 Hack",IDC_GH2_HACK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,223,106,79,10
|
||||
PUSHBUTTON "Restore Defaults",ID_RESTORE_DEFAULTS,306,168,62,15
|
||||
PUSHBUTTON "Load Bindings",ID_LOAD,271,186,62,15
|
||||
PUSHBUTTON "Save Bindings",ID_SAVE,345,186,62,15
|
||||
END
|
||||
|
||||
IDD_DIAG DIALOGEX 0, 0, 190, 178
|
||||
@@ -560,7 +561,7 @@ IDR_INI1 RCDATA "Default.ini"
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
|
||||
#endif // Anglais (�tats-Unis) resources
|
||||
#endif // English (United States) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -573,5 +574,4 @@ IDR_INI1 RCDATA "Default.ini"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
@@ -183,7 +183,7 @@ void WriteSettings()
|
||||
}
|
||||
|
||||
CfgWriteInt(L"MIXING", L"Interpolation", Interpolation);
|
||||
CfgWriteInt(L"MIXING", L"FinalVolume", (int)(FinalVolume * 100 + 0.5f));
|
||||
CfgWriteInt(L"MIXING", L"FinalVolume", (int)(FinalVolume * 100));
|
||||
|
||||
CfgWriteBool(L"MIXING", L"AdvancedVolumeControl", AdvancedVolumeControl);
|
||||
CfgWriteFloat(L"MIXING", L"VolumeAdjustC(dB)", VolumeAdjustCdb);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -86,7 +86,7 @@ extern u32 SdlOutputAPI;
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
const int LATENCY_MAX = 3000;
|
||||
#else
|
||||
const int LATENCY_MAX = 750;
|
||||
const int LATENCY_MAX = 200;
|
||||
#endif
|
||||
|
||||
const int LATENCY_MIN = 3;
|
||||
|
||||
@@ -111,11 +111,17 @@ StereoOut32 V_Core::ReadInput()
|
||||
SetIrqCall(i);
|
||||
|
||||
// PlayMode & 2 is Bypass Mode, so it doesn't go through the SPU
|
||||
if ((AutoDMACtrl & (Index + 1)) && !(Index == 0 && (PlayMode & 2) != 0))
|
||||
if ((Index == 1) || !(Index == 0 && (PlayMode & 2) != 0))
|
||||
{
|
||||
retval = StereoOut32(
|
||||
(s32)(*GetMemPtr(0x2000 + (Index << 10) + ReadIndex)),
|
||||
(s32)(*GetMemPtr(0x2200 + (Index << 10) + ReadIndex)));
|
||||
|
||||
// Not accurate behaviour but shouldn't hurt for now, need to run some tests
|
||||
// to see why Prince of Persia Warrior Within buzzes when going in to the map
|
||||
// since it starts an ADMA of music, then kills ADMA, so it loops on a few ms of data.
|
||||
GetMemPtr(0x2000 + (Index << 10) + ReadIndex)[0] = 0;
|
||||
GetMemPtr(0x2200 + (Index << 10) + ReadIndex)[0] = 0;
|
||||
}
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
static const int LATENCY_MAX = 3000;
|
||||
#else
|
||||
static const int LATENCY_MAX = 750;
|
||||
static const int LATENCY_MAX = 200;
|
||||
#endif
|
||||
|
||||
static const int LATENCY_MIN = 3;
|
||||
@@ -151,7 +151,7 @@ void WriteSettings()
|
||||
{
|
||||
CfgWriteInt(L"MIXING", L"Interpolation", Interpolation);
|
||||
|
||||
CfgWriteInt(L"MIXING", L"FinalVolume", (int)(FinalVolume * 100 + 0.5f));
|
||||
CfgWriteInt(L"MIXING", L"FinalVolume", (int)(FinalVolume * 100));
|
||||
|
||||
CfgWriteBool(L"MIXING", L"AdvancedVolumeControl", AdvancedVolumeControl);
|
||||
CfgWriteFloat(L"MIXING", L"VolumeAdjustC(dB)", VolumeAdjustCdb);
|
||||
@@ -236,16 +236,16 @@ BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
}
|
||||
SendDialogMsg(hWnd, IDC_OUTPUT, CB_SETCURSEL, OutputModule, 0);
|
||||
|
||||
double minlat = (SynchMode == 0) ? LATENCY_MIN_TS : LATENCY_MIN;
|
||||
float minlat = (SynchMode == 0) ? LATENCY_MIN_TS : LATENCY_MIN;
|
||||
int minexp = (int)(pow(minlat + 1, 1.0 / 3.0) * 128.0);
|
||||
int maxexp = (int)(pow((double)LATENCY_MAX + 2, 1.0 / 3.0) * 128.0);
|
||||
INIT_SLIDER(IDC_LATENCY_SLIDER, minexp, maxexp, 200, 13, 15);
|
||||
int maxexp = (int)(pow((float)LATENCY_MAX + 1, 1.0 / 3.0) * 128.0);
|
||||
INIT_SLIDER(IDC_LATENCY_SLIDER, minexp, maxexp, 54, 10, 11);
|
||||
|
||||
SendDialogMsg(hWnd, IDC_LATENCY_SLIDER, TBM_SETPOS, TRUE, (int)((pow((double)SndOutLatencyMS, 1.0 / 3.0) * 128.0) + 1));
|
||||
SendDialogMsg(hWnd, IDC_LATENCY_SLIDER, TBM_SETPOS, TRUE, (int)((pow((float)SndOutLatencyMS, 1.0 / 3.0) * 128.0) + 1));
|
||||
swprintf_s(temp, L"%d ms (avg)", SndOutLatencyMS);
|
||||
SetWindowText(GetDlgItem(hWnd, IDC_LATENCY_LABEL), temp);
|
||||
|
||||
int configvol = (int)(FinalVolume * 100 + 0.5f);
|
||||
int configvol = (int)(FinalVolume * 100);
|
||||
INIT_SLIDER(IDC_VOLUME_SLIDER, 0, 100, 10, 5, 1);
|
||||
|
||||
SendDialogMsg(hWnd, IDC_VOLUME_SLIDER, TBM_SETPOS, TRUE, configvol);
|
||||
@@ -270,7 +270,7 @@ BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
case IDOK:
|
||||
{
|
||||
double res = ((int)SendDialogMsg(hWnd, IDC_LATENCY_SLIDER, TBM_GETPOS, 0, 0)) / 128.0;
|
||||
float res = ((int)SendDialogMsg(hWnd, IDC_LATENCY_SLIDER, TBM_GETPOS, 0, 0)) / 128.0;
|
||||
SndOutLatencyMS = (int)pow(res, 3.0);
|
||||
Clampify(SndOutLatencyMS, LATENCY_MIN, LATENCY_MAX);
|
||||
FinalVolume = (float)(SendDialogMsg(hWnd, IDC_VOLUME_SLIDER, TBM_GETPOS, 0, 0)) / 100;
|
||||
@@ -320,13 +320,13 @@ BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
if (wmEvent == CBN_SELCHANGE)
|
||||
{
|
||||
int sMode = (int)SendDialogMsg(hWnd, IDC_SYNCHMODE, CB_GETCURSEL, 0, 0);
|
||||
double minlat = (sMode == 0) ? LATENCY_MIN_TS : LATENCY_MIN;
|
||||
float minlat = (sMode == 0) ? LATENCY_MIN_TS : LATENCY_MIN;
|
||||
int minexp = (int)(pow(minlat + 1, 1.0 / 3.0) * 128.0);
|
||||
int maxexp = (int)(pow((double)LATENCY_MAX + 2, 1.0 / 3.0) * 128.0);
|
||||
INIT_SLIDER(IDC_LATENCY_SLIDER, minexp, maxexp, 200, 42, 1);
|
||||
int maxexp = (int)(pow((float)LATENCY_MAX + 1, 1.0 / 3.0) * 128.0);
|
||||
INIT_SLIDER(IDC_LATENCY_SLIDER, minexp, maxexp, 54, 10, 11);
|
||||
|
||||
int curpos = (int)SendMessage(GetDlgItem(hWnd, IDC_LATENCY_SLIDER), TBM_GETPOS, 0, 0);
|
||||
double res = pow(curpos / 128.0, 3.0);
|
||||
float res = pow(curpos / 128.0, 3.0);
|
||||
curpos = (int)res;
|
||||
swprintf_s(temp, L"%d ms (avg)", curpos);
|
||||
SetDlgItemText(hWnd, IDC_LATENCY_LABEL, temp);
|
||||
@@ -379,7 +379,7 @@ BOOL CALLBACK ConfigProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
if (hwndDlg == GetDlgItem(hWnd, IDC_LATENCY_SLIDER))
|
||||
{
|
||||
double res = pow(curpos / 128.0, 3.0);
|
||||
float res = pow(curpos / 128.0, 3.0);
|
||||
curpos = (int)res;
|
||||
swprintf_s(temp, L"%d ms (avg)", curpos);
|
||||
SetDlgItemText(hWnd, IDC_LATENCY_LABEL, temp);
|
||||
|
||||
+22
-21
@@ -24,36 +24,36 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_CONFIG DIALOGEX 0, 0, 311, 194
|
||||
IDD_CONFIG DIALOGEX 0, 0, 325, 195
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Audio Settings"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x0
|
||||
BEGIN
|
||||
PUSHBUTTON "OK",IDOK,102,174,50,14,NOT WS_TABSTOP
|
||||
PUSHBUTTON "Cancel",IDCANCEL,156,174,50,14,NOT WS_TABSTOP
|
||||
GROUPBOX "Mixing Settings",IDC_STATIC,6,5,151,115
|
||||
PUSHBUTTON "OK",IDOK,113,174,50,14,NOT WS_TABSTOP
|
||||
PUSHBUTTON "Cancel",IDCANCEL,173,174,50,14,NOT WS_TABSTOP
|
||||
GROUPBOX "Mixing Settings",IDC_STATIC,6,5,157,115
|
||||
LTEXT "Interpolation:",IDC_STATIC,12,16,61,10,NOT WS_GROUP
|
||||
COMBOBOX IDC_INTERPOLATE,12,26,142,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
GROUPBOX "",IDC_STATIC,3,124,154,45
|
||||
GROUPBOX "",IDC_STATIC,6,124,157,45
|
||||
CHECKBOX "Enable Debug Options",IDC_DEBUG_ENABLE,11,135,118,10,NOT WS_TABSTOP
|
||||
PUSHBUTTON "Configure...",IDC_OPEN_CONFIG_DEBUG,11,147,52,13
|
||||
GROUPBOX "Output Settings",IDC_STATIC,165,5,141,164
|
||||
LTEXT "Module:",IDC_STATIC,171,16,50,9,NOT WS_GROUP
|
||||
COMBOBOX IDC_OUTPUT,173,26,130,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Configure...",IDC_OUTCONF,173,42,52,13
|
||||
LTEXT "Volume:",IDC_STATIC,200,61,27,8,NOT WS_GROUP
|
||||
CTEXT "100%",IDC_VOLUME_LABEL,234,61,58,9
|
||||
CONTROL "",IDC_VOLUME_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,170,72,129,10
|
||||
LTEXT "Latency:",IDC_STATIC,196,86,29,8,NOT WS_GROUP
|
||||
CTEXT "100 ms (avg)",IDC_LATENCY_LABEL,233,86,58,9
|
||||
CONTROL "Slider2",IDC_LATENCY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,173,96,129,10
|
||||
GROUPBOX "Output Settings",IDC_STATIC,173,5,145,164
|
||||
LTEXT "Module:",IDC_STATIC,179,16,50,9,NOT WS_GROUP
|
||||
COMBOBOX IDC_OUTPUT,179,26,130,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Configure...",IDC_OUTCONF,179,42,52,13
|
||||
LTEXT "Volume:",IDC_STATIC,204,61,27,8,NOT WS_GROUP
|
||||
CTEXT "100%",IDC_VOLUME_LABEL,242,61,58,9
|
||||
CONTROL "",IDC_VOLUME_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,181,72,129,10
|
||||
LTEXT "Latency:",IDC_STATIC,204,86,29,8,NOT WS_GROUP
|
||||
CTEXT "100 ms (avg)",IDC_LATENCY_LABEL,241,86,58,9
|
||||
CONTROL "Slider2",IDC_LATENCY_SLIDER,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,181,96,129,10
|
||||
CONTROL "Synchronizing Mode:",IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,12,42,133,8
|
||||
COMBOBOX IDC_SYNCHMODE,12,54,129,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
COMBOBOX IDC_SYNCHMODE,12,54,142,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Advanced...",IDC_OPEN_CONFIG_SOUNDTOUCH,12,72,52,13
|
||||
LTEXT "Audio Expansion Mode:",IDC_SPEAKERS_TEXT,12,90,137,10,NOT WS_GROUP
|
||||
COMBOBOX IDC_SPEAKERS,12,102,129,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
CONTROL "Use a Winamp DSP plugin",IDC_DSP_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,173,110,129,11
|
||||
LTEXT "(currently requires manual configuration via the ini file)",IDC_STATIC,185,122,100,20
|
||||
COMBOBOX IDC_SPEAKERS,12,102,142,84,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
CONTROL "Use a Winamp DSP plugin",IDC_DSP_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,181,110,129,11
|
||||
LTEXT "(currently requires manual configuration via the ini file)",IDC_STATIC,193,122,100,20
|
||||
END
|
||||
|
||||
IDD_DEBUG DIALOGEX 0, 0, 303, 473
|
||||
@@ -127,9 +127,10 @@ BEGIN
|
||||
IDD_CONFIG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 6
|
||||
RIGHTMARGIN, 310
|
||||
RIGHTMARGIN, 324
|
||||
VERTGUIDE, 218
|
||||
VERTGUIDE, 282
|
||||
BOTTOMMARGIN, 194
|
||||
END
|
||||
|
||||
IDD_DEBUG, DIALOG
|
||||
@@ -139,7 +140,7 @@ BEGIN
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 465
|
||||
END
|
||||
|
||||
|
||||
IDD_CONFIG_SOUNDTOUCH, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 5
|
||||
|
||||
+5
-2
@@ -29,6 +29,7 @@
|
||||
#include "Counters.h"
|
||||
#include "Patch.h"
|
||||
#include "System/SysThreads.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
|
||||
#include "common/pxStreams.h"
|
||||
#include "common/SafeArray.inl"
|
||||
@@ -67,6 +68,8 @@ static void PostLoadPrep()
|
||||
// WriteCP0Status(cpuRegs.CP0.n.Status.val);
|
||||
for(int i=0; i<48; i++) MapTLB(i);
|
||||
if (EmuConfig.Gamefixes.GoemonTlbHack) GoemonPreloadTlb();
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, 0);
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, 0);
|
||||
|
||||
UpdateVSyncRate();
|
||||
}
|
||||
@@ -611,7 +614,7 @@ public:
|
||||
wxString GetFilename() const { return L"USB.bin"; }
|
||||
void FreezeIn(pxInputStream& reader) const { return SysState_ComponentFreezeIn(reader, USB); }
|
||||
void FreezeOut(SaveStateBase& writer) const { return SysState_ComponentFreezeOut(writer, USB); }
|
||||
bool IsRequired() const { return true; }
|
||||
bool IsRequired() const { return false; }
|
||||
};
|
||||
|
||||
class SavestateEntry_PAD : public BaseSavestateEntry
|
||||
@@ -923,4 +926,4 @@ void SaveState_UnzipFromDisk(const wxString& filename)
|
||||
reader->Read(buffer.GetPtr(), foundInternal->GetSize());
|
||||
|
||||
memLoadingState(buffer).FreezeBios().FreezeInternals();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -161,7 +161,7 @@ void SysLogMachineCaps()
|
||||
// tagged commit - more modern implementation of dev build versioning
|
||||
// - there is no need to include the commit - that is associated with the tag,
|
||||
// - git is implied and the tag is timestamped
|
||||
Console.WriteLn(Color_StrongGreen, "\nPCSX2 Nightly - %s", GIT_TAG);
|
||||
Console.WriteLn(Color_StrongGreen, "\nPCSX2 Nightly - %s Compiled on %s", GIT_TAG, __DATE__);
|
||||
} else {
|
||||
Console.WriteLn(Color_StrongGreen, "\nPCSX2 %u.%u.%u-%lld"
|
||||
#ifndef DISABLE_BUILD_DATE
|
||||
|
||||
@@ -508,6 +508,8 @@ AppConfig::AppConfig()
|
||||
EnableGameFixes = false;
|
||||
EnableFastBoot = true;
|
||||
|
||||
DevMode = false;
|
||||
|
||||
EnablePresets = true;
|
||||
PresetIndex = 1;
|
||||
|
||||
@@ -594,6 +596,8 @@ void AppConfig::LoadSaveRootItems(IniInterface& ini)
|
||||
IniEntry(PresetIndex);
|
||||
IniEntry(AskOnBoot);
|
||||
|
||||
IniEntry(DevMode);
|
||||
|
||||
ini.EnumEntry(L"CdvdSource", CdvdSource, CDVD_SourceLabels, CdvdSource);
|
||||
|
||||
#ifdef __WXMSW__
|
||||
|
||||
@@ -270,6 +270,8 @@ public:
|
||||
|
||||
bool AskOnBoot;
|
||||
|
||||
bool DevMode; // Enable extra options in config menus
|
||||
|
||||
|
||||
wxString CurrentIso;
|
||||
wxString CurrentELF;
|
||||
|
||||
@@ -149,12 +149,12 @@ void BreakpointWindow::setDefaultValues()
|
||||
if (address != 0xFFFFFFFF)
|
||||
{
|
||||
swprintf(str,64,L"0x%08X",address);
|
||||
editAddress->SetLabel(str);
|
||||
editAddress->SetValue(str);
|
||||
}
|
||||
|
||||
swprintf(str,64,L"0x%08X",size);
|
||||
editSize->SetLabel(str);
|
||||
editCondition->SetLabel(wxString(condition,wxConvUTF8));
|
||||
editSize->SetValue(str);
|
||||
editCondition->SetValue(wxString(condition,wxConvUTF8));
|
||||
}
|
||||
|
||||
void BreakpointWindow::loadFromMemcheck(MemCheck& memcheck)
|
||||
|
||||
@@ -671,11 +671,11 @@ void CtrlDisassemblyView::assembleOpcode(u32 address, std::string defaultText)
|
||||
{
|
||||
SysClearExecutionCache();
|
||||
|
||||
if((selectRangeEnd - selectRangeStart) > 4)
|
||||
if ((selectRangeEnd - selectRangeStart) > 4)
|
||||
{
|
||||
for(u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 0x4)
|
||||
for (u32 addr = selectRangeStart; addr < selectRangeEnd; addr += 0x4)
|
||||
{
|
||||
cpu->write32(addr,encoded);
|
||||
cpu->write32(addr, encoded);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1152,7 +1152,7 @@ void CtrlDisassemblyView::mouseEvent(wxMouseEvent& evt)
|
||||
toggleBreakpoint(false);
|
||||
}
|
||||
|
||||
if(setNewAddress)
|
||||
if (setNewAddress)
|
||||
setCurAddress(newAddress, wxGetKeyState(WXK_SHIFT));
|
||||
|
||||
SetFocus();
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "CtrlMemSearch.h"
|
||||
#include "DebugTools/Debug.h"
|
||||
#include "gui/AppConfig.h"
|
||||
#include "common/BitCast.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "Patch.h" // Required for SwapEndian :(
|
||||
|
||||
|
||||
#include "BreakpointWindow.h"
|
||||
#include "DebugEvents.h"
|
||||
#include "DisassemblyDialog.h"
|
||||
#include <wchar.h>
|
||||
#include <wx/clipbrd.h>
|
||||
|
||||
wxDEFINE_EVENT(pxEvt_SearchFinished, wxCommandEvent);
|
||||
|
||||
wxBEGIN_EVENT_TABLE(CtrlMemSearch, wxWindow)
|
||||
EVT_SET_FOCUS(CtrlMemSearch::focusEvent)
|
||||
EVT_KILL_FOCUS(CtrlMemSearch::focusEvent)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
enum MemoryViewMenuIdentifiers {
|
||||
ID_MEMVIEW_GOTOINDISASM = 1,
|
||||
ID_MEMVIEW_GOTOADDRESS,
|
||||
ID_MEMVIEW_COPYADDRESS,
|
||||
ID_MEMVIEW_FOLLOWADDRESS,
|
||||
ID_MEMVIEW_DISPLAYVALUE_8,
|
||||
ID_MEMVIEW_DISPLAYVALUE_16,
|
||||
ID_MEMVIEW_DISPLAYVALUE_32,
|
||||
ID_MEMVIEW_DISPLAYVALUE_64,
|
||||
ID_MEMVIEW_DISPLAYVALUE_128,
|
||||
ID_MEMVIEW_COPYVALUE_8,
|
||||
ID_MEMVIEW_COPYVALUE_16,
|
||||
ID_MEMVIEW_COPYVALUE_32,
|
||||
ID_MEMVIEW_COPYVALUE_64,
|
||||
ID_MEMVIEW_COPYVALUE_128,
|
||||
ID_MEMVIEW_ALIGNWINDOW,
|
||||
};
|
||||
|
||||
// Kind of lame, but it works.
|
||||
const wxString wxStringTypes[] =
|
||||
{
|
||||
"Byte",
|
||||
"2 Bytes",
|
||||
"4 Bytes",
|
||||
"8 Bytes",
|
||||
"Float",
|
||||
"Double",
|
||||
"String"};
|
||||
const wxArrayString SearchTypes = wxArrayString(7, wxStringTypes);
|
||||
|
||||
// StringUtils::FromChars doesn't appreciate the leading 0x.
|
||||
__fi wxString CheckHexadecimalString(wxString s)
|
||||
{
|
||||
if(s.StartsWith("0x"))
|
||||
return s.Remove(0, 2);
|
||||
return s;
|
||||
}
|
||||
|
||||
CtrlMemSearch::CtrlMemSearch(wxWindow* parent, DebugInterface* _cpu)
|
||||
: wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize)
|
||||
, cpu(_cpu)
|
||||
{
|
||||
|
||||
m_SearchThread.reset(new SearchThread(this, _cpu));
|
||||
m_SearchThread->SetName("Debugger Memory Search");
|
||||
|
||||
Bind(pxEvt_SearchFinished, &CtrlMemSearch::onSearchFinished, this);
|
||||
|
||||
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
txtSearch = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(250, -1));
|
||||
btnSearch = new wxButton(this, wxID_ANY, L"Search", wxDefaultPosition);
|
||||
|
||||
Bind(wxEVT_BUTTON, &CtrlMemSearch::Search, this, btnSearch->GetId());
|
||||
|
||||
cmbSearchType = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(250, -1), 0, NULL, wxCB_READONLY);
|
||||
cmbSearchType->Set(SearchTypes);
|
||||
cmbSearchType->SetSelection(0);
|
||||
|
||||
Bind(wxEVT_COMBOBOX, &CtrlMemSearch::onSearchTypeChanged, this, cmbSearchType->GetId());
|
||||
|
||||
chkHexadecimal = new wxCheckBox(this, wxID_ANY, L"Hex");
|
||||
chkHexadecimal->SetValue(true);
|
||||
|
||||
radBigEndian = new wxRadioButton(this, wxID_ANY, L"Big Endian", wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
radLittleEndian = new wxRadioButton(this, wxID_ANY, L"Little Endian");
|
||||
radLittleEndian->SetValue(true);
|
||||
|
||||
txtMemoryStart = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(250, -1));
|
||||
txtMemoryStart->SetValue(L"0x0");
|
||||
txtMemoryEnd = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(250, -1));
|
||||
if (_cpu->getCpuType() == BREAKPOINT_EE)
|
||||
txtMemoryEnd->SetValue(L"0x200000");
|
||||
else
|
||||
txtMemoryEnd->SetValue(L"0x20000");
|
||||
|
||||
lblSearchHits = new wxStaticText(this, wxID_ANY, L"Hits: 0");
|
||||
lblSearchHitSelected = new wxStaticText(this, wxID_ANY, L"Cur: 0");
|
||||
|
||||
btnNext = new wxButton(this, wxID_ANY, L"Next", wxDefaultPosition);
|
||||
btnNext->Enable(false);
|
||||
Bind(wxEVT_BUTTON, &CtrlMemSearch::onSearchNext, this, btnNext->GetId());
|
||||
btnPrev = new wxButton(this, wxID_ANY, L"Prev", wxDefaultPosition);
|
||||
btnPrev->Enable(false);
|
||||
Bind(wxEVT_BUTTON, &CtrlMemSearch::onSearchPrev, this, btnPrev->GetId());
|
||||
|
||||
// GUI design
|
||||
|
||||
// Search box and search button
|
||||
wxBoxSizer* searchSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
searchSizer->Add(txtSearch, 0);
|
||||
searchSizer->Add(btnSearch, 0, wxLEFT, 5);
|
||||
|
||||
mainSizer->Add(searchSizer, 0, wxUP | wxLEFT | wxRIGHT, 5);
|
||||
|
||||
// Search type combo box and hexadecimal checkbox
|
||||
wxBoxSizer* searchTypeSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
searchTypeSizer->Add(cmbSearchType, 0, wxEXPAND);
|
||||
searchTypeSizer->Add(chkHexadecimal, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
mainSizer->Add(searchTypeSizer, 0, wxUP | wxLEFT | wxRIGHT, 5);
|
||||
|
||||
// Big / Little Endianess radio button
|
||||
wxBoxSizer* endianessSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
endianessSizer->Add(radLittleEndian, 0, wxALIGN_CENTER_VERTICAL);
|
||||
endianessSizer->Add(radBigEndian, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 5);
|
||||
|
||||
mainSizer->Add(endianessSizer, 0, wxUP | wxLEFT | wxRIGHT, 5);
|
||||
|
||||
// Address range type text boxes
|
||||
wxFlexGridSizer* addrRangeSizer = new wxFlexGridSizer(2, 2, 5);
|
||||
|
||||
addrRangeSizer->Add(new wxStaticText(this, wxID_ANY, L"Start Address"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
|
||||
addrRangeSizer->Add(txtMemoryStart, 0, wxEXPAND);
|
||||
|
||||
addrRangeSizer->Add(new wxStaticText(this, wxID_ANY, L"End Address"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL);
|
||||
addrRangeSizer->Add(txtMemoryEnd, 0, wxEXPAND);
|
||||
|
||||
mainSizer->Add(addrRangeSizer, 0, wxUP | wxLEFT | wxRIGHT, 5);
|
||||
|
||||
wxBoxSizer* resultSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
resultSizer->Add(lblSearchHits, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
|
||||
resultSizer->Add(lblSearchHitSelected, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
|
||||
resultSizer->Add(btnPrev, 0, wxRIGHT, 5);
|
||||
resultSizer->Add(btnNext, 0, wxRIGHT, 5);
|
||||
|
||||
mainSizer->Add(resultSizer, 0, wxUP | wxLEFT | wxRIGHT, 5);
|
||||
this->SetSizer(mainSizer);
|
||||
SetDoubleBuffered(true);
|
||||
}
|
||||
|
||||
void CtrlMemSearch::postEvent(wxEventType type, wxString text)
|
||||
{
|
||||
wxCommandEvent event(type, GetId());
|
||||
event.SetEventObject(this);
|
||||
event.SetClientData(cpu);
|
||||
event.SetString(text);
|
||||
wxPostEvent(this, event);
|
||||
}
|
||||
|
||||
void CtrlMemSearch::postEvent(wxEventType type, int value)
|
||||
{
|
||||
wxCommandEvent event(type, GetId());
|
||||
event.SetEventObject(this);
|
||||
event.SetClientData(cpu);
|
||||
event.SetInt(value);
|
||||
wxPostEvent(this, event);
|
||||
}
|
||||
|
||||
// Set up the thread with out UI params
|
||||
// Then execute the thread
|
||||
void CtrlMemSearch::Search(wxCommandEvent& evt)
|
||||
{
|
||||
if (!m_searchResultsMutex.try_lock())
|
||||
{
|
||||
// Uh, if it doesn't lock then means we somehow tried to search while
|
||||
// the search was still running.
|
||||
return;
|
||||
}
|
||||
m_searchResults.clear();
|
||||
m_searchResultsMutex.unlock();
|
||||
|
||||
lblSearchHits->SetLabelText(L"Hits: 0");
|
||||
btnNext->Enable(false);
|
||||
btnPrev->Enable(false);
|
||||
|
||||
u64 startAddress = 0;
|
||||
u64 endAddress = 0;
|
||||
|
||||
const auto resStart = StringUtil::FromChars<u64>(CheckHexadecimalString(txtMemoryStart->GetValue()).ToStdString(), 16);
|
||||
if (!resStart.has_value())
|
||||
{
|
||||
wxMessageBox(L"Invalid start address", L"Error", wxOK | wxICON_ERROR);
|
||||
return;
|
||||
}
|
||||
startAddress = resStart.value();
|
||||
|
||||
const auto resEnd = StringUtil::FromChars<u64>(CheckHexadecimalString(txtMemoryEnd->GetValue()).ToStdString(), 16);
|
||||
if (!resStart.has_value())
|
||||
{
|
||||
wxMessageBox(L"Invalid end address", L"Error", wxOK | wxICON_ERROR);
|
||||
return;
|
||||
}
|
||||
endAddress = resEnd.value();
|
||||
|
||||
m_SearchThread->m_start = startAddress;
|
||||
m_SearchThread->m_end = endAddress;
|
||||
m_SearchThread->m_type = static_cast<SEARCHTYPE>(cmbSearchType->GetSelection());
|
||||
|
||||
// Prepare the search value for the thread
|
||||
|
||||
wxString searchString = txtSearch->GetValue();
|
||||
if (m_SearchThread->m_type == SEARCHTYPE::STRING)
|
||||
{
|
||||
m_SearchThread->m_value_string = searchString;
|
||||
}
|
||||
else if (chkHexadecimal->IsChecked())
|
||||
{
|
||||
const auto res = StringUtil::FromChars<u64>(CheckHexadecimalString(txtSearch->GetValue()).ToStdString(), 16);
|
||||
if (!res.has_value())
|
||||
{
|
||||
wxMessageBox(L"Invalid hexadecimal value", L"Error", wxOK | wxICON_ERROR);
|
||||
return;
|
||||
}
|
||||
m_SearchThread->m_value = radBigEndian->GetValue() ? SwapEndian(res.value(), SEARCHTYPEBITS[cmbSearchType->GetSelection()]) : res.value();
|
||||
}
|
||||
else
|
||||
{
|
||||
// According to my logic, we end up here if we aren't searching for a string
|
||||
// Aren't in hexadecimal mode.
|
||||
|
||||
// Let's check if we're searching for a signed or unsigned value
|
||||
// The thread will handle the interpretation for us.
|
||||
m_SearchThread->m_signed = txtSearch->GetValue().First('-');
|
||||
|
||||
// Now we can convert the string to a number
|
||||
|
||||
if (m_SearchThread->m_type == SEARCHTYPE::FLOAT || m_SearchThread->m_type == SEARCHTYPE::DOUBLE)
|
||||
{
|
||||
// We're searching for a float or double, so we need to convert the string to a double
|
||||
const auto res = StringUtil::FromChars<double>(txtSearch->GetValue().ToStdString());
|
||||
if (!res.has_value())
|
||||
{
|
||||
wxMessageBox(L"Invalid floating point value", L"Error", wxOK | wxICON_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_SearchThread->m_type == SEARCHTYPE::FLOAT)
|
||||
{
|
||||
const u32 u32SearchValue = bit_cast<u32, float>(res.value());
|
||||
m_SearchThread->m_value = u32SearchValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
const u64 u64SearchValue = bit_cast<u64, double>(res.value());
|
||||
m_SearchThread->m_value = u64SearchValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're searching for either a BYTE, WORD, DWORD or QWORD
|
||||
|
||||
const auto res = StringUtil::FromChars<u64>(txtSearch->GetValue().ToStdString());
|
||||
if(!res.has_value())
|
||||
{
|
||||
wxMessageBox(L"Invalid decimal search value", L"Error", wxOK | wxICON_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't need to bitcast here, because the thread already has the correct value type of u64
|
||||
m_SearchThread->m_value = radBigEndian->GetValue() ? SwapEndian(res.value(), SEARCHTYPEBITS[cmbSearchType->GetSelection()]) : res.value();
|
||||
}
|
||||
}
|
||||
|
||||
m_SearchThread->Start();
|
||||
};
|
||||
|
||||
void CtrlMemSearch::onSearchFinished(wxCommandEvent& evt)
|
||||
{
|
||||
// We're done searching, so let's update the UI
|
||||
|
||||
m_searchResultsMutex.lock();
|
||||
|
||||
lblSearchHits->SetLabelText(wxString::Format(L"Hits: %d", m_searchResults.size()));
|
||||
|
||||
// Enable the buttons only if we have results
|
||||
// -1 indicates we haven't jumped to a result yet
|
||||
m_searchIter = -1;
|
||||
lblSearchHitSelected->SetLabelText(L"Cur: 0");
|
||||
btnNext->Enable(m_searchResults.size() > 0);
|
||||
btnPrev->Enable(m_searchResults.size() > 0);
|
||||
|
||||
m_searchResultsMutex.unlock();
|
||||
|
||||
this->Layout(); // This makes sure the search hit count label doesn't get cut off
|
||||
}
|
||||
|
||||
void CtrlMemSearch::onSearchNext(wxCommandEvent& evt)
|
||||
{
|
||||
m_searchIter++;
|
||||
if (m_searchIter == m_searchResults.size())
|
||||
{
|
||||
m_searchIter = 0;
|
||||
}
|
||||
|
||||
lblSearchHitSelected->SetLabelText(wxString::Format(L"Cur: %d",m_searchIter + 1));
|
||||
this->Layout();
|
||||
postEvent(debEVT_GOTOINMEMORYVIEW, m_searchResults[m_searchIter]);
|
||||
}
|
||||
|
||||
void CtrlMemSearch::onSearchPrev(wxCommandEvent& evt)
|
||||
{
|
||||
m_searchIter--;
|
||||
// Unsigned underflow
|
||||
if (m_searchIter > m_searchResults.size())
|
||||
{
|
||||
m_searchIter = m_searchResults.size() - 1;
|
||||
}
|
||||
|
||||
lblSearchHitSelected->SetLabelText(wxString::Format(L"Cur: %d",m_searchIter + 1));
|
||||
this->Layout();
|
||||
postEvent(debEVT_GOTOINMEMORYVIEW, m_searchResults[m_searchIter]);
|
||||
}
|
||||
|
||||
void CtrlMemSearch::onSearchTypeChanged(wxCommandEvent& evt)
|
||||
{
|
||||
// Update the search value text box to match the search type
|
||||
switch (static_cast<SEARCHTYPE>(cmbSearchType->GetSelection()))
|
||||
{
|
||||
case SEARCHTYPE::BYTE:
|
||||
case SEARCHTYPE::WORD:
|
||||
case SEARCHTYPE::DWORD:
|
||||
case SEARCHTYPE::QWORD:
|
||||
radBigEndian->Enable(true);
|
||||
radLittleEndian->Enable(true);
|
||||
chkHexadecimal->Enable(true);
|
||||
break;
|
||||
case SEARCHTYPE::FLOAT:
|
||||
case SEARCHTYPE::DOUBLE:
|
||||
case SEARCHTYPE::STRING:
|
||||
radBigEndian->Enable(false);
|
||||
radLittleEndian->Enable(false);
|
||||
chkHexadecimal->Enable(false);
|
||||
chkHexadecimal->SetValue(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -- SearchThread
|
||||
|
||||
// There might be a prettier way to read from the vtlb
|
||||
template <class T>
|
||||
void memSearch(std::vector<u32>& out, u32 start, u32 end, T value, DebugInterface* cpu)
|
||||
{
|
||||
for (u32 addr = start; addr < end; addr += sizeof(T))
|
||||
{
|
||||
if (!cpu->isValidAddress(addr))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
T val = 0;
|
||||
if (sizeof(T) == 1)
|
||||
{
|
||||
val = cpu->read8(addr);
|
||||
}
|
||||
else if (sizeof(T) == 2)
|
||||
{
|
||||
val = cpu->read16(addr);
|
||||
}
|
||||
else if (sizeof(T) == 4)
|
||||
{
|
||||
if (std::is_same<T, float>::value)
|
||||
{
|
||||
float fpVal = bit_cast<float, u32>(value);
|
||||
// Love floating point
|
||||
if (bit_cast<float, u32>(cpu->read32(addr)) < fpVal + 0.001f && bit_cast<float, u32>(cpu->read32(addr)) > fpVal - 0.001f)
|
||||
{
|
||||
out.push_back(addr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
val = cpu->read32(addr);
|
||||
}
|
||||
else if (sizeof(T) == 8)
|
||||
{
|
||||
if (std::is_same<T, double>::value)
|
||||
{
|
||||
double dbVal = bit_cast<double, u64>(value);
|
||||
if (bit_cast<double, u64>(cpu->read64(addr)) < dbVal + 0.001 && bit_cast<double, u64>(cpu->read64(addr)) > dbVal - 0.001)
|
||||
{
|
||||
out.push_back(addr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
val = cpu->read64(addr);
|
||||
}
|
||||
|
||||
if (val == value)
|
||||
{
|
||||
out.push_back(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SearchThread::ExecuteTaskInThread()
|
||||
{
|
||||
// First, make sure we can lock the mutex
|
||||
if (!m_parent->m_searchResultsMutex.try_lock())
|
||||
{
|
||||
// We couldn't lock the mutex, this thread either didn't unlock, or we've somehow raced
|
||||
// with the main UI thread ?
|
||||
assert("Failed to lock our memory search mutex?");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (m_type)
|
||||
{
|
||||
case SEARCHTYPE::BYTE:
|
||||
if (m_signed)
|
||||
{
|
||||
memSearch<s8>(m_parent->m_searchResults, m_start, m_end, m_value, m_cpu);
|
||||
}
|
||||
else
|
||||
{
|
||||
memSearch<u8>(m_parent->m_searchResults, m_start, m_end, m_value, m_cpu);
|
||||
}
|
||||
break;
|
||||
case SEARCHTYPE::WORD:
|
||||
if (m_signed)
|
||||
{
|
||||
memSearch<s16>(m_parent->m_searchResults, m_start, m_end, m_value, m_cpu);
|
||||
}
|
||||
else
|
||||
{
|
||||
memSearch<u16>(m_parent->m_searchResults, m_start, m_end, m_value, m_cpu);
|
||||
}
|
||||
break;
|
||||
case SEARCHTYPE::DWORD:
|
||||
if (m_signed)
|
||||
{
|
||||
memSearch<s32>(m_parent->m_searchResults, m_start, m_end, m_value, m_cpu);
|
||||
}
|
||||
else
|
||||
{
|
||||
memSearch<u32>(m_parent->m_searchResults, m_start, m_end, m_value, m_cpu);
|
||||
}
|
||||
break;
|
||||
case SEARCHTYPE::QWORD:
|
||||
if (m_signed)
|
||||
{
|
||||
memSearch<s64>(m_parent->m_searchResults, m_start, m_end, m_value, m_cpu);
|
||||
}
|
||||
else
|
||||
{
|
||||
memSearch<u64>(m_parent->m_searchResults, m_start, m_end, m_value, m_cpu);
|
||||
}
|
||||
break;
|
||||
case SEARCHTYPE::FLOAT:
|
||||
memSearch<float>(m_parent->m_searchResults, m_start, m_end, m_value, m_cpu);
|
||||
break;
|
||||
case SEARCHTYPE::DOUBLE:
|
||||
memSearch<double>(m_parent->m_searchResults, m_start, m_end, m_value, m_cpu);
|
||||
break;
|
||||
case SEARCHTYPE::STRING:
|
||||
for (u32 addr = m_start; addr < m_end; addr++)
|
||||
{
|
||||
// There is no easy way to do this with the vtable.
|
||||
bool match = true;
|
||||
for (u32 stringIndex = 0; stringIndex < m_value_string.size(); stringIndex++)
|
||||
{
|
||||
if ((char)m_cpu->read8(addr + stringIndex) != m_value_string[stringIndex])
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match)
|
||||
{
|
||||
m_parent->m_searchResults.push_back(addr);
|
||||
addr += m_value_string.size() - 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_parent->m_searchResultsMutex.unlock();
|
||||
|
||||
wxCommandEvent done(pxEvt_SearchFinished);
|
||||
m_parent->GetEventHandler()->AddPendingEvent(done);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user