mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-08-12 17:10:23 +02:00
Compare commits
@@ -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
|
||||
+315
-38
@@ -1543,6 +1543,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 +1573,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 +1723,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 +3028,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 +3091,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 +3100,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 +3111,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 +3180,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 +3248,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 +3278,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 +3305,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 +3338,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 +3419,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 +3461,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 +3473,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 +3528,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 +5229,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 +6632,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 +6642,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 +6654,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 +6687,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 +6703,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 +6723,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 +6743,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 +6760,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 +7565,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 +8424,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"
|
||||
@@ -19132,9 +19388,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 +19473,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 +19673,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 +19731,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 +19763,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 +19805,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 +19901,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 +20041,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 +20261,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"
|
||||
@@ -21786,7 +22063,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"
|
||||
@@ -22272,7 +22549,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 +22927,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 +24807,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 +25894,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 +26005,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 +26465,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 +27364,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 +27486,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"
|
||||
@@ -41131,7 +41408,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
|
||||
|
||||
@@ -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. >_<
|
||||
|
||||
@@ -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;
|
||||
|
||||
+6
-13
@@ -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
|
||||
@@ -679,7 +670,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 +702,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
|
||||
|
||||
+3
-6
@@ -1262,22 +1262,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";
|
||||
|
||||
@@ -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 );
|
||||
|
||||
+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__)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -156,22 +156,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))
|
||||
@@ -310,20 +307,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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-2
@@ -611,7 +611,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 +923,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
|
||||
|
||||
@@ -74,8 +74,8 @@ CtrlRegisterList::CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu)
|
||||
SetDoubleBuffered(true);
|
||||
|
||||
const wxSize optSize = getOptimalSize();
|
||||
SetVirtualSize(optSize);
|
||||
SetScrollbars(1, rowHeight, optSize.x, optSize.y / rowHeight, 0, 0);
|
||||
SetVirtualSize(optSize.x,optSize.y);
|
||||
SetScrollbars(1, rowHeight, optSize.x, optSize.y * MSW_GetDPIScale() / rowHeight, 0, 0);
|
||||
}
|
||||
|
||||
CtrlRegisterList::~CtrlRegisterList()
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#pragma once
|
||||
#include <wx/wx.h>
|
||||
|
||||
#include "gui/MSWstuff.h" // Required for MSW_GetDPIScale()
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/DisassemblyManager.h"
|
||||
|
||||
@@ -38,7 +39,7 @@ public:
|
||||
if (GetWindowStyle() & wxVSCROLL)
|
||||
optimalSize.x += wxSystemSettings::GetMetric(wxSYS_VSCROLL_X);
|
||||
|
||||
return wxSize(optimalSize.x, 0);
|
||||
return wxSize(optimalSize.x * MSW_GetDPIScale(), 0);
|
||||
}
|
||||
|
||||
virtual wxSize DoGetBestClientSize() const
|
||||
|
||||
+7
-13
@@ -46,6 +46,7 @@
|
||||
<PrecompiledHeaderFile>PrecompiledHeader.h</PrecompiledHeaderFile>
|
||||
<ForcedIncludeFiles>PrecompiledHeader.h;%(ForcedIncludeFiles)</ForcedIncludeFiles>
|
||||
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
|
||||
<AdditionalOptions>/Zc:externConstexpr %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>WIN32_LEAN_AND_MEAN;LZMA_API_STATIC;BUILD_DX=1;SPU2X_PORTAUDIO;DIRECTINPUT_VERSION=0x0800;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="$(Configuration.Contains(Debug))">PCSX2_DEBUG;PCSX2_DEVBUILD;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions Condition="$(Configuration.Contains(Devel))">PCSX2_DEVEL;PCSX2_DEVBUILD;NDEBUG;_SECURE_SCL_=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
@@ -466,12 +467,8 @@
|
||||
<ClCompile Include="GS\GSDrawingContext.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanline.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x64.avx.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x64.avx2.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x64.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x86.avx.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x86.avx2.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x86.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.all.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSNewCodeGenerator.cpp" />
|
||||
<ClCompile Include="GS\GSDump.cpp" />
|
||||
<ClCompile Include="GS\Renderers\Common\GSFunctionMap.cpp" />
|
||||
<ClCompile Include="GS\Renderers\HW\GSHwHack.cpp" />
|
||||
@@ -490,12 +487,7 @@
|
||||
<ClCompile Include="GS\Window\GSSetting.cpp" />
|
||||
<ClCompile Include="GS\Window\GSSettingsDlg.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x64.avx.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x64.avx2.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x64.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x86.avx.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x86.avx2.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x86.cpp" />
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.all.cpp" />
|
||||
<ClCompile Include="GS\Renderers\OpenGL\GSShaderOGL.cpp" />
|
||||
<ClCompile Include="GS\GSState.cpp" />
|
||||
<ClCompile Include="GS\GSTables.cpp" />
|
||||
@@ -815,7 +807,6 @@
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GLLoader.h" />
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GLState.h" />
|
||||
<ClInclude Include="GS\GS.h" />
|
||||
<ClInclude Include="GS\GS_codegen.h" />
|
||||
<ClInclude Include="GS\GS_types.h" />
|
||||
<ClInclude Include="GS\GSAlignedClass.h" />
|
||||
<ClInclude Include="GS\GSBlock.h" />
|
||||
@@ -834,6 +825,8 @@
|
||||
<ClInclude Include="GS\GSDrawingEnvironment.h" />
|
||||
<ClInclude Include="GS\Renderers\SW\GSDrawScanline.h" />
|
||||
<ClInclude Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.h" />
|
||||
<ClInclude Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.all.h" />
|
||||
<ClInclude Include="GS\Renderers\SW\GSNewCodeGenerator.h" />
|
||||
<ClInclude Include="GS\GSDump.h" />
|
||||
<ClInclude Include="GS\Renderers\Common\GSFastList.h" />
|
||||
<ClInclude Include="GS\Renderers\Common\GSFunctionMap.h" />
|
||||
@@ -853,6 +846,7 @@
|
||||
<ClInclude Include="GS\Window\GSSetting.h" />
|
||||
<ClInclude Include="GS\Window\GSSettingsDlg.h" />
|
||||
<ClInclude Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.h" />
|
||||
<ClInclude Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.all.h" />
|
||||
<ClInclude Include="GS\Renderers\OpenGL\GSShaderOGL.h" />
|
||||
<ClInclude Include="GS\GSState.h" />
|
||||
<ClInclude Include="GS\GSTables.h" />
|
||||
|
||||
+11
-35
@@ -1517,22 +1517,10 @@
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x64.avx.cpp">
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.all.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x64.avx2.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x64.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x86.avx.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x86.avx2.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.x86.cpp">
|
||||
<ClCompile Include="GS\Renderers\SW\GSNewCodeGenerator.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSRendererSW.cpp">
|
||||
@@ -1541,24 +1529,6 @@
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x64.avx.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x64.avx2.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x64.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x86.avx.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x86.avx2.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.x86.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GS\Renderers\SW\GSTextureCacheSW.cpp">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClCompile>
|
||||
@@ -2508,9 +2478,6 @@
|
||||
<ClInclude Include="GS\GS.h">
|
||||
<Filter>System\Ps2\GS</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\GS_codegen.h">
|
||||
<Filter>System\Ps2\GS</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\GS_types.h">
|
||||
<Filter>System\Ps2\GS</Filter>
|
||||
</ClInclude>
|
||||
@@ -2631,6 +2598,12 @@
|
||||
<ClInclude Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\SW\GSDrawScanlineCodeGenerator.all.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\SW\GSNewCodeGenerator.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\SW\GSRendererSW.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClInclude>
|
||||
@@ -2640,6 +2613,9 @@
|
||||
<ClInclude Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\SW\GSSetupPrimCodeGenerator.all.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GS\Renderers\SW\GSTextureCacheSW.h">
|
||||
<Filter>System\Ps2\GS\Renderers\Software</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -538,6 +538,11 @@ void recLDL()
|
||||
if (GPR_IS_CONST1(_Rs_))
|
||||
{
|
||||
u32 srcadr = g_cpuConstRegs[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
// If _Rs_ is equal to _Rt_ we need to put the shift in to eax since it won't take the CONST path
|
||||
if (_Rs_ == _Rt_)
|
||||
xMOV(calleeSavedReg1d, srcadr);
|
||||
|
||||
srcadr &= ~0x07;
|
||||
|
||||
t2reg = vtlb_DynGenRead64_Const(64, srcadr, -1);
|
||||
@@ -609,6 +614,11 @@ void recLDR()
|
||||
if (GPR_IS_CONST1(_Rs_))
|
||||
{
|
||||
u32 srcadr = g_cpuConstRegs[_Rs_].UL[0] + _Imm_;
|
||||
|
||||
// If _Rs_ is equal to _Rt_ we need to put the shift in to eax since it won't take the CONST path
|
||||
if(_Rs_ == _Rt_)
|
||||
xMOV(calleeSavedReg1d, srcadr);
|
||||
|
||||
srcadr &= ~0x07;
|
||||
|
||||
t2reg = vtlb_DynGenRead64_Const(64, srcadr, -1);
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
#include "GSLocalMemory.h"
|
||||
|
||||
GSLocalMemory::psm_t GSLocalMemory::m_psm[64];
|
||||
GSOffset* GSLocalMemory::GetOffset(uint32 bp, uint32 bw, uint32 psm)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
void* vmalloc(size_t size, bool code)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user