Compare commits

...

20 Commits

Author SHA1 Message Date
TellowKrinkle
8fd91cb7df Formatting: Apply AlignWithSpaces 2025-07-31 15:20:27 +02:00
TellowKrinkle
c5820a4f54 Formatting: Set UseTab to AlignWithSpaces
Should make things look nicer on GitHub
2025-07-31 15:20:27 +02:00
TheLastRar
572eae596c FSUI: Use emoji for reset settings 2025-07-30 12:25:32 -04:00
TheLastRar
6f3c189129 FSUI: Support Emojis for settings icons 2025-07-30 12:25:32 -04:00
TheLastRar
7a0017bd40 FSUI: Support Emojis 2025-07-30 12:25:32 -04:00
TheLastRar
74f840f66b CI/AppImage: Bundle FreeType & HalfBuzz 2025-07-30 12:25:32 -04:00
TheLastRar
4a7c194157 Deps: Build FreeType & HalfBuzz on Linux 2025-07-30 12:25:32 -04:00
TJnotJT
116eb6dc5b Misc: Fix changing console log file.
Console logging file should be updated whenever it is not equal to the old file. The test to check this was inverted.
2025-07-30 12:10:04 -04:00
Julien Reichardt
0bab3c74ea CI/Flatpak: Upgrade runtime to 6.9 2025-07-30 12:07:00 -04:00
Joseph Hazell
6328de43e3 Qt: Use radio buttons for actions under 'Switch Renderer' menu 2025-07-30 12:02:55 -04:00
PCSX2 Bot
5becdc9ab5 [ci skip] PAD: Update to latest controller database. 2025-07-28 18:04:40 +02:00
TJnotJT
26b6394b67 GS: Use std::array for fixed size array. 2025-07-27 12:56:10 -04:00
PCSX2 Bot
1b6086ab62 [ci skip] Qt: Update Base Translation. 2025-07-27 15:48:42 +02:00
HeyImRuu
87a4536a2e GameDB: Fix wrong title for SLES-54435. 2025-07-27 15:48:25 +02:00
JordanTheToaster
d20b897ac8 GameDB: Valkyrie Profile 2 DX shadow fix 2025-07-27 14:34:08 +02:00
JordanTheToaster
6f26b064b9 Resources: Update Redump Database (27/07/2025) 2025-07-27 14:34:08 +02:00
lightningterror
3a2c78d17c Qt: Fix default post processing values.
Brightness, contrast, gamma, saturation.
2025-07-26 03:39:37 +02:00
PCSX2 Bot
19d375b4bd [ci skip] Qt: Update Base Translation. 2025-07-25 03:35:06 +02:00
JordanTheToaster
8162461618 GraphicsSettingsWidget: Index regression fix 2025-07-24 22:13:42 +02:00
Gonzalosilvalde
0cadc3189c GS: Add gamma control to ShadeBoost 2025-07-24 18:10:53 +02:00
72 changed files with 2883 additions and 2030 deletions

View File

@@ -86,5 +86,5 @@ SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: ForContinuationAndIndentation
UseTab: AlignWithSpaces
...

View File

@@ -41,8 +41,13 @@ BINARY=pcsx2-qt
APPDIRNAME=PCSX2.AppDir
STRIP=strip
# Need both libharfbuzz.so and libharfbuzz.so.0 for bundled libs
declare -a MANUAL_LIBS=(
"libshaderc_shared.so.1"
"libharfbuzz.so.0"
"libharfbuzz.so"
"libfreetype.so.6"
)
declare -a REMOVE_LIBS=(
@@ -75,22 +80,29 @@ fi
OUTDIR=$(realpath "./$APPDIRNAME")
rm -fr "$OUTDIR"
# Our deps build dosn't create libharfbuzz.so.0, so we have to symlink it here
hbpath=$(find "$DEPSDIR" -name "libharfbuzz.so")
if [ ! -f "$hbpath" ]; then
echo "Missing harfbuzz. Exiting."
exit 1
fi
if [ ! -f "$hbpath.0" ]; then
echo "Symlinking libharfbuzz.so.0"
ln -s "$hbpath" "$hbpath.0"
fi
echo "Locating extra libraries..."
EXTRA_LIBS_ARGS=""
EXTRA_LIBS_ARGS=()
for lib in "${MANUAL_LIBS[@]}"; do
srcpath=$(find "$DEPSDIR" -name "$lib")
if [ ! -f "$srcpath" ]; then
echo "Missinge extra library $lib. Exiting."
echo "Missing extra library $lib. Exiting."
exit 1
fi
echo "Found $lib at $srcpath."
if [ "$EXTRA_LIBS_ARGS" == "" ]; then
EXTRA_LIBS_ARGS="--library=$srcpath"
else
EXTRA_LIBS_ARGS="$EXTRA_LIBS_ARGS,$srcpath"
fi
EXTRA_LIBS_ARGS+=( "--library=$srcpath" )
done
# Why the nastyness? linuxdeploy strips our main binary, and there's no option to turn it off.
@@ -122,7 +134,7 @@ EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" \
DEPLOY_PLATFORM_THEMES="1" \
QMAKE="$DEPSDIR/bin/qmake" \
NO_STRIP="1" \
$LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/pcsx2-qt" $EXTRA_LIBS_ARGS \
$LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/pcsx2-qt" ${EXTRA_LIBS_ARGS[@]} \
--desktop-file="net.pcsx2.PCSX2.desktop" --icon-file="PCSX2.png"
echo "Copying resources into AppDir..."

View File

@@ -14,6 +14,8 @@ if [ "${INSTALLDIR:0:1}" != "/" ]; then
INSTALLDIR="$PWD/$INSTALLDIR"
fi
FREETYPE=2.13.3
HARFBUZZ=11.2.0
LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075
LIBJPEGTURBO=3.1.1
LIBPNG=1.6.50
@@ -35,6 +37,8 @@ mkdir -p deps-build
cd deps-build
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
16c0204704f3ebeed057aba100fe7db18d71035505cb10e595ea33d346457fc8 harfbuzz-$HARFBUZZ.tar.gz
fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.zip
aadc97ea91f6ef078b0ae3a62bba69e008d9a7db19b34e4ac973b19b71b4217c libjpeg-turbo-$LIBJPEGTURBO.tar.gz
4df396518620a7aa3651443e87d1b2862e4e88cad135a8b93423e01706232307 libpng-$LIBPNG.tar.xz
@@ -58,6 +62,8 @@ b8529755b2d54205341766ae168e83177c6120660539f9afba71af6bca4b81ec KDDockWidgets-
EOF
curl -L \
-o "freetype-$FREETYPE.tar.xz" "https://sourceforge.net/projects/freetype/files/freetype2/$FREETYPE/freetype-$FREETYPE.tar.xz/download" \
-o "harfbuzz-$HARFBUZZ.tar.gz" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/$HARFBUZZ.tar.gz" \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.zip" \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$LIBPNG/libpng-$LIBPNG.tar.xz" \
@@ -137,6 +143,33 @@ cmake --build build --parallel
ninja -C build install
cd ..
echo "Building FreeType without HarfBuzz..."
rm -fr "freetype-$FREETYPE"
tar xf "freetype-$FREETYPE.tar.xz"
cd "freetype-$FREETYPE"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_DISABLE_HARFBUZZ=TRUE -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building HarfBuzz..."
rm -fr "harfbuzz-$HARFBUZZ"
tar xf "harfbuzz-$HARFBUZZ.tar.gz"
cd "harfbuzz-$HARFBUZZ"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DHB_BUILD_UTILS=OFF -DHB_HAVE_FREETYPE=ON -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building FreeType with HarfBuzz..."
rm -fr "freetype-$FREETYPE"
tar xf "freetype-$FREETYPE.tar.xz"
cd "freetype-$FREETYPE"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DFT_REQUIRE_ZLIB=ON -DFT_REQUIRE_PNG=ON -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_BROTLI=TRUE -DFT_REQUIRE_HARFBUZZ=TRUE -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..
echo "Building SDL..."
rm -fr "$SDL"
tar xf "$SDL.tar.gz"
@@ -240,7 +273,7 @@ echo "Building PlutoSVG..."
rm -fr "plutosvg-$PLUTOSVG"
tar xf "plutosvg-$PLUTOSVG.tar.gz"
cd "plutosvg-$PLUTOSVG"
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DPLUTOSVG_ENABLE_FREETYPE=OFF -DPLUTOSVG_BUILD_EXAMPLES=OFF -B build -G Ninja
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DPLUTOSVG_ENABLE_FREETYPE=ON -DPLUTOSVG_BUILD_EXAMPLES=OFF -B build -G Ninja
cmake --build build --parallel
ninja -C build install
cd ..

View File

@@ -1,7 +1,7 @@
{
"app-id": "net.pcsx2.PCSX2",
"runtime": "org.kde.Platform",
"runtime-version": "6.8",
"runtime-version": "6.9",
"sdk": "org.kde.Sdk",
"sdk-extensions": [
"org.freedesktop.Sdk.Extension.llvm18"

View File

@@ -66,7 +66,7 @@
//#define IMGUI_USE_LEGACY_CRC32_ADLER
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
//#define IMGUI_USE_WCHAR32
#define IMGUI_USE_WCHAR32
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
@@ -91,7 +91,7 @@
// - plutosvg is currently easier to install, as e.g. it is part of vcpkg. It will support more fonts and may load them faster. See misc/freetype/README for instructions.
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
//---- Use stb_truetype to build and rasterize the font atlas (default)

View File

@@ -2402,6 +2402,7 @@ SCAJ-20177:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SCAJ-20178:
name: "Ape Escape - Million Monkeys"
region: "NTSC-Unk"
@@ -2521,6 +2522,7 @@ SCAJ-20197:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SCAJ-20198:
name: "Everybody's Tennis [PlayStation2 the Best]"
region: "NTSC-Unk"
@@ -3798,8 +3800,11 @@ SCED-52461:
SCED-52491:
name: "Athens 2004"
region: "PAL-M6"
SCED-52496:
name: "This Is Football 2004 [Demo]"
region: "PAL-M4"
SCED-52497:
name: "This is Football 2004"
name: "This Is Football 2004 [Demo]"
region: "PAL-M4"
SCED-52549:
name: "Official PlayStation 2 Magazine Demo 47"
@@ -7639,6 +7644,7 @@ SCKA-20079:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SCKA-20081:
name: "Tekken 5 [PlayStation 2 Big Hit Series]"
region: "NTSC-K"
@@ -26209,7 +26215,7 @@ SLES-54434:
name: "Babe"
region: "PAL-A"
SLES-54435:
name: "Babe"
name: "Casper and the Ghostly Trio"
region: "PAL-A"
SLES-54436:
name: "Jumanji"
@@ -26876,6 +26882,7 @@ SLES-54644:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SLES-54645:
name: "Valkyrie Profile 2 - Silmeria"
region: "PAL-F"
@@ -26886,6 +26893,7 @@ SLES-54645:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SLES-54646:
name: "Valkyrie Profile 2 - Silmeria"
region: "PAL-G"
@@ -26897,6 +26905,7 @@ SLES-54646:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SLES-54647:
name: "Valkyrie Profile 2 - Silmeria"
region: "PAL-I"
@@ -26908,6 +26917,7 @@ SLES-54647:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SLES-54648:
name: "Valkyrie Profile 2 - Silmeria"
region: "PAL-S"
@@ -26918,6 +26928,7 @@ SLES-54648:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SLES-54653:
name: "Freak Out - Extreme Freeride"
region: "PAL-M5"
@@ -48427,6 +48438,7 @@ SLPM-66419:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SLPM-66420:
name: "フロントミッション4 [Ultimate Hits]"
name-sort: "ふろんとみっしょん4 [Ultimate Hits]"
@@ -50742,6 +50754,7 @@ SLPM-66782:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SLPM-66783:
name: "アイドル雀士 スーチーパイⅣ 「完全限定版・コレクターズエディション」"
name-sort: "あいどるじゃんし すーちーぱい4 [かんぜんげんていばん・これくたーずえでぃしょん]"
@@ -70909,6 +70922,7 @@ SLUS-21452:
textureInsideRT: 1 # Required for swirl battle transition.
nativeScaling: 2 # Fixes depth of field effects and bloom.
roundSprite: 1 # Fixes lines in transitions.
autoFlush: 2 # Fixes shadow rendering in certain scenarios when using DirectX.
SLUS-21453:
name: "Meet the Robinsons"
region: "NTSC-U"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
Copyright 2021 Google Inc. All Rights Reserved.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

View File

@@ -822,7 +822,7 @@
030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000fd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e0000a802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000006f0e0000c802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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:Windows,
03000000c62400003a54000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
@@ -1824,6 +1824,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000005e040000120b00000b050000,Xbox Series 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,
060000005e040000120b00000d050000,Xbox Series 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,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b00000f050000,Xbox Series 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,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b000011050000,Xbox Series X 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,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000130b000022050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,

View File

@@ -21,6 +21,7 @@ float4 ContrastSaturationBrightness(float4 color) // Ported to HLSL
float brt = params.x;
float con = params.y;
float sat = params.z;
float gam = params.w;
// Increase or decrease these values to adjust r, g and b color channels separately
const float AvgLumR = 0.5;
@@ -34,8 +35,10 @@ float4 ContrastSaturationBrightness(float4 color) // Ported to HLSL
float3 intensity = dot(brtColor, LumCoeff);
float3 satColor = lerp(intensity, brtColor, sat);
float3 conColor = lerp(AvgLumin, satColor, con);
color.rgb = conColor;
float3 csb = conColor;
csb = pow(csb, 1.0 / gam);
color.rgb = csb;
return color;
}

View File

@@ -30,6 +30,7 @@ vec4 ContrastSaturationBrightness(vec4 color)
float brt = params.x;
float con = params.y;
float sat = params.z;
float gam = params.w;
// Increase or decrease these values to adjust r, g and b color channels separately
const float AvgLumR = 0.5;
@@ -45,7 +46,10 @@ vec4 ContrastSaturationBrightness(vec4 color)
vec3 satColor = mix(intensity, brtColor, sat);
vec3 conColor = mix(AvgLumin, satColor, con);
color.rgb = conColor;
vec3 csb = conColor;
csb = pow(csb, vec3(1.0 / gam));
color.rgb = csb;
return color;
}

View File

@@ -44,6 +44,7 @@ vec4 ContrastSaturationBrightness(vec4 color)
float brt = params.x;
float con = params.y;
float sat = params.z;
float gam = params.w;
// Increase or decrease these values to adjust r, g and b color channels separately
const float AvgLumR = 0.5;
@@ -59,7 +60,9 @@ vec4 ContrastSaturationBrightness(vec4 color)
vec3 satColor = mix(intensity, brtColor, sat);
vec3 conColor = mix(AvgLumin, satColor, con);
color.rgb = conColor;
vec3 csb = conColor;
csb = pow(csb, vec3(1.0 / gam));
color.rgb = csb;
return color;
}

View File

@@ -18,7 +18,7 @@ find_package(Zstd 1.5.5 REQUIRED)
find_package(LZ4 REQUIRED)
find_package(WebP REQUIRED) # v1.3.2, spews an error on Linux because no pkg-config.
find_package(SDL3 3.2.6 REQUIRED)
find_package(Freetype 2.11.1 REQUIRED)
find_package(Freetype 2.12 REQUIRED)
find_package(plutovg 1.1.0 REQUIRED)
find_package(plutosvg 0.0.7 REQUIRED)

View File

@@ -335,7 +335,7 @@ bool Log::SetFileOutputLevel(LOGLEVEL level, std::string path)
const bool was_enabled = (s_file_level > LOGLEVEL_NONE);
const bool new_enabled = (level > LOGLEVEL_NONE && !path.empty());
if (was_enabled != new_enabled || (new_enabled && path == s_file_path))
if (was_enabled != new_enabled || (new_enabled && path != s_file_path))
{
if (new_enabled)
{

View File

@@ -600,7 +600,7 @@ bool SmallStringBase::starts_with(const char* str, bool case_sensitive) const
return false;
return (case_sensitive) ? (std::strncmp(str, m_buffer, other_length) == 0) :
(CASE_N_COMPARE(str, m_buffer, other_length) == 0);
(CASE_N_COMPARE(str, m_buffer, other_length) == 0);
}
bool SmallStringBase::starts_with(const SmallStringBase& str, bool case_sensitive) const
@@ -610,7 +610,7 @@ bool SmallStringBase::starts_with(const SmallStringBase& str, bool case_sensitiv
return false;
return (case_sensitive) ? (std::strncmp(str.m_buffer, m_buffer, other_length) == 0) :
(CASE_N_COMPARE(str.m_buffer, m_buffer, other_length) == 0);
(CASE_N_COMPARE(str.m_buffer, m_buffer, other_length) == 0);
}
bool SmallStringBase::starts_with(const std::string_view str, bool case_sensitive) const
@@ -620,7 +620,7 @@ bool SmallStringBase::starts_with(const std::string_view str, bool case_sensitiv
return false;
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer, other_length) == 0) :
(CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0);
(CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0);
}
bool SmallStringBase::starts_with(const std::string& str, bool case_sensitive) const
@@ -630,7 +630,7 @@ bool SmallStringBase::starts_with(const std::string& str, bool case_sensitive) c
return false;
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer, other_length) == 0) :
(CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0);
(CASE_N_COMPARE(str.data(), m_buffer, other_length) == 0);
}
bool SmallStringBase::ends_with(const char* str, bool case_sensitive) const
@@ -641,7 +641,7 @@ bool SmallStringBase::ends_with(const char* str, bool case_sensitive) const
u32 start_offset = m_length - other_length;
return (case_sensitive) ? (std::strncmp(str, m_buffer + start_offset, other_length) == 0) :
(CASE_N_COMPARE(str, m_buffer + start_offset, other_length) == 0);
(CASE_N_COMPARE(str, m_buffer + start_offset, other_length) == 0);
}
bool SmallStringBase::ends_with(const SmallStringBase& str, bool case_sensitive) const
@@ -652,7 +652,7 @@ bool SmallStringBase::ends_with(const SmallStringBase& str, bool case_sensitive)
const u32 start_offset = m_length - other_length;
return (case_sensitive) ? (std::strncmp(str.m_buffer, m_buffer + start_offset, other_length) == 0) :
(CASE_N_COMPARE(str.m_buffer, m_buffer + start_offset, other_length) == 0);
(CASE_N_COMPARE(str.m_buffer, m_buffer + start_offset, other_length) == 0);
}
bool SmallStringBase::ends_with(const std::string_view str, bool case_sensitive) const
@@ -663,7 +663,7 @@ bool SmallStringBase::ends_with(const std::string_view str, bool case_sensitive)
const u32 start_offset = m_length - other_length;
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer + start_offset, other_length) == 0) :
(CASE_N_COMPARE(str.data(), m_buffer + start_offset, other_length) == 0);
(CASE_N_COMPARE(str.data(), m_buffer + start_offset, other_length) == 0);
}
bool SmallStringBase::ends_with(const std::string& str, bool case_sensitive) const
@@ -674,7 +674,7 @@ bool SmallStringBase::ends_with(const std::string& str, bool case_sensitive) con
const u32 start_offset = m_length - other_length;
return (case_sensitive) ? (std::strncmp(str.data(), m_buffer + start_offset, other_length) == 0) :
(CASE_N_COMPARE(str.data(), m_buffer + start_offset, other_length) == 0);
(CASE_N_COMPARE(str.data(), m_buffer + start_offset, other_length) == 0);
}
void SmallStringBase::clear()

View File

@@ -47,16 +47,16 @@ AboutDialog::AboutDialog(QWidget* parent)
m_ui.links->setTextInteractionFlags(Qt::TextBrowserInteraction);
m_ui.links->setText(QStringLiteral(
R"(<a href="%1">%2</a> | <a href="%3">%4</a> | <a href="%5">%6</a> | <a href="%7">%8</a> | <a href="%9">%10</a>)")
.arg(getWebsiteUrl())
.arg(tr("Website"))
.arg(getSupportForumsUrl())
.arg(tr("Support Forums"))
.arg(getGitHubRepositoryUrl())
.arg(tr("GitHub Repository"))
.arg(getLicenseUrl())
.arg(tr("License"))
.arg(getThirdPartyLicensesUrl())
.arg(tr("Third-Party Licenses")));
.arg(getWebsiteUrl())
.arg(tr("Website"))
.arg(getSupportForumsUrl())
.arg(tr("Support Forums"))
.arg(getGitHubRepositoryUrl())
.arg(tr("GitHub Repository"))
.arg(getLicenseUrl())
.arg(tr("License"))
.arg(getThirdPartyLicensesUrl())
.arg(tr("Third-Party Licenses")));
connect(m_ui.links, &QLabel::linkActivated, this, &AboutDialog::linksLinkActivated);
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &QDialog::close);

View File

@@ -874,10 +874,10 @@ inline QString DisassemblyView::DisassemblyStringFromAddress(u32 address, QFont
}
lineString = lineString.leftJustified(4, ' ') // Address / symbol
.arg(line.name.c_str())
.arg(line.params.c_str()) // opcode + arguments
.arg(isConditional ? (isConditionalMet ? "# true" : "# false") : "")
.arg(isCurrentPC ? "<--" : "");
.arg(line.name.c_str())
.arg(line.params.c_str()) // opcode + arguments
.arg(isConditional ? (isConditionalMet ? "# true" : "# false") : "")
.arg(isCurrentPC ? "<--" : "");
return lineString;
}

View File

@@ -504,10 +504,13 @@ void MainWindow::createRendererSwitchMenu()
};
const GSRendererType current_renderer = static_cast<GSRendererType>(
Host::GetBaseIntSettingValue("EmuCore/GS", "Renderer", static_cast<int>(GSRendererType::Auto)));
QActionGroup* switch_renderer_group = new QActionGroup(m_ui.menuDebugSwitchRenderer);
for (const GSRendererType renderer : renderers)
{
QAction* action = m_ui.menuDebugSwitchRenderer->addAction(
QString::fromUtf8(Pcsx2Config::GSOptions::GetRendererName(renderer)));
QAction* action = new QAction(
QString::fromUtf8(Pcsx2Config::GSOptions::GetRendererName(renderer)), switch_renderer_group);
action->setCheckable(true);
action->setChecked(current_renderer == renderer);
connect(action,
@@ -515,15 +518,10 @@ void MainWindow::createRendererSwitchMenu()
Host::SetBaseIntSettingValue("EmuCore/GS", "Renderer", static_cast<int>(renderer));
Host::CommitBaseSettingChanges();
g_emu_thread->applySettings();
// clear all others
for (QObject* obj : m_ui.menuDebugSwitchRenderer->children())
{
if (QAction* act = qobject_cast<QAction*>(obj); act && act != action)
act->setChecked(false);
}
});
}
m_ui.menuDebugSwitchRenderer->addActions(switch_renderer_group->actions());
}
void MainWindow::recreate()
@@ -1131,8 +1129,8 @@ bool MainWindow::shouldHideMainWindow() const
{
// NOTE: We can't use isRenderingToMain() here, because this happens post-fullscreen-switch.
return (Host::GetBoolSettingValue("UI", "HideMainWindowWhenRunning", false) && !g_emu_thread->shouldRenderToMain()) ||
(g_emu_thread->shouldRenderToMain() && (isRenderingFullscreen() || m_is_temporarily_windowed)) ||
Host::InNoGUIMode();
(g_emu_thread->shouldRenderToMain() && (isRenderingFullscreen() || m_is_temporarily_windowed)) ||
Host::InNoGUIMode();
}
bool MainWindow::shouldMouseLock() const
@@ -1144,8 +1142,8 @@ bool MainWindow::shouldMouseLock() const
return false;
bool windowsHidden = (!g_debugger_window || g_debugger_window->isHidden()) &&
(!m_controller_settings_window || m_controller_settings_window->isHidden()) &&
(!m_settings_window || m_settings_window->isHidden());
(!m_controller_settings_window || m_controller_settings_window->isHidden()) &&
(!m_settings_window || m_settings_window->isHidden());
return windowsHidden && (isActiveWindow() || isRenderingFullscreen());
}

