Compare commits

...

23 Commits

Author SHA1 Message Date
refractionpcsx2
06307abd03 GS/HW: Only enable depth writes/floor calculation if depth is output 2026-01-11 02:36:55 +01:00
refractionpcsx2
daf735b047 GS/HW: Floor depth writes to improve Z testing 2026-01-11 02:36:55 +01:00
JordanTheToaster
f591c88aff GS/HW: Add Limit 24 Bit Depth Hack 2026-01-10 15:53:25 -05:00
refractionpcsx2
ca47a08882 GS: Fix up adding GS_to_GS transfers to the draw_transfers list 2026-01-10 15:50:59 -05:00
refractionpcsx2
92adacf99e GS: Disallow flipped GS->GS transfer when destination overwrites source 2026-01-10 15:50:59 -05:00
JordanTheToaster
43e5ec25ab microVU: Ignore MAC flags in block match if not required 2026-01-10 15:49:57 -05:00
KamFretoZ
1018b75847 DiscordRPC: Simplify Game Icon Retrieval 2026-01-10 15:49:45 -05:00
Shiva9361
3871d1bd5d Qt: Patch for distinguishing left and right variants of shift/alt/ctrl keys 2026-01-10 15:49:18 -05:00
Mrlinkwii
976d4a8dbb Revert "CI/Windows: Disable Qt's PCRE2 JIT"
This reverts commit 1ec4c248fb.
2026-01-10 15:47:32 -05:00
Ty
40b1b9b717 Qt: Add an EE SIO RX input textbox to the log window 2026-01-10 15:46:59 -05:00
Ty
a3b817cb1f Core: Use deque for EE SIO RX/TX FIFOs 2026-01-10 15:46:59 -05:00
SternXD
83e152cd21 GameDB: Add post-bloom alignment and native scaling for Urban Reign 2026-01-10 17:18:43 +01:00
TheLastRar
50a9568d65 GS/DX12: Backport DATE stencil one single pass from DX11/VK
Co-Authored-By: lightningterror <18107717+lightningterror@users.noreply.github.com>
2026-01-09 03:36:58 +01:00
KamFretoZ
a33cbdee09 Qt: Fix alternate row colors for Ruby/Emerald/Sapphire theme
For consistency
2026-01-08 20:18:11 +01:00
KamFretoZ
b02bcc5690 Qt: Cobalt Sky theme refresh 2026-01-08 20:18:11 +01:00
KamFretoZ
2e60a1d081 Qt: AMOLED theme refresh 2026-01-08 20:18:11 +01:00
oltolm
28da984b01 UI: remove unnecessary uses of QOverload 2026-01-07 15:23:29 +01:00
oltolm
967987b25f GS, UI: use u32 instead of s32 for width and height 2026-01-07 14:15:00 +01:00
PCSX2 Bot
e41f63b821 [ci skip] Qt: Update Base Translation. 2026-01-07 01:03:59 +01:00
SilentHeII
0f82503cf7 GameDB: Added various memory card filters
Reads Twisted Metal Black for bonus unlockable.

Adds memcardFilters for Shadow Hearts: Covenant

Ignore my previous pull request. I have no idea why it formatted it so obnoxiously.

Anyway, you get extra ingame items if you have a save file from Shadow Hearts 1.

GameIndex changes

Added memcardFilters for Biohazard Outbreak & Biohazard Outbreak File 2 to allow for creation of network configurations.

Added missing titles

Added missing titles to allow games to load their own saves.
2026-01-06 20:56:26 +01:00
Christopher Obbard
33f625a4e2 cmake: only require Qt modules when Qt UI is enabled
The Qt6 CorePrivate/GuiPrivate/WidgetsPrivate components are only needed
for the Qt UI build. Move their find_package() call under ENABLE_QT_UI
to avoid requiring private Qt modules when building without the UI.

Signed-off-by: Christopher Obbard <obbardc@gmail.com>
2026-01-06 20:44:35 +01:00
JordanTheToaster
5b0c22c343 Mac: Update MoltenVK to v1.4.1 2026-01-06 20:37:29 +01:00
Florin9doi
ea963ffd72 USB: Train Mascon and Master Controller emulation 2026-01-06 20:18:15 +01:00
61 changed files with 1164 additions and 373 deletions

View File

@@ -47,7 +47,7 @@ LIBPNG=1.6.53
LIBJPEGTURBO=3.1.2
LIBWEBP=1.6.0
FFMPEG=8.0
MOLTENVK=1.2.9
MOLTENVK=1.4.1
QT=6.10.1
QTAPNG=1.3.0
KDDOCKWIDGETS=2.4.0
@@ -88,7 +88,7 @@ e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWE
452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c libpng-$LIBPNG-apng.patch.gz
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c v$MOLTENVK.tar.gz
5a6226f7e23db51fdc3223121eba53f3f5447cf0cc4d6cb82a3a2df7a65d265d qtbase-everywhere-src-$QT.tar.xz
498eabdf2381db96f808942b3e3c765f6360fe6c0e9961f0a45ff7a4c68d7a72 qtimageformats-everywhere-src-$QT.tar.xz
c02f355a58f3bbcf404a628bf488b6aeb2d84a94c269afdb86f6e529343ab01f qtsvg-everywhere-src-$QT.tar.xz
@@ -277,7 +277,7 @@ rm -fr "MoltenVK-${MOLTENVK}"
tar xf "v$MOLTENVK.tar.gz"
cd "MoltenVK-${MOLTENVK}"
./fetchDependencies --macos
make macos
make macos MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0 MVK_CONFIG_USE_METAL_PRIVATE_API=1
cp Package/Latest/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib "$INSTALLDIR/lib/"
cd ..

View File

@@ -29,7 +29,7 @@ LIBPNG=1.6.53
LIBJPEGTURBO=3.1.2
LIBWEBP=1.6.0
FFMPEG=8.0
MOLTENVK=1.2.9
MOLTENVK=1.4.1
QT=6.10.1
QTAPNG=1.3.0
KDDOCKWIDGETS=2.4.0
@@ -69,7 +69,7 @@ e4ab7009bf0629fd11982d4c2aa83964cf244cffba7347ecd39019a9e38c4564 libwebp-$LIBWE
452a1a290bd0cf18737fad0057dc17b7fdf10a73eda2d6d4f31ba04fda25ef2c libpng-$LIBPNG-apng.patch.gz
8f0012234b464ce50890c490f18194f913a7b1f4e6a03d6644179fa0f867d0cf libjpeg-turbo-$LIBJPEGTURBO.tar.gz
b2751fccb6cc4c77708113cd78b561059b6fa904b24162fa0be2d60273d27b8e ffmpeg-$FFMPEG.tar.xz
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
9985f141902a17de818e264d17c1ce334b748e499ee02fcb4703e4dc0038f89c v$MOLTENVK.tar.gz
5a6226f7e23db51fdc3223121eba53f3f5447cf0cc4d6cb82a3a2df7a65d265d qtbase-everywhere-src-$QT.tar.xz
498eabdf2381db96f808942b3e3c765f6360fe6c0e9961f0a45ff7a4c68d7a72 qtimageformats-everywhere-src-$QT.tar.xz
c02f355a58f3bbcf404a628bf488b6aeb2d84a94c269afdb86f6e529343ab01f qtsvg-everywhere-src-$QT.tar.xz
@@ -225,7 +225,7 @@ cd "MoltenVK-${MOLTENVK}"
sed -i '' 's/xcodebuild "$@"/xcodebuild $XCODEBUILD_EXTRA_ARGS "$@"/g' fetchDependencies
sed -i '' 's/XCODEBUILD :=/XCODEBUILD ?=/g' Makefile
XCODEBUILD_EXTRA_ARGS="VALID_ARCHS=x86_64" ./fetchDependencies --macos
XCODEBUILD="set -o pipefail && xcodebuild VALID_ARCHS=x86_64" make macos
XCODEBUILD="set -o pipefail && xcodebuild VALID_ARCHS=x86_64" make macos MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS=0 MVK_CONFIG_USE_METAL_PRIVATE_API=1
cp Package/Latest/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib "$INSTALLDIR/lib/"
cd ..

View File

@@ -201,10 +201,6 @@ echo Building Qt base...
rmdir /S /Q "qtbase-everywhere-src-%QT%"
%SEVENZIP% x "qtbase-everywhere-src-%QT%.zip" || goto error
cd "qtbase-everywhere-src-%QT%" || goto error
rem Disable the PCRE2 JIT, it doesn't properly verify AVX2 support.
%PATCH% -p1 < "%SCRIPTDIR%\qtbase-disable-pcre2-jit.patch" || goto error
cmake -B build -DFEATURE_sql=OFF -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" %FORCEPDB% -DINPUT_gui=yes -DINPUT_widgets=yes -DINPUT_ssl=yes -DINPUT_openssl=no -DINPUT_schannel=yes -DFEATURE_system_png=ON -DFEATURE_system_jpeg=ON -DFEATURE_system_zlib=ON -DFEATURE_system_freetype=ON -DFEATURE_system_harfbuzz=ON %QTBUILDSPEC% || goto error
cmake --build build --parallel || goto error
ninja -C build install || goto error

View File

@@ -1,35 +0,0 @@
--- qtbase/src/3rdparty/pcre2/CMakeLists.txt 2024-03-19 08:46:43.000000000 -0700
+++ qtbase/src/3rdparty/pcre2/CMakeLists.txt 2024-06-06 21:52:20.539619500 -0700
@@ -41,6 +41,7 @@
src/pcre2_xclass.c
DEFINES
HAVE_CONFIG_H
+ PCRE2_DISABLE_JIT
PUBLIC_DEFINES
PCRE2_CODE_UNIT_WIDTH=16
PUBLIC_INCLUDE_DIRECTORIES
@@ -52,23 +53,8 @@
## Scopes:
#####################################################################
-qt_internal_extend_target(BundledPcre2 CONDITION QNX OR UIKIT
- DEFINES
- PCRE2_DISABLE_JIT
-)
-
-qt_internal_extend_target(BundledPcre2 CONDITION (TEST_architecture_arch STREQUAL "arm") AND WIN32
- DEFINES
- PCRE2_DISABLE_JIT
-)
-
-qt_internal_extend_target(BundledPcre2 CONDITION (TEST_architecture_arch STREQUAL "arm64") AND WIN32
- DEFINES
- PCRE2_DISABLE_JIT
-)
-
if (APPLE)
- target_compile_options(BundledPcre2 PRIVATE "SHELL:-Xarch_arm64 -DPCRE2_DISABLE_JIT")
+ target_compile_options(BundledPcre2 PRIVATE "SHELL:-Xarch_arm64")
endif()
qt_internal_extend_target(BundledPcre2 CONDITION WIN32

View File

@@ -2239,6 +2239,8 @@ SCAJ-20152:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
textureInsideRT: 1 # Fixes corruption.
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 2 # Fixes post effects.
getSkipCount: "GSC_UrbanReign"
SCAJ-20153:
name: "コード・エイジ コマンダーズ"
@@ -6229,6 +6231,8 @@ SCES-53688:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
textureInsideRT: 1 # Fixes corruption.
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 2 # Fixes post effects.
getSkipCount: "GSC_UrbanReign"
SCES-53795:
name: "SingStar - '80s"
@@ -7698,6 +7702,8 @@ SCKA-20065:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
textureInsideRT: 1 # Fixes corruption.
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 2 # Fixes post effects.
getSkipCount: "GSC_UrbanReign"
SCKA-20066:
name: "아이토이 - 플레이 3"
@@ -11384,6 +11390,10 @@ SCUS-97197:
name: "War of the Monsters"
region: "NTSC-U"
compat: 5
memcardFilters: # Reads Twisted Metal Black for bonus unlockable.
- "SCUS-97101"
- "SCUS-97179"
- "SCUS-97197"
SCUS-97198:
name: "Sly Cooper and the Thievius Raccoonus"
region: "NTSC-U"
@@ -30583,6 +30593,11 @@ SLES-82030:
halfPixelOffset: 5 # Fixes shadow positioning.
autoFlush: 2 # Makes the shadow monsters appear.
nativeScaling: 2 # Aligns post processing and bloom.
memcardFilters: # Reads Shadow Hearts for extra items.
- "SLES-82030"
- "SLES-82031"
- "SLES-50677"
- "SLES-50822"
SLES-82031:
name: "Shadow Hearts - Covenant [Disc 2 of 2]"
region: "PAL-M3"
@@ -30590,8 +30605,11 @@ SLES-82031:
halfPixelOffset: 5 # Fixes shadow positioning.
autoFlush: 2 # Makes the shadow monsters appear.
nativeScaling: 2 # Aligns post processing and bloom.
memcardFilters:
memcardFilters: # Reads Shadow Hearts for extra items.
- "SLES-82030"
- "SLES-82031"
- "SLES-50677"
- "SLES-50822"
SLES-82032:
name: "Metal Gear Solid 3 - Snake Eater"
region: "PAL-G"
@@ -35940,6 +35958,8 @@ SLPM-60272:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
textureInsideRT: 1 # Fixes corruption.
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 2 # Fixes post effects.
getSkipCount: "GSC_UrbanReign"
SLPM-60273:
name: "絶体絶命都市2 -凍てついた記憶たち- [体験版 Type-B]"
@@ -43473,6 +43493,11 @@ SLPM-65428:
name-en: "BioHazard Outbreak"
region: "NTSC-J"
compat: 5
memcardFilters:
- "SLPM-65428"
- "SLPM-74201"
- "SLPM-65286"
- "BWNETCNF"
SLPM-65429:
name: "ギャラクシーエンジェル Moonlit Lovers [初回限定版ファーストパッケージ]"
name-sort: "ぎゃらくしーえんじぇる Moonlit Lovers [しょかいげんていばんふぁーすとぱっけーじ]"
@@ -44973,6 +44998,8 @@ SLPM-65692:
- "SLPM-65692"
- "SLPM-65428"
- "SLPM-74201"
- "SLPM-65286"
- "BWNETCNF"
SLPM-65693:
name: "ときめきメモリアル3 ~約束のあの場所で~ [コナミ殿堂セレクション]"
name-sort: "ときめきめもりある3 やくそくのあのばしょで [こなみでんどうせれくしょん]"
@@ -53680,6 +53707,11 @@ SLPM-74201:
name-sort: "ばいおはざーど あうとぶれいく [PlayStation2 the Best]"
name-en: "BioHazard Outbreak [PlayStation2 the Best]"
region: "NTSC-J"
memcardFilters:
- "SLPM-65428"
- "SLPM-74201"
- "SLPM-65286"
- "BWNETCNF"
SLPM-74202:
name: "風雲 新撰組 [PlayStation2 the Best]"
name-sort: "ふううん しんせんぐみ [PlayStation2 the Best]"
@@ -58845,6 +58877,11 @@ SLPS-25317:
halfPixelOffset: 5 # Fixes shadow positioning.
autoFlush: 2 # Makes the shadow monsters appear.
nativeScaling: 2 # Aligns post processing and bloom.
memcardFilters: # Reads Shadow Hearts for extra items.
- "SLPS-25317"
- "SLPS-25318"
- "SLPS-25041"
- "SLPS-73418"
SLPS-25318:
name: "シャドウハーツⅡ [DXパック] [ディスク2/2]"
name-sort: "しゃどうはーつ2 [DXぱっく] [でぃすく2/2]"
@@ -58854,8 +58891,11 @@ SLPS-25318:
halfPixelOffset: 5 # Fixes shadow positioning.
autoFlush: 2 # Makes the shadow monsters appear.
nativeScaling: 2 # Aligns post processing and bloom.
memcardFilters:
memcardFilters: # Reads Shadow Hearts for extra items.
- "SLPS-25317"
- "SLPS-25318"
- "SLPS-25041"
- "SLPS-73418"
SLPS-25319:
name: "ケロケロキング スーパーDX"
name-sort: "けろけろきんぐ すーぱーDX"
@@ -58934,6 +58974,11 @@ SLPS-25334:
halfPixelOffset: 5 # Fixes shadow positioning.
autoFlush: 2 # Makes the shadow monsters appear.
nativeScaling: 2 # Aligns post processing and bloom.
memcardFilters: # Reads Shadow Hearts for extra items.
- "SLPS-25334"
- "SLPS-25335"
- "SLPS-25041"
- "SLPS-73418"
SLPS-25335:
name: "シャドウハーツⅡ [通常版] [ディスク2/2]"
name-sort: "しゃどうはーつ2 [つうじょうばん] [でぃすく2/2]"
@@ -58943,8 +58988,11 @@ SLPS-25335:
halfPixelOffset: 5 # Fixes shadow positioning.
autoFlush: 2 # Makes the shadow monsters appear.
nativeScaling: 2 # Aligns post processing and bloom.
memcardFilters:
memcardFilters: # Reads Shadow Hearts for extra items.
- "SLPS-25334"
- "SLPS-25335"
- "SLPS-25041"
- "SLPS-73418"
SLPS-25336:
name: "バスランディング3 [Sammy best] [つりコン2+ 同梱版]"
name-sort: "ばすらんでぃんぐ3 [Sammy best] [つりこん2 どうこんばん]"
@@ -60300,6 +60348,8 @@ SLPS-25557:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
textureInsideRT: 1 # Fixes corruption.
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 2 # Fixes post effects.
getSkipCount: "GSC_UrbanReign"
SLPS-25558:
name: "ネオジオ バトルコロシアム"
@@ -63242,6 +63292,11 @@ SLPS-73214:
halfPixelOffset: 5 # Fixes shadow positioning.
autoFlush: 2 # Makes the shadow monsters appear.
nativeScaling: 2 # Aligns post processing and bloom.
memcardFilters: # Reads Shadow Hearts for extra items.
- "SLPS-73214"
- "SLPS-73215"
- "SLPS-25041"
- "SLPS-73418"
SLPS-73215:
name: "シャドウハーツⅡ ディレクターズカット [PlayStation2 the Best] [ディスク2/2]"
name-sort: "しゃどうはーつ2 でぃれくたーずかっと [PlayStation2 the Best] [でぃすく2/2]"
@@ -63251,8 +63306,11 @@ SLPS-73215:
halfPixelOffset: 5 # Fixes shadow positioning.
autoFlush: 2 # Makes the shadow monsters appear.
nativeScaling: 2 # Aligns post processing and bloom.
memcardFilters:
memcardFilters: # Reads Shadow Hearts for extra items.
- "SLPS-73214"
- "SLPS-73215"
- "SLPS-25041"
- "SLPS-73418"
SLPS-73216:
name: "マグナカルタ [PlayStation2 the Best]"
name-sort: "まぐなかるた [PlayStation2 the Best]"
@@ -69321,6 +69379,10 @@ SLUS-21041:
halfPixelOffset: 5 # Fixes shadow positioning.
autoFlush: 2 # Makes the shadow monsters appear.
nativeScaling: 2 # Aligns post processing and bloom.
memcardFilters: # Reads Shadow Hearts for extra items.
- "SLUS-21041"
- "SLUS-21044"
- "SLUS-20347"
SLUS-21042:
name: "Darkwatch"
region: "NTSC-U"
@@ -69339,8 +69401,10 @@ SLUS-21044:
halfPixelOffset: 5 # Fixes shadow positioning.
autoFlush: 2 # Makes the shadow monsters appear.
nativeScaling: 2 # Aligns post processing and bloom.
memcardFilters:
memcardFilters: # Reads Shadow Hearts for extra items.
- "SLUS-21041"
- "SLUS-21044"
- "SLUS-20347"
SLUS-21045:
name: "Conflict - Vietnam"
region: "NTSC-U"
@@ -70306,6 +70370,8 @@ SLUS-21209:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
textureInsideRT: 1 # Fixes corruption.
halfPixelOffset: 4 # Aligns post bloom.
nativeScaling: 2 # Fixes post effects.
getSkipCount: "GSC_UrbanReign"
SLUS-21212:
name: "Spartan - Total Warrior"

View File

@@ -71,6 +71,7 @@
#define PS_DITHER 0
#define PS_DITHER_ADJUST 0
#define PS_ZCLAMP 0
#define PS_ZFLOOR 0
#define PS_SCANMSK 0
#define PS_AUTOMATIC_LOD 0
#define PS_MANUAL_LOD 0
@@ -138,7 +139,7 @@ struct PS_OUTPUT
#endif
#endif
#endif
#if PS_ZCLAMP
#if PS_ZCLAMP || PS_ZFLOOR
float depth : SV_Depth;
#endif
};
@@ -1209,8 +1210,16 @@ PS_OUTPUT ps_main(PS_INPUT input)
#endif // PS_DATE != 1/2
#if PS_ZFLOOR
float depth_value = floor(input.p.z * exp2(32.0f)) * exp2(-32.0f);
#else
float depth_value = input.p.z;
#endif
#if PS_ZCLAMP
output.depth = min(input.p.z, MaxDepthPS);
output.depth = min(depth_value, MaxDepthPS);
#elif PS_ZFLOOR
output.depth = depth_value;
#endif
return output;

