Compare commits

...
49 Commits
Author SHA1 Message Date
PCSX2 Botandlightningterror e934bec4b7 pad-linux: Update to latest controller database. 2021-11-08 17:27:08 +01:00
TellowKrinkleandrefractionpcsx2 4e5d7ba8ef GS:SW: Fix fog on x64 avx2 2021-11-08 09:19:05 +00:00
TellowKrinkleandrefractionpcsx2 59fd815c3d GS: Faster GSOffset::PAHelper 2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 b901c6af71 GS: Switch back to row+column for pixel lookups
Code for the full calculation was way too complicated to run for every pixel in a loop
2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 b2fb6c7804 GS: Don't calculate a pageOffset per bp 2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 84c5f8f738 GS: Remove rowOffset 2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 39c7f11b98 GS: Pixel loop optimizations 2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 86a2d73931 GS: Clean up old GSOffset remnants 2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 8eb50c3517 GS: Switch to new non-cached GSOffset 2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 d9defb19f9 GS: Add new GSOffset class 2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 874804bcfd GS: Add block/page loop functions to GSSwizzleInfo 2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 b0f9662811 GS: Add srav and blend backwards compat to GSVector4i 2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 24850823a2 GS: Use new swizzle calculation class 2021-11-07 03:44:31 +00:00
TellowKrinkleandrefractionpcsx2 951604475b GS: Add class for swizzle calculations 2021-11-07 03:44:31 +00:00
Ty Lamontagneandrefractionpcsx2 74f3bb2aa9 Debugger: Make the register list DPI aware 2021-11-07 03:43:55 +00:00
Tyler Wildingandrefractionpcsx2 4442b798c9 CDVD: set the correct RTC year when input recording 2021-11-07 02:21:01 +00:00
Tyler Wildingandrefractionpcsx2 f10a8de2c1 input-rec: Use a constant RTC for power-on recordings 2021-11-06 16:24:53 +00:00
Tokman5andrefractionpcsx2 329b29269b GameDB: Add and fix Power Pros series 2021-11-06 16:23:02 +00:00
Mrlinkwiiandrefractionpcsx2 5b3ffe6bab GameDB: add EE clamping to 'Shadow of Zorro' and 'Evil Twin - Cyprien's Chronicles'
GameDB: add EE clamping to 'Shadow of Zorro' and 'Evil Twin - Cyprien's Chronicles'
2021-11-06 16:20:04 +00:00
JoeyandGitHub fb14500b41 pad-linux: Abort 'set all btns' on escape key + gui fixes (#4809) 2021-11-06 00:44:08 -07:00
TellowKrinkleandtellowkrinkle ad29594d08 Use correct clock for GS fps calculations on unix 2021-11-05 23:11:53 -05:00
tellowkrinkle 37e2142cca Common: Fix Darwin thread times
Percentages will now actually be percentages instead of permille (units of 1/1000)
Was caused by trying to match Windows's returns of 100ns units, but then reporting 1µs units from `GetThreadTicksPerSecond()`
2021-11-05 23:11:53 -05:00
tellowkrinkle 1e5f1de12c CMake: Increase deployment target to 10.13
Allows use of throwing `optional` and `variant` methods
2021-11-05 23:11:53 -05:00
tellowkrinkle 0f93dbcd5e USB: Make save state non-required
Fixes save state loading for systems using a null USB plugin (macOS, BSD)
2021-11-05 23:11:53 -05:00
RedDevilusandrefractionpcsx2 e415d85dbe GameDB: Add and fix SingStar Entries
I noticed we had a ton of missing SingStar serial + minor other fixes.
2021-11-05 15:59:29 +00:00
Mrlinkwiiandrefractionpcsx2 4c8bf53e69 CI:Add build date to program log of nightly builds 2021-11-05 01:16:08 +00:00
refractionpcsx2 83fcd4bd1f SPU: Kind of revert last ADMA change. Clear as reading.
This is a temporary measure while we run some hardware tests, the previous change broke Burnout 3's engine sounds.
2021-11-04 20:13:18 +00:00
TellowKrinkleandrefractionpcsx2 bfd960ad1b GHActions:Linux: Upgrade to Clang 9 2021-11-04 20:11:15 +00:00
qurious-pixelandrefractionpcsx2 6b81808ecc gcc compatibility for older distros
Add compatibility layer for using newer gcc on older distros.
- use AppImageKit-checkrt
- copy build system stdc++ and gcc_s
2021-11-04 20:11:15 +00:00
TellowKrinkleandrefractionpcsx2 c615a6f6e2 GHActions:Linux: Upgrade to GCC 10 2021-11-04 20:11:15 +00:00
TellowKrinkleandrefractionpcsx2 40b522b42f GHActions:Linux: Remove unneccessary packages 2021-11-04 20:11:15 +00:00
TellowKrinkleandrefractionpcsx2 f2655b763f GHActions:Linux: Clean up setup scripts 2021-11-04 20:11:15 +00:00
TellowKrinkleandrefractionpcsx2 fd145e65aa GS: Remove virtual destructor from GSAlignedClass
No point, and made it not a standard layout type
2021-11-04 19:32:27 +00:00
TellowKrinkleandrefractionpcsx2 6596b7f27e GS: Enable AVX2 on x64 2021-11-04 19:32:27 +00:00
TellowKrinkleandrefractionpcsx2 9d767838d6 GS: Remove old DrawScanline code generators 2021-11-04 19:32:27 +00:00
TellowKrinkleandrefractionpcsx2 f55219bb1b GS: Replace 6 DrawScanline code generators with one merged one 2021-11-04 19:32:27 +00:00
TellowKrinkleandrefractionpcsx2 805b647c73 GS: Remove old SetupPrim code generators 2021-11-04 19:32:27 +00:00
TellowKrinkleandrefractionpcsx2 fd0351ca8f GS: Replace 6 SetupPrim code generators with one merged one 2021-11-04 19:32:27 +00:00
TellowKrinkleandrefractionpcsx2 ed5a7802f3 Common: Add non-constant offsetof macro 2021-11-04 19:32:27 +00:00
TellowKrinkleandrefractionpcsx2 44f8317b7e GS: Add new code generator for easy native-isa codegen 2021-11-04 19:32:27 +00:00
TellowKrinkleandrefractionpcsx2 0200933ddd GS: Don't catch code generation exceptions
If codegen throws an exception, it ends up just crashing when you jump to the incompletely-generated code which is kind of useless
2021-11-04 19:32:27 +00:00
lightningterror f712b2b63a GSDeviceOGL: Fix Wunused-private-field warnings. 2021-11-04 11:18:26 +01:00
Tyler Wildingandrefractionpcsx2 71923e7cba actions: cleanup discord embed links and add release body 2021-11-03 23:46:45 +00:00
refractionpcsx2 532d14611c GS: Properly loop when reading 32bit CLUT from offset 2021-11-03 18:24:57 +00:00
refractionpcsx2 3a91a07d51 GS: Fix up CLUT offset handling in 32bit I8 mode 2021-11-03 18:24:57 +00:00
refractionpcsx2 6a8287ea9f EE JIT: Backup shift on LDR/L if rs==rt 2021-11-03 18:03:09 +00:00
Tyler Wildingandlightningterror dc051541bd actions: create automatic controller db updating workflow 2021-11-03 16:40:36 +01:00
lightningterror 3265c2a614 GS-ogl: Put GL_ARB_get_texture_sub_image code under a define.
Code is currently disabled, no need to check for the extension.
2021-11-03 16:37:55 +01:00
lightningterror f798401e93 GS-ogl: Remove checks for extensions we don't yet use.
They serve no purpose, no need to check unless we actually use them

GL_ARB_compute_shader,
GL_ARB_shader_storage_buffer_object,
GL_ARB_texture_view,
GL_ARB_vertex_attrib_binding,
GL_ARB_multi_bind
2021-11-03 16:37:55 +01:00
77 changed files with 6899 additions and 18609 deletions
@@ -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)
+7 -1
View File
@@ -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
View File
@@ -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"
+5 -3
View File
@@ -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
+3 -7
View File
@@ -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()
+4
View File
@@ -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. >_<
+33
View File
@@ -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
View File
@@ -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
View File
@@ -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";
+4 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+3 -3
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+463 -220
View File
@@ -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);
}
+5 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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__)
+2 -2
View File
@@ -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);
+19 -23
View File
@@ -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
+37 -81
View File
@@ -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;
+4 -4
View File
@@ -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;
+8 -14
View File
@@ -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)
-2
View File
@@ -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);
+1 -1
View File
@@ -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
+24 -31
View File
@@ -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)
{
+4 -4
View File
@@ -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"
+489
View File
@@ -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
};
+101 -99
View File
@@ -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;
}
+6 -7
View File
@@ -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
+22 -34
View File
@@ -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++;
}
+3 -3
View File
@@ -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();
+2
View File
@@ -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.
+7 -3
View File
@@ -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,
+19 -8
View File
@@ -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();
+2 -2
View File
@@ -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();
+7 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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()
+2 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+10
View File
@@ -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);
-4
View File
@@ -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)
{