View File

@@ -1000,21 +1000,21 @@ void EmuThread::updatePerformanceMetrics(bool force)
if (THREAD_VU1)
{
gs_stat = tr("Slot: %1 | Volume: %2% | %3 | EE: %4% | VU: %5% | GS: %6%")
.arg(SaveStateSelectorUI::GetCurrentSlot())
.arg(SPU2::GetOutputVolume())
.arg(gs_stat_str.c_str())
.arg(PerformanceMetrics::GetCPUThreadUsage(), 0, 'f', 0)
.arg(PerformanceMetrics::GetVUThreadUsage(), 0, 'f', 0)
.arg(PerformanceMetrics::GetGSThreadUsage(), 0, 'f', 0);
.arg(SaveStateSelectorUI::GetCurrentSlot())
.arg(SPU2::GetOutputVolume())
.arg(gs_stat_str.c_str())
.arg(PerformanceMetrics::GetCPUThreadUsage(), 0, 'f', 0)
.arg(PerformanceMetrics::GetVUThreadUsage(), 0, 'f', 0)
.arg(PerformanceMetrics::GetGSThreadUsage(), 0, 'f', 0);
}
else
{
gs_stat = tr("Slot: %1 | Volume: %2% | %3 | EE: %4% | GS: %5%")
.arg(SaveStateSelectorUI::GetCurrentSlot())
.arg(SPU2::GetOutputVolume())
.arg(gs_stat_str.c_str())
.arg(PerformanceMetrics::GetCPUThreadUsage(), 0, 'f', 0)
.arg(PerformanceMetrics::GetGSThreadUsage(), 0, 'f', 0);
.arg(SaveStateSelectorUI::GetCurrentSlot())
.arg(SPU2::GetOutputVolume())
.arg(gs_stat_str.c_str())
.arg(PerformanceMetrics::GetCPUThreadUsage(), 0, 'f', 0)
.arg(PerformanceMetrics::GetGSThreadUsage(), 0, 'f', 0);
}
QMetaObject::invokeMethod(g_main_window->getStatusVerboseWidget(), "setText", Qt::QueuedConnection, Q_ARG(const QString&, gs_stat));
@@ -1129,9 +1129,9 @@ void Host::OnAchievementsRefreshed()
game_id = Achievements::GetGameID();
game_info = qApp
->translate("EmuThread", "Game: %1 (%2)\n")
.arg(QString::fromStdString(Achievements::GetGameTitle()))
.arg(game_id);
->translate("EmuThread", "Game: %1 (%2)\n")
.arg(QString::fromStdString(Achievements::GetGameTitle()))
.arg(game_id);
const std::string& rich_presence_string = Achievements::GetRichPresenceString();
if (!rich_presence_string.empty())
@@ -1181,7 +1181,7 @@ void Host::OpenHostFileSelectorAsync(std::string_view title, bool select_directo
if (!filters.empty())
{
filters_str.append(QStringLiteral("All File Types (%1)")
.arg(QString::fromStdString(StringUtil::JoinString(filters.begin(), filters.end(), " "))));
.arg(QString::fromStdString(StringUtil::JoinString(filters.begin(), filters.end(), " "))));
for (const std::string& filter : filters)
{
filters_str.append(

View File

@@ -90,9 +90,7 @@ namespace QtUtils
const int min_column_width = header->minimumSectionSize();
const int scrollbar_width = ((view->verticalScrollBar() && view->verticalScrollBar()->isVisible()) ||
view->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) ?
view->verticalScrollBar()->width() :
0;
view->verticalScrollBarPolicy() == Qt::ScrollBarAlwaysOn) ? view->verticalScrollBar()->width() : 0;
int num_flex_items = 0;
int total_width = 0;
int column_index = 0;

View File

@@ -242,8 +242,8 @@ namespace SettingWidgetBinder
static std::optional<QString> getNullableStringValue(const QCheckBox* widget)
{
return (widget->checkState() == Qt::PartiallyChecked) ?
std::nullopt :
std::optional<QString>(widget->isChecked() ? QStringLiteral("1") : QStringLiteral("0"));
std::nullopt :
std::optional<QString>(widget->isChecked() ? QStringLiteral("1") : QStringLiteral("0"));
}
static void setNullableStringValue(QCheckBox* widget, std::optional<QString> value)
{

View File

@@ -40,7 +40,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.notificationPosition, "Achievements", "NotificationPosition", static_cast<int>(OsdOverlayPos::TopLeft));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.encoreMode, "Achievements", "EncoreMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.spectatorMode, "Achievements", "SpectatorMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unofficialAchievements, "Achievements", "UnofficialTestMode",false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unofficialAchievements, "Achievements", "UnofficialTestMode", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.achievementNotificationsDuration, "Achievements", "NotificationsDuration", Pcsx2Config::AchievementsOptions::DEFAULT_NOTIFICATION_DURATION);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.leaderboardNotificationsDuration, "Achievements", "LeaderboardsDuration", Pcsx2Config::AchievementsOptions::DEFAULT_LEADERBOARD_DURATION);
@@ -57,7 +57,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsWindow* dialog, QWi
dialog->registerWidgetHelp(m_ui.overlays, tr("Enable In-Game Overlays"), tr("Checked"), tr("Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active."));
dialog->registerWidgetHelp(m_ui.overlayPosition, tr("Overlay Position"), tr("Bottom Right"), tr("Determines where achievement overlays are positioned on the screen."));
dialog->registerWidgetHelp(m_ui.notificationPosition, tr("Notification Position"), tr("Top Left"), tr("Determines where achievement notification popups are positioned on the screen."));
dialog->registerWidgetHelp(m_ui.encoreMode, tr("Enable Encore Mode"), tr("Unchecked"),tr("When enabled, each session will behave as if no achievements have been unlocked."));
dialog->registerWidgetHelp(m_ui.encoreMode, tr("Enable Encore Mode"), tr("Unchecked"), tr("When enabled, each session will behave as if no achievements have been unlocked."));
dialog->registerWidgetHelp(m_ui.spectatorMode, tr("Enable Spectator Mode"), tr("Unchecked"), tr("When enabled, PCSX2 will assume all achievements are locked and not send any unlock notifications to the server."));
dialog->registerWidgetHelp(m_ui.unofficialAchievements, tr("Test Unofficial Achievements"), tr("Unchecked"), tr("When enabled, PCSX2 will list achievements from unofficial sets. Please note that these achievements are not tracked by RetroAchievements, so they unlock every time."));
@@ -211,8 +211,8 @@ void AchievementSettingsWidget::updateLoginState()
StringUtil::FromChars<u64>(Host::GetBaseStringSettingValue("Achievements", "LoginTimestamp", "0")).value_or(0);
const QDateTime login_timestamp(QDateTime::fromSecsSinceEpoch(static_cast<qint64>(login_unix_timestamp)));
m_ui.loginStatus->setText(tr("Username: %1\nLogin token generated on %2.")
.arg(QString::fromStdString(username))
.arg(login_timestamp.toString(Qt::TextDate)));
.arg(QString::fromStdString(username))
.arg(login_timestamp.toString(Qt::TextDate)));
m_ui.loginButton->setText(tr("Logout"));
}
else

View File

@@ -54,7 +54,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.patches, "EmuCore", "EnablePatches", true);
dialog->registerWidgetHelp(m_ui.savestateSelector, tr("Use Save State Selector"), tr("Checked"),
tr("Show a save state selector UI when switching slots instead of showing a notification bubble."));
tr("Show a save state selector UI when switching slots instead of showing a notification bubble."));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.savestateCompressionMethod, "EmuCore", "SavestateCompressionType", static_cast<int>(SavestateCompressionMethod::Zstandard));
@@ -220,6 +220,6 @@ void AdvancedSettingsWidget::setClampingMode(int vunum, int index)
void AdvancedSettingsWidget::onSavestateCompressionTypeChanged()
{
const bool uncompressed = (m_dialog->getEffectiveIntValue("EmuCore", "SavestateCompressionType", static_cast<int>(SavestateCompressionMethod::Zstandard)) ==
static_cast<int>(SavestateCompressionMethod::Uncompressed));
static_cast<int>(SavestateCompressionMethod::Uncompressed));
m_ui.savestateCompressionLevel->setDisabled(uncompressed);
}
}

View File

@@ -160,20 +160,20 @@ void AudioSettingsWidget::onSyncModeChanged()
{
const Pcsx2Config::SPU2Options::SPU2SyncMode sync_mode =
Pcsx2Config::SPU2Options::ParseSyncMode(
m_dialog
->getEffectiveStringValue("SPU2/Output", "SyncMode",
Pcsx2Config::SPU2Options::GetSyncModeName(Pcsx2Config::SPU2Options::DEFAULT_SYNC_MODE))
.c_str())
.value_or(Pcsx2Config::SPU2Options::DEFAULT_SYNC_MODE);
m_dialog->getEffectiveStringValue("SPU2/Output", "SyncMode",
Pcsx2Config::SPU2Options::GetSyncModeName(Pcsx2Config::SPU2Options::DEFAULT_SYNC_MODE)
).c_str()
).value_or(Pcsx2Config::SPU2Options::DEFAULT_SYNC_MODE);
m_ui.stretchSettings->setEnabled(sync_mode == Pcsx2Config::SPU2Options::SPU2SyncMode::TimeStretch);
}
AudioBackend AudioSettingsWidget::getEffectiveBackend() const
{
return AudioStream::ParseBackendName(m_dialog->getEffectiveStringValue("SPU2/Output", "Backend",
AudioStream::GetBackendName(Pcsx2Config::SPU2Options::DEFAULT_BACKEND))
.c_str())
.value_or(Pcsx2Config::SPU2Options::DEFAULT_BACKEND);
return AudioStream::ParseBackendName(
m_dialog->getEffectiveStringValue("SPU2/Output", "Backend",
AudioStream::GetBackendName(Pcsx2Config::SPU2Options::DEFAULT_BACKEND)
).c_str()
).value_or(Pcsx2Config::SPU2Options::DEFAULT_BACKEND);
}
void AudioSettingsWidget::updateDriverNames()
@@ -263,17 +263,17 @@ void AudioSettingsWidget::updateLatencyLabel()
if (expand_buffer_ms > 0)
{
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms buffer + %3 ms expand + %4 ms output)")
.arg(config_buffer_ms + expand_buffer_ms + output_latency_ms)
.arg(config_buffer_ms)
.arg(expand_buffer_ms)
.arg(output_latency_ms));
.arg(config_buffer_ms + expand_buffer_ms + output_latency_ms)
.arg(config_buffer_ms)
.arg(expand_buffer_ms)
.arg(output_latency_ms));
}
else
{
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms buffer + %3 ms output)")
.arg(config_buffer_ms + output_latency_ms)
.arg(config_buffer_ms)
.arg(output_latency_ms));
.arg(config_buffer_ms + output_latency_ms)
.arg(config_buffer_ms)
.arg(output_latency_ms));
}
}
else
@@ -281,8 +281,8 @@ void AudioSettingsWidget::updateLatencyLabel()
if (expand_buffer_ms > 0)
{
m_ui.bufferingLabel->setText(tr("Maximum Latency: %1 ms (%2 ms expand, minimum output latency unknown)")
.arg(expand_buffer_ms + config_buffer_ms)
.arg(expand_buffer_ms));
.arg(expand_buffer_ms + config_buffer_ms)
.arg(expand_buffer_ms));
}
else
{

View File

@@ -206,7 +206,7 @@ void ControllerSettingsWindow::onRenameProfileClicked()
{
std::string game_settings_path(game_settings.FileName.c_str());
std::unique_ptr<INISettingsInterface> update_sif(std::make_unique<INISettingsInterface>(std::move(game_settings_path)));
update_sif->Load();
if (!old_profile_name.compare(update_sif->GetStringValue("EmuCore", "InputProfileName")))
@@ -458,9 +458,9 @@ void ControllerSettingsWindow::createWidgets()
QListWidgetItem* item = new QListWidgetItem();
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
item->setText(mtap_enabled[port] ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) :
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
item->setText(mtap_enabled[port] ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name))
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
: tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
item->setIcon(m_port_bindings[global_slot]->getIcon());
item->setData(Qt::UserRole, QVariant(global_slot));
m_ui.settingsCategory->addItem(item);
@@ -514,9 +514,9 @@ void ControllerSettingsWindow::updateListDescription(u32 global_slot, Controller
const QString display_name = QString::fromUtf8(ci ? ci->GetLocalizedName() : "Unknown");
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
item->setText(mtap_enabled ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) :
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
item->setText(mtap_enabled ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name))
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
: tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
item->setIcon(widget->getIcon());
break;
}

View File

@@ -290,7 +290,7 @@ void DEV9SettingsWidget::onEthDeviceChanged(int index)
void DEV9SettingsWidget::onEthDHCPInterceptChanged(Qt::CheckState state)
{
const bool enabled = (state == Qt::CheckState::PartiallyChecked ? Host::GetBaseBoolSettingValue("DEV9/Eth", "InterceptDHCP", false) : state) ||
((m_adapter_options & AdapterOptions::DHCP_ForcedOn) == AdapterOptions::DHCP_ForcedOn);
((m_adapter_options & AdapterOptions::DHCP_ForcedOn) == AdapterOptions::DHCP_ForcedOn);
// clang-format off
const bool ipOverride = (m_adapter_options & AdapterOptions::DHCP_OverrideIP) == AdapterOptions::DHCP_OverrideIP;

View File

@@ -55,11 +55,11 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* dialog, QWidget
connect(m_ui.manuallySetRealTimeClock, &QCheckBox::checkStateChanged, this, &EmulationSettingsWidget::onManuallySetRealTimeClockChanged);
EmulationSettingsWidget::onManuallySetRealTimeClockChanged();
m_ui.eeCycleRate->insertItem(
0, tr("Use Global Setting [%1]")
.arg(m_ui.eeCycleRate->itemText(
std::clamp(Host::GetBaseIntSettingValue("EmuCore/Speedhacks", "EECycleRate", DEFAULT_EE_CYCLE_RATE) - MINIMUM_EE_CYCLE_RATE,
0, MAXIMUM_EE_CYCLE_RATE - MINIMUM_EE_CYCLE_RATE))));
m_ui.eeCycleRate->insertItem(0,
tr("Use Global Setting [%1]")
.arg(m_ui.eeCycleRate->itemText(
std::clamp(Host::GetBaseIntSettingValue("EmuCore/Speedhacks", "EECycleRate", DEFAULT_EE_CYCLE_RATE) - MINIMUM_EE_CYCLE_RATE,
0, MAXIMUM_EE_CYCLE_RATE - MINIMUM_EE_CYCLE_RATE))));
// Disable cheats, use the cheats panel instead (move fastcvd up in its spot).
const int count = m_ui.systemSettingsLayout->count();
@@ -92,9 +92,9 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* dialog, QWidget
const std::optional<int> cycle_rate =
m_dialog->getIntValue("EmuCore/Speedhacks", "EECycleRate", sif ? std::nullopt : std::optional<int>(DEFAULT_EE_CYCLE_RATE));
m_ui.eeCycleRate->setCurrentIndex(cycle_rate.has_value() ? (std::clamp(cycle_rate.value(), MINIMUM_EE_CYCLE_RATE, MAXIMUM_EE_CYCLE_RATE) +
(0 - MINIMUM_EE_CYCLE_RATE) + static_cast<int>(m_dialog->isPerGameSettings())) :
0);
m_ui.eeCycleRate->setCurrentIndex(cycle_rate.has_value() ? (std::clamp(cycle_rate.value(), MINIMUM_EE_CYCLE_RATE, MAXIMUM_EE_CYCLE_RATE)
+ (0 - MINIMUM_EE_CYCLE_RATE) + static_cast<int>(m_dialog->isPerGameSettings()))
: 0);
connect(m_ui.eeCycleRate, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
std::optional<int> value;
if (!m_dialog->isPerGameSettings() || index > 0)
@@ -164,9 +164,9 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* dialog, QWidget
tr("Manually set a real-time clock to use for the virtual PlayStation 2 instead of using your OS' system clock."));
dialog->registerWidgetHelp(m_ui.rtcDateTime, tr("Real-Time Clock"), tr("Current date and time"),
tr("Real-time clock (RTC) used by the virtual PlayStation 2. Date format is the same as the one used by your OS. "
"This time is only applied upon booting the PS2; changing it while in-game will have no effect. "
"NOTE: This assumes you have your PS2 set to the default timezone of GMT+0 and default DST of Summer Time. "
"Some games require an RTC date/time set after their release date."));
"This time is only applied upon booting the PS2; changing it while in-game will have no effect. "
"NOTE: This assumes you have your PS2 set to the default timezone of GMT+0 and default DST of Summer Time. "
"Some games require an RTC date/time set after their release date."));
updateOptimalFramePacing();
updateUseVSyncForTimingEnabled();

View File

@@ -205,7 +205,7 @@ void GameCheatSettingsWidget::reloadList()
{
u32 num_unlabelled_codes = 0;
bool showAllCRCS = m_ui.allCRCsCheckbox->isChecked();
m_patches = Patch::GetPatchInfo(m_dialog->getSerial(), m_dialog->getDiscCRC(), true, showAllCRCS, & num_unlabelled_codes);
m_patches = Patch::GetPatchInfo(m_dialog->getSerial(), m_dialog->getDiscCRC(), true, showAllCRCS, &num_unlabelled_codes);
m_enabled_patches =
m_dialog->getSettingsInterface()->GetStringList(Patch::CHEATS_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY);

View File

@@ -340,15 +340,15 @@ void GameSummaryWidget::onVerifyClicked()
if (!hentry->version.empty())
{
setVerifyResult(tr("Verified as %1 [%2] (Version %3).")
.arg(QString::fromStdString(hentry->name))
.arg(QString::fromStdString(hentry->serial))
.arg(QString::fromStdString(hentry->version)));
.arg(QString::fromStdString(hentry->name))
.arg(QString::fromStdString(hentry->serial))
.arg(QString::fromStdString(hentry->version)));
}
else
{
setVerifyResult(tr("Verified as %1 [%2].")
.arg(QString::fromStdString(hentry->name))
.arg(QString::fromStdString(hentry->serial)));
.arg(QString::fromStdString(hentry->name))
.arg(QString::fromStdString(hentry->serial)));
}
}
else

View File