View File

@@ -1143,7 +1143,16 @@ void ps_main()
#endif
#endif
#if PS_ZCLAMP
gl_FragDepth = min(gl_FragCoord.z, MaxDepthPS);
#if PS_ZFLOOR
float depth_value = floor(gl_FragCoord.z * exp2(32.0f)) * exp2(-32.0f);
#else
float depth_value = gl_FragCoord.z;
#endif
#if PS_ZCLAMP
gl_FragDepth = min(depth_value, MaxDepthPS);
#elif PS_ZFLOOR
gl_FragDepth = depth_value;
#endif
}

View File

@@ -288,6 +288,7 @@ void main()
#define PS_DITHER 0
#define PS_DITHER_ADJUST 0
#define PS_ZCLAMP 0
#define PS_ZFLOOR 0
#define PS_FEEDBACK_LOOP 0
#define PS_TEX_IS_FB 0
#endif
@@ -1400,8 +1401,16 @@ void main()
#endif
#endif
#if PS_ZFLOOR
float depth_value = floor(gl_FragCoord.z * exp2(32.0f)) * exp2(-32.0f);;
#else
float depth_value = gl_FragCoord.z;
#endif
#if PS_ZCLAMP
gl_FragDepth = min(gl_FragCoord.z, MaxDepthPS);
#elif PS_ZFLOOR
gl_FragDepth = depth_value;
#endif
#endif // PS_DATE

View File

@@ -109,14 +109,14 @@ disable_compiler_warnings_for_target(speex)
# Find the Qt components that we need.
if(ENABLE_QT_UI)
find_package(Qt6 6.10.0 COMPONENTS CoreTools Core GuiTools Gui WidgetsTools Widgets LinguistTools REQUIRED)
endif()
if (Qt6_VERSION VERSION_GREATER_EQUAL 6.10.0)
find_package(Qt6 COMPONENTS CorePrivate GuiPrivate WidgetsPrivate REQUIRED)
endif()
if (Qt6_VERSION VERSION_GREATER_EQUAL 6.10.0)
find_package(Qt6 COMPONENTS CorePrivate GuiPrivate WidgetsPrivate REQUIRED)
endif()
# The docking system for the debugger.
# The docking system for the debugger.
find_package(KDDockWidgets-qt6 2.3.0 REQUIRED)
endif()
if(WIN32)
add_subdirectory(3rdparty/rainterface EXCLUDE_FROM_ALL)

View File

@@ -37,7 +37,7 @@ public:
void restoreGeometry(const QByteArray& geometry);
Q_SIGNALS:
void windowResizedEvent(int width, int height, float scale);
void windowResizedEvent(u32 width, u32 height, float scale);
void windowRestoredEvent();
void dragEnterEvent(QDragEnterEvent* event);

View File

@@ -5,10 +5,14 @@
#include "MainWindow.h"
#include "QtHost.h"
#include "SettingWidgetBinder.h"
#include "VMManager.h"
#include <QtCore/QLatin1StringView>
#include <QtCore/QUtf8StringView>
#include <QtGui/QIcon>
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QScrollBar>
@@ -46,6 +50,12 @@ void LogWindow::updateSettings()
const bool new_enabled = Host::GetBaseBoolSettingValue("Logging", "EnableLogWindow", false) && !Host::InNoGUIMode();
const bool attach_to_main = Host::GetBaseBoolSettingValue("Logging", "AttachLogWindowToMainWindow", true);
const bool curr_enabled = Log::IsHostOutputEnabled();
const bool input_enabled = Host::GetBaseBoolSettingValue("Logging", "ShowEESIOInput");
if(g_log_window && g_log_window->m_line_input)
{
g_log_window->m_input_widget->setVisible(input_enabled);
}
if (new_enabled == curr_enabled)
{
@@ -171,6 +181,10 @@ void LogWindow::createUi()
action->setCheckable(true);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "EnableTimestamps", true);
action = settings_menu->addAction(tr("Show EE SIO &Input"));
action->setCheckable(true);
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "ShowEESIOInput", false);
settings_menu->addSeparator();
// TODO: Log Level
@@ -181,6 +195,30 @@ void LogWindow::createUi()
m_text->setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
m_text->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_text->setWordWrapMode(QTextOption::WrapAnywhere);
m_text->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_line_input = new QLineEdit(this);
connect(m_line_input, &QLineEdit::returnPressed, this, &LogWindow::onInputEntered);
m_local_echo_checkbox = new QCheckBox(tr("Local Echo"), this);
m_local_echo_checkbox->setChecked(m_local_echo);
connect(m_local_echo_checkbox, &QCheckBox::checkStateChanged, this, [&](Qt::CheckState state)
{
m_local_echo = state == Qt::CheckState::Checked;
});
m_newline_on_enter_checkbox = new QCheckBox(tr("Newline on send"), this);
m_newline_on_enter_checkbox->setChecked(m_newline_on_enter);
connect(m_newline_on_enter_checkbox, &QCheckBox::checkStateChanged, this, [&](Qt::CheckState state)
{
m_newline_on_enter = state == Qt::CheckState::Checked;
});
m_input_hbox = new QHBoxLayout(this);
m_input_hbox->addWidget(m_line_input, 1);
m_input_hbox->addWidget(m_local_echo_checkbox);
m_input_hbox->addWidget(m_newline_on_enter_checkbox);
m_input_hbox->setSpacing(8);
#if defined(_WIN32)
QFont font("Consolas");
@@ -194,7 +232,19 @@ void LogWindow::createUi()
#endif
m_text->setFont(font);
setCentralWidget(m_text);
QWidget* central_widget = new QWidget(this);
m_input_widget = new QWidget(this);
m_input_widget->setVisible(Host::GetBaseBoolSettingValue("Logging", "ShowEESIOInput"));
m_input_widget->setLayout(m_input_hbox);
QVBoxLayout* vlayout = new QVBoxLayout(central_widget);
vlayout->setContentsMargins(0, 0, 0, 0);
vlayout->setSpacing(0);
vlayout->addWidget(m_text);
vlayout->addWidget(m_input_widget);
central_widget->setLayout(vlayout);
setCentralWidget(central_widget);
}
void LogWindow::onClearTriggered()
@@ -361,6 +411,31 @@ void LogWindow::appendMessage(quint32 level, quint32 color, const QString& messa
}
}
void LogWindow::onInputEntered()
{
QString text = m_line_input->text();
if (text.isEmpty() && !m_newline_on_enter)
return;
if(m_newline_on_enter)
text.append('\n');
std::string str = text.toUtf8().toStdString();
if(VMManager::WriteBytesToEESIORXFIFO({reinterpret_cast<const u8*>(str.data()), str.size()}))
{
m_line_input->clear();
if(m_local_echo)
// appendMessage expects a newline to be at the end of the string
appendMessage(0, 0, m_newline_on_enter ? text : (text + '\n') );
QTextCursor cursor(m_text->textCursor());
cursor.movePosition(QTextCursor::End);
m_text->setTextCursor(cursor);
}
}
void LogWindow::saveSize()
{
const int current_width = Host::GetBaseIntSettingValue("UI", "LogWindowWidth", DEFAULT_WIDTH);

View File

@@ -5,6 +5,9 @@
#include "common/Console.h"
#include <QtWidgets/QCheckBox>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QPlainTextEdit>
@@ -36,6 +39,7 @@ private Q_SLOTS:
void onClearTriggered();
void onSaveTriggered();
void appendMessage(quint32 level, quint32 color, const QString& message);
void onInputEntered();
private:
static constexpr int DEFAULT_WIDTH = 750;
@@ -45,8 +49,15 @@ private:
void restoreSize();
QPlainTextEdit* m_text;
QLineEdit* m_line_input;
QMenu* m_level_menu;
QWidget* m_input_widget;
QHBoxLayout* m_input_hbox;
QCheckBox* m_local_echo_checkbox;
QCheckBox* m_newline_on_enter_checkbox;
bool m_local_echo = false;
bool m_newline_on_enter = true;
bool m_attached_to_main_window = true;
bool m_destroying = false;
};

View File

@@ -777,7 +777,7 @@ void EmuThread::connectDisplaySignals(DisplaySurface* widget)
connect(widget, &DisplaySurface::windowRestoredEvent, this, &EmuThread::redrawDisplayWindow);
}
void EmuThread::onDisplayWindowResized(int width, int height, float scale)
void EmuThread::onDisplayWindowResized(u32 width, u32 height, float scale)
{
if (!MTGS::IsOpen())
return;

View File

@@ -191,7 +191,7 @@ private:
private Q_SLOTS:
void stopInThread();
void doBackgroundControllerPoll();
void onDisplayWindowResized(int width, int height, float scale);
void onDisplayWindowResized(u32 width, u32 height, float scale);
void onApplicationStateChanged(Qt::ApplicationState state);
void redrawDisplayWindow();

View File

@@ -67,6 +67,17 @@ struct KeyCodeName
const char* icon_name;
};
// Extended keys for left/right versions, Non conflicting with Qt::Key enum
enum ExtendedKeys
{
Key_RightShift = 0x01100022,
Key_LeftShift = 0x01100023,
Key_RightControl = 0x01100024,
Key_LeftControl = 0x01100025,
Key_RightAlt = 0x01100026,
Key_LeftAlt = 0x01100027,
};
static constexpr const KeyCodeName s_qt_key_names[] = {
{Qt::Key_Escape, "Escape", ICON_PF_ESC},
{Qt::Key_Tab, "Tab", ICON_PF_TAB},
@@ -92,6 +103,13 @@ static constexpr const KeyCodeName s_qt_key_names[] = {
{Qt::Key_Control, "Control", ICON_PF_CTRL},
{Qt::Key_Meta, "Meta", ICON_PF_SUPER},
{Qt::Key_Alt, "Alt", ICON_PF_ALT},
// patch for left and right versions of the keys
{ExtendedKeys::Key_LeftShift, "LShift", ICON_PF_SHIFT},
{ExtendedKeys::Key_RightShift, "RShift", ICON_PF_SHIFT},
{ExtendedKeys::Key_LeftControl, "LCtrl", ICON_PF_CTRL},
{ExtendedKeys::Key_RightControl, "RCtrl", ICON_PF_CTRL},
{ExtendedKeys::Key_LeftAlt, "LAlt", ICON_PF_ALT},
{ExtendedKeys::Key_RightAlt, "RAlt", ICON_PF_ALT},
{Qt::Key_CapsLock, "CapsLock", ICON_PF_CAPS},
{Qt::Key_NumLock, "NumLock", ICON_PF_NUMLOCK},
{Qt::Key_ScrollLock, "ScrollLock", ICON_PF_SCRLK},
@@ -575,6 +593,41 @@ u32 QtUtils::KeyEventToCode(const QKeyEvent* ev)
const u8 keycode = set_keycode ? map_text_to_keycode(text) : 0;
int key = ev->key();
if (key == Qt::Key_Shift || key == Qt::Key_Alt || key == Qt::Key_Control)
{
#if defined(Q_OS_WIN) or defined(Q_OS_LINUX)
// Scan codes (Tested it)
// 0x2A : Left shift
// 0x36 : Right shift
// 0x1D : Left ctrl
// 0xE01D : Right ctrl
// 0x38 : Left alt
// right alt can become ctrl + right alt in some keyboard layouts (windows)
// but thats fine for our use case
switch (ev->nativeScanCode())
{
case 0x2A:
key = ExtendedKeys::Key_LeftShift;
break;
case 0x36:
key = ExtendedKeys::Key_RightShift;
break;
case 0x1D:
key = ExtendedKeys::Key_LeftControl;
break;
case 0xE01D:
key = ExtendedKeys::Key_RightControl;
break;
case 0x38:
key = ExtendedKeys::Key_LeftAlt;
break;
default:
break;
}
#endif
}
if (keycode != 0)
key = keycode; // Override key if mapped

View File

@@ -463,7 +463,7 @@ namespace SettingWidgetBinder
{
if (!isNullable(widget))
{
widget->connect(widget, QOverload<int>::of(&QSpinBox::valueChanged), func);
widget->connect(widget, &QSpinBox::valueChanged, func);
}
else
{
@@ -591,7 +591,7 @@ namespace SettingWidgetBinder
{
if (!isNullable(widget))
{
widget->connect(widget, QOverload<double>::of(&QDoubleSpinBox::valueChanged), func);
widget->connect(widget, &QDoubleSpinBox::valueChanged, func);
}
else
{
@@ -608,7 +608,7 @@ namespace SettingWidgetBinder
});
menu.exec(widget->mapToGlobal(pt));
});
widget->connect(widget, QOverload<double>::of(&QDoubleSpinBox::valueChanged), widget, [widget, func = std::move(func)]() {
widget->connect(widget, &QDoubleSpinBox::valueChanged, widget, [widget, func = std::move(func)]() {
if (widget->property(IS_NULL_PROPERTY).toBool())
{
widget->setProperty(IS_NULL_PROPERTY, QVariant(false));

View File

@@ -42,9 +42,9 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* settings_dialog,
m_ui.eeClampMode->setCurrentIndex(getClampingModeIndex(-1));
m_ui.vu0ClampMode->setCurrentIndex(getClampingModeIndex(0));
m_ui.vu1ClampMode->setCurrentIndex(getClampingModeIndex(1));
connect(m_ui.eeClampMode, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) { setClampingMode(-1, index); });
connect(m_ui.vu0ClampMode, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) { setClampingMode(0, index); });
connect(m_ui.vu1ClampMode, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int index) { setClampingMode(1, index); });
connect(m_ui.eeClampMode, &QComboBox::currentIndexChanged, [this](int index) { setClampingMode(-1, index); });
connect(m_ui.vu0ClampMode, &QComboBox::currentIndexChanged, [this](int index) { setClampingMode(0, index); });
connect(m_ui.vu1ClampMode, &QComboBox::currentIndexChanged, [this](int index) { setClampingMode(1, index); });
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.iopRecompiler, "EmuCore/CPU/Recompiler", "EnableIOP", true);
@@ -60,7 +60,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* settings_dialog,
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_ui.savestateCompressionLevel, "EmuCore", "SavestateCompressionRatio", static_cast<int>(SavestateCompressionLevel::Medium));
connect(m_ui.savestateCompressionMethod, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
connect(m_ui.savestateCompressionMethod, &QComboBox::currentIndexChanged, this,
&AdvancedSettingsWidget::onSavestateCompressionTypeChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.backupSaveStates, "EmuCore", "BackupSavestate", true);

View File

@@ -49,7 +49,7 @@ ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSett
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(m_dialog->getProfileSettingsInterface(),
m_ui.controllerType, m_config_section, "Type", Pad::GetControllerInfo(Pad::GetDefaultPadType(port))->name);
connect(m_ui.controllerType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ControllerBindingWidget::onTypeChanged);
connect(m_ui.controllerType, &QComboBox::currentIndexChanged, this, &ControllerBindingWidget::onTypeChanged);
connect(m_ui.bindings, &QPushButton::clicked, this, &ControllerBindingWidget::onBindingsClicked);
connect(m_ui.settings, &QPushButton::clicked, this, &ControllerBindingWidget::onSettingsClicked);
connect(m_ui.macros, &QPushButton::clicked, this, &ControllerBindingWidget::onMacrosClicked);
@@ -1002,8 +1002,8 @@ USBDeviceWidget::USBDeviceWidget(QWidget* parent, ControllerSettingsWindow* dial
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
m_dialog->getProfileSettingsInterface(), m_ui.deviceType, m_config_section, "Type", "None");
connect(m_ui.deviceType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &USBDeviceWidget::onTypeChanged);
connect(m_ui.deviceSubtype, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &USBDeviceWidget::onSubTypeChanged);
connect(m_ui.deviceType, &QComboBox::currentIndexChanged, this, &USBDeviceWidget::onTypeChanged);
connect(m_ui.deviceSubtype, &QComboBox::currentIndexChanged, this, &USBDeviceWidget::onSubTypeChanged);
connect(m_ui.bindings, &QPushButton::clicked, this, &USBDeviceWidget::onBindingsClicked);
connect(m_ui.settings, &QPushButton::clicked, this, &USBDeviceWidget::onSettingsClicked);
connect(m_ui.automaticBinding, &QPushButton::clicked, this, &USBDeviceWidget::onAutomaticBindingClicked);

View File

@@ -62,8 +62,8 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsWindow* settings_dialog, QWidget*
//////////////////////////////////////////////////////////////////////////
// Eth Device Settings
//////////////////////////////////////////////////////////////////////////
connect(m_ui.ethDevType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &DEV9SettingsWidget::onEthDeviceTypeChanged);
connect(m_ui.ethDev, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &DEV9SettingsWidget::onEthDeviceChanged);
connect(m_ui.ethDevType, &QComboBox::currentIndexChanged, this, &DEV9SettingsWidget::onEthDeviceTypeChanged);
connect(m_ui.ethDev, &QComboBox::currentIndexChanged, this, &DEV9SettingsWidget::onEthDeviceChanged);
//Comboboxes populated in show event
//////////////////////////////////////////////////////////////////////////
@@ -125,12 +125,12 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsWindow* settings_dialog, QWidget*
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.ethDNS1Mode, "DEV9/Eth", "ModeDNS1",
s_dns_name, Pcsx2Config::DEV9Options::DnsModeNames, Pcsx2Config::DEV9Options::DnsModeNames[static_cast<int>(Pcsx2Config::DEV9Options::DnsMode::Auto)], "DEV9SettingsWidget");
onEthDNSModeChanged(m_ui.ethDNS1Mode, m_ui.ethDNS1Mode->currentIndex(), m_ui.ethDNS1Addr, "DEV9/Eth", "ModeDNS1");
connect(m_ui.ethDNS1Mode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [&](int index) { onEthDNSModeChanged(m_ui.ethDNS1Mode, index, m_ui.ethDNS1Addr, "DEV9/Eth", "ModeDNS1"); });
connect(m_ui.ethDNS1Mode, &QComboBox::currentIndexChanged, this, [&](int index) { onEthDNSModeChanged(m_ui.ethDNS1Mode, index, m_ui.ethDNS1Addr, "DEV9/Eth", "ModeDNS1"); });
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.ethDNS2Mode, "DEV9/Eth", "ModeDNS2",
s_dns_name, Pcsx2Config::DEV9Options::DnsModeNames, Pcsx2Config::DEV9Options::DnsModeNames[static_cast<int>(Pcsx2Config::DEV9Options::DnsMode::Auto)], "DEV9SettingsWidget");
onEthDNSModeChanged(m_ui.ethDNS2Mode, m_ui.ethDNS2Mode->currentIndex(), m_ui.ethDNS2Addr, "DEV9/Eth", "ModeDNS2");
connect(m_ui.ethDNS2Mode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [&](int index) { onEthDNSModeChanged(m_ui.ethDNS2Mode, index, m_ui.ethDNS2Addr, "DEV9/Eth", "ModeDNS2"); });
connect(m_ui.ethDNS2Mode, &QComboBox::currentIndexChanged, this, [&](int index) { onEthDNSModeChanged(m_ui.ethDNS2Mode, index, m_ui.ethDNS2Addr, "DEV9/Eth", "ModeDNS2"); });
//////////////////////////////////////////////////////////////////////////
// DNS Settings
@@ -144,7 +144,7 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsWindow* settings_dialog, QWidget*
headers.push_back(tr("Enabled"));
m_ethHost_model->setHorizontalHeaderLabels(headers);
connect(m_ethHost_model, QOverload<QStandardItem*>::of(&QStandardItemModel::itemChanged), this, &DEV9SettingsWidget::onEthHostEdit);
connect(m_ethHost_model, &QStandardItemModel::itemChanged, this, &DEV9SettingsWidget::onEthHostEdit);
m_ethHosts_proxy = new QSortFilterProxyModel(m_ui.ethHosts);
m_ethHosts_proxy->setSourceModel(m_ethHost_model);
@@ -186,7 +186,7 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsWindow* settings_dialog, QWidget*
connect(m_ui.hddFile, &QLineEdit::editingFinished, this, &DEV9SettingsWidget::onHddFileEdit);
connect(m_ui.hddBrowseFile, &QPushButton::clicked, this, &DEV9SettingsWidget::onHddBrowseFileClicked);
connect(m_ui.hddSizeSlider, QOverload<int>::of(&QSlider::valueChanged), this, &DEV9SettingsWidget::onHddSizeSlide);
connect(m_ui.hddSizeSlider, &QSlider::valueChanged, this, &DEV9SettingsWidget::onHddSizeSlide);
SettingWidgetBinder::SettingAccessor<QSpinBox>::connectValueChanged(m_ui.hddSizeSpinBox, [&]() { onHddSizeAccessorSpin(); });
connect(m_ui.hddCreate, &QPushButton::clicked, this, &DEV9SettingsWidget::onHddCreateClicked);

View File

@@ -94,7 +94,7 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsWindow* settings_dialog
const std::optional<int> cycle_rate =
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>(dialog()->isPerGameSettings())) : 0);
connect(m_ui.eeCycleRate, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [&](int index) {
connect(m_ui.eeCycleRate, &QComboBox::currentIndexChanged, this, [&](int index) {
std::optional<int> value;
if (!dialog()->isPerGameSettings() || index > 0)
value = MINIMUM_EE_CYCLE_RATE + index - static_cast<int>(dialog()->isPerGameSettings());
@@ -218,7 +218,7 @@ void EmulationSettingsWidget::initializeSpeedCombo(QComboBox* cb, const char* se
cb->setCurrentIndex(custom_index);
}
connect(cb, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
connect(cb, &QComboBox::currentIndexChanged, this,
[this, cb, section, key](int index) { handleSpeedComboChange(cb, section, key); });
}

View File

@@ -14,8 +14,31 @@
<string/>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
<item row="3" column="1">
<widget class="QComboBox" name="hwAutoFlush">
<item row="8" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="0">
<widget class="QLabel" name="skipDrawLabel">
<property name="text">
<string>Skip Draw Range:</string>
</property>
<property name="buddy">
<cstring>skipDrawStart</cstring>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="textureInsideRt">
<item>
<property name="text">
<string>Disabled (Default)</string>
@@ -23,12 +46,12 @@
</item>
<item>
<property name="text">
<string>Enabled (Sprites Only)</string>
<string>Inside Target</string>
</property>
</item>
<item>
<property name="text">
<string>Enabled (All Primitives)</string>
<string>Merge Targets</string>
</property>
</item>
</widget>
@@ -43,41 +66,6 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="skipDrawLabel">
<property name="text">
<string>Skip Draw Range:</string>
</property>
<property name="buddy">
<cstring>skipDrawStart</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cpuCLUTRender">
<property name="currentText">
<string extracomment="0 (Disabled)">0 (Disabled)</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>0 (Disabled)</string>
</property>
</item>
<item>
<property name="text">
<string>1 (Normal)</string>
</property>
</item>
<item>
<property name="text">
<string>2 (Aggressive)</string>
</property>
</item>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="cpuCLUTRenderLayout" stretch="0,0">
<item>
@@ -160,8 +148,36 @@
</item>
</layout>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="textureInsideRt">
<item row="3" column="0">
<widget class="QLabel" name="hwAutoFlushLabel">
<property name="text">
<string>Auto Flush:</string>
</property>
<property name="buddy">
<cstring>hwAutoFlush</cstring>
</property>
</widget>
</item>
<item row="6" column="1">
<layout class="QHBoxLayout" name="skipDrawLayout">
<item>
<widget class="QSpinBox" name="skipDrawStart">
<property name="maximum">
<number>10000</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="skipDrawEnd">
<property name="maximum">
<number>10000</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="gpuTargetCLUTMode">
<item>
<property name="text">
<string>Disabled (Default)</string>
@@ -169,12 +185,57 @@
</item>
<item>
<property name="text">
<string>Inside Target</string>
<string>Enabled (Exact Match)</string>
</property>
</item>
<item>
<property name="text">
<string>Merge Targets</string>
<string>Enabled (Check Inside Target)</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="cpuCLUTRenderLabel">
<property name="text">
<string>CPU Sprite Render Size:</string>
</property>
<property name="buddy">
<cstring>cpuSpriteRenderBW</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="gpuTargetCLUTLabel">
<property name="text">
<string extracomment="CLUT: Color Look Up Table, often referred to as a palette in non-PS2 things. GPU Target CLUT: GPU handling of when a game uses data from a render target as a CLUT.">GPU Target CLUT:</string>
</property>
<property name="buddy">
<cstring>gpuTargetCLUTMode</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cpuCLUTRender">
<property name="currentText">
<string extracomment="0 (Disabled)">0 (Disabled)</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>0 (Disabled)</string>
</property>
</item>
<item>
<property name="text">
<string>1 (Normal)</string>
</property>
</item>
<item>
<property name="text">
<string>2 (Aggressive)</string>
</property>
</item>
</widget>
@@ -189,7 +250,26 @@
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<item row="3" column="1">
<widget class="QComboBox" name="hwAutoFlush">
<item>
<property name="text">
<string>Disabled (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Enabled (Sprites Only)</string>
</property>
</item>
<item>
<property name="text">
<string>Enabled (All Primitives)</string>
</property>
</item>
</widget>
</item>
<item row="7" column="0" colspan="2">
<layout class="QGridLayout" name="hwFixesLayout">
<item row="4" column="0">
<widget class="QCheckBox" name="estimateTextureRegion">
@@ -256,28 +336,8 @@
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QLabel" name="hwAutoFlushLabel">
<property name="text">
<string>Auto Flush:</string>
</property>
<property name="buddy">
<cstring>hwAutoFlush</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="gpuTargetCLUTLabel">
<property name="text">
<string extracomment="CLUT: Color Look Up Table, often referred to as a palette in non-PS2 things. GPU Target CLUT: GPU handling of when a game uses data from a render target as a CLUT.">GPU Target CLUT:</string>
</property>
<property name="buddy">
<cstring>gpuTargetCLUTMode</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="gpuTargetCLUTMode">
<item row="5" column="1">
<widget class="QComboBox" name="limit24BitDepth">
<item>
<property name="text">
<string>Disabled (Default)</string>
@@ -285,57 +345,23 @@
</item>
<item>
<property name="text">
<string>Enabled (Exact Match)</string>
<string>Prioritize Upper</string>
</property>
</item>
<item>
<property name="text">
<string>Enabled (Check Inside Target)</string>
<string>Prioritize Lower</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="cpuCLUTRenderLabel">
<item row="5" column="0">
<widget class="QLabel" name="limitDepthLabel">
<property name="text">
<string>CPU Sprite Render Size:</string>
</property>
<property name="buddy">
<cstring>cpuSpriteRenderBW</cstring>
<string>Limit 24 Bit Depth</string>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="skipDrawLayout">
<item>
<widget class="QSpinBox" name="skipDrawStart">
<property name="maximum">
<number>10000</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="skipDrawEnd">
<property name="maximum">
<number>10000</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="7" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<tabstops>

View File

@@ -99,7 +99,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_display.cropBottom, "EmuCore/GS", "CropBottom", 0);
connect(
m_display.fullscreenModes, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onFullscreenModeChanged);
m_display.fullscreenModes, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onFullscreenModeChanged);
//////////////////////////////////////////////////////////////////////////
// HW Settings
@@ -114,9 +114,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_hw.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_hw.enableHWFixes, "EmuCore/GS", "UserHacks", false);
connect(m_hw.upscaleMultiplier, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
connect(m_hw.upscaleMultiplier, &QComboBox::currentIndexChanged, this,
&GraphicsSettingsWidget::onUpscaleMultiplierChanged);
connect(m_hw.trilinearFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
connect(m_hw.trilinearFiltering, &QComboBox::currentIndexChanged, this,
&GraphicsSettingsWidget::onTrilinearFilteringChanged);
onTrilinearFilteringChanged();
@@ -147,10 +147,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
sif, m_fixes.disablePartialInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_fixes.textureInsideRt, "EmuCore/GS", "UserHacks_TextureInsideRt", static_cast<int>(GSTextureInRtMode::Disabled));
SettingWidgetBinder::BindWidgetToIntSetting(
sif, m_fixes.limit24BitDepth, "EmuCore/GS", "UserHacks_Limit24BitDepth", static_cast<int>(GSLimit24BitDepth::Disabled));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.readTCOnClose, "EmuCore/GS", "UserHacks_ReadTCOnClose", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.estimateTextureRegion, "EmuCore/GS", "UserHacks_EstimateTextureRegion", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_fixes.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
connect(m_fixes.cpuSpriteRenderBW, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
connect(m_fixes.cpuSpriteRenderBW, &QComboBox::currentIndexChanged, this,
&GraphicsSettingsWidget::onCPUSpriteRenderBWChanged);
connect(m_fixes.gpuPaletteConversion, &QCheckBox::checkStateChanged, this, &GraphicsSettingsWidget::onGpuPaletteConversionChanged);
onCPUSpriteRenderBWChanged();
@@ -295,8 +297,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
m_header.rendererDropdown->setCurrentIndex(0);
}
connect(m_header.rendererDropdown, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onRendererChanged);
connect(m_header.adapterDropdown, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onAdapterChanged);
connect(m_header.rendererDropdown, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onRendererChanged);
connect(m_header.adapterDropdown, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onAdapterChanged);
connect(m_hw.enableHWFixes, &QCheckBox::checkStateChanged, this, &GraphicsSettingsWidget::updateRendererDependentOptions);
connect(m_advanced.extendedUpscales, &QCheckBox::checkStateChanged, this, &GraphicsSettingsWidget::updateRendererDependentOptions);
connect(m_hw.textureFiltering, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onTextureFilteringChange);
@@ -624,6 +626,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
dialog()->registerWidgetHelp(m_fixes.textureInsideRt, tr("Texture Inside RT"), tr("Disabled"),
tr("Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer."));
dialog()->registerWidgetHelp(m_fixes.limit24BitDepth, tr("Limit 24 Bit Depth"), tr("Disabled"),
tr("Eats your cheese."));
dialog()->registerWidgetHelp(m_fixes.readTCOnClose, tr("Read Targets When Closing"), tr("Unchecked"),
tr("Flushes all targets in the texture cache back to local memory when shutting down. Can prevent lost visuals when saving "
"state or switching graphics APIs, but can also cause graphical corruption."));

View File

@@ -133,18 +133,18 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* settings_dialog
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.theme, "UI", "Theme", THEME_NAMES, THEME_VALUES,
QtHost::GetDefaultThemeName(), "InterfaceSettingsWidget");
connect(m_ui.theme, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() { emit themeChanged(); });
connect(m_ui.theme, &QComboBox::currentIndexChanged, [this]() { emit themeChanged(); });
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.backgroundOpacity, "UI", "GameListBackgroundOpacity", 100.0f);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.backgroundScale, "UI", "GameListBackgroundMode", BACKGROUND_SCALE_NAMES, QtUtils::ScalingMode::Fit);
connect(m_ui.backgroundBrowse, &QPushButton::clicked, [this]() { onSetGameListBackgroundTriggered(); });
connect(m_ui.backgroundReset, &QPushButton::clicked, [this]() { onClearGameListBackgroundTriggered(); });
connect(m_ui.backgroundOpacity, &QSpinBox::editingFinished, [this]() { emit backgroundChanged(); });
connect(m_ui.backgroundScale, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() { emit backgroundChanged(); });
connect(m_ui.backgroundScale, &QComboBox::currentIndexChanged, [this]() { emit backgroundChanged(); });
populateLanguages();
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.language, "UI", "Language", QtHost::GetDefaultLanguage());
connect(m_ui.language, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() { emit languageChanged(); });
connect(m_ui.language, &QComboBox::currentIndexChanged, [this]() { emit languageChanged(); });
// Per-game settings is special, we don't want to bind it if we're editing per-game settings.
if (!dialog()->isPerGameSettings())