@@ -131,11 +131,16 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowVideoCapture, "EmuCore/GS", "OsdShowVideoCapture", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowInputRec, "EmuCore/GS", "OsdShowInputRec", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdWarnAboutUnsafeSettings, "EmuCore", "OsdWarnAboutUnsafeSettings", true);
//////////////////////////////////////////////////////////////////////////
// Post-Processing Settings
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fxaa, "EmuCore/GS", "fxaa", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.shadeBoost, "EmuCore/GS", "ShadeBoost", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.shadeBoostBrightness, "EmuCore/GS", "ShadeBoost_Brightness", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.shadeBoostContrast, "EmuCore/GS", "ShadeBoost_Contrast", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.shadeBoostSaturation, "EmuCore/GS", "ShadeBoost_Saturation", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.shadeBoostBrightness, "EmuCore/GS", "ShadeBoost_Brightness", Pcsx2Config::GSOptions::DEFAULT_SHADEBOOST_BRIGHTNESS);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.shadeBoostContrast, "EmuCore/GS", "ShadeBoost_Contrast", Pcsx2Config::GSOptions::DEFAULT_SHADEBOOST_CONTRAST);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.shadeBoostGamma, "EmuCore/GS", "ShadeBoost_Gamma", Pcsx2Config::GSOptions::DEFAULT_SHADEBOOST_GAMMA);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.shadeBoostSaturation, "EmuCore/GS", "ShadeBoost_Saturation", Pcsx2Config::GSOptions::DEFAULT_SHADEBOOST_SATURATION);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.tvShader, "EmuCore/GS", "TVShader", DEFAULT_TV_SHADER_MODE);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.casMode, "EmuCore/GS", "CASMode", static_cast<int>(GSCASMode::Disabled));
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.casSharpness, "EmuCore/GS", "CASSharpness", DEFAULT_CAS_SHARPNESS);
@@ -727,6 +732,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.shadeBoostContrast, tr("Contrast"), tr("50"), tr("Adjusts contrast. 50 is normal."));
dialog->registerWidgetHelp(m_ui.shadeBoostGamma, tr("Gamma"), tr("50"), tr("Adjusts gamma. 50 is normal."));
dialog->registerWidgetHelp(m_ui.shadeBoostSaturation, tr("Saturation"), tr("50"), tr("Adjusts saturation. 50 is normal."));
dialog->registerWidgetHelp(m_ui.tvShader, tr("TV Shader"), tr("None (Default)"),
@@ -944,6 +951,7 @@ void GraphicsSettingsWidget::onShadeBoostChanged()
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "ShadeBoost", false);
m_ui.shadeBoostBrightness->setEnabled(enabled);
m_ui.shadeBoostContrast->setEnabled(enabled);
m_ui.shadeBoostGamma->setEnabled(enabled);
m_ui.shadeBoostSaturation->setEnabled(enabled);
}
@@ -1272,8 +1280,8 @@ void GraphicsSettingsWidget::populateUpscaleMultipliers(u32 max_upscale_multipli
m_ui.upscaleMultiplier->clear();
const u32 max_shown_multiplier = m_ui.extendedUpscales && m_ui.extendedUpscales->checkState() == Qt::Checked ?
max_upscale_multiplier :
std::min(max_upscale_multiplier, max_non_advanced_multiplier);
max_upscale_multiplier :
std::min(max_upscale_multiplier, max_non_advanced_multiplier);
for (const auto& [name, value] : templates)
{
if (value > max_shown_multiplier)

View File

@@ -55,7 +55,7 @@
<item>
<widget class="QTabWidget" name="tabs">
<property name="currentIndex">
<number>9</number>
<number>0</number>
</property>
<property name="documentMode">
<bool>true</bool>
@@ -1433,6 +1433,23 @@
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="gammaLabel">
<property name="text">
<string>Gamma:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="shadeBoostGamma">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="saturationLabel">
<property name="text">

View File

@@ -260,7 +260,7 @@ void InputBindingWidget::clearBinding()
void InputBindingWidget::reloadBinding()
{
m_bindings_settings = m_sif ? m_sif->GetStringList(m_section_name.c_str(), m_key_name.c_str()) :
Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
m_bindings_ui.clear();
m_bindings_ui.reserve(m_bindings_settings.size());

View File

@@ -250,7 +250,7 @@ void MemoryCardConvertDialog::ConvertCard()
baseName.replace(extensionPos, 4, "");
// Add _converted to the end of it
baseName.append("_converted");
size_t num = 0;
QString destName = baseName;
destName.append(".ps2");
@@ -322,5 +322,5 @@ void MemoryCardConvertDialog::SetType_Folder()
void MemoryCardConvertDialog::FileOpenError(const QString errmsg)
{
QMessageBox::critical(this, tr("Cannot Convert Memory Card"),tr("There was an error when accessing the memory card directory. Error message: %0").arg(errmsg));
QMessageBox::critical(this, tr("Cannot Convert Memory Card"), tr("There was an error when accessing the memory card directory. Error message: %0").arg(errmsg));
}

View File

@@ -42,7 +42,7 @@ private:
void SetType_64();
void SetType_Folder();
void FileOpenError(const QString errmsg);
Ui::MemoryCardConvertDialog m_ui;
bool isSetup = false;
@@ -57,7 +57,7 @@ private:
static constexpr u32 FLAGS = FILESYSTEM_FIND_RECURSIVE | FILESYSTEM_FIND_FOLDERS | FILESYSTEM_FIND_FILES;
};
// Card capacities computed from freshly formatted superblocks.
// Card capacities computed from freshly formatted superblocks.
namespace CardCapacity
{
static constexpr size_t _8_MB = 0x1f40 * 512 * 2; //(0x1fc7 - 0x29) * 2 * 512;

View File

@@ -75,7 +75,7 @@ bool MemoryCardConvertWorker::ConvertToFile(const std::string& srcFolderName, co
{
sourceFolderMemoryCard.Read(sourceBuffer.data() + address, address, FolderMemoryCard::PageSizeRaw);
address += FolderMemoryCard::PageSizeRaw;
// Only report progress every 16 pages. Substantially speeds up the conversion.
if (address % (FolderMemoryCard::PageSizeRaw * 16) == 0)
this->SetProgressValue(address);
@@ -140,7 +140,7 @@ bool MemoryCardConvertWorker::ConvertToFolder(const std::string& srcFileName, co
{
targetFolderMemoryCard.Save(sourceBuffer.data() + address, address, FolderMemoryCard::PageSizeRaw);
address += FolderMemoryCard::PageSizeRaw;
// Only report progress every 16 pages. Substantially speeds up the conversion.
if (address % (FolderMemoryCard::PageSizeRaw * 16) == 0)
this->SetProgressValue(address + (i * sourceBuffer.size()));

View File

@@ -101,7 +101,7 @@ void MemoryCardCreateDialog::createCard()
const QString name = m_ui.name->text();
const std::string name_str = QStringLiteral("%1.%2").arg(name)
.arg((m_fileType == MemoryCardFileType::PS1) ? QStringLiteral("mcr") : QStringLiteral("ps2"))
.toStdString();
.toStdString();
if (!Path::IsValidFileName(name_str, false))
{
QMessageBox::critical(this, tr("Create Memory Card"),
@@ -123,7 +123,7 @@ void MemoryCardCreateDialog::createCard()
return;
}
#ifdef _WIN32
#ifdef _WIN32
if (m_type == MemoryCardType::File)
{
const std::string fullPath = Path::Combine(EmuFolders::MemoryCards, name_str);

File diff suppressed because it is too large Load Diff

View File

@@ -701,13 +701,13 @@ uint32_t Achievements::ClientReadMemory(uint32_t address, uint8_t* buffer, uint3
void Achievements::ClientServerCall(
const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client)
{
HTTPDownloader::Request::Callback hd_callback = [callback, callback_data](s32 status_code, const std::string& content_type,
HTTPDownloader::Request::Data data) {
HTTPDownloader::Request::Callback hd_callback = [callback, callback_data](s32 status_code, const std::string& content_type, HTTPDownloader::Request::Data data)
{
rc_api_server_response_t rr;
rr.http_status_code = (status_code <= 0) ? (status_code == HTTPDownloader::HTTP_STATUS_CANCELLED ?
RC_API_SERVER_RESPONSE_CLIENT_ERROR :
RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR) :
status_code;
RC_API_SERVER_RESPONSE_CLIENT_ERROR :
RC_API_SERVER_RESPONSE_RETRYABLE_CLIENT_ERROR)
: status_code;
rr.body_length = data.size();
rr.body = reinterpret_cast<const char*>(data.data());
@@ -1486,7 +1486,7 @@ bool Achievements::ResetHardcoreMode(bool is_booting)
// because the gameid can be cached, and identify immediately on GameChanged(),
// which gets called before ResetHardcoreMode().
const bool wanted_hardcore_mode = (IsLoggedInOrLoggingIn() || s_load_game_request) &&
EmuConfig.Achievements.HardcoreMode;
EmuConfig.Achievements.HardcoreMode;
if (s_hardcore_mode == wanted_hardcore_mode)
return false;

View File

@@ -12,13 +12,15 @@ using namespace R5900::Interpreter;
//#define CP2COND (vif1Regs.stat.VEW)
//Run the FINISH either side of the VCALL's as we have no control over it past here.
void VCALLMS() {
void VCALLMS()
{
_vu0FinishMicro();
vu0ExecMicro(((cpuRegs.code >> 6) & 0x7FFF));
//vif0Regs.stat.VEW = false;
}
void VCALLMSR() {
void VCALLMSR()
{
_vu0FinishMicro();
vu0ExecMicro(VU0.VI[REG_CMSAR0].US[0]);
//vif0Regs.stat.VEW = false;
@@ -50,7 +52,7 @@ void BC2FL()
}
else
{
cpuRegs.pc+= 4;
cpuRegs.pc += 4;
}
}
void BC2TL()
@@ -62,6 +64,6 @@ void BC2TL()
}
else
{
cpuRegs.pc+= 4;
cpuRegs.pc += 4;
}
}

View File

@@ -23,7 +23,7 @@ namespace
// When this happens, the cache still fills with the data and when it gets evicted the data is lost.
// We don't emulate memory access on a logic level, so we need to ensure that we don't try to load/store to a non-existant physical address.
// This fixes the Find My Own Way demo.
// The lower parts of a cache tags structure is as follows:
// 31 - 12: The physical address cache tag.
// 11: Used by PCSX2 to indicate if the physical address is valid.
@@ -468,7 +468,7 @@ namespace R5900
const int way = addr & 0x1;
CacheLine line = cache.lineAt(index, way);
line.tag.setAddr(cpuRegs.CP0.n.TagLo);
line.tag.setAddr(cpuRegs.CP0.n.TagLo);
line.tag.rawValue &= ~CacheTag::ALL_FLAGS;
line.tag.rawValue |= (cpuRegs.CP0.n.TagLo & CacheTag::ALL_FLAGS);

View File

@@ -704,6 +704,11 @@ struct Pcsx2Config
static constexpr int DEFAULT_AUDIO_CAPTURE_BITRATE = 192;
static const char* DEFAULT_CAPTURE_CONTAINER;
static constexpr int DEFAULT_SHADEBOOST_BRIGHTNESS = 50;
static constexpr int DEFAULT_SHADEBOOST_CONTRAST = 50;
static constexpr int DEFAULT_SHADEBOOST_GAMMA = 50;
static constexpr int DEFAULT_SHADEBOOST_SATURATION = 50;
union
{
u64 bitset;
@@ -837,9 +842,10 @@ struct Pcsx2Config
s8 OverrideTextureBarriers = -1;
u8 CAS_Sharpness = 50;
u8 ShadeBoost_Brightness = 50;
u8 ShadeBoost_Contrast = 50;
u8 ShadeBoost_Saturation = 50;
u8 ShadeBoost_Brightness = DEFAULT_SHADEBOOST_BRIGHTNESS;
u8 ShadeBoost_Contrast = DEFAULT_SHADEBOOST_CONTRAST;
u8 ShadeBoost_Saturation = DEFAULT_SHADEBOOST_SATURATION;
u8 ShadeBoost_Gamma = DEFAULT_SHADEBOOST_GAMMA;
u8 PNGCompressionLevel = 1;
u16 SWExtraThreads = 2;

View File

@@ -234,7 +234,7 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca
{
hBlank /= 2;
hRender /= 2;
}
}
//TODO: Carry fixed-point math all the way through the entire vsync and hsync counting processes, and continually apply rounding
//as needed for each scheduled v/hsync related event. Much better to handle than this messed state.
@@ -412,8 +412,8 @@ void UpdateVSyncRate(bool force)
s32 vdiff = vsyncCounter.deltaCycles;
hsyncCounter.deltaCycles = (hsyncCounter.Mode == MODE_HBLANK) ? vSyncInfo.hBlank : vSyncInfo.hRender;
vsyncCounter.deltaCycles = (vsyncCounter.Mode == MODE_GSBLANK) ?
vSyncInfo.GSBlank :
((vsyncCounter.Mode == MODE_VBLANK) ? vSyncInfo.Blank : vSyncInfo.Render);
vSyncInfo.GSBlank :
((vsyncCounter.Mode == MODE_VBLANK) ? vSyncInfo.Blank : vSyncInfo.Render);
hsyncCounter.startCycle += hdiff - hsyncCounter.deltaCycles;
vsyncCounter.startCycle += vdiff - vsyncCounter.deltaCycles;
@@ -653,10 +653,10 @@ __fi void rcntUpdate_hScanline()
}
else
{ //HBLANK START / HRENDER End
// set up the hblank's start and end cycle information:
hsyncCounter.startCycle += vSyncInfo.hRender; // start (absolute cycle value)
hsyncCounter.deltaCycles = vSyncInfo.hBlank; // endpoint (delta from start value)
hsyncCounter.deltaCycles = vSyncInfo.hBlank; // endpoint (delta from start value)
if (!GSSMODE1reg.SINT)
{
if (!CSRreg.HSINT)
@@ -765,7 +765,7 @@ __fi void rcntUpdate()
rcntSyncCounter(i);
if (counters[i].mode.ClockSource == 0x3 || !rcntCanCount(i)) // don't count hblank sources
continue;
continue;
_cpuTestOverflow(i);
_cpuTestTarget(i);
@@ -813,7 +813,7 @@ static __fi void rcntStartGate(bool isVblank, u32 sCycle)
switch (counters[i].mode.GateMode)
{
case 0x0: //Count When Signal is low (V_RENDER ONLY)
case 0x0: // Count When Signal is low (V_RENDER ONLY)
// Just set the start cycle -- counting will be done as needed
// for events (overflows, targets, mode changes, and the gate off below)
@@ -955,7 +955,7 @@ __fi u32 rcntRcount(int index)
u32 ret;
rcntSyncCounter(index);
ret = counters[index].count;
// Spams the Console.

View File

@@ -355,10 +355,10 @@ bool GSopen(const Pcsx2Config::GSOptions& config, GSRendererType renderer, u8* b
if (!res)
{
Host::ReportErrorAsync(
"Error", fmt::format(TRANSLATE_FS("GS","Failed to create render device. This may be due to your GPU not supporting the "
"chosen renderer ({}), or because your graphics drivers need to be updated."),
Pcsx2Config::GSOptions::GetRendererName(GSConfig.Renderer)));
Host::ReportErrorAsync("Error",
fmt::format(TRANSLATE_FS("GS", "Failed to create render device. This may be due to your GPU not supporting the "
"chosen renderer ({}), or because your graphics drivers need to be updated."),
Pcsx2Config::GSOptions::GetRendererName(GSConfig.Renderer)));
return false;
}
@@ -500,7 +500,7 @@ void GSEndCapture()
{
if (g_gs_renderer)
g_gs_renderer->EndCapture();
}
}
void GSPresentCurrentFrame()
{
@@ -661,7 +661,7 @@ void GSgetStats(SmallStringBase& info)
const double fillrate = pm.Get(GSPerfMon::Fillrate);
double pps = fps * fillrate;
char prefix = '\0';
if (pps >= 170000000)
{
pps /= 1073741824; // Gpps
@@ -689,7 +689,7 @@ void GSgetStats(SmallStringBase& info)
(int)pm.Get(GSPerfMon::Draw),
pm.Get(GSPerfMon::Swizzle) / 1024,
pm.Get(GSPerfMon::Unswizzle) / 1024,
pps,prefix);
pps, prefix);
}
else if (GSCurrentRenderer == GSRendererType::Null)
{

View File

@@ -1384,12 +1384,12 @@ TinyString GSCapture::GetElapsedTime()
if (s_video_stream)
{
seconds = (s_next_video_pts * static_cast<s64>(s_video_codec_context->time_base.num)) /
static_cast<s64>(s_video_codec_context->time_base.den);
static_cast<s64>(s_video_codec_context->time_base.den);
}
else if (s_audio_stream)
{
seconds = (s_next_audio_pts * static_cast<s64>(s_audio_codec_context->time_base.num)) /
static_cast<s64>(s_audio_codec_context->time_base.den);
static_cast<s64>(s_audio_codec_context->time_base.den);
}
else
{

View File

@@ -38,7 +38,7 @@ namespace GSCapture
CodecList GetVideoCodecList(const char* container);
CodecList GetAudioCodecList(const char* container);
using FormatName = std::pair<int , std::string>; // id,name
using FormatName = std::pair<int, std::string>; // id,name
using FormatList = std::vector<FormatName>;
FormatList GetVideoFormatList(const char* codec);
}; // namespace GSCapture

View File

@@ -185,7 +185,7 @@ bool GSClut::CanLoadCLUT(const GIFRegTEX0& TEX0, const bool update_CBP)
case 4:
if (m_CBP[0] == TEX0.CBP)
return false;
if(update_CBP)
if (update_CBP)
m_CBP[0] = TEX0.CBP;
break;
case 5:
@@ -531,7 +531,7 @@ void GSClut::GetAlphaMinMax32(int& amin_out, int& amax_out)
void GSClut::WriteCLUT_T32_I8_CSM1(const u32* RESTRICT src, u16* RESTRICT clut, u16 offset)
{
// 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 ++)
for (int i = offset; i < 16; i++)
{
const int off = i << 4; // WriteCLUT_T32_I4_CSM1 loads 16 at a time
// Source column

View File

@@ -509,15 +509,15 @@ GSVector4i GSLocalMemory::GetRectForPageOffset(u32 base_bp, u32 offset_bp, u32 b
return GSVector4i(pgs * page_offset_xy).xyxy() + GSVector4i::loadh(pgs);
}
bool GSLocalMemory::HasOverlap(const u32 src_bp, const u32 src_bw, const u32 src_psm, const GSVector4i src_rect
, const u32 dst_bp, const u32 dst_bw, const u32 dst_psm, const GSVector4i dst_rect)
bool GSLocalMemory::HasOverlap(const u32 src_bp, const u32 src_bw, const u32 src_psm, const GSVector4i src_rect,
const u32 dst_bp, const u32 dst_bw, const u32 dst_psm, const GSVector4i dst_rect)
{
const u32 src_start_bp = GSLocalMemory::GetStartBlockAddress(src_bp, src_bw, src_psm, src_rect) & ~(GS_BLOCKS_PER_PAGE - 1);
const u32 dst_start_bp = GSLocalMemory::GetStartBlockAddress(dst_bp, dst_bw, dst_psm, dst_rect) & ~(GS_BLOCKS_PER_PAGE - 1);
u32 src_end_bp = ((GSLocalMemory::GetEndBlockAddress(src_bp, src_bw, src_psm, src_rect) + 1) + (GS_BLOCKS_PER_PAGE - 1)) & ~(GS_BLOCKS_PER_PAGE - 1);
u32 dst_end_bp = ((GSLocalMemory::GetEndBlockAddress(dst_bp, dst_bw, dst_psm, dst_rect) + 1) + (GS_BLOCKS_PER_PAGE - 1)) & ~(GS_BLOCKS_PER_PAGE - 1);
if (src_start_bp == src_end_bp)
{
src_end_bp = (src_end_bp + GS_BLOCKS_PER_PAGE) & ~(GS_MAX_BLOCKS - 1);

View File

@@ -23,7 +23,7 @@ void GSPerfMon::EndFrame(bool frame_only)
{
m_frame++;
if(!frame_only)
if (!frame_only)
m_count++;
}

View File

@@ -2916,14 +2916,14 @@ void GSState::GrowVertexBuffer()
u32 old_size;
u32 new_size;
};
std::vector<AllocDesc> alloc_desc = {
const std::array<AllocDesc, 5> alloc_desc = {{
{reinterpret_cast<void**>(&m_vertex.buff), old_vertex_size, new_vertex_size},
// discard contents of buff_copy by setting old_size = 0
{reinterpret_cast<void**>(&m_vertex.buff_copy), 0, new_vertex_size},
{reinterpret_cast<void**>(&m_draw_vertex.buff), old_vertex_size, new_vertex_size},
{reinterpret_cast<void**>(&m_index.buff), old_index_size, new_index_size},
{reinterpret_cast<void**>(&m_draw_index.buff), old_index_size, new_index_size}
};
}};
// For logging
u32 total_size = 0;

View File

@@ -835,6 +835,7 @@ void GSDevice::ShadeBoost()
static_cast<float>(GSConfig.ShadeBoost_Brightness) * (1.0f / 50.0f),
static_cast<float>(GSConfig.ShadeBoost_Contrast) * (1.0f / 50.0f),
static_cast<float>(GSConfig.ShadeBoost_Saturation) * (1.0f / 50.0f),
static_cast<float>(GSConfig.ShadeBoost_Gamma) * (1.0f / 50.0f),
};
DoShadeBoost(m_current, m_target_tmp, params);

View File

@@ -586,8 +586,8 @@ void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
{
// Check all three formats, since the feature means any can be used.
m_features.dxt_textures = SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC1_UNORM) &&
SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC2_UNORM) &&
SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC3_UNORM);
SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC2_UNORM) &&
SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC3_UNORM);
m_features.bptc_textures = SupportsTextureFormat(m_dev.get(), DXGI_FORMAT_BC7_UNORM);
@@ -595,8 +595,8 @@ void GSDevice11::SetFeatures(IDXGIAdapter1* adapter)
m_features.cas_sharpening = (m_feature_level >= D3D_FEATURE_LEVEL_11_0);
m_max_texture_size = (m_feature_level >= D3D_FEATURE_LEVEL_11_0) ?
D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION :
D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION :
D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
}
bool GSDevice11::HasSurface() const
@@ -752,7 +752,7 @@ bool GSDevice11::CreateSwapChain()
else
{
Console.ErrorFmt("D3D11: GetParent() on swap chain to get factory failed: {}", Error::CreateHResult(hr).GetDescription());
}
}
if (!CreateSwapChainRTV())
{
@@ -801,7 +801,7 @@ bool GSDevice11::CreateSwapChainRTV()
SUCCEEDED(m_swap_chain->GetDesc(&desc)))
{
m_window_info.surface_refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) /
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
}
}
@@ -1263,7 +1263,7 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha, ShaderConvert shader)
{
const u8 index = static_cast<u8>(red) | (static_cast<u8>(green) << 1) | (static_cast<u8>(blue) << 2) |
(static_cast<u8>(alpha) << 3);
(static_cast<u8>(alpha) << 3);
StretchRect(sTex, sRect, dTex, dRect, m_convert.ps[static_cast<int>(shader)].get(), nullptr,
m_convert.bs[index].get(), false);
}
@@ -1316,7 +1316,7 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
};
IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices));
IASetVertexBuffer(vertices, sizeof(vertices[0]), std::size(vertices));
IASetInputLayout(m_convert.il.get());
IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
@@ -1795,8 +1795,8 @@ void GSDevice11::SetupPS(const PSSelector& sel, const GSHWDrawConfig::PSConstant
}};
const u8 index = (static_cast<u8>(ssel.IsMipFilterLinear()) << 2) |
(static_cast<u8>(ssel.IsMagFilterLinear()) << 1) |
static_cast<u8>(ssel.IsMinFilterLinear());
(static_cast<u8>(ssel.IsMagFilterLinear()) << 1) |
static_cast<u8>(ssel.IsMinFilterLinear());
sd.Filter = filters[index];
}

View File

@@ -63,7 +63,7 @@ bool GSTexture11::Update(const GSVector4i& r, const void* data, int pitch, int l
g_perfmon.Put(GSPerfMon::TextureUploads, 1);
const u32 bs = GetCompressedBlockSize();
const D3D11_BOX box = {Common::AlignDownPow2((u32)r.left, bs), Common::AlignDownPow2((u32)r.top, bs), 0U,
Common::AlignUpPow2((u32)r.right, bs), Common::AlignUpPow2((u32)r.bottom, bs), 1U};
const UINT subresource = layer; // MipSlice + (ArraySlice * MipLevels).

View File

@@ -134,7 +134,7 @@ bool GSDevice12::SupportsTextureFormat(DXGI_FORMAT format)
D3D12_FEATURE_DATA_FORMAT_SUPPORT support = {format};
return SUCCEEDED(m_device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &support, sizeof(support))) &&
(support.Support1 & required) == required;
(support.Support1 & required) == required;
}
u32 GSDevice12::GetAdapterVendorID() const
@@ -958,7 +958,7 @@ bool GSDevice12::CreateSwapChainRTV()
SUCCEEDED(m_swap_chain->GetDesc(&desc)))
{
m_window_info.surface_refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) /
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
}
}
@@ -1238,8 +1238,8 @@ bool GSDevice12::CheckFeatures(const u32& vendor_id)
m_features.vs_expand = !GSConfig.DisableVertexShaderExpand;
m_features.dxt_textures = SupportsTextureFormat(DXGI_FORMAT_BC1_UNORM) &&
SupportsTextureFormat(DXGI_FORMAT_BC2_UNORM) &&
SupportsTextureFormat(DXGI_FORMAT_BC3_UNORM);
SupportsTextureFormat(DXGI_FORMAT_BC2_UNORM) &&
SupportsTextureFormat(DXGI_FORMAT_BC3_UNORM);
m_features.bptc_textures = SupportsTextureFormat(DXGI_FORMAT_BC7_UNORM);
m_max_texture_size = D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
@@ -1643,8 +1643,8 @@ void GSDevice12::BeginRenderPassForStretchRect(
GSTexture12* dTex, const GSVector4i& dtex_rc, const GSVector4i& dst_rc, bool allow_discard)
{
const D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE load_op = (allow_discard && dst_rc.eq(dtex_rc)) ?
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD :
GetLoadOpForTexture(dTex);
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_DISCARD :
GetLoadOpForTexture(dTex);
dTex->SetState(GSTexture::State::Dirty);
if (dTex->GetType() != GSTexture::Type::DepthStencil)
@@ -1742,8 +1742,8 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
(sTex[0] && (sTex[0]->GetState() == GSTexture::State::Dirty ||
(sTex[0]->GetState() == GSTexture::State::Cleared || sTex[0]->GetClearColor() != 0)));
const bool has_input_1 = (PMODE.SLBG == 0 || feedback_write_2_but_blend_bg) && sTex[1] &&
(sTex[1]->GetState() == GSTexture::State::Dirty ||
(sTex[1]->GetState() == GSTexture::State::Cleared || sTex[1]->GetClearColor() != 0));
(sTex[1]->GetState() == GSTexture::State::Dirty ||
(sTex[1]->GetState() == GSTexture::State::Cleared || sTex[1]->GetClearColor() != 0));
if (has_input_0)
{
static_cast<GSTexture12*>(sTex[0])->CommitClear();
@@ -2261,7 +2261,7 @@ bool GSDevice12::GetSampler(D3D12DescriptorHandle* cpu_handle, GSHWDrawConfig::S
}};
const u8 index = (static_cast<u8>(ss.IsMipFilterLinear()) << 2) |
(static_cast<u8>(ss.IsMagFilterLinear()) << 1) | static_cast<u8>(ss.IsMinFilterLinear());
(static_cast<u8>(ss.IsMagFilterLinear()) << 1) | static_cast<u8>(ss.IsMinFilterLinear());
sd.Filter = filters[index];
}
@@ -2448,8 +2448,7 @@ bool GSDevice12::CompileConvertPipelines()
gpb.SetNoBlendingState();
gpb.SetVertexShader(m_convert_vs.get());
for (ShaderConvert i = ShaderConvert::COPY; static_cast<int>(i) < static_cast<int>(ShaderConvert::Count);
i = static_cast<ShaderConvert>(static_cast<int>(i) + 1))
for (ShaderConvert i = ShaderConvert::COPY; i < ShaderConvert::Count; i = static_cast<ShaderConvert>(static_cast<int>(i) + 1))
{
const bool depth = HasDepthOutput(i);
const int index = static_cast<int>(i);
@@ -2621,8 +2620,7 @@ bool GSDevice12::CompilePresentPipelines()
gpb.SetNoStencilState();
gpb.SetRenderTarget(0, DXGI_FORMAT_R8G8B8A8_UNORM);
for (PresentShader i = PresentShader::COPY; static_cast<int>(i) < static_cast<int>(PresentShader::Count);
i = static_cast<PresentShader>(static_cast<int>(i) + 1))
for (PresentShader i = PresentShader::COPY; i < PresentShader::Count; i = static_cast<PresentShader>(static_cast<int>(i) + 1))
{
const int index = static_cast<int>(i);
@@ -2963,8 +2961,8 @@ GSDevice12::ComPtr<ID3D12PipelineState> GSDevice12::CreateTFXPipeline(const Pipe
if (p.rt)
{
const GSTexture::Format format = IsDATEModePrimIDInit(p.ps.date) ?
GSTexture::Format::PrimID :
(p.ps.colclip_hw ? GSTexture::Format::ColorClip : GSTexture::Format::Color);
GSTexture::Format::PrimID :
(p.ps.colclip_hw ? GSTexture::Format::ColorClip : GSTexture::Format::Color);
DXGI_FORMAT native_format;
LookupNativeFormat(format, nullptr, nullptr, &native_format, nullptr);
@@ -3650,8 +3648,8 @@ bool GSDevice12::ApplyTFXState(bool already_execed)
{
m_current_root_signature = RootSignature::TFX;
flags |= DIRTY_FLAG_VS_CONSTANT_BUFFER_BINDING | DIRTY_FLAG_PS_CONSTANT_BUFFER_BINDING |
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE | DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE |
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 | DIRTY_FLAG_PIPELINE;
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE | DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE |
DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 | DIRTY_FLAG_PIPELINE;
cmdlist->SetGraphicsRootSignature(m_tfx_root_signature.get());
}

View File

@@ -544,11 +544,11 @@ private:
DIRTY_FLAG_STENCIL_REF = (1 << 19),
DIRTY_BASE_STATE = DIRTY_FLAG_VS_CONSTANT_BUFFER_BINDING | DIRTY_FLAG_PS_CONSTANT_BUFFER_BINDING |
DIRTY_FLAG_VS_VERTEX_BUFFER_BINDING | DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE |
DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE | DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 |
DIRTY_FLAG_VERTEX_BUFFER | DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PRIMITIVE_TOPOLOGY |
DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_RENDER_TARGET | DIRTY_FLAG_PIPELINE |
DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_STENCIL_REF,
DIRTY_FLAG_VS_VERTEX_BUFFER_BINDING | DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE |
DIRTY_FLAG_SAMPLERS_DESCRIPTOR_TABLE | DIRTY_FLAG_TEXTURES_DESCRIPTOR_TABLE_2 |
DIRTY_FLAG_VERTEX_BUFFER | DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PRIMITIVE_TOPOLOGY |
DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | DIRTY_FLAG_RENDER_TARGET | DIRTY_FLAG_PIPELINE |
DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_STENCIL_REF,
DIRTY_TFX_STATE =
DIRTY_BASE_STATE | DIRTY_FLAG_TFX_TEXTURES | DIRTY_FLAG_TFX_SAMPLERS | DIRTY_FLAG_TFX_RT_TEXTURES,

View File

@@ -125,7 +125,7 @@ std::unique_ptr<GSTexture12> GSTexture12::Create(Type type, Format format, int w
// This is a little annoying. basically, to do mipmap generation, we need to be a render target.
// If it's a compressed texture, we won't be generating mips anyway, so this should be fine.
desc.Flags = (levels > 1 && !IsCompressedFormat(format)) ? D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET :
D3D12_RESOURCE_FLAG_NONE;
D3D12_RESOURCE_FLAG_NONE;
state = D3D12_RESOURCE_STATE_COPY_DEST;
}
break;

View File

@@ -1093,7 +1093,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
rt_again->m_texture = tex;
rt = tex;
}
GSVector2i rt_size(rt->GetSize());
// This is awful, but so is the CRC hack... it's a texture shuffle split horizontally instead of vertically.
@@ -1102,14 +1102,14 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
if (rt_again->m_unscaled_size.x < src->m_unscaled_size.x || rt_again->m_unscaled_size.y < src->m_unscaled_size.y)
{
GSVector2i new_size = GSVector2i(std::max(rt_again->m_unscaled_size.x, src->m_unscaled_size.x),
std::max(rt_again->m_unscaled_size.y, src->m_unscaled_size.y));
std::max(rt_again->m_unscaled_size.y, src->m_unscaled_size.y));
rt_again->ResizeTexture(new_size.x, new_size.y);
rt = rt_again->m_texture;
rt_size = new_size * GSVector2i(src->GetScale());
rt_again->UpdateDrawn(GSVector4i::loadh(new_size));
}
}
const GSVector2i copy_size(std::min(rt_size.x, src_size.x), std::min(rt_size.y, src_size.y));

View File

@@ -332,7 +332,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(u32& process_rg, u32& process_ba,
const GSVertex second_vert = (start_verts[0].XYZ.X <= start_verts[1].XYZ.X) ? start_verts[1] : start_verts[0];
// vertex position is 8 to 16 pixels, therefore it is the 16-31 bits of the colors
const int pos = (first_vert.XYZ.X - o.OFX) & 0xFF;
// Read texture is 8 to 16 pixels (same as above)
const float tw = static_cast<float>(1u << m_cached_ctx.TEX0.TW);
int tex_pos = (PRIM->FST) ? first_vert.U : static_cast<int>(tw * first_vert.ST.S * 16.0f);
@@ -359,7 +359,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(u32& process_rg, u32& process_ba,
const u32 minu = (m_cached_ctx.CLAMP.MINU & 8);
if (maxu)
{
process_ba |= SHUFFLE_READ;
process_ba |= SHUFFLE_READ;
process_rg &= ~SHUFFLE_READ;
if (!PRIM->ABE && (process_rg & SHUFFLE_WRITE))
{
@@ -1124,7 +1124,7 @@ GSVector2i GSRendererHW::GetValidSize(const GSTextureCache::Source* tex, const b
height = std::min(height, valid_max_size);
}
return GSVector2i(width, height);
return GSVector2i(width, height);
}
GSVector2i GSRendererHW::GetTargetSize(const GSTextureCache::Source* tex, const bool can_expand, const bool is_shuffle)
@@ -1167,7 +1167,7 @@ bool GSRendererHW::IsPossibleChannelShuffle() const
const int draw_height = std::abs(v[1].XYZ.Y - v[0].XYZ.Y) >> 4;
const bool mask_clamp = (m_cached_ctx.CLAMP.WMS | m_cached_ctx.CLAMP.WMT) & 0x2;
const bool draw_match = (draw_height == 2) || (draw_width == 8);
if (draw_match || mask_clamp)
@@ -1616,18 +1616,18 @@ bool GSRendererHW::IsRTWritten()
const u32 written_bits = (~m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk);
const GIFRegALPHA ALPHA = m_context->ALPHA;
return (
// A not masked
(written_bits & 0xFF000000u) != 0) ||
(
// RGB not entirely masked
((written_bits & 0x00FFFFFFu) != 0) &&
// RGB written through no-blending, or blend result being non-zero
(!PRIM->ABE || // not blending
ALPHA.D != 1 || // additive to Cs
(ALPHA.A != ALPHA.B && // left side is not zero
(ALPHA.C == 1 || // multiply by Ad
(ALPHA.C == 2 && ALPHA.FIX != 0) || // multiply by 0
(ALPHA.C == 0 && GetAlphaMinMax().max != 0)))));
// A not masked
(written_bits & 0xFF000000u) != 0) ||
(
// RGB not entirely masked
((written_bits & 0x00FFFFFFu) != 0) &&
// RGB written through no-blending, or blend result being non-zero
(!PRIM->ABE || // not blending
ALPHA.D != 1 || // additive to Cs
(ALPHA.A != ALPHA.B && // left side is not zero
(ALPHA.C == 1 || // multiply by Ad
(ALPHA.C == 2 && ALPHA.FIX != 0) || // multiply by 0
(ALPHA.C == 0 && GetAlphaMinMax().max != 0)))));
}
bool GSRendererHW::IsDepthAlwaysPassing()
@@ -1636,8 +1636,8 @@ bool GSRendererHW::IsDepthAlwaysPassing()
const int check_index = m_vt.m_primclass == GS_SPRITE_CLASS ? 1 : 0;
// Depth is always pass/fail (no read) and write are discarded.
return (!m_cached_ctx.TEST.ZTE || m_cached_ctx.TEST.ZTST <= ZTST_ALWAYS) ||
// Depth test will always pass
(m_cached_ctx.TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[check_index].XYZ.Z, max_z) == max_z);
// Depth test will always pass
(m_cached_ctx.TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[check_index].XYZ.Z, max_z) == max_z);
}
bool GSRendererHW::IsUsingCsInBlend()
@@ -1673,14 +1673,14 @@ bool GSRendererHW::IsTBPFrameOrZ(u32 tbp, bool frame_only)
const u32 max_z = (0xFFFFFFFF >> (GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].fmt * 8));
const bool no_rt = (!IsRTWritten() && !m_cached_ctx.TEST.DATE);
const bool no_ds = (
// Depth is always pass/fail (no read) and write are discarded.
(zm != 0 && m_cached_ctx.TEST.ZTST <= ZTST_ALWAYS) ||
// Depth test will always pass
(zm != 0 && m_cached_ctx.TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[0].XYZ.Z, max_z) == max_z) ||
// Depth will be written through the RT
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && zm == 0 && (fm & fm_mask) == 0 && m_cached_ctx.TEST.ZTE)) ||
// No color or Z being written.
(no_rt && zm != 0);
// Depth is always pass/fail (no read) and write are discarded.
(zm != 0 && m_cached_ctx.TEST.ZTST <= ZTST_ALWAYS) ||
// Depth test will always pass
(zm != 0 && m_cached_ctx.TEST.ZTST == ZTST_GEQUAL && m_vt.m_eq.z && std::min(m_vertex.buff[0].XYZ.Z, max_z) == max_z) ||
// Depth will be written through the RT
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && zm == 0 && (fm & fm_mask) == 0 && m_cached_ctx.TEST.ZTE)) ||
// No color or Z being written.
(no_rt && zm != 0);
// Relying a lot on the optimizer here... I don't like it.
return (is_frame && !no_rt) || (is_z && !no_ds && !frame_only);
@@ -1777,7 +1777,7 @@ void GSRendererHW::InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GS
if (!(iter->draw == s_n && BITBLTBUF.SBP == iter->blit.DBP && iter->blit.DPSM == BITBLTBUF.SPSM && r.eq(iter->rect)))
continue;
g_texture_cache->InvalidateVideoMem(m_mem.GetOffset(BITBLTBUF.SBP, BITBLTBUF.SBW, BITBLTBUF.SPSM), r);
skip = true;
break;
@@ -1917,12 +1917,12 @@ void GSRendererHW::SwSpriteRender()
const GSVertex& v = m_index.tail > 0 ? m_vertex.buff[m_index.buff[m_index.tail - 1]] : GSVertex(); // Last vertex if any.
const GSVector4i vc = GSVector4i(v.RGBAQ.R, v.RGBAQ.G, v.RGBAQ.B, v.RGBAQ.A) // 0x000000AA000000BB000000GG000000RR
.ps32(); // 0x00AA00BB00GG00RR00AA00BB00GG00RR
.ps32(); // 0x00AA00BB00GG00RR00AA00BB00GG00RR
const GSVector4i a_mask = GSVector4i::xff000000().u8to16(); // 0x00FF00000000000000FF000000000000
const GSVector4i a_mask = GSVector4i::xff000000().u8to16(); // 0x00FF00000000000000FF000000000000
const bool fb_mask_enabled = m_cached_ctx.FRAME.FBMSK != 0x0;
const GSVector4i fb_mask = GSVector4i(m_cached_ctx.FRAME.FBMSK).u8to16(); // 0x00AA00BB00GG00RR00AA00BB00GG00RR
const GSVector4i fb_mask = GSVector4i(m_cached_ctx.FRAME.FBMSK).u8to16(); // 0x00AA00BB00GG00RR00AA00BB00GG00RR
const u8 tex0_tfx = m_cached_ctx.TEX0.TFX;
const u8 tex0_tcc = m_cached_ctx.TEX0.TCC;
@@ -2250,8 +2250,8 @@ void GSRendererHW::Draw()
// Tomb Raider: Underworld does similar, except with R, G, B in separate palettes, therefore
// we need to split on those too.
m_channel_shuffle = !m_channel_shuffle_abort && IsPossibleChannelShuffle() && m_last_channel_shuffle_fbmsk == m_context->FRAME.FBMSK &&
m_last_channel_shuffle_fbp <= m_context->FRAME.Block() && m_last_channel_shuffle_end_block > m_context->FRAME.Block() &&
m_last_channel_shuffle_tbp <= m_context->TEX0.TBP0;
m_last_channel_shuffle_fbp <= m_context->FRAME.Block() && m_last_channel_shuffle_end_block > m_context->FRAME.Block() &&
m_last_channel_shuffle_tbp <= m_context->TEX0.TBP0;
if (m_channel_shuffle)
{
@@ -2296,7 +2296,7 @@ void GSRendererHW::Draw()
else
m_conf.scissor.z = std::min(m_conf.scissor.z, static_cast<int>((m_channel_shuffle_width * 64) * m_conf.cb_ps.ScaleFactor.z));
}
m_last_rt->UpdateValidity(valid_area);
g_gs_device->RenderHW(m_conf);
@@ -2308,7 +2308,7 @@ void GSRendererHW::Draw()
if (m_last_rt && GSConfig.SaveRT)
{
const u64 frame = g_perfmon.GetFrame();
std::string s = GetDrawDumpPath("%05d_f%05lld_rt1_%05x_(%05x)_%s.bmp", s_n - 1, frame, m_last_channel_shuffle_fbp, m_last_rt->m_TEX0.TBP0, GSUtil::GetPSMName(m_cached_ctx.FRAME.PSM));
m_last_rt->m_texture->Save(s);
@@ -2354,9 +2354,9 @@ void GSRendererHW::Draw()
// Note: do it first so we know if frame/depth writes are masked
u32 fm = m_cached_ctx.FRAME.FBMSK;
u32 zm = (m_cached_ctx.ZBUF.ZMSK || m_cached_ctx.TEST.ZTE == 0 ||
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ZTST_NEVER && m_cached_ctx.TEST.AFAIL != AFAIL_ZB_ONLY)) ?
0xffffffffu :
0;
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ZTST_NEVER && m_cached_ctx.TEST.AFAIL != AFAIL_ZB_ONLY)) ?
0xffffffffu :
0;
const u32 fm_mask = GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk;
// Note required to compute TryAlphaTest below. So do it now.
@@ -2424,8 +2424,8 @@ void GSRendererHW::Draw()
bool no_rt = (!IsRTWritten() && !m_cached_ctx.TEST.DATE);
const bool all_depth_tests_pass = IsDepthAlwaysPassing();
bool no_ds = (zm != 0 && all_depth_tests_pass) ||
// No color or Z being written.
(no_rt && zm != 0);
// No color or Z being written.
(no_rt && zm != 0);
// No Z test if no z buffer.
if (no_ds || all_depth_tests_pass)
@@ -2465,7 +2465,6 @@ void GSRendererHW::Draw()
g_gs_device->Recycle(colclip_texture);
g_gs_device->SetColorClipTexture(nullptr);
}
else
DevCon.Warning("HW: Error resolving colclip texture for pre-draw resolve");
@@ -2922,13 +2921,13 @@ void GSRendererHW::Draw()
(m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index.tail % 6) == 0 && TrianglesAreQuads(true) && m_index.tail > 6)))
{
// Tail check is to make sure we have enough strips to go all the way across the page, or if it's using a region clamp could be used to draw strips.
if (GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 &&
if (GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 &&
(m_index.tail >= (m_cached_ctx.TEX0.TBW * 2) || m_cached_ctx.TEX0.TBP0 == m_cached_ctx.FRAME.Block() || m_cached_ctx.CLAMP.WMS > CLAMP_CLAMP || m_cached_ctx.CLAMP.WMT > CLAMP_CLAMP))
{
const GSVertex* v = &m_vertex.buff[0];
const int first_x = std::clamp((static_cast<int>(((v[0].XYZ.X - m_context->XYOFFSET.OFX) + 8))) >> 4, 0, 2048);
const bool offset_last = PRIM->FST ? (v[1].U > v[0].U) : ((v[1].ST.S / v[1].RGBAQ.Q) > (v[0].ST.S / v[1].RGBAQ.Q));
const bool offset_last = PRIM->FST ? (v[1].U > v[0].U) : ((v[1].ST.S / v[1].RGBAQ.Q) > (v[0].ST.S / v[1].RGBAQ.Q));
const int first_u = PRIM->FST ? ((v[0].U + (offset_last ? 0 : 9)) >> 4) : std::clamp(static_cast<int>(((1 << m_cached_ctx.TEX0.TW) * (v[0].ST.S / v[1].RGBAQ.Q)) + (offset_last ? 0.0f : 0.6f)), 0, 2048);
const int second_u = PRIM->FST ? ((v[1].U + (offset_last ? 9 : 0)) >> 4) : std::clamp(static_cast<int>(((1 << m_cached_ctx.TEX0.TW) * (v[1].ST.S / v[1].RGBAQ.Q)) + (offset_last ? 0.6f : 0.0f)), 0, 2048);
// offset coordinates swap around RG/BA. (Ace Combat)
@@ -3007,9 +3006,9 @@ void GSRendererHW::Draw()
}
else
{
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha) :
g_texture_cache->LookupSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr,
possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha);
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha)
: g_texture_cache->LookupSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr,
possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha);
if (!src) [[unlikely]]
{
@@ -3022,9 +3021,8 @@ void GSRendererHW::Draw()
const u32 draw_end = GSLocalMemory::GetEndBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r) + 1;
const u32 draw_start = GSLocalMemory::GetStartBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r);
draw_uses_target = src->m_from_target && ((src->m_from_target_TEX0.TBP0 <= draw_start &&
src->m_from_target->UnwrappedEndBlock() > m_cached_ctx.FRAME.Block()) ||
(m_cached_ctx.FRAME.Block() < src->m_from_target_TEX0.TBP0 && draw_end > src->m_from_target_TEX0.TBP0));
draw_uses_target = src->m_from_target && ((src->m_from_target_TEX0.TBP0 <= draw_start && src->m_from_target->UnwrappedEndBlock() > m_cached_ctx.FRAME.Block()) ||
(m_cached_ctx.FRAME.Block() < src->m_from_target_TEX0.TBP0 && draw_end > src->m_from_target_TEX0.TBP0));
if (possible_shuffle && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp != 16)
possible_shuffle &= draw_uses_target;
@@ -3047,9 +3045,9 @@ void GSRendererHW::Draw()
u32 new_fm = m_context->FRAME.FBMSK;
u32 new_zm = (m_cached_ctx.ZBUF.ZMSK || m_cached_ctx.TEST.ZTE == 0 ||
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ZTST_NEVER && m_cached_ctx.TEST.AFAIL != AFAIL_ZB_ONLY)) ?
0xffffffffu :
0;
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.ATST == ZTST_NEVER && m_cached_ctx.TEST.AFAIL != AFAIL_ZB_ONLY)) ?
0xffffffffu :
0;
if (m_cached_ctx.TEST.ATE && GSRenderer::TryAlphaTest(new_fm, new_zm))
{
m_cached_ctx.TEST.ATE = false;
@@ -3059,10 +3057,10 @@ void GSRendererHW::Draw()
zm = new_zm;
no_rt = no_rt || (!IsRTWritten() && !m_cached_ctx.TEST.DATE);
no_ds = no_ds || (zm != 0 && all_depth_tests_pass) ||
// Depth will be written through the RT
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && zm == 0 && (fm & fm_mask) == 0 && m_cached_ctx.TEST.ZTE) ||
// No color or Z being written.
(no_rt && zm != 0);
// Depth will be written through the RT
(!no_rt && m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP && !PRIM->TME && zm == 0 && (fm & fm_mask) == 0 && m_cached_ctx.TEST.ZTE) ||
// No color or Z being written.
(no_rt && zm != 0);
if (no_rt && no_ds)
{
GL_INS("HW: Late draw cancel because no pixels pass alpha test.");
@@ -3362,16 +3360,18 @@ void GSRendererHW::Draw()
if (!no_rt)
{
possible_shuffle |= draw_sprite_tex && m_process_texture && m_primitive_covers_without_gaps != NoGapsType::FullCover && (((src && src->m_target && src->m_from_target && src->m_from_target->m_32_bits_fmt) &&
(GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 || draw_uses_target) && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) ||
IsPossibleChannelShuffle());
possible_shuffle |= draw_sprite_tex && m_process_texture && m_primitive_covers_without_gaps != NoGapsType::FullCover &&
(((src && src->m_target && src->m_from_target && src->m_from_target->m_32_bits_fmt) &&
(GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 || draw_uses_target) &&
GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) ||
IsPossibleChannelShuffle());
const bool possible_horizontal_texture_shuffle = possible_shuffle && src && src->m_from_target && m_r.w <= src->m_from_target->m_valid.w && m_r.z > src->m_from_target->m_valid.z && m_cached_ctx.FRAME.FBW > src->m_from_target_TEX0.TBW;
// FBW is going to be wrong for channel shuffling into a new target, so take it from the source.
FRAME_TEX0.U64 = 0;
FRAME_TEX0.TBP0 = ((m_last_channel_shuffle_end_block + 1) == m_cached_ctx.FRAME.Block() && possible_shuffle) ? m_last_channel_shuffle_fbp : m_cached_ctx.FRAME.Block();
FRAME_TEX0.TBW = (possible_horizontal_texture_shuffle || (possible_shuffle && src && src->m_from_target && IsPossibleChannelShuffle()&& m_cached_ctx.FRAME.FBW <= 2)) ? src->m_from_target_TEX0.TBW : m_cached_ctx.FRAME.FBW;
FRAME_TEX0.TBW = (possible_horizontal_texture_shuffle || (possible_shuffle && src && src->m_from_target && IsPossibleChannelShuffle() && m_cached_ctx.FRAME.FBW <= 2)) ? src->m_from_target_TEX0.TBW : m_cached_ctx.FRAME.FBW;
FRAME_TEX0.PSM = m_cached_ctx.FRAME.PSM;
// Don't clamp on shuffle, the height cache may troll us with the REAL height.
@@ -3459,8 +3459,8 @@ void GSRendererHW::Draw()
return;
}
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src, possible_shuffle), (GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && scale_draw < 0 && is_possible_mem_clear != ClearType::NormalClear) ? ((src && src->m_from_target) ? src->m_from_target->GetScale() : (ds ? ds->m_scale : 1.0f)) : target_scale,
GSTextureCache::RenderTarget, true, fm, false, force_preload, preserve_rt_color || possible_shuffle, lookup_rect, src);
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src, possible_shuffle), (GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && scale_draw < 0 && is_possible_mem_clear != ClearType::NormalClear) ? ((src && src->m_from_target) ? src->m_from_target->GetScale() : (ds ? ds->m_scale : 1.0f)) : target_scale,
GSTextureCache::RenderTarget, true, fm, false, force_preload, preserve_rt_color || possible_shuffle, lookup_rect, src);
if (!rt) [[unlikely]]
{
@@ -3474,8 +3474,8 @@ void GSRendererHW::Draw()
rt->UpdateValidity(GSVector4i::loadh(GSVector2i(GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs.x, GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs.y)), true);
}
if (src && !src->m_from_target && GSLocalMemory::m_psm[src->m_TEX0.PSM].bpp == GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp &&
(GSUtil::GetChannelMask(src->m_TEX0.PSM) & GSUtil::GetChannelMask(m_context->FRAME.PSM)) != 0)
if (src && !src->m_from_target && GSLocalMemory::m_psm[src->m_TEX0.PSM].bpp == GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp &&
(GSUtil::GetChannelMask(src->m_TEX0.PSM) & GSUtil::GetChannelMask(m_context->FRAME.PSM)) != 0)
{
const u32 draw_end = GSLocalMemory::GetEndBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r) + 1;
const u32 draw_start = GSLocalMemory::GetStartBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r);
@@ -3494,7 +3494,7 @@ void GSRendererHW::Draw()
src->m_valid_rect = rt->m_valid;
src->m_alpha_minmax.first = rt->m_alpha_min;
src->m_alpha_minmax.second = rt->m_alpha_max;
const int target_width = std::max(FRAME_TEX0.TBW, 1U);
const int page_offset = (src->m_TEX0.TBP0 - rt->m_TEX0.TBP0) >> 5;
const int vertical_page_offset = page_offset / target_width;
@@ -3652,7 +3652,7 @@ void GSRendererHW::Draw()
}
}
}
}
}
// Z or RT are offset from each other, so we need a temp Z to align it
if (ds && rt && ((m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) != (m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) || (g_texture_cache->GetTemporaryZ() != nullptr && g_texture_cache->GetTemporaryZInfo().ZBP == ds->m_TEX0.TBP0)))
{
@@ -3716,7 +3716,7 @@ void GSRendererHW::Draw()
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
const int vertical_page_offset = (rt_page_offset / std::max(static_cast<int>(rt->m_TEX0.TBW), 1));
const int vertical_offset = vertical_page_offset * frame_psm.pgs.y;
const int horizontal_offset = (rt_page_offset - (vertical_page_offset * std::max(static_cast<int>(rt->m_TEX0.TBW), 1))) * frame_psm.pgs.x;
const int horizontal_offset = (rt_page_offset - (vertical_page_offset * std::max(static_cast<int>(rt->m_TEX0.TBW), 1))) * frame_psm.pgs.x;
const u32 horizontal_size = std::max(rt->m_unscaled_size.x, ds->m_unscaled_size.x);
const u32 vertical_size = std::max(rt->m_unscaled_size.y, ds->m_unscaled_size.y);
@@ -3768,7 +3768,6 @@ void GSRendererHW::Draw()
src->m_texture = rt->m_texture;
src->m_scale = rt->GetScale();
src->m_unscaled_size = rt->m_unscaled_size;
}
target_scale = rt->GetScale();
@@ -3884,17 +3883,16 @@ void GSRendererHW::Draw()
// copy of a 16bit source in to this target, make sure it's opaque and not bilinear to reduce false positives.
m_copy_16bit_to_target_shuffle = m_cached_ctx.TEX0.TBP0 != m_cached_ctx.FRAME.Block() && rt->m_32_bits_fmt == true && IsOpaque()
&& !(context->TEX1.MMIN & 1) && !src->m_32_bits_fmt && m_cached_ctx.FRAME.FBMSK;
&& !(context->TEX1.MMIN & 1) && !src->m_32_bits_fmt && m_cached_ctx.FRAME.FBMSK;
// It's not actually possible to do a C16->C16 texture shuffle of B to A as they are the same group
// However you can do it by using C32 and offsetting the target verticies to point to B A, then mask as appropriate.
m_same_group_texture_shuffle = draw_uses_target && (m_cached_ctx.TEX0.PSM & 0xE) == PSMCT32 && (m_cached_ctx.FRAME.PSM & 0x7) == PSMCT16 && (m_vt.m_min.p.x == 8.0f);
// Both input and output are 16 bits and texture was initially 32 bits! Same for the target, Sonic Unleash makes a new target which really is 16bit.
m_texture_shuffle = ((m_same_group_texture_shuffle || (tex_psm.bpp == 16)) && (GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) &&
(shuffle_coords || rt->m_32_bits_fmt)) &&
(src->m_32_bits_fmt || m_copy_16bit_to_target_shuffle) &&
(draw_sprite_tex || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index.tail % 6) == 0 && TrianglesAreQuads(true)));
m_texture_shuffle = ((m_same_group_texture_shuffle || (tex_psm.bpp == 16)) && (GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) && (shuffle_coords || rt->m_32_bits_fmt)) &&
(src->m_32_bits_fmt || m_copy_16bit_to_target_shuffle) &&
(draw_sprite_tex || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index.tail % 6) == 0 && TrianglesAreQuads(true)));
if (m_texture_shuffle && IsSplitTextureShuffle(rt->m_TEX0, rt->m_valid))
{
@@ -4285,7 +4283,8 @@ void GSRendererHW::Draw()
{
// if the height cache gave a different size to our final size, we need to check if it needs preloading.
// Pirates - Legend of the Black Kat starts a draw of 416, but Z is 448 and it preloads the background.
if (rt->m_drawn_since_read.rempty() && rt->m_dirty.size() > 0 && new_height && (preserve_rt_color || preserve_rt_alpha)) {
if (rt->m_drawn_since_read.rempty() && rt->m_dirty.size() > 0 && new_height && (preserve_rt_color || preserve_rt_alpha))
{
RGBAMask mask;
mask._u32 = preserve_rt_color ? 0x7 : 0;
mask.c.a |= preserve_rt_alpha;
@@ -4659,8 +4658,11 @@ void GSRendererHW::Draw()
if (!m_temp_z_full_copy && was_written)
{
GSVector4i dRect = GSVector4i((z_horizontal_offset + (real_rect.x - horizontal_offset)) * ds->m_scale, (z_vertical_offset + (real_rect.y - vertical_offset)) * ds->m_scale, ((z_horizontal_offset + real_rect.z + (1.0f / ds->m_scale)) - horizontal_offset) * ds->m_scale, (z_vertical_offset + (real_rect.w + (1.0f / ds->m_scale) - vertical_offset)) * ds->m_scale);
GSVector4 sRect = GSVector4((real_rect.x * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()), static_cast<float>(real_rect.y * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()), ((real_rect.z + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
static_cast<float>((real_rect.w + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()));
GSVector4 sRect = GSVector4(
(real_rect.x * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
static_cast<float>(real_rect.y * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()),
((real_rect.z + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
static_cast<float>((real_rect.w + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()));
GL_CACHE("HW: RT in RT Z copy back draw %d z_vert_offset %d rt_vert_offset %d z_horz_offset %d rt_horz_offset %d", s_n, z_vertical_offset, vertical_offset, z_horizontal_offset, horizontal_offset);
g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
@@ -4669,7 +4671,10 @@ void GSRendererHW::Draw()
else if (m_temp_z_full_copy)
{
GSVector4i dRect = GSVector4i((ds->m_valid.x + z_horizontal_offset) * ds->m_scale, (ds->m_valid.y + z_vertical_offset) * ds->m_scale, (ds->m_valid.z + z_horizontal_offset + (1.0f / ds->m_scale)) * ds->m_scale, (ds->m_valid.w + z_vertical_offset + (1.0f / ds->m_scale)) * ds->m_scale);
GSVector4 sRect = GSVector4(((ds->m_valid.x + horizontal_offset) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()), static_cast<float>((ds->m_valid.y + vertical_offset) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()), (((ds->m_valid.z + horizontal_offset) + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
GSVector4 sRect = GSVector4(
((ds->m_valid.x + horizontal_offset) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
static_cast<float>((ds->m_valid.y + vertical_offset) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()),
(((ds->m_valid.z + horizontal_offset) + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetWidth()),
static_cast<float>((ds->m_valid.w + vertical_offset + (1.0f / ds->m_scale)) * ds->m_scale) / static_cast<float>(g_texture_cache->GetTemporaryZ()->GetHeight()));
GL_CACHE("HW: RT in RT Z copy back draw %d z_vert_offset %d z_offset %d", s_n, z_vertical_offset, vertical_offset);
@@ -5371,7 +5376,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
// Page align test to limit false detections (there is a few).
GSVector4i min_uv = GSVector4i(m_vt.m_min.t.upld(GSVector4::zero()));
ChannelFetch channel = ChannelFetch_NONE;
const GSLocalMemory::psm_t& t_psm = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM];;
const GSLocalMemory::psm_t& t_psm = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM];
const GSLocalMemory::psm_t& f_psm = GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM];
GSVector4i block_offset = GSVector4i(min_uv.x / t_psm.bs.x, min_uv.y / t_psm.bs.y).xyxy();
GSVector4i m_r_block_offset = GSVector4i((m_r.x & (f_psm.pgs.x - 1)) / f_psm.bs.x, (m_r.y & (f_psm.pgs.y - 1)) / f_psm.bs.y);
@@ -5444,7 +5449,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
s[1].U = 16384;
s[0].V = 0;
s[1].V = 16384;
m_r = GSVector4i(0, 0, 1024, 1024);
// We need to count the pages that get shuffled to, some games (like Hitman Blood Money dialogue blur effects) only do half the screen.
@@ -5476,7 +5481,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
if (rt && rt->m_TEX0.TBP0 == m_cached_ctx.FRAME.Block())
{
const bool req_offset = (m_cached_ctx.CLAMP.WMS != 3 || (m_cached_ctx.CLAMP.MAXU & ~0xF) == 0) &&
(m_cached_ctx.CLAMP.WMT != 3 || (m_cached_ctx.CLAMP.MAXV & ~0x3) == 0);
(m_cached_ctx.CLAMP.WMT != 3 || (m_cached_ctx.CLAMP.MAXV & ~0x3) == 0);
//DevCon.Warning("HW: Draw %d offset %d", s_n, frame_page_offset);
// Offset the frame but clear the draw offset
if (req_offset)
@@ -5514,7 +5519,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
new_valid.w = std::max(new_valid.w, offset_height);
rt->UpdateValidity(new_valid, true);
}
m_vertex.head = m_vertex.tail = m_vertex.next = 2;
m_index.tail = 2;
@@ -5568,7 +5573,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
#endif
// If the colour is modulated to zero or we're not using a texture and the color is zero, we can replace any Cs with 0
if ((!PRIM->TME || m_cached_ctx.TEX0.TFX != TFX_DECAL) && (!PRIM->FGE || m_draw_env->FOGCOL.U32[0] == 0) &&
if ((!PRIM->TME || m_cached_ctx.TEX0.TFX != TFX_DECAL) && (!PRIM->FGE || m_draw_env->FOGCOL.U32[0] == 0) &&
((m_vt.m_max.c == GSVector4i::zero()).mask() & 0xfff) == 0xfff)
{
// If using modulate or is HIGHLIGHT by the vertex alpha is zero, we should be safe to kill it.
@@ -5739,7 +5744,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
// Condition 4: If it's tex in fb draw and there's no overlap prefer sw blend, fb is already being read.
const bool prefer_sw_blend = (features.texture_barrier && m_conf.require_full_barrier) || (m_conf.require_one_barrier && (no_prim_overlap || m_channel_shuffle)) || m_conf.ps.shuffle || (no_prim_overlap && (m_conf.tex == m_conf.rt));
const bool free_blend = blend_non_recursive // Free sw blending, doesn't require barriers or reading fb
|| accumulation_blend; // Mix of hw/sw blending
|| accumulation_blend; // Mix of hw/sw blending
// Warning no break on purpose
// Note: the [[fallthrough]] attribute tell compilers not to complain about not having breaks.
@@ -5795,7 +5800,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
else
{
const bool ad_second_pass = blend_multi_pass_support && alpha_c1_high_no_rta_correct && COLCLAMP.CLAMP &&
(blend_flag & (BLEND_HW3 | BLEND_HW5 | BLEND_HW6 | BLEND_HW7 | BLEND_HW9));
(blend_flag & (BLEND_HW3 | BLEND_HW5 | BLEND_HW6 | BLEND_HW7 | BLEND_HW9));
switch (GSConfig.AccurateBlendingUnit)
{
@@ -6137,7 +6142,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
new_rt_alpha_scale = true;
alpha_c1_high_no_rta_correct = false;
m_conf.ps.rta_correction = rt->m_rt_alpha_scale;
}
@@ -6307,9 +6312,9 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
// Remove second color output when unused. Works around bugs in some drivers (e.g. Intel).
m_conf.ps.no_color1 = !GSDevice::IsDualSourceBlendFactor(m_conf.blend.src_factor) &&
!GSDevice::IsDualSourceBlendFactor(m_conf.blend.dst_factor) &&
!GSDevice::IsDualSourceBlendFactor(m_conf.blend_multi_pass.blend.src_factor) &&
!GSDevice::IsDualSourceBlendFactor(m_conf.blend_multi_pass.blend.dst_factor);
!GSDevice::IsDualSourceBlendFactor(m_conf.blend.dst_factor) &&
!GSDevice::IsDualSourceBlendFactor(m_conf.blend_multi_pass.blend.src_factor) &&
!GSDevice::IsDualSourceBlendFactor(m_conf.blend_multi_pass.blend.dst_factor);
}
// Notify the shader that it needs to invert rounding
@@ -6380,9 +6385,9 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
// we keep the shader clamp. See #5851 on github, and the note in Draw().
[[maybe_unused]] static constexpr const char* clamp_modes[] = {"REPEAT", "CLAMP", "REGION_CLAMP", "REGION_REPEAT"};
const bool redundant_wms = IsRedundantClamp(m_cached_ctx.CLAMP.WMS, m_cached_ctx.CLAMP.MINU,
m_cached_ctx.CLAMP.MAXU, m_cached_ctx.TEX0.TW);
m_cached_ctx.CLAMP.MAXU, m_cached_ctx.TEX0.TW);
const bool redundant_wmt = IsRedundantClamp(m_cached_ctx.CLAMP.WMT, m_cached_ctx.CLAMP.MINV,
m_cached_ctx.CLAMP.MAXV, m_cached_ctx.TEX0.TH);
m_cached_ctx.CLAMP.MAXV, m_cached_ctx.TEX0.TH);
const u8 wms = EffectiveClamp(m_cached_ctx.CLAMP.WMS, !tex->m_target && (source_region.HasX() || redundant_wms));
const u8 wmt = EffectiveClamp(m_cached_ctx.CLAMP.WMT, !tex->m_target && (source_region.HasY() || redundant_wmt));
const bool complex_wms_wmt = !!((wms | wmt) & 2) || target_region;
@@ -6394,7 +6399,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
const bool need_mipmap = IsMipMapDraw();
const bool shader_emulated_sampler = tex->m_palette || (tex->m_target && !m_conf.ps.shuffle && cpsm.fmt != 0) ||
complex_wms_wmt || psm.depth || target_region;
complex_wms_wmt || psm.depth || target_region;
const bool can_trilinear = !tex->m_palette && !tex->m_target && !m_conf.ps.shuffle;
const bool trilinear_manual = need_mipmap && GSConfig.HWMipmap;
@@ -6667,7 +6672,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
// This "fixes" a lot of the rainbow garbage in games when upscaling (and xenosaga shadows + VP2 forest seem quite happy).
// Note that this is done on the original texture scale, during upscales it can mess up otherwise.
const GSVector4 region_clamp_offset = GSVector4::cxpr(0.5f, 0.5f, 0.1f, 0.1f) + (GSVector4::cxpr(0.1f, 0.1f, 0.0f, 0.0f) * tex->GetScale());
const GSVector4 region_clamp = (GSVector4(clamp) + region_clamp_offset) / WH.xyxy();
if (wms >= CLAMP_REGION_CLAMP)
{
@@ -6680,7 +6685,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
m_conf.cb_ps.MinMax.w = (wmt == CLAMP_REGION_CLAMP && !m_conf.ps.depth_fmt) ? region_clamp.w : region_repeat.w;
}
}
if (trilinear_manual)
{
m_conf.cb_ps.LODParams.x = static_cast<float>(m_context->TEX1.K) / 16.0f;
@@ -6711,8 +6716,8 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
// Remove linear from trilinear, since we're doing the bilinear in the shader, and we only want this for mip selection.
m_conf.sampler.triln = (trilinear >= static_cast<u8>(GS_MIN_FILTER::Linear_Mipmap_Nearest)) ?
(trilinear - static_cast<u8>(GS_MIN_FILTER::Nearest_Mipmap_Nearest)) :
0;
(trilinear - static_cast<u8>(GS_MIN_FILTER::Nearest_Mipmap_Nearest)) :
0;
}
else
{
@@ -6933,8 +6938,8 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
static_cast<int>(std::ceil(static_cast<float>(copy_size.y) * scale)));
src_copy.reset(src_target->m_texture->IsDepthStencil() ?
g_gs_device->CreateDepthStencil(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), false) :
g_gs_device->CreateRenderTarget(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), true, true));
g_gs_device->CreateDepthStencil(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), false) :
g_gs_device->CreateRenderTarget(scaled_copy_size.x, scaled_copy_size.y, src_target->m_texture->GetFormat(), true, true));
if (!src_copy) [[unlikely]]
{
Console.Error("HW: Failed to allocate %dx%d texture for hazard copy", scaled_copy_size.x, scaled_copy_size.y);
@@ -6961,8 +6966,8 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
// causing bleeding into the edges of the downsampled texture.
const u32 downsample_factor = static_cast<u32>(src_target->GetScale());
const GSVector2i clamp_min = (GSConfig.UserHacks_HalfPixelOffset < GSHalfPixelOffset::Native) ?
GSVector2i(0, 0) :
GSVector2i(downsample_factor, downsample_factor);
GSVector2i(0, 0) :
GSVector2i(downsample_factor, downsample_factor);
GSVector4i copy_rect = tmm.coverage;
if (target_region)
{
@@ -7212,7 +7217,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
m_conf.ps.scanmsk = env.SCANMSK.MSK;
m_conf.rt = rt ? rt->m_texture : nullptr;
m_conf.ds = ds ? (m_using_temp_z ? g_texture_cache->GetTemporaryZ() : ds->m_texture) : nullptr;
pxAssert(!ds || !rt || (m_conf.ds->GetSize().x == m_conf.rt->GetSize().x && m_conf.ds->GetSize().y == m_conf.rt->GetSize().y));
// Z setup has to come before channel shuffle
@@ -7802,12 +7807,12 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
const int unscaled_y = rt_or_ds ? rt_or_ds->GetUnscaledHeight() : 0;
sx = 2.0f / (unscaled_x << 4);
sy = 2.0f / (unscaled_y << 4);
if (GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::NativeWTexOffset)
{
ox2 = (-1.0f / (unscaled_x * rtscale));
oy2 = (-1.0f / (unscaled_y * rtscale));
// Having the vertex negatively offset is a common thing for copying sprites but this causes problems when upscaling, so we need to further adjust the offset.
// This kinda screws things up when using ST, so let's not.
if (m_vt.m_primclass == GS_SPRITE_CLASS && rtscale > 1.0f && (tex && PRIM->FST))
@@ -8127,7 +8132,7 @@ GSRendererHW::CLUTDrawTestResult GSRendererHW::PossibleCLUTDraw()
const float draw_width = (m_vt.m_max.p.x - m_vt.m_min.p.x);
const float draw_height = (m_vt.m_max.p.y - m_vt.m_min.p.y);
const bool valid_size = ((draw_width >= min_clut_width || draw_height >= min_clut_height))
&& (((draw_width < page_width && draw_height <= page_height) || (draw_width == page_width)) && draw_divder_match); // Make sure draw is multiples of 8 wide (AC5 midetection).
&& (((draw_width < page_width && draw_height <= page_height) || (draw_width == page_width)) && draw_divder_match); // Make sure draw is multiples of 8 wide (AC5 midetection).
// Make sure the draw hits the next CLUT and it's marked as invalid (kind of a sanity check).
// We can also allow draws which are of a sensible size within the page, as they could also be CLUT draws (or gradients for the CLUT).
@@ -8257,7 +8262,7 @@ bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_t
{
GSTextureCache::Target* dst_target = g_texture_cache->GetTargetWithSharedBits(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.PSM);
if (dst_target && dst_target->m_dirty.empty() && ((!(GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & 0x7)) || dst_target->m_valid_rgb) &&
if (dst_target && dst_target->m_dirty.empty() && ((!(GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & 0x7)) || dst_target->m_valid_rgb) &&
((!(GSUtil::GetChannelMask(m_cached_ctx.FRAME.PSM) & 0x8)) || (dst_target->m_valid_alpha_low && dst_target->m_valid_alpha_high)))
return false;
}
@@ -8355,12 +8360,11 @@ bool GSRendererHW::DetectStripedDoubleClear(bool& no_rt, bool& no_ds)
{
const bool single_page_offset =
std::abs(static_cast<int>(m_cached_ctx.FRAME.FBP) - static_cast<int>(m_cached_ctx.ZBUF.ZBP)) == 1;
const bool z_is_frame = (m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP ||
(m_cached_ctx.FRAME.FBW > 1 && single_page_offset)) && // GT4O Public Beta
!m_cached_ctx.ZBUF.ZMSK &&
(m_cached_ctx.FRAME.PSM & 0x30) != (m_cached_ctx.ZBUF.PSM & 0x30) &&
(m_cached_ctx.FRAME.PSM & 0xF) == (m_cached_ctx.ZBUF.PSM & 0xF) && m_vt.m_eq.z == 1 &&
m_vertex.buff[1].XYZ.Z == m_vertex.buff[1].RGBAQ.U32[0];
const bool z_is_frame = (m_cached_ctx.FRAME.FBP == m_cached_ctx.ZBUF.ZBP || (m_cached_ctx.FRAME.FBW > 1 && single_page_offset)) && // GT4O Public Beta
!m_cached_ctx.ZBUF.ZMSK &&
(m_cached_ctx.FRAME.PSM & 0x30) != (m_cached_ctx.ZBUF.PSM & 0x30) &&
(m_cached_ctx.FRAME.PSM & 0xF) == (m_cached_ctx.ZBUF.PSM & 0xF) && m_vt.m_eq.z == 1 &&
m_vertex.buff[1].XYZ.Z == m_vertex.buff[1].RGBAQ.U32[0];
// Z and color must be constant and the same and must be drawing strips.
if (!z_is_frame || m_vt.m_eq.rgba != 0xFFFF)
@@ -8874,7 +8878,7 @@ void GSRendererHW::ClearGSLocalMemory(const GSOffset& off, const GSVector4i& r,
else if (format == GSLocalMemory::PSM_FMT_16)
{
const u16 converted_color = ((vert_color >> 16) & 0x8000) | ((vert_color >> 9) & 0x7C00) |
((vert_color >> 6) & 0x7E0) | ((vert_color >> 3) & 0x1F);
((vert_color >> 6) & 0x7E0) | ((vert_color >> 3) & 0x1F);
const GSVector4i vcolor = GSVector4i::broadcast16(converted_color);
const u32 iterations_per_page = (pages_wide * pixels_per_page) / 8;
pxAssert((off.bp() & (GS_BLOCKS_PER_PAGE - 1)) == 0);
@@ -8997,27 +9001,27 @@ bool GSRendererHW::OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Sourc
bool GSRendererHW::AreAnyPixelsDiscarded() const
{
return ((m_draw_env->SCANMSK.MSK & 2) || // skipping rows
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.AFAIL != AFAIL_FB_ONLY) || // testing alpha (might discard some pixels)
m_cached_ctx.TEST.DATE); // reading alpha
(m_cached_ctx.TEST.ATE && m_cached_ctx.TEST.AFAIL != AFAIL_FB_ONLY) || // testing alpha (might discard some pixels)
m_cached_ctx.TEST.DATE); // reading alpha
}
bool GSRendererHW::IsDiscardingDstColor()
{
return ((!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack()) && // no blending or writing black
!AreAnyPixelsDiscarded() && (m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) == 0); // no channels masked
!AreAnyPixelsDiscarded() && (m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) == 0); // no channels masked
}
bool GSRendererHW::IsDiscardingDstRGB()
{
return ((!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack() || !m_context->ALPHA.IsCdInBlend()) && // no blending or writing black
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFFFFFFu) == 0); // RGB isn't masked
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFFFFFFu) == 0); // RGB isn't masked
}
bool GSRendererHW::IsDiscardingDstAlpha() const
{
return ((!PRIM->ABE || m_context->ALPHA.C != 1) && // not using Ad
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFF000000u) == 0) && // alpha isn't masked
(!m_cached_ctx.TEST.ATE || !(m_cached_ctx.TEST.ATST == ATST_NEVER && m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && m_cached_ctx.FRAME.PSM == PSMCT32)); // No alpha test or no rbg only
((m_cached_ctx.FRAME.FBMSK & GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].fmsk) & 0xFF000000u) == 0) && // alpha isn't masked
(!m_cached_ctx.TEST.ATE || !(m_cached_ctx.TEST.ATST == ATST_NEVER && m_cached_ctx.TEST.AFAIL == AFAIL_RGB_ONLY && m_cached_ctx.FRAME.PSM == PSMCT32)); // No alpha test or no rbg only
}
// Like PrimitiveCoversWithoutGaps but with texture coordinates.
@@ -9068,12 +9072,12 @@ bool GSRendererHW::TextureCoversWithoutGapsNotEqual()
const int this_start_U = v[i].U;
const int last_start_U = v[i - 2].U;
const int dtU = v[i + 1].U - v[i].U;
const int dtU = v[i + 1].U - v[i].U;
if (this_start_U < last_start_U)
{
if (std::abs(dtU - last_start_U) >= 16 || std::abs(this_start_U) >= 16)
{;
{
return false;
}
}
@@ -9440,7 +9444,7 @@ void GSRendererHW::EndHLEHardwareDraw(bool force_copy_on_hazard /* = false */)
return;
}
const GSVector4i copy_rect = config.drawarea.rintersect(src->GetRect());
const GSVector4i copy_rect = config.drawarea.rintersect(src->GetRect());
g_gs_device->CopyRect(src, copy, copy_rect - copy_rect.xyxy(), copy_rect.x, copy_rect.y);
config.tex = copy;
}
@@ -9449,8 +9453,8 @@ void GSRendererHW::EndHLEHardwareDraw(bool force_copy_on_hazard /* = false */)
// Drop color1 if dual-source is not being used.
config.ps.no_color = !config.rt;
config.ps.no_color1 = !config.rt || !config.blend.enable ||
(!GSDevice::IsDualSourceBlendFactor(config.blend.src_factor) &&
!GSDevice::IsDualSourceBlendFactor(config.blend.dst_factor));
(!GSDevice::IsDualSourceBlendFactor(config.blend.src_factor) &&
!GSDevice::IsDualSourceBlendFactor(config.blend.dst_factor));
g_gs_device->RenderHW(m_conf);

View File

@@ -348,7 +348,7 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
const int rect_pages = std::max(((in_rect.width() / t_psm.pgs.x) % src_pgw) + ((in_rect.height() / t_psm.pgs.y) * src_pgw), 1);
page_offset += rect_offset;
in_rect -= GSVector4i(horizontal_offset * t_psm.pgs.x, vertical_offset * t_psm.pgs.y).xyxy();
if (sbw == 0) // Intentionally check this separately
{
// BW == 0 loops vertically on the first page. So just copy the whole page vertically.
@@ -391,7 +391,7 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
}
else
{
// Fills full length, so count pages based on the width, adjust rect to fill original rect.
// Battle Assault 3 does a move with BW 7 instead of 8 and does 448x512, instead of 512x448. Same result, but confusing for us.
@@ -1334,7 +1334,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
continue;
const bool width_match = (std::max(64U, bw * 64U) >> GSLocalMemory::m_psm[psm].info.pageShiftX()) ==
(std::max(64U, t->m_TEX0.TBW * 64U) >> GSLocalMemory::m_psm[t->m_TEX0.PSM].info.pageShiftX());
(std::max(64U, t->m_TEX0.TBW * 64U) >> GSLocalMemory::m_psm[t->m_TEX0.PSM].info.pageShiftX());
if (bp == t->m_TEX0.TBP0 && !t->m_dirty.empty() && GSUtil::GetChannelMask(psm) == GSUtil::GetChannelMask(t->m_TEX0.PSM) && GSRendererHW::GetInstance()->m_draw_transfers.size() > 0)
{
@@ -1461,7 +1461,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
{
rect_clean = false;
if(!dirty_rect.rintersect(t->m_valid).eq(t->m_valid) || GSUtil::GetChannelMask(t->m_TEX0.PSM) != t->m_dirty.GetDirtyChannels())
if (!dirty_rect.rintersect(t->m_valid).eq(t->m_valid) || GSUtil::GetChannelMask(t->m_TEX0.PSM) != t->m_dirty.GetDirtyChannels())
partial |= !new_rect.rintersect(dirty_rect).eq(new_rect) || dirty_rect.eq(new_rect);
else // Nothing is valid anymore, kill it.
{
@@ -1484,7 +1484,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
const u32 channels = t->m_dirty.GetDirtyChannels() & channel_mask;
const bool dirty_overlap = !t->m_dirty.GetTotalRect(t->m_TEX0, t->m_unscaled_size).rintersect(new_rect).rempty();
// If the source is reading the rt, make sure it's big enough.
if (!possible_shuffle && t && GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM)&& real_fmt_match)
if (!possible_shuffle && t && GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM) && real_fmt_match)
{
// Be careful if a new texture has been uploaded that expands the current one (Valkyrie Profile 2 does this)
GSVector4i dirty_rect = (t->m_dirty.size() > 0 && bw == t->m_TEX0.TBW) ? t->m_dirty.GetTotalRect(t->m_TEX0, GSVector2i(new_rect.z, new_rect.w)) : GSVector4i(GSVector4(t->m_valid) * GSVector4(2));
@@ -1595,7 +1595,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
const u32 color_psm = ((psm & 0x30) == 0x30) ? (psm & ~0x30) : psm;
const u32 tex_color_psm = ((t->m_TEX0.PSM & 0x30) == 0x30) ? (t->m_TEX0.PSM & ~0x30) : t->m_TEX0.PSM;
const bool can_convert = (GSUtil::HasCompatibleBits(psm, t_psm) && ((bw == t->m_TEX0.TBW) || (bw <= 1 && req_rect.w < GSLocalMemory::m_psm[psm].pgs.y))) ||
(possible_shuffle && ((bw == t->m_TEX0.TBW) || (bw == (t->m_TEX0.TBW * 2) || bw <= 2)) && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32);
(possible_shuffle && ((bw == t->m_TEX0.TBW) || (bw == (t->m_TEX0.TBW * 2) || bw <= 2)) && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32);
if (t->m_was_dst_matched)
{
@@ -1608,7 +1608,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
for (Target* dst_match : m_dst[DepthStencil])
{
// Be careful of dirty overlap on the targets, we don't really want dirty data.
if (dst_match->m_TEX0.TBP0 != t->m_TEX0.TBP0 || !dst_match->m_valid_rgb ||(!dst_match->m_dirty.empty() && !dst_match->m_dirty.GetTotalRect(dst_match->m_TEX0, dst_match->m_unscaled_size).rintersect(block_boundary_rect).rempty()))
if (dst_match->m_TEX0.TBP0 != t->m_TEX0.TBP0 || !dst_match->m_valid_rgb || (!dst_match->m_dirty.empty() && !dst_match->m_dirty.GetTotalRect(dst_match->m_TEX0, dst_match->m_unscaled_size).rintersect(block_boundary_rect).rempty()))
continue;
if (!CopyRGBFromDepthToColor(t, dst_match))
@@ -1684,8 +1684,8 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
// Make sure the texture actually is INSIDE the RT, it's possibly not valid if it isn't.
// Also check BP >= TBP, create source isn't equpped to expand it backwards and all data comes from the target. (GH3)
else if (GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets &&
(GSLocalMemory::m_psm[color_psm].bpp >= 16 || (/*possible_shuffle &&*/ GSLocalMemory::m_psm[color_psm].bpp == 8 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp >= 16)) && // Channel shuffles or non indexed lookups.
t->m_age <= 1 && (!found_t || t->m_last_draw > dst->m_last_draw) /*&& CanTranslate(bp, bw, psm, block_boundary_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW)*/)
(GSLocalMemory::m_psm[color_psm].bpp >= 16 || (/*possible_shuffle &&*/ GSLocalMemory::m_psm[color_psm].bpp == 8 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp >= 16)) && // Channel shuffles or non indexed lookups.
t->m_age <= 1 && (!found_t || t->m_last_draw > dst->m_last_draw) /*&& CanTranslate(bp, bw, psm, block_boundary_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW)*/)
{
u32 rt_tbw = std::max(1U, t->m_TEX0.TBW);
u32 horz_page_offset = ((bp - t->m_TEX0.TBP0) >> 5) % rt_tbw;
@@ -1694,18 +1694,20 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
continue;
if (GSLocalMemory::m_psm[color_psm].bpp == 16 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32 && bw != 1 &&
((t->m_TEX0.TBW < (horz_page_offset + ((block_boundary_rect.z + GSLocalMemory::m_psm[psm].pgs.x - 1) / GSLocalMemory::m_psm[psm].pgs.x)) ||
(t->m_TEX0.TBW != bw && block_boundary_rect.w > GSLocalMemory::m_psm[psm].pgs.y))))
((t->m_TEX0.TBW < (horz_page_offset + ((block_boundary_rect.z + GSLocalMemory::m_psm[psm].pgs.x - 1) / GSLocalMemory::m_psm[psm].pgs.x)) ||
(t->m_TEX0.TBW != bw && block_boundary_rect.w > GSLocalMemory::m_psm[psm].pgs.y))))
{
DbgCon.Warning("BP %x - 16bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
continue;
}
// Keep note that 2 bw is basically 1 normal page, as bw is in 64 pixels, and 8bit pages are 128 pixels wide, aka 2 bw.
// Also check for 4HH/HL and 8H which use the alpha channel, if the page order is wrong this can cause problems as well (Jak X font).
else if (!possible_shuffle && GSLocalMemory::m_psm[psm].trbpp <= 8 && (GSUtil::GetChannelMask(t->m_TEX0.PSM) != 0xF ||
((GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp != 16 || GSLocalMemory::m_psm[psm].bpp < 16) && (!(block_boundary_rect.w <= GSLocalMemory::m_psm[psm].pgs.y &&
((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) <= t->m_TEX0.TBW) &&
!(((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) == rt_tbw)))))
else if (!possible_shuffle && GSLocalMemory::m_psm[psm].trbpp <= 8 &&
(GSUtil::GetChannelMask(t->m_TEX0.PSM) != 0xF ||
((GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp != 16 || GSLocalMemory::m_psm[psm].bpp < 16) &&
(!(block_boundary_rect.w <= GSLocalMemory::m_psm[psm].pgs.y &&
((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) <= t->m_TEX0.TBW) &&
!(((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) == rt_tbw)))))
{
DbgCon.Warning("BP %x - 8bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
continue;
@@ -1870,9 +1872,9 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
const GSOffset offset(GSLocalMemory::m_psm[src_psm].info, bp, bw, psm);
const u32 offset_bp = offset.bn(region.GetMinX(), region.GetMinY());
if (bp < t->m_TEX0.TBP0 && region.HasX() && region.HasY() &&
(region.GetMinX() & (page_size.x - 1)) == 0 && (region.GetMinY() & (page_size.y - 1)) == 0 &&
(offset.bn(region.GetMinX(), region.GetMinY()) == t->m_TEX0.TBP0 ||
((offset_bp >= t->m_TEX0.TBP0) && ((((offset_bp - t->m_TEX0.TBP0) >> 5) % bw) + (rect.width() / page_size.x)) <= bw)))
(region.GetMinX() & (page_size.x - 1)) == 0 && (region.GetMinY() & (page_size.y - 1)) == 0 &&
(offset.bn(region.GetMinX(), region.GetMinY()) == t->m_TEX0.TBP0 ||
((offset_bp >= t->m_TEX0.TBP0) && ((((offset_bp - t->m_TEX0.TBP0) >> 5) % bw) + (rect.width() / page_size.x)) <= bw)))
{
GL_CACHE("TC: Target 0x%x detected in front of TBP 0x%x with %d,%d offset (%d pages)",
t->m_TEX0.TBP0, TEX0.TBP0, region.GetMinX(), region.GetMinY(),
@@ -2292,7 +2294,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
if (bp == t->m_TEX0.TBP0)
{
bool can_use = true;
if (dst && ((GSState::s_n - dst->m_last_draw) < (GSState::s_n - t->m_last_draw) && dst->m_TEX0.TBP0 <= bp))
{
DevCon.Warning("Ignoring target at %x as one at %x is newer", t->m_TEX0.TBP0, dst->m_TEX0.TBP0);
@@ -2452,7 +2454,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
const GSVector4i dirty_rect = t->m_dirty.empty() ? GSVector4i::zero() : t->m_dirty.GetTotalRect(t->m_TEX0, t->m_unscaled_size);
const bool all_dirty = dirty_rect.eq(t->m_valid);
if (!is_shuffle && !dirty_rect.rempty() && (!preserve_alpha && !preserve_rgb) && (GSState::s_n - 3) > t->m_last_draw)
{
GL_INS("TC: Deleting RT BP 0x%x BW %d PSM %s due to dirty areas not preserved (Likely change in target)", t->m_TEX0.TBP0, t->m_TEX0.TBW, GSUtil::GetPSMName(t->m_TEX0.PSM));
@@ -2627,7 +2629,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
{
calcRescale(dst);
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) :
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
if (!tex)
return nullptr;
@@ -2680,8 +2682,11 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
new_scaled_size = ScaleRenderTargetSize(dst->m_unscaled_size, dst->m_scale);
dRect = (GSVector4(dst->m_valid) * GSVector4(dst->m_scale)).ceil();
GSVector4 source_rect = GSVector4(static_cast<float>(dst->m_valid.x) / static_cast<float>(dst->m_unscaled_size.x), static_cast<float>(dst->m_valid.y) / static_cast<float>(dst->m_unscaled_size.y),
static_cast<float>(dst->m_valid.z) / static_cast<float>(dst->m_unscaled_size.x), static_cast<float>(dst->m_valid.w) / static_cast<float>(dst->m_unscaled_size.y));
GSVector4 source_rect = GSVector4(
static_cast<float>(dst->m_valid.x) / static_cast<float>(dst->m_unscaled_size.x),
static_cast<float>(dst->m_valid.y) / static_cast<float>(dst->m_unscaled_size.y),
static_cast<float>(dst->m_valid.z) / static_cast<float>(dst->m_unscaled_size.x),
static_cast<float>(dst->m_valid.w) / static_cast<float>(dst->m_unscaled_size.y));
if (!is_shuffle || GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 16)
{
if (scale_down)
@@ -2727,7 +2732,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
else
{
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) :
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
if (!tex)
return nullptr;
@@ -2748,7 +2753,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
else
{
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) :
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
if (!tex)
return nullptr;
@@ -2769,7 +2774,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
}
// New format or doing a shuffle to a 32bit target that used to be 16bit
if ((!is_shuffle && (GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp != GSLocalMemory::m_psm[TEX0.PSM].bpp || GSLocalMemory::m_psm[dst->m_TEX0.PSM].depth != GSLocalMemory::m_psm[TEX0.PSM].depth)) ||
if ((!is_shuffle && (GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp != GSLocalMemory::m_psm[TEX0.PSM].bpp || GSLocalMemory::m_psm[dst->m_TEX0.PSM].depth != GSLocalMemory::m_psm[TEX0.PSM].depth)) ||
(is_shuffle && GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 16))
{
if (GSLocalMemory::m_psm[dst->m_TEX0.PSM].depth != GSLocalMemory::m_psm[TEX0.PSM].depth || dst->m_TEX0.TBW != TEX0.TBW)
@@ -2835,8 +2840,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
}
const ShaderConvert shader = (GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 16) ? ShaderConvert::RGB5A1_TO_FLOAT16 :
(GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32) ? ShaderConvert::RGBA8_TO_FLOAT32 :
ShaderConvert::RGBA8_TO_FLOAT24;
(GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32) ? ShaderConvert::RGBA8_TO_FLOAT32 :
ShaderConvert::RGBA8_TO_FLOAT24;
g_gs_device->StretchRect(dst_match->m_texture, GSVector4(0, 0, 1, 1),
dst->m_texture, GSVector4(dst->GetUnscaledRect()) * GSVector4(dst->GetScale()), shader, false);
@@ -2859,10 +2864,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
// Unfortunately, we still have an alpha channel to preserve, and we can't clear RGB...
// So, create a new target, clear/preload it, and copy RGB in.
GSTexture* tex = (type == RenderTarget) ?
g_gs_device->CreateRenderTarget(dst->m_texture->GetWidth(),
dst->m_texture->GetHeight(), GSTexture::Format::Color, true) :
g_gs_device->CreateDepthStencil(dst->m_texture->GetWidth(),
dst->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true);
g_gs_device->CreateRenderTarget(dst->m_texture->GetWidth(), dst->m_texture->GetHeight(), GSTexture::Format::Color, true) :
g_gs_device->CreateDepthStencil(dst->m_texture->GetWidth(), dst->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true);
if (!tex)
return nullptr;
@@ -2943,7 +2946,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
}
// If the format is completely different, but it's the same location, it's likely just overwriting it, so get rid.
// Make sure it's not currently in use, that could be bad.
if (!is_shuffle && (!ds || (ds != t)) &&
if (!is_shuffle && (!ds || (ds != t)) &&
t->m_TEX0.TBW != TEX0.TBW && TEX0.TBW != 1 && !preserve_rgb && min_rect.w > GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.y)
{
if (src && src->m_target && src->m_from_target == t && src->m_target_direct)
@@ -3017,7 +3020,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
// If we don't need A, and the existing target doesn't have valid alpha, don't bother converting it.
const bool has_alpha = dst_match->HasValidAlpha();
const bool preserve_target = (preserve_rgb || (preserve_alpha && has_alpha)) ||
!draw_rect.rintersect(dst_match->m_valid).eq(dst_match->m_valid);
!draw_rect.rintersect(dst_match->m_valid).eq(dst_match->m_valid);
bool half_width = false;
@@ -3069,7 +3072,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
GL_CACHE("TC: Lookup Target(Depth) %dx%d, hit Color (0x%x, TBW %d, %s was %s)", new_size.x, new_size.y,
bp, TEX0.TBW, GSUtil::GetPSMName(TEX0.PSM), GSUtil::GetPSMName(dst_match->m_TEX0.PSM));
shader = (fmt_16_bits) ? ShaderConvert::RGB5A1_TO_FLOAT16 :
(ShaderConvert)(static_cast<int>(ShaderConvert::RGBA8_TO_FLOAT32) + psm_s.fmt);
(ShaderConvert)(static_cast<int>(ShaderConvert::RGBA8_TO_FLOAT32) + psm_s.fmt);
}
else
{
@@ -3402,7 +3405,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
}
}
const GSVector4i dst_valid = dst->m_valid.rempty() ? GSVector4i::loadh(valid_size) : dst->m_valid;
u32 dst_end_block = GSLocalMemory::GetEndBlockAddress(dst->m_TEX0.TBP0, dst->m_TEX0.TBW, dst->m_TEX0.PSM, dst_valid);
if (dst_end_block < dst->m_TEX0.TBP0)
@@ -3433,7 +3436,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
// Probably best we don't poke the beast if it's being used as the current source.
if (src && src->m_target_direct && src->m_from_target == t)
continue;
InvalidateSourcesFromTarget(t);
i = list.erase(j);
delete t;
@@ -3541,7 +3544,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
GL_INS("TC: RT double buffer copy from FBP 0x%x, %dx%d => %d,%d", t->m_TEX0.TBP0, copy_width, copy_height, 0, dst_offset_scaled_height);
// Clear the dirty first
t->Update();
dst->Update();
@@ -3621,11 +3624,12 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
t->m_was_dst_matched = true;
dst->ResizeTexture(t->m_unscaled_size.x, t->m_unscaled_size.y);
const ShaderConvert shader = (GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 16) ? ShaderConvert::RGB5A1_TO_FLOAT16 :
(GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32) ? ShaderConvert::RGBA8_TO_FLOAT32 : ShaderConvert::RGBA8_TO_FLOAT24;
g_gs_device->StretchRect(t->m_texture, GSVector4(0,0,1,1),
const ShaderConvert shader = (GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 16) ? ShaderConvert::RGB5A1_TO_FLOAT16 :
(GSLocalMemory::m_psm[dst->m_TEX0.PSM].trbpp == 32) ? ShaderConvert::RGBA8_TO_FLOAT32 :
ShaderConvert::RGBA8_TO_FLOAT24;
g_gs_device->StretchRect(t->m_texture, GSVector4(0, 0, 1, 1),
dst->m_texture, GSVector4(t->GetUnscaledRect()) * GSVector4(dst->GetScale()), shader, false);
break;
@@ -3658,10 +3662,8 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
t->ResizeValidity(t->m_valid);
GSTexture* tex = (t->m_type == RenderTarget) ?
g_gs_device->CreateRenderTarget(t->m_texture->GetWidth(),
t->m_texture->GetHeight(), GSTexture::Format::Color, true) :
g_gs_device->CreateDepthStencil(t->m_texture->GetWidth(),
t->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true);
g_gs_device->CreateRenderTarget(t->m_texture->GetWidth(), t->m_texture->GetHeight(), GSTexture::Format::Color, true) :
g_gs_device->CreateDepthStencil(t->m_texture->GetWidth(), t->m_texture->GetHeight(), GSTexture::Format::DepthStencil, true);
if (tex)
{
g_gs_device->CopyRect(t->m_texture, tex, GSVector4i(0, height_adjust * t->m_scale, t->m_texture->GetWidth(), t->m_texture->GetHeight()), 0, 0);
@@ -3702,7 +3704,6 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
continue;
}
}
}
i++;
}
@@ -3937,8 +3938,8 @@ float GSTextureCache::ConvertColorToDepth(u32 c, ShaderConvert convert)
{
case ShaderConvert::RGB5A1_TO_FLOAT16:
return static_cast<float>(((c & 0xF8u) >> 3) | (((c >> 8) & 0xF8u) << 2) | (((c >> 16) & 0xF8u) << 7) |
(((c >> 24) & 0x80u) << 8)) *
mult;
(((c >> 24) & 0x80u) << 8)) *
mult;
case ShaderConvert::RGBA8_TO_FLOAT16:
return static_cast<float>(c & 0x0000FFFF) * mult;
@@ -4185,7 +4186,7 @@ void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 wr
if (type == DepthStencil && t->m_TEX0.TBP0 < start_bp && t->m_end_block > start_bp)
{
const GSVector4i masked_valid = GSVector4i(t->m_valid.x, t->m_valid.y, t->m_valid.z & ~1, t->m_valid.w & ~1);
const u32 reduced_endblock = GSLocalMemory::GetEndBlockAddress(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, masked_valid);
const u32 reduced_endblock = GSLocalMemory::GetEndBlockAddress(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, masked_valid);
if (reduced_endblock <= start_bp)
{
@@ -5040,8 +5041,8 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
if (SBP == DBP && (!(GSVector4i(sx, sy, sx + w, sy + h).rintersect(GSVector4i(dx, dy, dx + w, dy + h))).rempty() || renderer_is_directx))
{
GSTexture* tmp_texture = src->m_texture->IsDepthStencil() ?
g_gs_device->CreateDepthStencil(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false) :
g_gs_device->CreateRenderTarget(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false);
g_gs_device->CreateDepthStencil(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false) :
g_gs_device->CreateRenderTarget(src->m_texture->GetWidth(), src->m_texture->GetHeight(), src->m_texture->GetFormat(), false);
if (!tmp_texture)
{
Console.Error("(HW Move) Failed to allocate temporary %dx%d texture on HW move", w, h);
@@ -5109,7 +5110,6 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
}
const GSVector4 src_rect = GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h) / (GSVector4(src->m_texture->GetSize()).xyxy());
g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h), shader, false);
}
else
{
@@ -5725,8 +5725,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
const bool outside_target = ((x + w) > dst->m_texture->GetWidth() || (y + h) > dst->m_texture->GetHeight());
GSTexture* sTex = dst->m_texture;
GSTexture* dTex = outside_target ?
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, true, PreferReusedLabelledTexture()) :
g_gs_device->CreateTexture(w, h, tlevels, GSTexture::Format::Color, PreferReusedLabelledTexture());
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, true, PreferReusedLabelledTexture()) :
g_gs_device->CreateTexture(w, h, tlevels, GSTexture::Format::Color, PreferReusedLabelledTexture());
if (!dTex) [[unlikely]]
{
Console.Error("Failed to allocate %dx%d texture for offset source", w, h);
@@ -6037,10 +6037,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
// 'src' is the new texture cache entry (hence the output)
GSTexture* sTex = dst->m_texture;
GSTexture* dTex = use_texture ?
g_gs_device->CreateTexture(new_size.x, new_size.y, 1, GSTexture::Format::Color,
PreferReusedLabelledTexture()) :
g_gs_device->CreateRenderTarget(new_size.x, new_size.y, GSTexture::Format::Color,
source_rect_empty || destX != 0 || destY != 0, PreferReusedLabelledTexture());
g_gs_device->CreateTexture(new_size.x, new_size.y, 1, GSTexture::Format::Color, PreferReusedLabelledTexture()) :
g_gs_device->CreateRenderTarget(new_size.x, new_size.y, GSTexture::Format::Color, source_rect_empty || destX != 0 || destY != 0, PreferReusedLabelledTexture());
if (!dTex) [[unlikely]]
{
Console.Error("Failed to allocate %dx%d texture for target copy to source", new_size.x, new_size.y);
@@ -6090,7 +6088,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
// Adjust to match a PSMT8 texture (coordinates are double C32, we shouldn't be converting from anything else).
x_offset *= 2;
if (GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 32)
if (GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 32)
y_offset *= 2;
src->m_region.SetX(x_offset, x_offset + tw);
@@ -6552,7 +6550,7 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0
{
// don't bother hashing if we're not dumping or replacing.
const bool dump = GSConfig.DumpReplaceableTextures && (!FMVstarted || GSConfig.DumpTexturesWithFMVActive) &&
(clut ? GSConfig.DumpPaletteTextures : GSConfig.DumpDirectTextures);
(clut ? GSConfig.DumpPaletteTextures : GSConfig.DumpDirectTextures);
const bool replace = GSConfig.LoadTextureReplacements && GSTextureReplacements::HasAnyReplacementTextures();
bool can_cache = (TEX0.PSM >= PSMT8H && TEX0.PSM <= PSMT4HH) ? CanPreloadTextureSize(TEX0.TW, TEX0.TH) : CanCacheTextureSize(TEX0.TW, TEX0.TH);
if (!dump && !replace && !can_cache)
@@ -6773,8 +6771,8 @@ GSTextureCache::Target* GSTextureCache::Target::Create(GIFRegTEX0 TEX0, int w, i
const int scaled_w = static_cast<int>(std::ceil(static_cast<float>(w) * scale));
const int scaled_h = static_cast<int>(std::ceil(static_cast<float>(h) * scale));
GSTexture* texture = (type == RenderTarget) ?
g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear, PreferReusedLabelledTexture()) :
g_gs_device->CreateDepthStencil(scaled_w, scaled_h, GSTexture::Format::DepthStencil, clear, PreferReusedLabelledTexture());
g_gs_device->CreateRenderTarget(scaled_w, scaled_h, GSTexture::Format::Color, clear, PreferReusedLabelledTexture()) :
g_gs_device->CreateDepthStencil(scaled_w, scaled_h, GSTexture::Format::DepthStencil, clear, PreferReusedLabelledTexture());
if (!texture)
return nullptr;
@@ -7314,7 +7312,7 @@ void GSTextureCache::Source::Flush(u32 count, int layer, const GSOffset& off)
// need to offset if we're a region texture
const u8* src = s_unswizzle_buffer + (pitch * static_cast<u32>(std::max(tex_r.top - r.top, 0))) +
(static_cast<u32>(std::max(tex_r.left - r.left, 0)) << (m_palette ? 0 : 2));
(static_cast<u32>(std::max(tex_r.left - r.left, 0)) << (m_palette ? 0 : 2));
m_texture->Update(rint - tex_r.xyxy(), src, pitch, layer);
}
@@ -7410,8 +7408,8 @@ GSTextureCache::Target::~Target()
if (src->m_from_target == this)
{
pxFail(fmt::format("Source at TBP {:x} for target at TBP {:x} on target invalidation",
static_cast<u32>(src->m_TEX0.TBP0), static_cast<u32>(m_TEX0.TBP0))
.c_str());
static_cast<u32>(src->m_TEX0.TBP0), static_cast<u32>(m_TEX0.TBP0)
).c_str());
break;
}
}
@@ -7749,10 +7747,8 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca
const bool clear = (new_size.x > size.x || new_size.y > size.y);
GSTexture* tex = m_texture->IsDepthStencil() ?
g_gs_device->CreateDepthStencil(new_size.x, new_size.y, m_texture->GetFormat(), clear,
PreferReusedLabelledTexture()) :
g_gs_device->CreateRenderTarget(new_size.x, new_size.y, m_texture->GetFormat(), clear,
PreferReusedLabelledTexture());
g_gs_device->CreateDepthStencil(new_size.x, new_size.y, m_texture->GetFormat(), clear, PreferReusedLabelledTexture()) :
g_gs_device->CreateRenderTarget(new_size.x, new_size.y, m_texture->GetFormat(), clear, PreferReusedLabelledTexture());
if (!tex)
{
Console.Error("(ResizeTexture) Failed to allocate %dx%d texture from %dx%d texture", size.x, size.y, new_size.x, new_size.y);
@@ -8261,8 +8257,8 @@ u64 GSTextureCache::PaletteKeyHash::operator()(const PaletteKey& key) const
{
pxAssert(key.pal == 16 || key.pal == 256);
return key.pal == 16 ?
GSXXH3_64bits(key.clut, sizeof(key.clut[0]) * 16) :
GSXXH3_64bits(key.clut, sizeof(key.clut[0]) * 256);
GSXXH3_64bits(key.clut, sizeof(key.clut[0]) * 16) :
GSXXH3_64bits(key.clut, sizeof(key.clut[0]) * 256);
};
// GSTextureCache::PaletteKeyEqual
@@ -8571,7 +8567,7 @@ static void HashTextureLevel(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, GST
// Hash the expanded texture.
u8* ptr = temp + (pitch * static_cast<u32>(rect.top - block_rect.top)) +
static_cast<u32>(rect.left - block_rect.left);
static_cast<u32>(rect.left - block_rect.left);
if (pitch == row_size)
{
BlockHashAccumulate(hash_st, ptr, pitch * static_cast<u32>(th));
@@ -8649,7 +8645,7 @@ void GSTextureCache::PreloadTexture(const GIFRegTEX0& TEX0, const GIFRegTEXA& TE
rtx(mem, off, block_rect, buff, pitch, TEXA);
const u8* ptr = buff + (pitch * static_cast<u32>(rect.top - block_rect.top)) +
(static_cast<u32>(rect.left - block_rect.left) << (paltex ? 0 : 2));
(static_cast<u32>(rect.left - block_rect.left) << (paltex ? 0 : 2));
if (alpha_minmax)
*alpha_minmax = GSGetRGBA8AlphaMinMax(ptr, unoffset_rect.width(), unoffset_rect.height(), pitch);

View File

@@ -290,7 +290,7 @@ public:
public:
HashCacheEntry* m_from_hash_cache = nullptr;
std::shared_ptr<Palette> m_palette_obj;
std::unique_ptr<u32[]> m_valid;// each u32 bits map to the 32 blocks of that page
std::unique_ptr<u32[]> m_valid; // each u32 bits map to the 32 blocks of that page
GSTexture* m_palette = nullptr;
GSVector4i m_valid_rect = {};
GSVector2i m_lod = {};
@@ -398,13 +398,13 @@ public:
struct SurfaceOffsetKey
{
std::array<SurfaceOffsetKeyElem, 2> elems; // A and B elems.
std::array<SurfaceOffsetKeyElem, 2> elems; // A and B elems.
};
struct SurfaceOffset
{
bool is_valid;
GSVector4i b2a_offset; // B to A offset in B coords.
GSVector4i b2a_offset; // B to A offset in B coords.
};
struct SurfaceOffsetKeyHash
@@ -504,9 +504,9 @@ public:
Target* FindTargetOverlap(Target* target, int type, int psm);
void CombineAlignedInsideTargets(Target* target, GSTextureCache::Source* src = nullptr);
Target* LookupTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, int type, bool used = true, u32 fbmask = 0,
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_rgb = true, bool preserve_alpha = true,
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_rgb = true, bool preserve_alpha = true,
const GSVector4i draw_rc = GSVector4i::zero(), bool is_shuffle = false, bool possible_clear = false, bool preserve_scale = false, GSTextureCache::Source* src = nullptr, GSTextureCache::Target* ds = nullptr, int offset = -1);
Target* CreateTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size,float scale, int type, bool used = true, u32 fbmask = 0,
Target* CreateTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size, float scale, int type, bool used = true, u32 fbmask = 0,
bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_target = true,
const GSVector4i draw_rc = GSVector4i::zero(), GSTextureCache::Source* src = nullptr);
Target* LookupDisplayTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, bool is_feedback);

View File

@@ -380,10 +380,8 @@ constexpr DDS_PIXELFORMAT DDSPF_R8G8B8 = {
static bool DDSPixelFormatMatches(const DDS_PIXELFORMAT& pf1, const DDS_PIXELFORMAT& pf2)
{
return std::tie(pf1.dwSize, pf1.dwFlags, pf1.dwFourCC, pf1.dwRGBBitCount, pf1.dwRBitMask,
pf1.dwGBitMask, pf1.dwGBitMask, pf1.dwBBitMask, pf1.dwABitMask) ==
std::tie(pf2.dwSize, pf2.dwFlags, pf2.dwFourCC, pf2.dwRGBBitCount, pf2.dwRBitMask,
pf2.dwGBitMask, pf2.dwGBitMask, pf2.dwBBitMask, pf2.dwABitMask);
return std::tie(pf1.dwSize, pf1.dwFlags, pf1.dwFourCC, pf1.dwRGBBitCount, pf1.dwRBitMask, pf1.dwGBitMask, pf1.dwGBitMask, pf1.dwBBitMask, pf1.dwABitMask) ==
std::tie(pf2.dwSize, pf2.dwFlags, pf2.dwFourCC, pf2.dwRGBBitCount, pf2.dwRBitMask, pf2.dwGBitMask, pf2.dwGBitMask, pf2.dwBBitMask, pf2.dwABitMask);
}
struct DDSLoadInfo

View File

@@ -527,11 +527,12 @@ fragment half4 ps_imgui(ImGuiShaderData data [[stage_in]], texture2d<half> textu
return data.c * texture.sample(s, data.t);
}
fragment float4 ps_shadeboost(float4 p [[position]], DirectReadTextureIn<float> tex, constant float3& cb [[buffer(GSMTLBufferIndexUniforms)]])
fragment float4 ps_shadeboost(float4 p [[position]], DirectReadTextureIn<float> tex, constant float4& cb [[buffer(GSMTLBufferIndexUniforms)]])
{
const float brt = cb.x;
const float con = cb.y;
const float sat = cb.z;
const float gam = cb.w;
// Increase or decrease these values to adjust r, g and b color channels separately
const float AvgLumR = 0.5;
const float AvgLumG = 0.5;
@@ -546,5 +547,7 @@ fragment float4 ps_shadeboost(float4 p [[position]], DirectReadTextureIn<float>
float3 satColor = mix(intensity, brtColor, sat);
float3 conColor = mix(AvgLumin, satColor, con);
return float4(conColor, 1);
float3 csb = pow(conColor, float3(1.0 / gam));
return float4(csb, 1);
}

View File

@@ -363,7 +363,7 @@ std::unique_ptr<GSDownloadTextureOGL> GSDownloadTextureOGL::Create(u32 width, u3
const u32 buffer_size = GetBufferSize(width, height, format, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
const bool use_buffer_storage = (GLAD_GL_VERSION_4_4 || GLAD_GL_ARB_buffer_storage || GLAD_GL_EXT_buffer_storage) &&
!GSDeviceOGL::GetInstance()->IsDownloadPBODisabled();
!GSDeviceOGL::GetInstance()->IsDownloadPBODisabled();
if (use_buffer_storage)
{
GLuint buffer_id;

View File

@@ -658,8 +658,8 @@ bool GSDeviceVK::CreateDevice(VkSurfaceKHR surface, bool enable_validation_layer
vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue);
}
m_spinning_supported = m_spin_queue_family_index != queue_family_count &&
queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0 &&
m_device_properties.limits.timestampPeriod > 0;
queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0 &&
m_device_properties.limits.timestampPeriod > 0;
m_spin_queue_is_graphics_queue =
m_spin_queue_family_index == m_graphics_queue_family_index && spin_queue_index == 0;
@@ -1089,7 +1089,7 @@ bool GSDeviceVK::SetGPUTimingEnabled(bool enabled)
void GSDeviceVK::ScanForCommandBufferCompletion()
{
for (u32 check_index = (m_current_frame + 1) % NUM_COMMAND_BUFFERS; check_index != m_current_frame;
check_index = (check_index + 1) % NUM_COMMAND_BUFFERS)
check_index = (check_index + 1) % NUM_COMMAND_BUFFERS)
{
FrameResources& resources = m_frame_resources[check_index];
if (resources.fence_counter <= m_completed_fence_counter)
@@ -2719,8 +2719,8 @@ VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const
}};
return (format != GSTexture::Format::DepthStencil || m_features.stencil_buffer) ?
s_format_mapping[static_cast<int>(format)] :
VK_FORMAT_D32_SFLOAT;
s_format_mapping[static_cast<int>(format)] :
VK_FORMAT_D32_SFLOAT;
}
GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
@@ -3197,12 +3197,10 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
EndRenderPass();
// transition everything before starting the new render pass
const bool has_input_0 =
(sTex[0] && (sTex[0]->GetState() == GSTexture::State::Dirty ||
(sTex[0]->GetState() == GSTexture::State::Cleared || sTex[0]->GetClearColor() != 0)));
const bool has_input_0 = (sTex[0] &&
(sTex[0]->GetState() == GSTexture::State::Dirty || (sTex[0]->GetState() == GSTexture::State::Cleared || sTex[0]->GetClearColor() != 0)));
const bool has_input_1 = (PMODE.SLBG == 0 || feedback_write_2_but_blend_bg) && sTex[1] &&
(sTex[1]->GetState() == GSTexture::State::Dirty ||
(sTex[1]->GetState() == GSTexture::State::Cleared || sTex[1]->GetClearColor() != 0));
(sTex[1]->GetState() == GSTexture::State::Dirty || (sTex[1]->GetState() == GSTexture::State::Cleared || sTex[1]->GetClearColor() != 0));
if (has_input_0)
{
static_cast<GSTextureVK*>(sTex[0])->CommitClear();
@@ -3825,15 +3823,14 @@ bool GSDeviceVK::CreateRenderPasses()
{
for (u32 opa = VK_ATTACHMENT_LOAD_OP_LOAD; opa <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; opa++)
{
for (u32 opb = VK_ATTACHMENT_LOAD_OP_LOAD; opb <= VK_ATTACHMENT_LOAD_OP_DONT_CARE;
opb++)
for (u32 opb = VK_ATTACHMENT_LOAD_OP_LOAD; opb <= VK_ATTACHMENT_LOAD_OP_DONT_CARE; opb++)
{
const VkFormat rp_rt_format =
(rt != 0) ? ((colclip != 0) ? colclip_rt_format : rt_format) : VK_FORMAT_UNDEFINED;
const VkFormat rp_depth_format = (ds != 0) ? depth_format : VK_FORMAT_UNDEFINED;
const VkAttachmentLoadOp opc = (!stencil || !m_features.stencil_buffer) ?
VK_ATTACHMENT_LOAD_OP_DONT_CARE :
VK_ATTACHMENT_LOAD_OP_LOAD;
VK_ATTACHMENT_LOAD_OP_DONT_CARE :
VK_ATTACHMENT_LOAD_OP_LOAD;
GET(m_tfx_render_pass[rt][ds][colclip][stencil][fbl][dsp][opa][opb], rp_rt_format,
rp_depth_format, (fbl != 0), (dsp != 0), static_cast<VkAttachmentLoadOp>(opa),
static_cast<VkAttachmentLoadOp>(opb), static_cast<VkAttachmentLoadOp>(opc));
@@ -3896,8 +3893,7 @@ bool GSDeviceVK::CompileConvertPipelines()
gpb.SetNoBlendingState();
gpb.SetVertexShader(vs);
for (ShaderConvert i = ShaderConvert::COPY; static_cast<int>(i) < static_cast<int>(ShaderConvert::Count);
i = static_cast<ShaderConvert>(static_cast<int>(i) + 1))
for (ShaderConvert i = ShaderConvert::COPY; i < ShaderConvert::Count; i = static_cast<ShaderConvert>(static_cast<int>(i) + 1))
{
const bool depth = HasDepthOutput(i);
const int index = static_cast<int>(i);
@@ -4108,8 +4104,7 @@ bool GSDeviceVK::CompilePresentPipelines()
gpb.SetNoStencilState();
gpb.SetRenderPass(m_swap_chain_render_pass, 0);
for (PresentShader i = PresentShader::COPY; static_cast<int>(i) < static_cast<int>(PresentShader::Count);
i = static_cast<PresentShader>(static_cast<int>(i) + 1))
for (PresentShader i = PresentShader::COPY; i < PresentShader::Count; i = static_cast<PresentShader>(static_cast<int>(i) + 1))
{
const int index = static_cast<int>(i);
@@ -5610,7 +5605,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
// If we have a colclip in progress, we need to use the colclip texture, but we can't check this later as there's a chicken/egg problem with the pipe setup.
GSTexture* backup_rt = config.rt;
if(colclip_rt)
if (colclip_rt)
config.rt = colclip_rt;
date_image = SetupPrimitiveTrackingDATE(config);
@@ -5838,8 +5833,9 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
// Only draw to the active area of the colclip hw target. Except when depth is cleared, we need to use the full
// buffer size, otherwise it'll only clear the draw part of the depth buffer.
const GSVector4i render_area = (pipe.ps.colclip_hw && (config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertAndResolve) && ds_op != VK_ATTACHMENT_LOAD_OP_CLEAR) ? config.drawarea :
GSVector4i::loadh(rtsize);
const GSVector4i render_area = (pipe.ps.colclip_hw && (config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertAndResolve) && ds_op != VK_ATTACHMENT_LOAD_OP_CLEAR)
? config.drawarea
: GSVector4i::loadh(rtsize);
if (is_clearing_rt)
{
@@ -6053,7 +6049,7 @@ VkImageMemoryBarrier GSDeviceVK::GetColorBufferBarrier(GSTextureVK* rt) const
VkDependencyFlags GSDeviceVK::GetColorBufferBarrierFlags() const
{
return UseFeedbackLoopLayout() ? (VK_DEPENDENCY_BY_REGION_BIT | VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT) :
VK_DEPENDENCY_BY_REGION_BIT;
VK_DEPENDENCY_BY_REGION_BIT;
}
void GSDeviceVK::SendHWDraw(const GSHWDrawConfig& config, GSTextureVK* draw_rt,

View File

@@ -640,10 +640,10 @@ private:
DIRTY_FLAG_TFX_TEXTURE_PRIMID = (DIRTY_FLAG_TFX_TEXTURE_0 << 3),
DIRTY_FLAG_TFX_TEXTURES = DIRTY_FLAG_TFX_TEXTURE_TEX | DIRTY_FLAG_TFX_TEXTURE_PALETTE |
DIRTY_FLAG_TFX_TEXTURE_RT | DIRTY_FLAG_TFX_TEXTURE_PRIMID,
DIRTY_FLAG_TFX_TEXTURE_RT | DIRTY_FLAG_TFX_TEXTURE_PRIMID,
DIRTY_BASE_STATE = DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_PIPELINE | DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR |
DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_LINE_WIDTH,
DIRTY_FLAG_BLEND_CONSTANTS | DIRTY_FLAG_LINE_WIDTH,
DIRTY_TFX_STATE = DIRTY_BASE_STATE | DIRTY_FLAG_TFX_TEXTURES,
DIRTY_UTILITY_STATE = DIRTY_BASE_STATE | DIRTY_FLAG_UTILITY_TEXTURE,
DIRTY_CONSTANT_BUFFER_STATE = DIRTY_FLAG_VS_CONSTANT_BUFFER | DIRTY_FLAG_PS_CONSTANT_BUFFER,

View File

@@ -33,14 +33,14 @@ static VkImageLayout GetVkImageLayout(GSTextureVK::Layout layout)
VK_IMAGE_LAYOUT_GENERAL, // General
}};
return (layout == GSTextureVK::Layout::FeedbackLoop && GSDeviceVK::GetInstance()->UseFeedbackLoopLayout()) ?
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
s_vk_layout_mapping[static_cast<u32>(layout)];
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT :
s_vk_layout_mapping[static_cast<u32>(layout)];
}
static VkAccessFlagBits GetFeedbackLoopInputAccessBits()
{
return GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_ACCESS_SHADER_READ_BIT :
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
}
GSTextureVK::GSTextureVK(Type type, Format format, int width, int height, int levels, VkImage image,
@@ -102,8 +102,8 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
ici.usage =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT :
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT
: VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT);
}
break;
@@ -113,8 +113,8 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
ici.usage =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT :
0);
(GSDeviceVK::GetInstance()->UseFeedbackLoopLayout() ? VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT
: 0);
vci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
}
break;
@@ -123,7 +123,7 @@ std::unique_ptr<GSTextureVK> GSTextureVK::Create(Type type, Format format, int w
{
pxAssert(levels == 1);
ici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT;
VK_IMAGE_USAGE_SAMPLED_BIT;
}
break;
@@ -202,8 +202,7 @@ void GSTextureVK::Destroy(bool defer)
{
if (other_tex)
{
for (auto other_it = other_tex->m_framebuffers.begin(); other_it != other_tex->m_framebuffers.end();
++other_it)
for (auto other_it = other_tex->m_framebuffers.begin(); other_it != other_tex->m_framebuffers.end(); ++other_it)
{
if (std::get<0>(*other_it) == this)
{
@@ -566,7 +565,7 @@ void GSTextureVK::TransitionSubresourcesToLayout(
if (m_type == Type::DepthStencil)
{
aspect = g_gs_device->Features().stencil_buffer ? (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) :
VK_IMAGE_ASPECT_DEPTH_BIT;
VK_IMAGE_ASPECT_DEPTH_BIT;
}
else
{
@@ -638,15 +637,12 @@ void GSTextureVK::TransitionSubresourcesToLayout(
break;
case Layout::FeedbackLoop:
barrier.srcAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
GetFeedbackLoopInputAccessBits()) :
(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
srcStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) :
(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
barrier.srcAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
? (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits())
: (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
srcStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
? (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
: (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
break;
case Layout::ReadWriteImage:
@@ -714,15 +710,12 @@ void GSTextureVK::TransitionSubresourcesToLayout(
break;
case Layout::FeedbackLoop:
barrier.dstAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
(VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
GetFeedbackLoopInputAccessBits()) :
(VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
dstStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT) ?
(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT) :
(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
barrier.dstAccessMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
? (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | GetFeedbackLoopInputAccessBits())
: (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT);
dstStageMask = (aspect == VK_IMAGE_ASPECT_COLOR_BIT)
? (VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)
: (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
break;
case Layout::ReadWriteImage:
@@ -946,4 +939,4 @@ void GSDownloadTextureVK::SetDebugName(std::string_view name)
Vulkan::SetObjectName(GSDeviceVK::GetInstance()->GetDevice(), m_buffer, "%.*s", static_cast<int>(name.size()), name.data());
}
#endif
#endif

View File

@@ -114,14 +114,14 @@ namespace Vulkan
void AddBlendAttachment(bool blend_enable, VkBlendFactor src_factor, VkBlendFactor dst_factor, VkBlendOp op,
VkBlendFactor alpha_src_factor, VkBlendFactor alpha_dst_factor, VkBlendOp alpha_op,
VkColorComponentFlags write_mask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
void SetBlendAttachment(u32 attachment, bool blend_enable, VkBlendFactor src_factor, VkBlendFactor dst_factor,
VkBlendOp op, VkBlendFactor alpha_src_factor, VkBlendFactor alpha_dst_factor, VkBlendOp alpha_op,
VkColorComponentFlags write_mask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
void SetColorWriteMask(
u32 attachment, VkColorComponentFlags write_mask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT);
void AddBlendFlags(u32 flags);
void ClearBlendAttachments();
@@ -407,4 +407,4 @@ namespace Vulkan
va_end(ap);
#endif
}
} // namespace Vulkan
} // namespace Vulkan

View File

@@ -66,10 +66,18 @@ namespace
{
SmallStackString<L>::format("{} {}", icon, Host::TranslateToStringView(TR_CONTEXT, str));
}
__fi IconStackString(const char8_t* icon, const char* str)
{
SmallStackString<L>::format("{} {}", reinterpret_cast<const char*>(icon), Host::TranslateToStringView(TR_CONTEXT, str));
}
__fi IconStackString(const char* icon, const char* str, const char* suffix)
{
SmallStackString<L>::format("{} {}##{}", icon, Host::TranslateToStringView(TR_CONTEXT, str), suffix);
}
__fi IconStackString(const char8_t* icon, const char* str, const char* suffix)
{
SmallStackString<L>::format("{} {}##{}", reinterpret_cast<const char*>(icon), Host::TranslateToStringView(TR_CONTEXT, str), suffix);
}
};
} // namespace
@@ -3676,7 +3684,7 @@ void FullscreenUI::DrawInterfaceSettingsPage()
s_osd_position_options, s_osd_position_values, std::size(s_osd_position_options), true);
MenuHeading(FSUI_CSTR("Operations"));
if (MenuButton(FSUI_ICONSTR(ICON_FA_DUMPSTER_FIRE, "Reset Settings"),
if (MenuButton(FSUI_ICONSTR(u8"🔥", "Reset Settings"),
FSUI_CSTR("Resets configuration to defaults (excluding controller settings)."), !IsEditingGameSettings(bsi)))
{
DoResetSettings();
@@ -4403,12 +4411,14 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
{
const bool shadeboost_active = GetEffectiveBoolSetting(bsi, "EmuCore/GS", "ShadeBoost", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GEM, "Shade Boost"), FSUI_CSTR("Enables brightness/contrast/saturation adjustment."), "EmuCore/GS",
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GEM, "Shade Boost"), FSUI_CSTR("Enables brightness/contrast/gamma/saturation adjustment."), "EmuCore/GS",
"ShadeBoost", false);
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_SUN, "Shade Boost Brightness"), FSUI_CSTR("Adjusts brightness. 50 is normal."), "EmuCore/GS",
"ShadeBoost_Brightness", 50, 1, 100, "%d", shadeboost_active);
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_LIGHTBULB, "Shade Boost Contrast"), FSUI_CSTR("Adjusts contrast. 50 is normal."), "EmuCore/GS",
"ShadeBoost_Contrast", 50, 1, 100, "%d", shadeboost_active);
DrawIntRangeSetting(bsi, FSUI_CSTR("Shade Boost Gamma"), FSUI_CSTR("Adjusts gamma. 50 is normal."), "EmuCore/GS",
"ShadeBoost_Gamma", 50, 1, 100, "%d", shadeboost_active);
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_DROPLET, "Shade Boost Saturation"), FSUI_CSTR("Adjusts saturation. 50 is normal."), "EmuCore/GS",
"ShadeBoost_Saturation", 50, 1, 100, "%d", shadeboost_active);
@@ -4864,7 +4874,7 @@ void FullscreenUI::DoSaveInputProfile()
void FullscreenUI::DoResetSettings()
{
OpenConfirmMessageDialog(FSUI_ICONSTR(ICON_FA_DUMPSTER_FIRE, "Reset Settings"),
OpenConfirmMessageDialog(FSUI_ICONSTR(u8"🔥", "Reset Settings"),
FSUI_STR("Are you sure you want to restore the default settings? Any preferences will be lost."), [](bool result) {
if (result)
{
@@ -4892,7 +4902,7 @@ void FullscreenUI::DrawControllerSettingsPage()
DoSaveInputProfile();
}
if (MenuButton(FSUI_ICONSTR(ICON_FA_DUMPSTER_FIRE, "Reset Settings"),
if (MenuButton(FSUI_ICONSTR(u8"🔥", "Reset Settings"),
FSUI_CSTR("Resets all configuration to defaults (including bindings).")))
{
ResetControllerSettings();
@@ -8170,9 +8180,11 @@ TRANSLATE_NOOP("FullscreenUI", "Enables FXAA post-processing shader.");
TRANSLATE_NOOP("FullscreenUI", "Enables FidelityFX Contrast Adaptive Sharpening.");
TRANSLATE_NOOP("FullscreenUI", "Determines the intensity the sharpening effect in CAS post-processing.");
TRANSLATE_NOOP("FullscreenUI", "Filters");
TRANSLATE_NOOP("FullscreenUI", "Enables brightness/contrast/saturation adjustment.");
TRANSLATE_NOOP("FullscreenUI", "Enables brightness/contrast/gamma/saturation adjustment.");
TRANSLATE_NOOP("FullscreenUI", "Adjusts brightness. 50 is normal.");
TRANSLATE_NOOP("FullscreenUI", "Adjusts contrast. 50 is normal.");
TRANSLATE_NOOP("FullscreenUI", "Shade Boost Gamma");
TRANSLATE_NOOP("FullscreenUI", "Adjusts gamma. 50 is normal.");
TRANSLATE_NOOP("FullscreenUI", "Adjusts saturation. 50 is normal.");
TRANSLATE_NOOP("FullscreenUI", "Applies a shader which replicates the visual effects of different styles of television set.");
TRANSLATE_NOOP("FullscreenUI", "Advanced");
@@ -8198,6 +8210,10 @@ TRANSLATE_NOOP("FullscreenUI", "Disable Vertex Shader Expand");
TRANSLATE_NOOP("FullscreenUI", "Falls back to the CPU for expanding sprites/lines.");
TRANSLATE_NOOP("FullscreenUI", "Texture Preloading");
TRANSLATE_NOOP("FullscreenUI", "Uploads full textures to the GPU on use, rather than only the utilized regions. Can improve performance in some games.");
TRANSLATE_NOOP("FullscreenUI", "NTSC Frame Rate");
TRANSLATE_NOOP("FullscreenUI", "Determines what frame rate NTSC games run at.");
TRANSLATE_NOOP("FullscreenUI", "PAL Frame Rate");
TRANSLATE_NOOP("FullscreenUI", "Determines what frame rate PAL games run at.");
TRANSLATE_NOOP("FullscreenUI", "Audio Control");
TRANSLATE_NOOP("FullscreenUI", "Controls the volume of the audio played on the host.");
TRANSLATE_NOOP("FullscreenUI", "Controls the volume of the audio played on the host when fast forwarding.");

View File

@@ -25,6 +25,7 @@
#include "fmt/format.h"
#include "imgui.h"
#include "imgui_freetype.h"
#include "imgui_internal.h"
#include "common/Image.h"
@@ -56,6 +57,7 @@ namespace ImGuiManager
static ImFont* AddTextFont();
static ImFont* AddFixedFont();
static bool AddIconFonts();
static bool AddEmojiFont();
static void AcquirePendingOSDMessages(Common::Timer::Value current_time);
static void DrawOSDMessages(Common::Timer::Value current_time);
static void CreateSoftwareCursorTextures();
@@ -74,6 +76,7 @@ static ImFont* s_fixed_font;
static std::vector<u8> s_standard_font_data;
static std::vector<u8> s_fixed_font_data;
static std::vector<u8> s_emoji_font_data;
static std::vector<u8> s_icon_fa_font_data;
static std::vector<u8> s_icon_pf_font_data;
@@ -415,6 +418,16 @@ bool ImGuiManager::LoadFontData()
s_fixed_font_data = std::move(font_data.value());
}
if (s_emoji_font_data.empty())
{
std::optional<std::vector<u8>> font_data = FileSystem::ReadBinaryFile(
EmuFolders::GetOverridableResourcePath("fonts" FS_OSPATH_SEPARATOR_STR "NotoColorEmoji-Regular.ttf").c_str());
if (!font_data.has_value())
return false;
s_emoji_font_data = std::move(font_data.value());
}
if (s_icon_fa_font_data.empty())
{
std::optional<std::vector<u8>> font_data =
@@ -442,6 +455,7 @@ void ImGuiManager::UnloadFontData()
{
std::vector<u8>().swap(s_standard_font_data);
std::vector<u8>().swap(s_fixed_font_data);
std::vector<u8>().swap(s_emoji_font_data);
std::vector<u8>().swap(s_icon_fa_font_data);
std::vector<u8>().swap(s_icon_pf_font_data);
}
@@ -475,11 +489,15 @@ bool ImGuiManager::AddIconFonts()
{
// Load FontAwesome after to avoid aliased codepoints overriding promptfont
{
// Exclude emojis
static constexpr ImWchar range_exclude_emojis[] = {0x10000, 0x1ffff, 0x0, 0x0};
ImFontConfig cfg;
cfg.MergeMode = true;
cfg.PixelSnapH = true;
cfg.GlyphMinAdvanceX = FONT_BASE_SIZE;
cfg.GlyphMaxAdvanceX = FONT_BASE_SIZE;
cfg.GlyphExcludeRanges = range_exclude_emojis;
cfg.FontDataOwnedByAtlas = false;
if (!ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
@@ -491,7 +509,7 @@ bool ImGuiManager::AddIconFonts()
{
// Exclude any characters outside the BMP PUA plane
static constexpr ImWchar range_exclude_non_bmp[] = {0x1, 0xdfff, 0xf900, 0xffff, 0x0, 0x0};
static constexpr ImWchar range_exclude_non_bmp[] = {0x1, 0xdfff, 0xf900, 0x10ffff, 0x0, 0x0};
ImFontConfig cfg;
cfg.MergeMode = true;
@@ -511,17 +529,75 @@ bool ImGuiManager::AddIconFonts()
return true;
}
bool ImGuiManager::AddEmojiFont()
{
{
// ImGui can't correctly handle some Unicode codepoints
// Remove them to avoid rendering blank/fallback characters
// See https://github.com/ocornut/imgui/issues/8240
static ImFontLoader filter_loader;
filter_loader.Name = "Emoji Preprocessor";
filter_loader.FontSrcContainsGlyph = [](ImFontAtlas* atlas, ImFontConfig* src, ImWchar codepoint) {
if (codepoint == 0xfe0e || codepoint == 0xfe0f)
return true;
return false;
};
filter_loader.FontBakedLoadGlyph = [](ImFontAtlas* atlas, ImFontConfig* src, ImFontBaked* baked, void*, ImWchar codepoint, ImFontGlyph* out_glyph, float* out_advance_x) {
if (codepoint != 0xfe0e && codepoint != 0xfe0f)
return false;
// Metrics only mode
if (out_advance_x != nullptr)
{
*out_advance_x = 0.0f;
return true;
}
out_glyph->Codepoint = codepoint;
out_glyph->AdvanceX = 0.0f;
out_glyph->Visible = false;
return true;
};
ImFontConfig cfg;
StringUtil::Strlcpy(cfg.Name, filter_loader.Name, sizeof(cfg.Name));
cfg.MergeMode = true;
cfg.SizePixels = FONT_BASE_SIZE;
cfg.FontLoader = &filter_loader;
if (!ImGui::GetIO().Fonts->AddFont(&cfg))
return false;
}
{
ImFontConfig cfg;
cfg.MergeMode = true;
// Set GlyphMin/MaxAdvanceX to allow replacing FA/PF icons.
cfg.GlyphMinAdvanceX = FONT_BASE_SIZE;
cfg.GlyphMaxAdvanceX = FONT_BASE_SIZE;
cfg.FontLoaderFlags |= ImGuiFreeTypeLoaderFlags_LoadColor;
cfg.FontDataOwnedByAtlas = false;
if (!ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
s_emoji_font_data.data(), static_cast<int>(s_emoji_font_data.size()), FONT_BASE_SIZE, &cfg, nullptr))
{
return false;
}
}
return true;
}
bool ImGuiManager::AddImGuiFonts()
{
ImGuiIO& io = ImGui::GetIO();
io.Fonts->Clear();
s_standard_font = AddTextFont();
if (!s_standard_font || !AddIconFonts())
if (!s_standard_font || !AddIconFonts() || !AddEmojiFont())
return false;
s_fixed_font = AddFixedFont();
if (!s_fixed_font)
if (!s_fixed_font || !AddEmojiFont())
return false;
ImGuiFullscreen::SetFont(s_standard_font);

View File

@@ -850,6 +850,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
OpEqu(ShadeBoost_Brightness) &&
OpEqu(ShadeBoost_Contrast) &&
OpEqu(ShadeBoost_Saturation) &&
OpEqu(ShadeBoost_Gamma) &&
OpEqu(PNGCompressionLevel) &&
OpEqu(SaveDrawStart) &&
OpEqu(SaveDrawCount) &&
@@ -1042,6 +1043,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitfield(ShadeBoost_Brightness);
SettingsWrapBitfield(ShadeBoost_Contrast);
SettingsWrapBitfield(ShadeBoost_Saturation);
SettingsWrapBitfield(ShadeBoost_Gamma);
SettingsWrapBitfield(ExclusiveFullscreenControl);
SettingsWrapBitfieldEx(PNGCompressionLevel, "png_compression_level");
SettingsWrapBitfieldEx(SaveDrawStart, "SaveDrawStart");

View File

@@ -3,4 +3,4 @@
/// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 69;
static constexpr u32 SHADER_CACHE_VERSION = 70;

View File

@@ -25,31 +25,50 @@ for token in ["FSUI_STR", "FSUI_CSTR", "FSUI_FSTR", "FSUI_NSTR", "FSUI_VSTR", "F
if full_source[last_pos + token_len] == '(':
start_pos = last_pos + token_len + 1
end_pos = full_source.find("\")", start_pos)
s = full_source[start_pos:end_pos+1]
end_pos = full_source.find(")", start_pos)
s = full_source[start_pos:end_pos]
# remove "
# Split into sting arguments, removing "
string_args = [""]
arg = 0;
cpos = s.find(',')
pos = s.find('"')
new_s = ""
while pos >= 0:
if pos == 0 or s[pos - 1] != '\\':
while pos >= 0 or cpos >= 0:
assert pos == 0 or s[pos - 1] != '\\'
if cpos == -1 or pos < cpos:
epos = pos
while True:
epos = s.find('"', epos + 1)
assert epos > pos
# found ')' in string, extend s to next ')'
if epos == -1:
end_pos = full_source.find(")", end_pos + 1)
s = full_source[start_pos:end_pos]
epos = pos
continue
if s[epos - 1] == '\\':
continue
else:
break
assert epos > pos
new_s += s[pos+1:epos]
string_args[arg] += s[pos+1:epos]
cpos = s.find(',', epos + 1)
pos = s.find('"', epos + 1)
if cpos >= 0 and pos >= 0 and cpos < pos:
break
else:
pos = s.find('"', pos + 1)
arg += 1
string_args.append("")
cpos = s.find(',', cpos + 1)
print(string_args)
# FSUI_ICONSTR and FSUI_ICONSTR_S need to translate the only the second argument
# other defines take only a single argument
if len(string_args) >= 2:
new_s = string_args[1]
else:
new_s = string_args[0]
assert len(new_s) > 0
#assert (end_pos - start_pos) < 300