View File

@@ -176,7 +176,7 @@ void SetupWizardDialog::setupLanguagePage()
{
SettingWidgetBinder::BindWidgetToEnumSetting(nullptr, m_ui.theme, "UI", "Theme",
InterfaceSettingsWidget::THEME_NAMES, InterfaceSettingsWidget::THEME_VALUES, QtHost::GetDefaultThemeName(), "InterfaceSettingsWidget");
connect(m_ui.theme, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SetupWizardDialog::themeChanged);
connect(m_ui.theme, &QComboBox::currentIndexChanged, this, &SetupWizardDialog::themeChanged);
for (const std::pair<QString, QString>& it : QtHost::GetAvailableLanguageList())
{
@@ -189,7 +189,7 @@ void SetupWizardDialog::setupLanguagePage()
SettingWidgetBinder::BindWidgetToStringSetting(
nullptr, m_ui.language, "UI", "Language", QtHost::GetDefaultLanguage());
connect(
m_ui.language, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SetupWizardDialog::languageChanged);
m_ui.language, &QComboBox::currentIndexChanged, this, &SetupWizardDialog::languageChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(
nullptr, m_ui.autoUpdateEnabled, "AutoUpdater", "CheckAtStartup", true);

View File

@@ -437,26 +437,26 @@ void QtHost::SetStyleFromSettings()
// Alternative dark theme.
qApp->setStyle(QStyleFactory::create("Fusion"));
const QColor gray(150, 150, 150);
const QColor royalBlue(29, 41, 81);
const QColor darkishBlue(17, 30, 108);
const QColor abyssBlue(39, 58, 114);
const QColor darkishBlue(29, 41, 81);
const QColor lighterBlue(25, 32, 130);
const QColor highlight(36, 93, 218);
const QColor link(0, 202, 255);
const QColor blue(198, 238, 255);
const QColor gray(150, 150, 150);
QPalette cobaltSkyPalette;
cobaltSkyPalette.setColor(QPalette::Window, royalBlue);
cobaltSkyPalette.setColor(QPalette::Window, abyssBlue);
cobaltSkyPalette.setColor(QPalette::WindowText, Qt::white);
cobaltSkyPalette.setColor(QPalette::Base, royalBlue.lighter());
cobaltSkyPalette.setColor(QPalette::AlternateBase, darkishBlue);
cobaltSkyPalette.setColor(QPalette::Base, darkishBlue);
cobaltSkyPalette.setColor(QPalette::AlternateBase, darkishBlue.darker());
cobaltSkyPalette.setColor(QPalette::ToolTipBase, darkishBlue);
cobaltSkyPalette.setColor(QPalette::ToolTipText, Qt::white);
cobaltSkyPalette.setColor(QPalette::Text, Qt::white);
cobaltSkyPalette.setColor(QPalette::Button, lighterBlue);
cobaltSkyPalette.setColor(QPalette::ButtonText, Qt::white);
cobaltSkyPalette.setColor(QPalette::Link, link);
cobaltSkyPalette.setColor(QPalette::Highlight, highlight);
cobaltSkyPalette.setColor(QPalette::Link, blue);
cobaltSkyPalette.setColor(QPalette::Highlight, abyssBlue.lighter());
cobaltSkyPalette.setColor(QPalette::HighlightedText, Qt::white);
cobaltSkyPalette.setColor(QPalette::PlaceholderText, gray);
cobaltSkyPalette.setColor(QPalette::Active, QPalette::Button, lighterBlue);
cobaltSkyPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
@@ -475,9 +475,9 @@ void QtHost::SetStyleFromSettings()
// OLED screens.
qApp->setStyle(QStyleFactory::create("Fusion"));
const QColor black(0, 0, 0);
const QColor gray(25, 25, 25);
const QColor lighterGray(75, 75, 75);
const QColor black(5, 5, 5);
const QColor gray(22, 22, 29);
const QColor lighterGray(65, 79, 98);
const QColor blue(198, 238, 255);
QPalette AMOLEDPalette;
@@ -519,7 +519,7 @@ void QtHost::SetStyleFromSettings()
rubyPalette.setColor(QPalette::Window, slate);
rubyPalette.setColor(QPalette::WindowText, Qt::white);
rubyPalette.setColor(QPalette::Base, slate.lighter());
rubyPalette.setColor(QPalette::AlternateBase, slate.lighter());
rubyPalette.setColor(QPalette::AlternateBase, slate.darker());
rubyPalette.setColor(QPalette::ToolTipBase, slate);
rubyPalette.setColor(QPalette::ToolTipText, Qt::white);
rubyPalette.setColor(QPalette::Text, Qt::white);
@@ -553,7 +553,7 @@ void QtHost::SetStyleFromSettings()
sapphirePalette.setColor(QPalette::Window, slate);
sapphirePalette.setColor(QPalette::WindowText, Qt::white);
sapphirePalette.setColor(QPalette::Base, slate.lighter());
sapphirePalette.setColor(QPalette::AlternateBase, slate.lighter());
sapphirePalette.setColor(QPalette::AlternateBase, slate.darker());
sapphirePalette.setColor(QPalette::ToolTipBase, slate);
sapphirePalette.setColor(QPalette::ToolTipText, Qt::white);
sapphirePalette.setColor(QPalette::Text, Qt::white);
@@ -587,7 +587,7 @@ void QtHost::SetStyleFromSettings()
emeraldPalette.setColor(QPalette::Window, slate);
emeraldPalette.setColor(QPalette::WindowText, Qt::white);
emeraldPalette.setColor(QPalette::Base, slate.lighter());
emeraldPalette.setColor(QPalette::AlternateBase, slate.lighter());
emeraldPalette.setColor(QPalette::AlternateBase, slate.darker());
emeraldPalette.setColor(QPalette::ToolTipBase, slate);
emeraldPalette.setColor(QPalette::ToolTipText, Qt::white);
emeraldPalette.setColor(QPalette::Text, Qt::white);

View File

@@ -23147,8 +23147,9 @@ Rename it to {} to remove this warning.</source>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="938"/>
<location filename="../../pcsx2/USB/usb-pad/usb-realplay.cpp" line="448"/>
<location filename="../../pcsx2/USB/usb-pad/usb-seamic.cpp" line="373"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="79"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="98"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="89"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="108"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="131"/>
<location filename="../../pcsx2/USB/usb-pad/usb-turntable.cpp" line="440"/>
<source>D-Pad Up</source>
<translation type="unfinished"></translation>
@@ -23160,8 +23161,9 @@ Rename it to {} to remove this warning.</source>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="940"/>
<location filename="../../pcsx2/USB/usb-pad/usb-realplay.cpp" line="449"/>
<location filename="../../pcsx2/USB/usb-pad/usb-seamic.cpp" line="374"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="80"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="99"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="90"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="109"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="132"/>
<location filename="../../pcsx2/USB/usb-pad/usb-turntable.cpp" line="441"/>
<source>D-Pad Down</source>
<translation type="unfinished"></translation>
@@ -23173,8 +23175,9 @@ Rename it to {} to remove this warning.</source>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="941"/>
<location filename="../../pcsx2/USB/usb-pad/usb-realplay.cpp" line="450"/>
<location filename="../../pcsx2/USB/usb-pad/usb-seamic.cpp" line="375"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="81"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="100"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="91"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="110"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="133"/>
<location filename="../../pcsx2/USB/usb-pad/usb-turntable.cpp" line="442"/>
<source>D-Pad Left</source>
<translation type="unfinished"></translation>
@@ -23186,8 +23189,9 @@ Rename it to {} to remove this warning.</source>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="939"/>
<location filename="../../pcsx2/USB/usb-pad/usb-realplay.cpp" line="451"/>
<location filename="../../pcsx2/USB/usb-pad/usb-seamic.cpp" line="376"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="82"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="101"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="92"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="111"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="134"/>
<location filename="../../pcsx2/USB/usb-pad/usb-turntable.cpp" line="443"/>
<source>D-Pad Right</source>
<translation type="unfinished"></translation>
@@ -23211,6 +23215,7 @@ Rename it to {} to remove this warning.</source>
<location filename="../../pcsx2/USB/usb-lightgun/guncon2.cpp" line="592"/>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="139"/>
<location filename="../../pcsx2/USB/usb-pad/usb-seamic.cpp" line="363"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="154"/>
<source>A</source>
<translation type="unfinished"></translation>
</message>
@@ -23218,12 +23223,14 @@ Rename it to {} to remove this warning.</source>
<location filename="../../pcsx2/USB/usb-lightgun/guncon2.cpp" line="593"/>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="140"/>
<location filename="../../pcsx2/USB/usb-pad/usb-seamic.cpp" line="364"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="155"/>
<source>B</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-lightgun/guncon2.cpp" line="594"/>
<location filename="../../pcsx2/USB/usb-pad/usb-seamic.cpp" line="365"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="156"/>
<source>C</source>
<translation type="unfinished"></translation>
</message>
@@ -23234,8 +23241,9 @@ Rename it to {} to remove this warning.</source>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="936"/>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="1003"/>
<location filename="../../pcsx2/USB/usb-pad/usb-seamic.cpp" line="371"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="87"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="107"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="97"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="117"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="141"/>
<location filename="../../pcsx2/USB/usb-pad/usb-turntable.cpp" line="448"/>
<source>Select</source>
<translation type="unfinished"></translation>
@@ -23247,8 +23255,9 @@ Rename it to {} to remove this warning.</source>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="937"/>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="1002"/>
<location filename="../../pcsx2/USB/usb-pad/usb-seamic.cpp" line="372"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="88"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="108"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="98"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="118"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="142"/>
<location filename="../../pcsx2/USB/usb-pad/usb-turntable.cpp" line="449"/>
<source>Start</source>
<translation type="unfinished"></translation>
@@ -23576,8 +23585,8 @@ Rename it to {} to remove this warning.</source>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="77"/>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="105"/>
<location filename="../../pcsx2/USB/usb-pad/usb-pad.cpp" line="134"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="78"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="97"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="88"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="107"/>
<source>Brake</source>
<translation type="unfinished"></translation>
</message>
@@ -24351,66 +24360,138 @@ Xbox 360 turntables require a 256x multiplier, most other turntables can use the
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="77"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="96"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="40"/>
<source>Train Mascon</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="41"/>
<source>Master Controller</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="87"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="106"/>
<source>Power</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="83"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="93"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="138"/>
<source>A Button</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="84"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="94"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="139"/>
<source>B Button</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="85"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="95"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="140"/>
<source>C Button</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="86"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="96"/>
<source>D Button</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="102"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="112"/>
<source>Announce</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="103"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="113"/>
<source>Horn</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="104"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="114"/>
<source>Left Door</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="105"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="115"/>
<source>Right Door</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="106"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="116"/>
<source>Camera Button</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="162"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="126"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="149"/>
<source>Power Up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="127"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="150"/>
<source>Power Down</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="128"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="151"/>
<source>Reverser Up</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="129"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="152"/>
<source>Reverser Down</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="136"/>
<source>ATS</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="137"/>
<source>Close</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="153"/>
<source>S</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="227"/>
<source>Axes Passthrough</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="163"/>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="228"/>
<source>Passes through the unprocessed input axis to the game. Enable if you are using a compatible Densha De Go! controller. Disable if you are using any other joystick.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="240"/>
<source>Power notches</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="241"/>
<source>Selects the number of power notches (3-6)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="249"/>
<source>Brake notches</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../pcsx2/USB/usb-pad/usb-train.cpp" line="250"/>
<source>Selects the number of brake notches (5-8)</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>USBBindingWidget</name>

View File

@@ -1043,21 +1043,11 @@ void Achievements::ClientLoadGameCallback(int result, const char* error_message,
s_has_leaderboards = has_leaderboards;
s_has_rich_presence = rc_client_has_rich_presence(client);
s_game_icon = {};
s_game_icon_url = {};
s_game_icon_url = info->badge_url;
// ensure fullscreen UI is ready for notifications
MTGS::RunOnGSThread(&ImGuiManager::InitializeFullscreenUI);
char url_buffer[URL_BUFFER_SIZE];
if (int err = rc_client_game_get_image_url(info, url_buffer, std::size(url_buffer)); err == RC_OK)
{
s_game_icon_url = url_buffer;
}
else
{
ReportRCError(err, "rc_client_game_get_image_url() failed: ");
}
if (const std::string_view badge_name = info->badge_name; !badge_name.empty())
{
s_game_icon = Path::Combine(s_image_directory, fmt::format("game_{}.png", badge_name));

View File

@@ -432,6 +432,13 @@ enum class GSTextureInRtMode : u8
MergeTargets,
};
enum class GSLimit24BitDepth : u8
{
Disabled,
PrioritizeUpper,
PrioritizeLower,
};
enum class GSBilinearDirtyMode : u8
{
Automatic,
@@ -844,6 +851,7 @@ struct Pcsx2Config
u8 UserHacks_CPUCLUTRender = 0;
GSGPUTargetCLUTMode UserHacks_GPUTargetCLUTMode = GSGPUTargetCLUTMode::Disabled;
GSTextureInRtMode UserHacks_TextureInsideRt = GSTextureInRtMode::Disabled;
GSLimit24BitDepth UserHacks_Limit24BitDepth = GSLimit24BitDepth::Disabled;
GSBilinearDirtyMode UserHacks_BilinearHack = GSBilinearDirtyMode::Automatic;
TriFiltering TriFilter = TriFiltering::Automatic;
s8 OverrideTextureBarriers = -1;

View File

@@ -533,7 +533,7 @@ bool GSHasDisplayWindow()
return (g_gs_device->GetWindowInfo().type != WindowInfo::Type::Surfaceless);
}
void GSResizeDisplayWindow(int width, int height, float scale)
void GSResizeDisplayWindow(u32 width, u32 height, float scale)
{
g_gs_device->ResizeWindow(width, height, scale);
ImGuiManager::WindowResized();

View File

@@ -83,7 +83,7 @@ void GSThrottlePresentation();
void GSGameChanged();
void GSSetDisplayAlignment(GSDisplayAlignment alignment);
bool GSHasDisplayWindow();
void GSResizeDisplayWindow(int width, int height, float scale);
void GSResizeDisplayWindow(u32 width, u32 height, float scale);
void GSUpdateDisplayWindow();
void GSSetVSyncMode(GSVSyncMode mode, bool allow_present_throttle);

View File

@@ -806,12 +806,12 @@ void GSState::DumpTransferList(const std::string& filename)
(*file) << std::endl;
// clear, EE->GS, or GS->GS
(*file) << LIST_ITEM << "type: " << (transfer.zero_clear ? "clear" : (transfer.ee_to_gs ? "EE_to_GS" : "GS_to_GS")) << std::endl;
(*file) << LIST_ITEM << "type: " << (transfer.zero_clear ? "clear" : ((transfer.transfer_type == EEGS_TransferType::EE_to_GS) ? "EE_to_GS" : "GS_to_GS")) << std::endl;
// Dump BITBLTBUF
(*file) << INDENT << "BITBLTBUF: " << OPEN_MAP;
const bool gs_to_gs = !transfer.ee_to_gs && !transfer.zero_clear;
const bool gs_to_gs = (transfer.transfer_type == EEGS_TransferType::GS_to_GS) && !transfer.zero_clear;
if (gs_to_gs)
{
@@ -857,7 +857,7 @@ void GSState::DumpTransferImages()
const GSUploadQueue& transfer = m_draw_transfers[i];
std::string filename;
if (transfer.ee_to_gs || transfer.zero_clear)
if ((transfer.transfer_type == EEGS_TransferType::EE_to_GS) || transfer.zero_clear)
{
// clear or EE->GS: only the destination info is relevant.
filename = GetDrawDumpPath("%05d_transfer%02d_%s_%04x_%d_%s_%d_%d_%d_%d.png",
@@ -2365,7 +2365,7 @@ void GSState::Write(const u8* mem, int len)
s_last_transfer_draw_n = s_n;
// Store the transfer for preloading new RT's.
if ((m_draw_transfers.size() > 0 && blit.DBP == m_draw_transfers.back().blit.DBP))
if ((m_draw_transfers.size() > 0 && blit.DBP == m_draw_transfers.back().blit.DBP && m_draw_transfers.back().transfer_type == EEGS_TransferType::EE_to_GS))
{
// Same BP, let's update the rect.
GSUploadQueue transfer = m_draw_transfers.back();
@@ -2377,7 +2377,7 @@ void GSState::Write(const u8* mem, int len)
}
else
{
const GSUploadQueue new_transfer = { blit, r, s_n, false, true };
const GSUploadQueue new_transfer = {blit, r, s_n, false, EEGS_TransferType::EE_to_GS};
m_draw_transfers.push_back(new_transfer);
}
@@ -2519,21 +2519,31 @@ void GSState::Move()
InvalidateLocalMem(m_env.BITBLTBUF, GSVector4i(sx, sy, sx + w, sy + h));
InvalidateVideoMem(m_env.BITBLTBUF, GSVector4i(dx, dy, dx + w, dy + h));
const bool overlaps = m_env.BITBLTBUF.SBP == m_env.BITBLTBUF.DBP;
const bool intersect = overlaps && !(GSVector4i(sx, sy, sx + w, sy + h).rintersect(GSVector4i(dx, dy, dx + w, dy + h)).rempty());
int xinc = 1;
int yinc = 1;
if (m_env.TRXPOS.DIRX)
{
sx += w - 1;
dx += w - 1;
xinc = -1;
// Only allow it to reverse if the destination is behind the source.
if (!intersect || (sx <= dx && (sx == dx || ((!m_env.TRXPOS.DIRY && sy >= dy) || (m_env.TRXPOS.DIRY && sy < dy)))))
{
sx += w - 1;
dx += w - 1;
xinc = -1;
}
}
if (m_env.TRXPOS.DIRY)
{
sy += h - 1;
dy += h - 1;
yinc = -1;
// Only allow it to reverse if the destination is behind the source.
if (!intersect || (sy <= dy && (sy == dy || ((!m_env.TRXPOS.DIRX && sx >= dx) || (m_env.TRXPOS.DIRX && sx < dx)))))
{
sy += h - 1;
dy += h - 1;
yinc = -1;
}
}
const GSLocalMemory::psm_t& spsm = GSLocalMemory::m_psm[m_env.BITBLTBUF.SPSM];
@@ -2556,7 +2566,7 @@ void GSState::Move()
s_last_transfer_draw_n = s_n;
// Store the transfer for preloading new RT's.
if ((m_draw_transfers.size() > 0 && m_env.BITBLTBUF.DBP == m_draw_transfers.back().blit.DBP))
if ((m_draw_transfers.size() > 0 && m_env.BITBLTBUF.DBP == m_draw_transfers.back().blit.DBP && m_draw_transfers.back().transfer_type == EEGS_TransferType::GS_to_GS))
{
// Same BP, let's update the rect.
GSUploadQueue transfer = m_draw_transfers.back();
@@ -2568,11 +2578,11 @@ void GSState::Move()
}
else
{
const GSUploadQueue new_transfer = { m_env.BITBLTBUF, r, s_n, false, false };
const GSUploadQueue new_transfer = {m_env.BITBLTBUF, r, s_n, false, EEGS_TransferType::GS_to_GS};
m_draw_transfers.push_back(new_transfer);
}
auto copy = [this, sbp, dbp, sx, sy, dx, dy, w, h, yinc, xinc](const GSOffset& dpo, const GSOffset& spo, auto&& pxCopyFn)
auto copy = [this, sbp, dbp, sx, sy, dx, dy, w, h, yinc, xinc, intersect](const GSOffset& dpo, const GSOffset& spo, auto&& pxCopyFn)
{
int _sy = sy, _dy = dy; // Faster with local copied variables, compiler optimizations are dumb
if (xinc > 0)
@@ -2584,8 +2594,6 @@ void GSState::Move()
// Copying from itself to itself (rotating textures) used in Gitaroo Man stage 8
// What probably happens is because the copy is buffered, the source stays just ahead of the destination.
// No need to do all this if the copy source/destination don't intersect, however.
const bool intersect = !(GSVector4i(sx, sy, sx + w, sy + h).rintersect(GSVector4i(dx, dy, dx + w, dy + h)).rempty());
if (intersect && sbp == dbp && (((_sy < _dy) && ((ypage + page_height) > _dy)) || ((sx < dx) && ((xpage + page_width) > dx))))
{
int starty = (yinc > 0) ? 0 : h-1;
@@ -4657,6 +4665,14 @@ __forceinline void GSState::VertexKick(u32 skip)
u32 next = m_vertex.next;
u32 xy_tail = m_vertex.xy_tail;
if (GSIsHardwareRenderer() && GSLocalMemory::m_psm[m_context->ZBUF.PSM].bpp == 32)
{
if (GSConfig.UserHacks_Limit24BitDepth == GSLimit24BitDepth::PrioritizeUpper)
m_v.XYZ.Z = ((m_v.XYZ.Z >> 8) & ~0xFF) | (m_v.XYZ.Z & 0xFF);
else if (GSConfig.UserHacks_Limit24BitDepth == GSLimit24BitDepth::PrioritizeLower)
m_v.XYZ.Z &= 0x00FFFFFF;
}
// callers should write XYZUVF to m_v.m[1] in one piece to have this load store-forwarded, either by the cpu or the compiler when this function is inlined
const GSVector4i new_v0(m_v.m[0]);

View File

@@ -211,13 +211,20 @@ protected:
void CorrectATEAlphaMinMax(const u32 atst, const int aref);
public:
enum EEGS_TransferType
{
EE_to_GS,
GS_to_GS,
GS_to_EE
};
struct GSUploadQueue
{
GIFRegBITBLTBUF blit;
GSVector4i rect;
int draw;
bool zero_clear;
bool ee_to_gs;
EEGS_TransferType transfer_type;
};
enum NoGapsType

View File

@@ -401,6 +401,7 @@ struct alignas(16) GSHWDrawConfig
// Depth clamp
u32 zclamp : 1;
u32 zfloor : 1;
// Hack
u32 tcoffsethack : 1;
@@ -1019,7 +1020,7 @@ public:
virtual bool UpdateWindow() = 0;
/// Call when the window size changes externally to recreate any resources.
virtual void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) = 0;
virtual void ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale) = 0;
/// Returns true if exclusive fullscreen is supported.
virtual bool SupportsExclusiveFullscreen() const = 0;

View File

@@ -278,7 +278,7 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
for (size_t i = 0; i < std::size(m_merge.ps); i++)
{
const std::string entry_point(StringUtil::StdStringFromFormat("ps_main%d", i));
const std::string entry_point(StringUtil::StdStringFromFormat("ps_main%zu", i));
m_merge.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *shader, nullptr, entry_point.c_str());
if (!m_merge.ps[i])
return false;
@@ -312,7 +312,7 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
return false;
for (size_t i = 0; i < std::size(m_interlace.ps); i++)
{
const std::string entry_point(StringUtil::StdStringFromFormat("ps_main%d", i));
const std::string entry_point(StringUtil::StdStringFromFormat("ps_main%zu", i));
m_interlace.ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *shader, nullptr, entry_point.c_str());
if (!m_interlace.ps[i])
return false;
@@ -498,7 +498,7 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
for (size_t i = 0; i < std::size(m_date.primid_init_ps); i++)
{
const std::string entry_point(StringUtil::StdStringFromFormat("ps_stencil_image_init_%d", i));
const std::string entry_point(StringUtil::StdStringFromFormat("ps_stencil_image_init_%zu", i));
m_date.primid_init_ps[i] = m_shader_cache.GetPixelShader(m_dev.get(), *convert_hlsl, nullptr, entry_point.c_str());
if (!m_date.primid_init_ps[i])
return false;
@@ -893,7 +893,7 @@ std::string GSDevice11::GetDriverInfo() const
return ret;
}
void GSDevice11::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
void GSDevice11::ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale)
{
if (!m_swap_chain || m_is_exclusive_fullscreen)
return;
@@ -1760,6 +1760,7 @@ void GSDevice11::SetupPS(const PSSelector& sel, const GSHWDrawConfig::PSConstant
sm.AddMacro("PS_DITHER", sel.dither);
sm.AddMacro("PS_DITHER_ADJUST", sel.dither_adjust);
sm.AddMacro("PS_ZCLAMP", sel.zclamp);
sm.AddMacro("PS_ZFLOOR", sel.zfloor);
sm.AddMacro("PS_SCANMSK", sel.scanmsk);
sm.AddMacro("PS_AUTOMATIC_LOD", sel.automatic_lod);
sm.AddMacro("PS_MANUAL_LOD", sel.manual_lod);

View File

@@ -273,7 +273,7 @@ public:
RenderAPI GetRenderAPI() const override;
bool UpdateWindow() override;
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
void ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale) override;
bool SupportsExclusiveFullscreen() const override;
bool HasSurface() const override;
void DestroySurface() override;

View File

@@ -750,6 +750,8 @@ bool GSDevice12::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
InitializeState();
InitializeSamplers();
// Reference stencil isn't tied to pipeline, so we can set it once and leave it.
SetStencilRef(1);
return true;
}
@@ -1054,7 +1056,7 @@ std::string GSDevice12::GetDriverInfo() const
return ret;
}
void GSDevice12::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
void GSDevice12::ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale)
{
if (!m_swap_chain)
return;
@@ -2920,6 +2922,7 @@ const ID3DBlob* GSDevice12::GetTFXPixelShader(const GSHWDrawConfig::PSSelector&
sm.AddMacro("PS_DITHER", sel.dither);
sm.AddMacro("PS_DITHER_ADJUST", sel.dither_adjust);
sm.AddMacro("PS_ZCLAMP", sel.zclamp);
sm.AddMacro("PS_ZFLOOR", sel.zfloor);
sm.AddMacro("PS_SCANMSK", sel.scanmsk);
sm.AddMacro("PS_AUTOMATIC_LOD", sel.automatic_lod);
sm.AddMacro("PS_MANUAL_LOD", sel.manual_lod);
@@ -3740,7 +3743,7 @@ void GSDevice12::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSV
IASetVertexBuffer(vertices, sizeof(vertices[0]), 4);
SetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
SetPipeline(m_convert[SetDATMShader(datm)].get());
SetStencilRef(1);
// Reference stencil value set on Create()
BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
@@ -3828,26 +3831,6 @@ GSTexture12* GSDevice12::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, Pipe
void GSDevice12::RenderHW(GSHWDrawConfig& config)
{
// Destination Alpha Setup
const bool stencil_DATE_One = config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne;
const bool stencil_DATE = (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::Stencil || stencil_DATE_One);
// TODO: Backport from vk.
if (stencil_DATE_One)
{
config.ps.date = 0;
config.alpha_second_pass.ps.date = 0;
if (!config.ps.IsFeedbackLoop())
{
config.require_one_barrier = false;
config.require_full_barrier = false;
}
if (!config.alpha_second_pass.ps.IsFeedbackLoop())
{
config.alpha_second_pass.require_one_barrier = false;
config.alpha_second_pass.require_full_barrier = false;
}
}
GSTexture12* colclip_rt = static_cast<GSTexture12*>(g_gs_device->GetColorClipTexture());
GSTexture12* draw_rt = static_cast<GSTexture12*>(config.rt);
@@ -3910,8 +3893,29 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
}
}
if (stencil_DATE)
SetupDATE(draw_rt, config.ds, config.datm, config.drawarea);
// Destination Alpha Setup
const bool need_barrier = m_features.texture_barrier && (config.require_one_barrier || config.require_full_barrier);
switch (config.destination_alpha)
{
case GSHWDrawConfig::DestinationAlphaMode::Off: // No setup
case GSHWDrawConfig::DestinationAlphaMode::Full: // No setup
case GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking: // Setup is done below
break;
case GSHWDrawConfig::DestinationAlphaMode::StencilOne: // setup is done below
{
// we only need to do the setup here if we don't have barriers, in which case do full DATE.
if (!need_barrier)
{
SetupDATE(draw_rt, config.ds, config.datm, config.drawarea);
config.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Stencil;
}
}
break;
case GSHWDrawConfig::DestinationAlphaMode::Stencil:
SetupDATE(draw_rt, config.ds, config.datm, config.drawarea);
break;
}
// stream buffer in first, in case we need to exec
SetVSConstantBuffer(config.cb_vs);
@@ -4033,6 +4037,17 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
// For depth testing and sampling, use a read only dsv, otherwise use a write dsv
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, config.tex && config.tex == config.ds);
// DX12 equivalent of vkCmdClearAttachments for StencilOne
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne)
{
EndRenderPass();
// Make sure the DSV is in writeable state
draw_ds->TransitionToState(D3D12_RESOURCE_STATE_DEPTH_WRITE);
D3D12_RECT rect = {config.drawarea.left, config.drawarea.top, config.drawarea.left + config.drawarea.width(), config.drawarea.top + config.drawarea.height()};
GetCommandList()->ClearDepthStencilView(draw_ds->GetWriteDescriptor(), D3D12_CLEAR_FLAG_STENCIL, 0.0f, 1, 1, &rect);
}
// Begin render pass if new target or out of the area.
if (!m_in_render_pass)
{
@@ -4042,14 +4057,18 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
// Denormalize clear color for hw colclip.
clear_color *= GSVector4::cxpr(255.0f / 65535.0f, 255.0f / 65535.0f, 255.0f / 65535.0f, 1.0f);
}
const bool stencil_DATE = config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::Stencil ||
config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne;
BeginRenderPass(GetLoadOpForTexture(draw_rt),
draw_rt ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
GetLoadOpForTexture(draw_ds),
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
stencil_DATE ? D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE :
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
stencil_DATE ? (feedback ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE :
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD) :
stencil_DATE ? (need_barrier ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE :
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD) :
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
clear_color, draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1);
}

View File

@@ -407,7 +407,7 @@ public:
void Destroy() override;
bool UpdateWindow() override;
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
void ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale) override;
bool SupportsExclusiveFullscreen() const override;
void DestroySurface() override;
std::string GetDriverInfo() const override;

View File

@@ -5138,6 +5138,7 @@ void GSRendererHW::EmulateZbuffer(const GSTextureCache::Target* ds)
m_conf.cb_vs.max_depth = GSVector2i(0xFFFFFFFF);
//ps_cb.MaxDepth = GSVector4(0.0f, 0.0f, 0.0f, 1.0f);
m_conf.ps.zclamp = 0;
m_conf.ps.zfloor = !m_cached_ctx.ZBUF.ZMSK;
if (clamp_z)
{

View File

@@ -385,7 +385,7 @@ public:
bool SupportsExclusiveFullscreen() const override;
std::string GetDriverInfo() const override;
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
void ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale) override;
void UpdateTexture(id<MTLTexture> texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride);

View File

@@ -1267,11 +1267,11 @@ std::string GSDeviceMTL::GetDriverInfo() const
return desc;
}}
void GSDeviceMTL::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
void GSDeviceMTL::ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale)
{
m_window_info.surface_scale = new_window_scale;
if (!m_layer ||
(m_window_info.surface_width == static_cast<u32>(new_window_width) && m_window_info.surface_height == static_cast<u32>(new_window_height)))
(m_window_info.surface_width == new_window_width && m_window_info.surface_height == new_window_height))
{
return;
}
@@ -1878,6 +1878,7 @@ void GSDeviceMTL::MRESetHWPipelineState(GSHWDrawConfig::VSSelector vssel, GSHWDr
setFnConstantI(m_fn_constants, pssel.dither, GSMTLConstantIndex_PS_DITHER);
setFnConstantI(m_fn_constants, pssel.dither_adjust, GSMTLConstantIndex_PS_DITHER_ADJUST);
setFnConstantB(m_fn_constants, pssel.zclamp, GSMTLConstantIndex_PS_ZCLAMP);
setFnConstantB(m_fn_constants, pssel.zfloor, GSMTLConstantIndex_PS_ZFLOOR);
setFnConstantB(m_fn_constants, pssel.tcoffsethack, GSMTLConstantIndex_PS_TCOFFSETHACK);
setFnConstantB(m_fn_constants, pssel.urban_chaos_hle, GSMTLConstantIndex_PS_URBAN_CHAOS_HLE);
setFnConstantB(m_fn_constants, pssel.tales_of_abyss_hle, GSMTLConstantIndex_PS_TALES_OF_ABYSS_HLE);

View File

@@ -208,6 +208,7 @@ enum GSMTLFnConstants
GSMTLConstantIndex_PS_DITHER,
GSMTLConstantIndex_PS_DITHER_ADJUST,
GSMTLConstantIndex_PS_ZCLAMP,
GSMTLConstantIndex_PS_ZFLOOR,
GSMTLConstantIndex_PS_TCOFFSETHACK,
GSMTLConstantIndex_PS_URBAN_CHAOS_HLE,
GSMTLConstantIndex_PS_TALES_OF_ABYSS_HLE,

View File

@@ -61,6 +61,7 @@ constant uint PS_CHANNEL [[function_constant(GSMTLConstantIndex_PS_CH
constant uint PS_DITHER [[function_constant(GSMTLConstantIndex_PS_DITHER)]];
constant uint PS_DITHER_ADJUST [[function_constant(GSMTLConstantIndex_PS_DITHER_ADJUST)]];
constant bool PS_ZCLAMP [[function_constant(GSMTLConstantIndex_PS_ZCLAMP)]];
constant bool PS_ZFLOOR [[function_constant(GSMTLConstantIndex_PS_ZFLOOR)]];
constant bool PS_TCOFFSETHACK [[function_constant(GSMTLConstantIndex_PS_TCOFFSETHACK)]];
constant bool PS_URBAN_CHAOS_HLE [[function_constant(GSMTLConstantIndex_PS_URBAN_CHAOS_HLE)]];
constant bool PS_TALES_OF_ABYSS_HLE [[function_constant(GSMTLConstantIndex_PS_TALES_OF_ABYSS_HLE)]];
@@ -102,6 +103,7 @@ constant bool NEEDS_RT = NEEDS_RT_FOR_AFAIL || NEEDS_RT_EARLY || (!PS_PRIM_CHECK
constant bool PS_COLOR0 = !PS_NO_COLOR;
constant bool PS_COLOR1 = !PS_NO_COLOR1;
constant bool PS_ZOUTPUT = PS_ZCLAMP || PS_ZFLOOR;
struct MainVSIn
{
@@ -137,7 +139,7 @@ struct MainPSOut
{
float4 c0 [[color(0), index(0), function_constant(PS_COLOR0)]];
float4 c1 [[color(0), index(1), function_constant(PS_COLOR1)]];
float depth [[depth(less), function_constant(PS_ZCLAMP)]];
float depth [[depth(less), function_constant(PS_ZOUTPUT)]];
};
// MARK: - Vertex functions
@@ -1209,8 +1211,13 @@ struct PSMain
}
if (PS_COLOR1)
out.c1 = alpha_blend;
float depth_value = PS_ZFLOOR ? (floor(in.p.z * exp2(32.0f)) * exp2(-32.0f)) : in.p.z;
if (PS_ZCLAMP)
out.depth = min(in.p.z, cb.max_depth);
out.depth = min(depth_value, cb.max_depth);
else if (PS_ZFLOOR)
out.depth = depth_value;
return out;
}

View File

@@ -888,17 +888,17 @@ bool GSDeviceOGL::UpdateWindow()
return true;
}
void GSDeviceOGL::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
void GSDeviceOGL::ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale)
{
m_window_info.surface_scale = new_window_scale;
if (m_window_info.type == WindowInfo::Type::Surfaceless ||
(m_window_info.surface_width == static_cast<u32>(new_window_width) &&
m_window_info.surface_height == static_cast<u32>(new_window_height)))
(m_window_info.surface_width == new_window_width &&
m_window_info.surface_height == new_window_height))
{
return;
}
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
m_gl_context->ResizeSurface(new_window_width, new_window_height);
m_window_info = m_gl_context->GetWindowInfo();
}
@@ -1389,7 +1389,9 @@ std::string GSDeviceOGL::GetPSSource(const PSSelector& sel)
+ fmt::format("#define PS_DITHER {}\n", sel.dither)
+ fmt::format("#define PS_DITHER_ADJUST {}\n", sel.dither_adjust)
+ fmt::format("#define PS_ZCLAMP {}\n", sel.zclamp)
+ fmt::format("#define PS_ZFLOOR {}\n", sel.zfloor)
+ fmt::format("#define PS_BLEND_MIX {}\n", sel.blend_mix)
+ fmt::format("#define PS_ZCLAMP {}\n", sel.zclamp)
+ fmt::format("#define PS_ROUND_INV {}\n", sel.round_inv)
+ fmt::format("#define PS_FIXED_ONE_A {}\n", sel.fixed_one_a)
+ fmt::format("#define PS_PABE {}\n", sel.pabe)

View File

@@ -297,7 +297,7 @@ public:
void Destroy() override;
bool UpdateWindow() override;
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
void ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale) override;
bool SupportsExclusiveFullscreen() const override;
void DestroySurface() override;
std::string GetDriverInfo() const override;

View File

@@ -2216,12 +2216,12 @@ bool GSDeviceVK::UpdateWindow()
return true;
}
void GSDeviceVK::ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale)
void GSDeviceVK::ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale)
{
m_resize_requested = false;
if (!m_swap_chain || (m_swap_chain->GetWidth() == static_cast<u32>(new_window_width) &&
m_swap_chain->GetHeight() == static_cast<u32>(new_window_height)))
if (!m_swap_chain || (m_swap_chain->GetWidth() == new_window_width &&
m_swap_chain->GetHeight() == new_window_height))
{
// skip unnecessary resizes
m_window_info.surface_scale = new_window_scale;
@@ -4777,6 +4777,7 @@ VkShaderModule GSDeviceVK::GetTFXFragmentShader(const GSHWDrawConfig::PSSelector
AddMacro(ss, "PS_DITHER", sel.dither);
AddMacro(ss, "PS_DITHER_ADJUST", sel.dither_adjust);
AddMacro(ss, "PS_ZCLAMP", sel.zclamp);
AddMacro(ss, "PS_ZFLOOR", sel.zfloor);
AddMacro(ss, "PS_PABE", sel.pabe);
AddMacro(ss, "PS_SCANMSK", sel.scanmsk);
AddMacro(ss, "PS_TEX_IS_FB", sel.tex_is_fb);

View File

@@ -506,7 +506,7 @@ public:
void Destroy() override;
bool UpdateWindow() override;
void ResizeWindow(s32 new_window_width, s32 new_window_height, float new_window_scale) override;
void ResizeWindow(u32 new_window_width, u32 new_window_height, float new_window_scale) override;
bool SupportsExclusiveFullscreen() const override;
void DestroySurface() override;
std::string GetDriverInfo() const override;

View File

@@ -11,15 +11,27 @@
#include "fmt/format.h"
#include <deque>
using namespace R5900;
const int rdram_devices = 2; // put 8 for TOOL and 2 for PS2 and PSX
int rdram_sdevid = 0;
std::deque<u8> ee_sio_rx_fifo;
std::deque<u8> ee_sio_tx_fifo;
void hwReset()
{
std::memset(eeHw, 0, sizeof(eeHw));
{
std::deque<u8> empty_rx;
std::swap(ee_sio_rx_fifo, empty_rx);
std::deque<u8> empty_tx;
std::swap(ee_sio_tx_fifo, empty_tx);
}
psHu32(SBUS_F260) = 0x1D000060;
// i guess this is kinda a version, it's used by some bioses

View File

@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#include <deque>
#pragma once
namespace EEMemoryMap
@@ -355,3 +357,6 @@ extern void hwReset();
extern const int rdram_devices;
extern int rdram_sdevid;
extern std::deque<u8> ee_sio_rx_fifo;
extern std::deque<u8> ee_sio_tx_fifo;

View File

@@ -125,7 +125,23 @@ mem32_t _hwRead32(u32 mem)
switch( mem )
{
case SIO_ISR:
// Not (yet) hardware tested
// The PS2SDK behaviour is as follows:
// TX: Don't write to TX FIFO until until bit 15 is 0
// RX: RX FIFO has data when bits 8-11 are not 0 (maybe a byte count?)
// RX: When reading from the RX FIFO, set bits 0-2 to 1 (why??)
// For TX, we don't do any LLE buffering, so we can keep bit 15 to 0
// For RX, just hack it so when the ee_rx_fifo.size() != 0, ISR = 0xf00
if(!ee_sio_rx_fifo.empty())
return 0xf00;
return 0x0;
break;
case 0x1000f410:
case MCH_RICM:
return 0;
@@ -211,6 +227,16 @@ mem32_t hwRead32_page_0F_INTC_HACK(u32 mem)
template< uint page >
mem8_t _hwRead8(u32 mem)
{
if(mem == SIO_RXFIFO)
{
if(ee_sio_rx_fifo.empty())
return 0; // needs hardware test, what does it return with the FIFO is empty
const char c = ee_sio_rx_fifo.front();
ee_sio_rx_fifo.pop_front();
return c;
}
u32 ret32 = _hwRead32<page, false>(mem & ~0x03);
return ((u8*)&ret32)[mem & 0x03];
}

View File

@@ -285,26 +285,35 @@ void _hwWrite8(u32 mem, u8 value)
#endif
if (mem == SIO_TXFIFO)
{
static bool included_newline = false;
static char sio_buffer[1024];
static int sio_count;
if (value == '\r')
static bool last_char_was_cr = false;
// skip the \n in \r\n
if(last_char_was_cr && (value == '\n'))
{
included_newline = true;
sio_buffer[sio_count++] = '\n';
last_char_was_cr = false;
return;
}
else if (!included_newline || (value != '\n'))
last_char_was_cr = value == '\r';
bool should_flush_cause_newline = false;
if (last_char_was_cr)
{
included_newline = false;
sio_buffer[sio_count++] = value;
should_flush_cause_newline = true;
ee_sio_tx_fifo.push_back('\n');
}
else
{
should_flush_cause_newline = value == '\n';
ee_sio_tx_fifo.push_back(value);
}
if ((sio_count == std::size(sio_buffer)-1) || (sio_count != 0 && sio_buffer[sio_count-1] == '\n'))
// Check if the only thing in the buffer
if (ee_sio_tx_fifo.size() == 1024 || should_flush_cause_newline)
{
sio_buffer[sio_count] = 0;
eeConLog( ShiftJIS_ConvertString(sio_buffer) );
sio_count = 0;
std::string output_string(ee_sio_tx_fifo.begin(), ee_sio_tx_fifo.end());
eeConLog(ShiftJIS_ConvertString(output_string.c_str()));
ee_sio_tx_fifo.clear();
}
return;
}

View File

@@ -708,16 +708,16 @@ void ImGuiFullscreen::EndLayout()
const float notification_margin = LayoutScale(10.0f);
const float spacing = LayoutScale(10.0f);
const float notification_vertical_pos = GetNotificationVerticalPosition();
// Get the horizonal position based on alignment
float horizontal_pos;
if (s_notification_horizontal_position <= 0.0f)
horizontal_pos = notification_margin; // Left
else if (s_notification_horizontal_position >= 1.0f)
else if (s_notification_horizontal_position >= 1.0f)
horizontal_pos = ImGui::GetIO().DisplaySize.x - notification_margin; // Right
else
horizontal_pos = ImGui::GetIO().DisplaySize.x * s_notification_horizontal_position; // Center
ImVec2 position(horizontal_pos, notification_vertical_pos * ImGui::GetIO().DisplaySize.y +
((notification_vertical_pos >= 0.5f) ? -notification_margin : notification_margin));
DrawProgressDialogs(position, spacing);
@@ -2574,11 +2574,11 @@ void ImGuiFullscreen::DrawInputDialog()
ImGuiInputTextFlags flags = ImGuiInputTextFlags_None;
if (s_input_dialog_filter_type != InputFilterType::None)
flags |= ImGuiInputTextFlags_CallbackCharFilter;
if (s_focus_reset_queued != FocusResetType::None)
ImGui::SetKeyboardFocusHere();
ImGui::InputText("##input", &s_input_dialog_text, flags,
ImGui::InputText("##input", &s_input_dialog_text, flags,
(s_input_dialog_filter_type != InputFilterType::None) ? input_callback : nullptr,
(s_input_dialog_filter_type != InputFilterType::None) ? static_cast<void*>(&s_input_dialog_filter_type) : nullptr);
@@ -3056,7 +3056,7 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
final_x = position.x - box_width;
else if (s_notification_horizontal_position > 0.0f && s_notification_horizontal_position < 1.0f)
final_x = position.x - (box_width * 0.5f);
const ImVec2 box_min(final_x, actual_y);
const ImVec2 box_max(box_min.x + box_width, box_min.y + box_height);
const u32 background_color = (toast_background_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
@@ -3209,14 +3209,14 @@ void ImGuiFullscreen::SetTheme(std::string_view theme)
}
else if (theme == "AMOLED")
{
UIBackgroundColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIBackgroundColor = HEX_TO_IMVEC4(0x0A0A0A, 0xff);
UIBackgroundTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIBackgroundLineColor = HEX_TO_IMVEC4(0xf0f0f0, 0xff);
UIBackgroundHighlightColor = HEX_TO_IMVEC4(0x0c0c0c, 0xff);
UIPopupBackgroundColor = HEX_TO_IMVEC4(0x212121, 0xf2);
UIPrimaryColor = HEX_TO_IMVEC4(0x0a0a0a, 0xff);
UIPrimaryLightColor = HEX_TO_IMVEC4(0xb5b5b5, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0x000000, 0xff);
UIPrimaryDarkColor = HEX_TO_IMVEC4(0x0A0A0A, 0xff);
UIPrimaryTextColor = HEX_TO_IMVEC4(0xffffff, 0xff);
UIDisabledColor = HEX_TO_IMVEC4(0x8d8d8d, 0xff);
UITextHighlightColor = HEX_TO_IMVEC4(0x676767, 0xff);

View File

@@ -619,6 +619,8 @@ __ri void ImGuiManager::DrawSettingsOverlay(float scale, float margin, float spa
APPEND("SD={}/{} ", GSConfig.SkipDrawStart, GSConfig.SkipDrawEnd);
if (GSConfig.UserHacks_TextureInsideRt != GSTextureInRtMode::Disabled)
APPEND("TexRT={} ", static_cast<unsigned>(GSConfig.UserHacks_TextureInsideRt));
if (GSConfig.UserHacks_Limit24BitDepth != GSLimit24BitDepth::Disabled)
APPEND("TDR={} ", static_cast<unsigned>(GSConfig.UserHacks_Limit24BitDepth));
if (GSConfig.UserHacks_BilinearHack != GSBilinearDirtyMode::Automatic)
APPEND("BLU={} ", static_cast<unsigned>(GSConfig.UserHacks_BilinearHack));
if (GSConfig.UserHacks_ForceEvenSpritePosition)

View File

@@ -946,7 +946,7 @@ void MTGS::ApplySettings()
WaitGS(false, false, false);
}
void MTGS::ResizeDisplayWindow(int width, int height, float scale)
void MTGS::ResizeDisplayWindow(u32 width, u32 height, float scale)
{
pxAssertRel(IsOpen(), "MTGS is running");
RunOnGSThread([width, height, scale]() {

View File

@@ -69,7 +69,7 @@ namespace MTGS
void RunOnGSThread(AsyncCallType func);
void GameChanged();
void ApplySettings();
void ResizeDisplayWindow(int width, int height, float scale);
void ResizeDisplayWindow(u32 width, u32 height, float scale);
void UpdateDisplayWindow();
void SetVSyncMode(GSVSyncMode mode, bool allow_present_throttle);
void UpdateVSyncMode();

View File

@@ -755,6 +755,7 @@ Pcsx2Config::GSOptions::GSOptions()
ManualUserHacks = false;
UserHacks_AlignSpriteX = false;
UserHacks_AutoFlush = GSHWAutoFlushLevel::Disabled;
UserHacks_Limit24BitDepth = GSLimit24BitDepth::Disabled;
UserHacks_CPUFBConversion = false;
UserHacks_ReadTCOnClose = false;
UserHacks_DisableDepthSupport = false;
@@ -847,6 +848,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
OpEqu(UserHacks_CPUCLUTRender) &&
OpEqu(UserHacks_GPUTargetCLUTMode) &&
OpEqu(UserHacks_TextureInsideRt) &&
OpEqu(UserHacks_Limit24BitDepth) &&
OpEqu(UserHacks_BilinearHack) &&
OpEqu(OverrideTextureBarriers) &&
@@ -983,6 +985,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapIntEnumEx(UserHacks_BilinearHack, "UserHacks_BilinearHack");
SettingsWrapBitBoolEx(UserHacks_NativePaletteDraw, "UserHacks_NativePaletteDraw");
SettingsWrapIntEnumEx(UserHacks_TextureInsideRt, "UserHacks_TextureInsideRt");
SettingsWrapIntEnumEx(UserHacks_Limit24BitDepth, "UserHacks_Limit24BitDepth");
SettingsWrapBitBoolEx(UserHacks_EstimateTextureRegion, "UserHacks_EstimateTextureRegion");
SettingsWrapBitBoolEx(FXAA, "fxaa");
SettingsWrapBitBool(ShadeBoost);
@@ -1111,6 +1114,7 @@ void Pcsx2Config::GSOptions::MaskUserHacks()
UserHacks_CPUFBConversion = false;
UserHacks_ReadTCOnClose = false;
UserHacks_TextureInsideRt = GSTextureInRtMode::Disabled;
UserHacks_Limit24BitDepth = GSLimit24BitDepth::Disabled;
UserHacks_EstimateTextureRegion = false;
UserHacks_TCOffsetX = 0;
UserHacks_TCOffsetY = 0;

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 = 77;
static constexpr u32 SHADER_CACHE_VERSION = 78;

View File

@@ -37,6 +37,8 @@ namespace usb_pad
TRANSLATE_NOOP("USB", "Type 2"),
TRANSLATE_NOOP("USB", "Shinkansen"),
TRANSLATE_NOOP("USB", "Ryojōhen"),
TRANSLATE_NOOP("USB", "Train Mascon"),
TRANSLATE_NOOP("USB", "Master Controller"),
};
return subtypes;
}
@@ -63,6 +65,14 @@ namespace usb_pad
CID_TC_L = CID_TC_C,
CID_TC_R = CID_TC_D,
// Train Mascon
CID_TC_ATS = CID_TC_D,
CID_TC_CLOSE = CID_TC_CAMERA,
CID_TC_POWER_UP,
CID_TC_POWER_DOWN,
CID_TC_REVERSER_UP,
CID_TC_REVERSER_DOWN,
BUTTONS_OFFSET = CID_TC_B,
};
@@ -110,6 +120,43 @@ namespace usb_pad
return bindings;
}
case TRAIN_MASCON:
{
static constexpr const InputBindingInfo bindings[] = {
{"PowerUp", TRANSLATE_NOOP("USB", "Power Up"), nullptr, InputBindingInfo::Type::Button, CID_TC_POWER_UP, GenericInputBinding::R1},
{"PowerDown", TRANSLATE_NOOP("USB", "Power Down"), nullptr, InputBindingInfo::Type::Button, CID_TC_POWER_DOWN, GenericInputBinding::L1},
{"ReverserUp", TRANSLATE_NOOP("USB", "Reverser Up"), nullptr, InputBindingInfo::Type::Button, CID_TC_REVERSER_UP, GenericInputBinding::R2},
{"ReverserDown", TRANSLATE_NOOP("USB", "Reverser Down"), nullptr, InputBindingInfo::Type::Button, CID_TC_REVERSER_DOWN, GenericInputBinding::L2},
{"Up", TRANSLATE_NOOP("USB", "D-Pad Up"), ICON_PF_DPAD_UP, InputBindingInfo::Type::Button, CID_TC_UP, GenericInputBinding::DPadUp},
{"Down", TRANSLATE_NOOP("USB", "D-Pad Down"), ICON_PF_DPAD_DOWN, InputBindingInfo::Type::Button, CID_TC_DOWN, GenericInputBinding::DPadDown},
{"Left", TRANSLATE_NOOP("USB", "D-Pad Left"), ICON_PF_DPAD_LEFT, InputBindingInfo::Type::Button, CID_TC_LEFT, GenericInputBinding::DPadLeft},
{"Right", TRANSLATE_NOOP("USB", "D-Pad Right"), ICON_PF_DPAD_RIGHT, InputBindingInfo::Type::Button, CID_TC_RIGHT, GenericInputBinding::DPadRight},
{"ATS", TRANSLATE_NOOP("USB", "ATS"), nullptr, InputBindingInfo::Type::Button, CID_TC_ATS, GenericInputBinding::Triangle},
{"Close", TRANSLATE_NOOP("USB", "Close"), nullptr, InputBindingInfo::Type::Button, CID_TC_CLOSE, GenericInputBinding::R3},
{"A", TRANSLATE_NOOP("USB", "A Button"), ICON_PF_KEY_A, InputBindingInfo::Type::Button, CID_TC_A, GenericInputBinding::Square},
{"B", TRANSLATE_NOOP("USB", "B Button"), ICON_PF_KEY_B, InputBindingInfo::Type::Button, CID_TC_B, GenericInputBinding::Cross},
{"C", TRANSLATE_NOOP("USB", "C Button"), ICON_PF_KEY_C, InputBindingInfo::Type::Button, CID_TC_C, GenericInputBinding::Circle},
{"Select", TRANSLATE_NOOP("USB", "Select"), ICON_PF_SELECT_SHARE, InputBindingInfo::Type::Button, CID_TC_SELECT, GenericInputBinding::Select},
{"Start", TRANSLATE_NOOP("USB", "Start"), ICON_PF_START, InputBindingInfo::Type::Button, CID_TC_START, GenericInputBinding::Start},
};
return bindings;
}
case MASTER_CONTROLLER:
{
static constexpr const InputBindingInfo bindings[] = {
{"PowerUp", TRANSLATE_NOOP("USB", "Power Up"), nullptr, InputBindingInfo::Type::Button, CID_TC_POWER_UP, GenericInputBinding::R1},
{"PowerDown", TRANSLATE_NOOP("USB", "Power Down"), nullptr, InputBindingInfo::Type::Button, CID_TC_POWER_DOWN, GenericInputBinding::L1},
{"ReverserUp", TRANSLATE_NOOP("USB", "Reverser Up"), nullptr, InputBindingInfo::Type::Button, CID_TC_REVERSER_UP, GenericInputBinding::R2},
{"ReverserDown", TRANSLATE_NOOP("USB", "Reverser Down"), nullptr, InputBindingInfo::Type::Button, CID_TC_REVERSER_DOWN, GenericInputBinding::L2},
{"S", TRANSLATE_NOOP("USB", "S"), ICON_PF_KEY_S, InputBindingInfo::Type::Button, CID_TC_D, GenericInputBinding::Cross},
{"A", TRANSLATE_NOOP("USB", "A"), ICON_PF_KEY_A, InputBindingInfo::Type::Button, CID_TC_A, GenericInputBinding::Square},
{"B", TRANSLATE_NOOP("USB", "B"), ICON_PF_KEY_B, InputBindingInfo::Type::Button, CID_TC_B, GenericInputBinding::Triangle},
{"C", TRANSLATE_NOOP("USB", "C"), ICON_PF_KEY_C, InputBindingInfo::Type::Button, CID_TC_C, GenericInputBinding::Circle},
};
return bindings;
}
default:
break;
}
@@ -151,21 +198,66 @@ namespace usb_pad
{
TrainDeviceState* s = USB_CONTAINER_OF(dev, TrainDeviceState, dev);
s->passthrough = USB::GetConfigBool(si, s->port, TypeName(), "Passthrough", false);
switch (s->type)
{
case TRAIN_TYPE2:
case TRAIN_SHINKANSEN:
case TRAIN_RYOJOUHEN:
s->passthrough = USB::GetConfigBool(si, s->port, TypeName(), "Passthrough", false);
break;
case MASTER_CONTROLLER:
s->power_notches = USB::GetConfigInt(si, s->port, TypeName(), "power_notches", 5);
s->brake_notches = USB::GetConfigInt(si, s->port, TypeName(), "brake_notches", 8);
break;
}
}
std::span<const SettingInfo> TrainDevice::Settings(u32 subtype) const
{
static constexpr const SettingInfo passthrough = {
SettingInfo::Type::Boolean,
"Passthrough",
TRANSLATE_NOOP("USB", "Axes Passthrough"),
TRANSLATE_NOOP("USB", "Passes through the unprocessed input axis to the game. Enable if you are using a compatible Densha De Go! controller. Disable if you are using any other joystick."),
"false",
};
static constexpr const SettingInfo info[] = {passthrough};
return info;
switch (subtype)
{
case TRAIN_TYPE2:
case TRAIN_SHINKANSEN:
case TRAIN_RYOJOUHEN:
{
static constexpr const SettingInfo info[] = {
{
.type = SettingInfo::Type::Boolean,
.name = "Passthrough",
.display_name = TRANSLATE_NOOP("USB", "Axes Passthrough"),
.description = TRANSLATE_NOOP("USB", "Passes through the unprocessed input axis to the game. Enable if you are using a compatible Densha De Go! controller. Disable if you are using any other joystick."),
.default_value = "false",
}
};
return info;
}
case MASTER_CONTROLLER:
{
static constexpr const SettingInfo info[] = {
{
.type = SettingInfo::Type::Integer,
.name = "power_notches",
.display_name = TRANSLATE_NOOP("USB", "Power notches"),
.description = TRANSLATE_NOOP("USB", "Selects the number of power notches (3-6)"),
.default_value = "5",
.min_value = "3",
.max_value = "6",
},
{
.type = SettingInfo::Type::Integer,
.name = "brake_notches",
.display_name = TRANSLATE_NOOP("USB", "Brake notches"),
.description = TRANSLATE_NOOP("USB", "Selects the number of brake notches (5-8)"),
.default_value = "8",
.min_value = "5",
.max_value = "8",
}
};
return info;
}
default:
return {};
}
}
static constexpr u32 button_mask(u32 bind_index)
@@ -173,7 +265,7 @@ namespace usb_pad
return (1u << (bind_index - TrainControlID::BUTTONS_OFFSET));
}
static constexpr u8 button_at(u8 value, u32 index)
static constexpr u16 button_at(u16 value, u32 index)
{
return value & button_mask(index);
}
@@ -205,6 +297,10 @@ namespace usb_pad
case CID_TC_SELECT:
case CID_TC_START:
case CID_TC_CAMERA:
case CID_TC_POWER_UP:
case CID_TC_POWER_DOWN:
case CID_TC_REVERSER_UP:
case CID_TC_REVERSER_DOWN:
{
return (button_at(s->data.buttons, bind_index) != 0u) ? 1.0f : 0.0f;
}
@@ -251,14 +347,18 @@ namespace usb_pad
case CID_TC_SELECT:
case CID_TC_START:
case CID_TC_CAMERA:
case CID_TC_POWER_UP:
case CID_TC_POWER_DOWN:
case CID_TC_REVERSER_UP:
case CID_TC_REVERSER_DOWN:
{
const u32 mask = button_mask(bind_index);
if (value >= 0.5f)
s->data.buttons |= mask;
else
s->data.buttons &= ~mask;
break;
}
break;
default:
break;
@@ -452,11 +552,23 @@ namespace usb_pad
return (get_ab(buttons) | (button_at(buttons, CID_TC_CAMERA) >> 4) | ((get_cd(buttons) | get_ss(buttons)) << 1));
}
void TrainDeviceState::UpdateHandles(u8 max_power, u8 max_brake)
{
if (!button_at(prev_buttons, CID_TC_POWER_UP) && button_at(data.buttons, CID_TC_POWER_UP) && handle < max_brake + 1 + max_power)
handle++;
if (!button_at(prev_buttons, CID_TC_POWER_DOWN) && button_at(data.buttons, CID_TC_POWER_DOWN) && handle > 0)
handle--;
if (!button_at(prev_buttons, CID_TC_REVERSER_UP) && button_at(data.buttons, CID_TC_REVERSER_UP) && reverser < 2)
reverser++;
if (!button_at(prev_buttons, CID_TC_REVERSER_DOWN) && button_at(data.buttons, CID_TC_REVERSER_DOWN) && reverser > 0)
reverser--;
}
static void train_handle_data(USBDevice* dev, USBPacket* p)
{
TrainDeviceState* s = USB_CONTAINER_OF(dev, TrainDeviceState, dev);
if (p->pid != USB_TOKEN_IN || p->ep->nr != 1)
if (s->type < MASTER_CONTROLLER && (p->pid != USB_TOKEN_IN || p->ep->nr != 1))
{
Console.Error("Unhandled TrainController request pid=%d ep=%u", p->pid, p->ep->nr);
p->status = USB_RET_STALL;
@@ -501,6 +613,77 @@ namespace usb_pad
usb_packet_copy(p, &out, sizeof(out));
break;
}
case TRAIN_MASCON:
{
s->UpdateHandles(5, 6);
s->prev_buttons = s->data.buttons;
TrainConData_TrainMascon out = {};
out.one = 0x01;
out.handle = 1 + s->handle;
out.reverser = s->reverser < 2 ? !s->reverser : s->reverser;
out.ats = !!button_at(s->data.buttons, CID_TC_ATS);
out.close = !!button_at(s->data.buttons, CID_TC_CLOSE);
out.button_a_soft = !!button_at(s->data.buttons, CID_TC_A);
out.button_a_hard = !!button_at(s->data.buttons, CID_TC_A);
out.button_b = !!button_at(s->data.buttons, CID_TC_B);
out.button_c = !!button_at(s->data.buttons, CID_TC_C);
out.start = !!button_at(s->data.buttons, CID_TC_START);
out.select = !!button_at(s->data.buttons, CID_TC_SELECT);
out.dpad_up = s->data.hat_up;
out.dpad_down = s->data.hat_down;
out.dpad_left = s->data.hat_left;
out.dpad_right = s->data.hat_right;
usb_packet_copy(p, &out, sizeof(out));
break;
}
case MASTER_CONTROLLER:
{
if (p->ep->nr == 1) // interrupt in
{
p->status = USB_RET_STALL;
break;
}
else if (p->ep->nr == 2) // bulk out
{
// The game sends a reset command after ~1500ms without updates. Resend the status during the next transfer
s->last_handle = -1;
s->last_reverser = -1;
break;
} // else bulk in
s->UpdateHandles(s->power_notches, s->brake_notches);
char data[100];
std::memset(data, 0, sizeof(data));
u8 pos = 0;
if (s->last_handle != s->handle)
{
pos += snprintf(data + pos, sizeof(data) - pos, "%s\x0d", s->mc_handle[s->handle + 8 - s->brake_notches]);
s->last_handle = s->handle;
}
if (s->last_reverser != s->reverser)
{
pos += snprintf(data + pos, sizeof(data) - pos, "%s\x0d", s->mc_reverser[s->reverser]);
s->last_reverser = s->reverser;
}
for (int i = 0; i < 4; i++)
{
if (!button_at(s->prev_buttons, BUTTONS_OFFSET + i) && button_at(s->data.buttons, BUTTONS_OFFSET + i))
{
pos += snprintf(data + pos, sizeof(data) - pos, "%s\x0d", s->mc_button_pressed[i]);
}
if (button_at(s->prev_buttons, BUTTONS_OFFSET + i) && !button_at(s->data.buttons, BUTTONS_OFFSET + i))
{
pos += snprintf(data + pos, sizeof(data) - pos, "%s\x0d", s->mc_button_released[i]);
}
}
s->prev_buttons = s->data.buttons;
usb_packet_copy(p, data, std::min<u16>(p->buffer_size, pos));
break;
}
default:
Console.Error("Unhandled TrainController USB_TOKEN_IN pid=%d ep=%u type=%u", p->pid, p->ep->nr, s->type);
p->status = USB_RET_IOERROR;
@@ -520,25 +703,42 @@ namespace usb_pad
s->desc.str = dct01_desc_strings;
if (usb_desc_parse_dev(dct01_dev_descriptor, sizeof(dct01_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(taito_denshacon_config_descriptor, sizeof(taito_denshacon_config_descriptor), s->desc_dev) < 0)
goto fail;
break;
case TRAIN_SHINKANSEN:
s->desc.str = dct02_desc_strings;
if (usb_desc_parse_dev(dct02_dev_descriptor, sizeof(dct02_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(taito_denshacon_config_descriptor, sizeof(taito_denshacon_config_descriptor), s->desc_dev) < 0)
goto fail;
break;
case TRAIN_RYOJOUHEN:
s->desc.str = dct03_desc_strings;
if (usb_desc_parse_dev(dct03_dev_descriptor, sizeof(dct03_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(taito_denshacon_config_descriptor, sizeof(taito_denshacon_config_descriptor), s->desc_dev) < 0)
goto fail;
break;
case TRAIN_MASCON:
s->desc.str = dct03_desc_strings;
if (usb_desc_parse_dev(train_mascon_dev_descriptor, sizeof(train_mascon_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(train_mascon_config_descriptor, sizeof(train_mascon_config_descriptor), s->desc_dev) < 0)
goto fail;
break;
case MASTER_CONTROLLER:
s->desc.str = dct03_desc_strings;
if (usb_desc_parse_dev(master_controller_dev_descriptor, sizeof(master_controller_dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(master_controller_config_descriptor, sizeof(master_controller_config_descriptor), s->desc_dev) < 0)
goto fail;
break;
default:
goto fail;
}
if (usb_desc_parse_config(taito_denshacon_config_descriptor, sizeof(taito_denshacon_config_descriptor), s->desc_dev) < 0)
goto fail;
s->dev.speed = USB_SPEED_FULL;
s->dev.klass.handle_attach = usb_desc_attach;
s->dev.klass.handle_reset = train_handle_reset;

View File

@@ -11,10 +11,11 @@ namespace usb_pad
{
enum TrainDeviceTypes
{
TRAIN_TYPE2, // TCPP20009 or similar
TRAIN_SHINKANSEN, // TCPP20011
TRAIN_RYOJOUHEN, // TCPP20014
TRAIN_COUNT,
TRAIN_TYPE2, // TCPP-20009 or similar
TRAIN_SHINKANSEN, // TCPP-20011
TRAIN_RYOJOUHEN, // TCPP-20014
TRAIN_MASCON, // COTM-02001
MASTER_CONTROLLER, // VOK-00105 or VOK-00106 with OGCW-10001 adapter
};
class TrainDevice final : public DeviceProxy
@@ -39,7 +40,7 @@ namespace usb_pad
u8 control;
u8 brake;
u8 power;
u8 horn;
u8 horn; // pedal
u8 hat;
u8 buttons;
};
@@ -49,7 +50,7 @@ namespace usb_pad
{
u8 brake;
u8 power;
u8 horn;
u8 horn; // pedal
u8 hat;
u8 buttons;
u8 pad;
@@ -60,12 +61,37 @@ namespace usb_pad
{
u8 brake;
u8 power;
u8 horn;
u8 horn; // pedal
u8 hat;
u8 buttons;
u8 pad[3];
};
static_assert(sizeof(TrainConData_Ryojouhen) == 8);
struct TrainConData_TrainMascon
{
u8 one;
u8 handle : 4;
u8 reverser : 4;
u8 ats : 1;
u8 close : 1;
u8 button_a_soft : 1;
u8 button_a_hard : 1;
u8 button_b : 1;
u8 button_c : 1;
u8 : 2;
u8 start : 1;
u8 select : 1;
u8 dpad_up : 1;
u8 dpad_down : 1;
u8 dpad_left : 1;
u8 dpad_right : 1;
u8 : 2;
};
static_assert(sizeof(TrainConData_TrainMascon) == 4);
#pragma pack(pop)
struct TrainDeviceState
@@ -75,6 +101,7 @@ namespace usb_pad
void Reset();
void UpdateHatSwitch() noexcept;
void UpdateHandles(u8 max_power, u8 max_brake);
USBDevice dev{};
USBDesc desc{};
@@ -95,12 +122,24 @@ namespace usb_pad
u8 power; // 255 is fully applied
u8 brake; // 255 is fully applied
u8 hatswitch; // direction
u8 buttons; // active high
u16 buttons; // active high
} data = {};
// Master Controller
const char* mc_handle[16] = {"TSB20", "TSB30", "TSB40", "TSE99", "TSA05", "TSA15", "TSA25", "TSA35", "TSA45", "TSA50", "TSA55", "TSA65", "TSA75", "TSA85", "TSA95", "TSB60"};
const char* mc_reverser[3] = {"TSG00", "TSG50", "TSG99"};
const char* mc_button_pressed[4] = {"TSY99", "TSX99", "TSZ99", "TSK99"};
const char* mc_button_released[4] = {"TSY00", "TSX00", "TSZ00", "TSK00"};
u8 power_notches;
u8 brake_notches;
u16 prev_buttons;
s8 last_handle = -1, handle = 0;
s8 last_reverser = -1, reverser = 1;
};
// Taito Densha Controllers as described at:
// https://marcriera.github.io/ddgo-controller-docs/controllers/usb/
// https://traincontrollerdb.marcriera.cat/hardware/#usb
#define DEFINE_DCT_DEV_DESCRIPTOR(prefix, subclass, product) \
static const uint8_t prefix##_dev_descriptor[] = { \
/* bLength */ USB_DEVICE_DESC_SIZE, \
@@ -185,4 +224,114 @@ namespace usb_pad
// dct03_dev_descriptor
DEFINE_DCT_DEV_DESCRIPTOR(dct03, 0xFF, 0x0007);
// ---- Train Mascon ----
static const uint8_t train_mascon_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x10, 0x01, // bcdUSB 1.10
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x08, // bMaxPacketSize0 8
0x06, 0x1C, // idVendor 0x1C06
0xA7, 0x77, // idProduct 0x77A7
0x02, 0x02, // bcdDevice 2.02
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x03, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t train_mascon_config_descriptor[] = {
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x19, 0x00, // wTotalLength 25
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x04, // iConfiguration (String Index)
0xA0, // bmAttributes Remote Wakeup
0x32, // bMaxPower 100mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
0x00, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x08, 0x00, // wMaxPacketSize 8
0x14, // bInterval 20 (unit depends on device speed)
};
// ---- Master Controller ----
// Implements a generic PL2303 adapter.
// Replace with official OGCW-10001 descriptors when available.
static const uint8_t master_controller_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x10, 0x01, // bcdUSB 1.10
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0x7B, 0x06, // idVendor 0x067B
0x03, 0x23, // idProduct 0x2303
0x00, 0x03, // bcdDevice 3.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t master_controller_config_descriptor[] = {
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x27, 0x00, // wTotalLength 39
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0x32, // bMaxPower 100mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x03, // bNumEndpoints 3
0xFF, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x0A, 0x00, // wMaxPacketSize 10
0x01, // bInterval 1 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x02, // bEndpointAddress (OUT/H2D)
0x02, // bmAttributes (Bulk)
0x40, 0x00, // wMaxPacketSize 64
0x00, // bInterval 0 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x83, // bEndpointAddress (IN/D2H)
0x02, // bmAttributes (Bulk)
0x40, 0x00, // wMaxPacketSize 64
0x00, // bInterval 0 (unit depends on device speed)
};
} // namespace usb_pad

View File

@@ -526,6 +526,7 @@ void VMManager::SetDefaultLoggingSettings(SettingsInterface& si)
si.SetBoolValue("Logging", "EnableSystemConsole", false);
si.SetBoolValue("Logging", "EnableFileLogging", true);
si.SetBoolValue("Logging", "EnableTimestamps", true);
si.SetBoolValue("Logging", "EnableEESIOInput", false);
si.SetBoolValue("Logging", "EnableVerbose", false);
si.SetBoolValue("Logging", "EnableEEConsole", false);
si.SetBoolValue("Logging", "EnableIOPConsole", false);
@@ -3725,15 +3726,16 @@ void VMManager::UpdateDiscordPresence(bool update_session_time)
auto lock = Achievements::GetLock();
if (Achievements::HasRichPresence())
if (Achievements::HasActiveGame() && Achievements::HasAchievementsOrLeaderboards())
{
rp.state = (state_string = StringUtil::Ellipsise(Achievements::GetRichPresenceString(), 128)).c_str();
if (const std::string& icon_url = Achievements::GetGameIconURL(); !icon_url.empty())
{
rp.largeImageKey = icon_url.c_str();
rp.largeImageText = s_title.c_str();
}
if (Achievements::HasRichPresence())
rp.state = (state_string = StringUtil::Ellipsise(Achievements::GetRichPresenceString(), 128)).c_str();
}
Discord_UpdatePresence(&rp);
@@ -3747,3 +3749,15 @@ void VMManager::PollDiscordPresence()
Discord_RunCallbacks();
}
bool VMManager::WriteBytesToEESIORXFIFO(const std::span<const u8> data)
{
if(ee_sio_rx_fifo.size() + data.size() > 1024)
{
Console.Warning("EE RX FIFO is full, not appending more bytes.");
return false;
}
ee_sio_rx_fifo.insert(ee_sio_rx_fifo.end(), data.begin(), data.end());
return true;
}

View File

@@ -6,6 +6,7 @@
#include <functional>
#include <mutex>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <vector>
@@ -264,6 +265,9 @@ namespace VMManager
/// Called when the rich presence string, provided by RetroAchievements, changes.
void UpdateDiscordPresence(bool update_session_time);
/// Append bytes to the EE SIO RX FIFO. If it returns false, the FIFO is full and data is not inserted.
bool WriteBytesToEESIORXFIFO(const std::span<const u8> data);
/// Internal callbacks, implemented in the emu core.
namespace Internal
{

View File

@@ -233,7 +233,13 @@ public:
const u64 quick64 = pState->quick64[0];
for (const microBlockLinkRef& ref : quickLookup)
{
if (ref.quick != quick64) continue;
// if we're using the flag hack, ignore the mac flags going in to the new block too if an exact match wasn't requested.
if (mVUsFlagHack)
{
if ((ref.quick & ~0x0C04) != (quick64 & ~0x0C04)) continue;
}
else if (ref.quick != quick64) continue;
if (doConstProp && (ref.pBlock->pState.vi15 != pState->vi15)) continue;
if (doConstProp && (ref.pBlock->pState.vi15v != pState->vi15v)) continue;
return ref.pBlock;