Compare commits

...

22 Commits

Author SHA1 Message Date
ElTioRata
4fa005ade0 GameDB: resident evil 4 - HPO Native w/ Texture Offset
Added 'Align to Native w/ Texture Offset'
2025-04-04 02:29:53 +02:00
PCSX2 Bot
bf656e892f [ci skip] Qt: Update Base Translation. 2025-04-04 02:29:37 +02:00
chaoticgd
abf074eaf4 Debugger: Fix some theming issues 2025-04-03 16:13:50 +02:00
chaoticgd
47657b51ab Debugger: Extract custom menu bar as its own class 2025-04-03 16:13:50 +02:00
PCSX2 Bot
76f8ffeb90 [ci skip] Qt: Update Base Translation. 2025-04-03 02:12:13 +02:00
TellowKrinkle
e68ae91b59 MacOS: Mark our help menu as the macOS help menu
This gives it a nice search box for searching other menus
2025-04-02 18:48:34 -04:00
JordanTheToaster
9222c21b4a Deps: Move Mac Qt download link to archive 2025-04-02 16:11:22 -04:00
chaoticgd
c837d9c91c Qt: Fix custom scan range settings and make sure to save symbol sources 2025-04-02 20:34:17 +02:00
JordanTheToaster
cdf7bef150 Deps: Update SDL to 3.2.10 2025-04-02 20:32:56 +02:00
PCSX2 Bot
eb52da9702 [ci skip] PAD: Update to latest controller database. 2025-04-02 20:31:11 +02:00
chaoticgd
8a1f2a151d Qt: Add GammaRay build scripts 2025-03-29 09:43:11 -04:00
lightningterror
1b4ced3e55 GS/HW: Don't use coverage when doing Af or Ad blend. 2025-03-27 21:27:06 +01:00
refractionpcsx2
29cd068dbd GS/HW: Fix typo on Tekken 5 CRC 2025-03-27 20:13:21 +00:00
TellowKrinkle
6681614f1a Core:Rec: Adjust bounds check asserts to not erroneously trip 2025-03-26 22:57:21 -04:00
PCSX2 Bot
1030db87d4 [ci skip] Qt: Update Base Translation. 2025-03-27 01:03:25 +01:00
JordanTheToaster
356ab30e89 3rdparty: Update CPUInfo to commit 5e3d2445e6a84d9599bee2bf78edbb4d80865e1d 2025-03-26 16:37:49 -04:00
KamFretoZ
0f09b8df77 BPM: GPU CLUT to FSUI 2025-03-26 10:54:55 -04:00
PCSX2 Bot
23c495b939 [ci skip] Qt: Update Base Translation. 2025-03-25 18:14:23 +01:00
PCSX2 Bot
2ac0420903 [ci skip] PAD: Update to latest controller database. 2025-03-25 18:14:06 +01:00
TellowKrinkle
aae070f826 GS:MTL: Avoid WC memory on Ryzen hackintoshes 2025-03-25 11:38:24 -04:00
chaoticgd
6ad825d1e0 Debugger: Fix Visual Studio filters 2025-03-24 20:00:35 -05:00
TellowKrinkle
7910506b3c GS:HW: Avoid using blend + fbfetch for AFAIL RGB_ONLY 2025-03-22 15:47:37 -05:00
47 changed files with 3408 additions and 2798 deletions

View File

@@ -19,7 +19,7 @@ LIBJPEGTURBO=3.1.0
LIBPNG=1.6.45
LIBWEBP=1.5.0
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
SDL=SDL3-3.2.8
SDL=SDL3-3.2.10
QT=6.8.2
ZSTD=1.5.7
KDDOCKWIDGETS=2.2.1
@@ -38,7 +38,7 @@ fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 $SDL.tar.gz
f87be7b4dec66db4098e9c167b2aa34e2ca10aeb5443bdde95ae03185ed513e0 $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05 qtbase-everywhere-src-$QT.tar.xz
d2a1bbb84707b8a0aec29227b170be00f04383fbf2361943596d09e7e443c8e1 qtimageformats-everywhere-src-$QT.tar.xz

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env bash
set -e
if [ "$#" -ne 2 ]; then
echo "Syntax: $0 <deps directory> <output directory>"
exit 1
fi
DEPSDIR=$(realpath "$1")
INSTALLDIR=$(realpath "$2")
if [ ! -d "$DEPSDIR/include/QtCore" ]; then
echo "Error: The build-dependencies-qt.sh script must be run on the deps directory first."
exit 1
fi
GAMMARAY=master
mkdir -p gammaray-build
cd gammaray-build
echo "Downloading..."
curl -L -o "GammaRay-$GAMMARAY.tar.gz" https://github.com/KDAB/GammaRay/archive/$GAMMARAY.tar.gz
rm -fr "GammaRay-$GAMMARAY"
echo "Extracting..."
tar xf "GammaRay-$GAMMARAY.tar.gz"
cd "GammaRay-$GAMMARAY"
mkdir build
cd build
echo "Configuring..."
cmake -DCMAKE_PREFIX_PATH="$DEPSDIR" -G Ninja -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DGAMMARAY_BUILD_DOCS=false ..
echo "Building..."
cmake --build . --parallel
echo "Installing..."
cmake --build . --target install
cd ../..
echo "Cleaning up..."
cd ..
rm -r gammaray-build

View File

@@ -14,8 +14,8 @@
"sources": [
{
"type": "archive",
"url": "https://libsdl.org/release/SDL3-3.2.8.tar.gz",
"sha256": "13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03"
"url": "https://libsdl.org/release/SDL3-3.2.10.tar.gz",
"sha256": "f87be7b4dec66db4098e9c167b2aa34e2ca10aeb5443bdde95ae03185ed513e0"
}
],
"cleanup": [

View File

@@ -40,7 +40,7 @@ fi
FREETYPE=2.13.3
HARFBUZZ=10.0.1
SDL=SDL3-3.2.8
SDL=SDL3-3.2.10
ZSTD=1.5.7
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
LIBPNG=1.6.45
@@ -77,7 +77,7 @@ CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 $SDL.tar.gz
f87be7b4dec66db4098e9c167b2aa34e2ca10aeb5443bdde95ae03185ed513e0 $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz

View File

@@ -22,7 +22,7 @@ fi
FREETYPE=2.13.3
HARFBUZZ=10.0.1
SDL=SDL3-3.2.8
SDL=SDL3-3.2.10
ZSTD=1.5.7
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
LIBPNG=1.6.45
@@ -57,7 +57,7 @@ CMAKE_COMMON=(
cat > SHASUMS <<EOF
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
13388fabb361de768ecdf2b65e52bb27d1054cae6ccb6942ba926e378e00db03 $SDL.tar.gz
f87be7b4dec66db4098e9c167b2aa34e2ca10aeb5443bdde95ae03185ed513e0 $SDL.tar.gz
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
@@ -88,11 +88,11 @@ curl -L \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qtsvg-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttools-everywhere-src-$QT.tar.xz" \
-O "https://download.qt.io/archive/qt/${QT%.*}/$QT/submodules/qttranslations-everywhere-src-$QT.tar.xz" \
-o "shaderc-$SHADERC.tar.gz" "https://github.com/google/shaderc/archive/refs/tags/v$SHADERC.tar.gz" \
-o "shaderc-glslang-$SHADERC_GLSLANG.tar.gz" "https://github.com/KhronosGroup/glslang/archive/$SHADERC_GLSLANG.tar.gz" \
-o "shaderc-spirv-headers-$SHADERC_SPIRVHEADERS.tar.gz" "https://github.com/KhronosGroup/SPIRV-Headers/archive/$SHADERC_SPIRVHEADERS.tar.gz" \

View File

@@ -49,7 +49,7 @@ set LIBPNG=1645
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
set QT=6.8.2
set QTMINOR=6.8
set SDL=SDL3-3.2.8
set SDL=SDL3-3.2.10
set WEBP=1.5.0
set ZLIB=1.3.1
set ZLIBSHORT=131
@@ -67,7 +67,7 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 7f8ff5c8246db4145301bc122601a5f8cef25ee2c326eddb3e88668849c61ddf || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 01d9ab20fc071b076be91df5396b464b4ef159e93b2b2addda1cc36750fc1f29 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error

View File

@@ -47,7 +47,7 @@ set LIBPNG=1645
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
set QT=6.8.2
set QTMINOR=6.8
set SDL=SDL3-3.2.8
set SDL=SDL3-3.2.10
set WEBP=1.5.0
set ZLIB=1.3.1
set ZLIBSHORT=131
@@ -65,7 +65,7 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 9564c72b1dfd1d6fe6274c5f95a8d989b59854575d4bbee44ade7bc17aa9bc93 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 7f8ff5c8246db4145301bc122601a5f8cef25ee2c326eddb3e88668849c61ddf || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 01d9ab20fc071b076be91df5396b464b4ef159e93b2b2addda1cc36750fc1f29 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error

View File

@@ -0,0 +1,68 @@
@echo off
setlocal enabledelayedexpansion
echo Setting environment...
if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" (
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
) else if exist "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" (
call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
) else (
echo Visual Studio 2022 not found.
goto error
)
pushd %~dp0
cd ..\..\..\..
cd deps || goto error
set "DEPSDIR=%CD%"
cd ..
mkdir gammaray
cd gammaray || goto error
set "INSTALLDIR=%CD%"
cd ..
mkdir gammaray-build
cd gammaray-build || goto error
set "BUILDDIR=%CD%"
echo DEPSDIR=%DEPSDIR%
echo BUILDDIR=%BUILDDIR%
echo INSTALLDIR=%INSTALLDIR%
set GAMMARAY="master"
echo Downloading...
curl -L -o "GammaRay-%GAMMARAY%.tar.gz" "https://github.com/KDAB/GammaRay/archive/%GAMMARAY%.tar.gz" || goto error
rmdir /s /q "GammaRay-%GAMMARAY%"
echo Extracting...
tar -xf "GammaRay-%GAMMARAY%.tar.gz" || goto error
echo Configuring...
cmake "GammaRay-%GAMMARAY%" -B build -DCMAKE_PREFIX_PATH="%DEPSDIR%" -G Ninja -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DGAMMARAY_BUILD_DOCS=false || goto error
echo Building...
cmake --build build --parallel || goto error
echo Installing...
cmake --build build --target install || goto errorlevel
echo Copying DLLs...
xcopy /y "%DEPSDIR%\bin\*.dll" "%INSTALLDIR%\bin\"
xcopy /y /e /s "%DEPSDIR%\plugins" "%INSTALLDIR%\bin\"
echo Cleaning up...
cd ..
rd /s /q gammaray-build
echo Exiting with success.
popd
pause
exit 0
:error
echo Failed with error #%errorlevel%.
popd
pause
exit %errorlevel%

2
.gitignore vendored
View File

@@ -109,6 +109,8 @@ oprofile_data/
/deps-build
/deps
/deps-arm64
/gammaray-build
/gammaray
/ipch
!/3rdparty/libjpeg/change.log

View File

@@ -522,6 +522,8 @@ enum cpuinfo_uarch {
cpuinfo_uarch_falkor = 0x00400103,
/** Qualcomm Saphira. */
cpuinfo_uarch_saphira = 0x00400104,
/** Qualcomm Oryon. */
cpuinfo_uarch_oryon = 0x00400105,
/** Nvidia Denver. */
cpuinfo_uarch_denver = 0x00500100,
@@ -821,6 +823,7 @@ struct cpuinfo_x86_isa {
bool avx512_4vnniw;
bool avx512_4fmaps;
bool avx10_1;
bool avx10_2;
bool amx_bf16;
bool amx_tile;
bool amx_int8;
@@ -1444,6 +1447,14 @@ static inline bool cpuinfo_has_x86_avx10_1(void) {
#endif
}
static inline bool cpuinfo_has_x86_avx10_2(void) {
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
return cpuinfo_isa.avx10_2;
#else
return false;
#endif
}
static inline bool cpuinfo_has_x86_hle(void) {
#if CPUINFO_ARCH_X86 || CPUINFO_ARCH_X86_64
return cpuinfo_isa.hle;

View File

@@ -1,5 +1,11 @@
#pragma once
#ifdef _MSC_VER
#define RESTRICT_STATIC /* nothing for MSVC */
#else
#define RESTRICT_STATIC restrict static
#endif
#include <stdbool.h>
#include <stdint.h>
@@ -82,11 +88,11 @@ struct cpuinfo_arm_chipset {
#ifndef __cplusplus
CPUINFO_INTERNAL void cpuinfo_arm_chipset_to_string(
const struct cpuinfo_arm_chipset chipset[restrict static 1],
char name[restrict static CPUINFO_ARM_CHIPSET_NAME_MAX]);
const struct cpuinfo_arm_chipset chipset[RESTRICT_STATIC 1],
char name[RESTRICT_STATIC CPUINFO_ARM_CHIPSET_NAME_MAX]);
CPUINFO_INTERNAL void cpuinfo_arm_fixup_chipset(
struct cpuinfo_arm_chipset chipset[restrict static 1],
struct cpuinfo_arm_chipset chipset[RESTRICT_STATIC 1],
uint32_t cores,
uint32_t max_cpu_freq_max);
@@ -95,23 +101,23 @@ CPUINFO_INTERNAL void cpuinfo_arm_decode_vendor_uarch(
#if CPUINFO_ARCH_ARM
bool has_vfpv4,
#endif
enum cpuinfo_vendor vendor[restrict static 1],
enum cpuinfo_uarch uarch[restrict static 1]);
enum cpuinfo_vendor vendor[RESTRICT_STATIC 1],
enum cpuinfo_uarch uarch[RESTRICT_STATIC 1]);
CPUINFO_INTERNAL void cpuinfo_arm_decode_cache(
enum cpuinfo_uarch uarch,
uint32_t cluster_cores,
uint32_t midr,
const struct cpuinfo_arm_chipset chipset[restrict static 1],
const struct cpuinfo_arm_chipset chipset[RESTRICT_STATIC 1],
uint32_t cluster_id,
uint32_t arch_version,
struct cpuinfo_cache l1i[restrict static 1],
struct cpuinfo_cache l1d[restrict static 1],
struct cpuinfo_cache l2[restrict static 1],
struct cpuinfo_cache l3[restrict static 1]);
struct cpuinfo_cache l1i[RESTRICT_STATIC 1],
struct cpuinfo_cache l1d[RESTRICT_STATIC 1],
struct cpuinfo_cache l2[RESTRICT_STATIC 1],
struct cpuinfo_cache l3[RESTRICT_STATIC 1]);
CPUINFO_INTERNAL uint32_t
cpuinfo_arm_compute_max_cache_size(const struct cpuinfo_processor processor[restrict static 1]);
cpuinfo_arm_compute_max_cache_size(const struct cpuinfo_processor processor[RESTRICT_STATIC 1]);
#else /* defined(__cplusplus) */
CPUINFO_INTERNAL void cpuinfo_arm_decode_cache(
enum cpuinfo_uarch uarch,

View File

@@ -101,7 +101,6 @@ static enum cpuinfo_uarch decode_uarch(uint32_t cpu_family, uint32_t core_index,
return cpuinfo_uarch_unknown;
}
/* Small bodge until cpuinfo merges PR #246 */
static int read_package_name_from_brand_string(char* package_name) {
size_t size;
if (sysctlbyname("machdep.cpu.brand_string", NULL, &size, NULL, 0) != 0) {

View File

@@ -9,8 +9,8 @@ void cpuinfo_arm_decode_vendor_uarch(
#if CPUINFO_ARCH_ARM
bool has_vfpv4,
#endif /* CPUINFO_ARCH_ARM */
enum cpuinfo_vendor vendor[restrict static 1],
enum cpuinfo_uarch uarch[restrict static 1]) {
enum cpuinfo_vendor vendor[RESTRICT_STATIC 1],
enum cpuinfo_uarch uarch[RESTRICT_STATIC 1]) {
switch (midr_get_implementer(midr)) {
case 'A':
*vendor = cpuinfo_vendor_arm;
@@ -332,6 +332,9 @@ void cpuinfo_arm_decode_vendor_uarch(
*uarch = cpuinfo_uarch_cortex_a55;
break;
#if CPUINFO_ARCH_ARM64
case 0x001:
*uarch = cpuinfo_uarch_oryon;
break;
case 0xC00:
*uarch = cpuinfo_uarch_falkor;
break;

View File

@@ -750,11 +750,14 @@ void store_core_info_per_processor(
if (cores) {
processors[processor_global_index].core = cores + core_id;
cores[core_id].core_id = core_id;
get_core_uarch_for_efficiency(
chip_info->chip_name,
core_info->Processor.EfficiencyClass,
&(cores[core_id].uarch),
&(cores[core_id].frequency));
if (chip_info->uarchs == NULL) {
cpuinfo_log_error("uarch is NULL for core %d", core_id);
return;
}
cores[core_id].uarch = chip_info->uarchs[0].uarch;
cores[core_id].frequency = chip_info->uarchs[0].frequency;
/* We don't have cluster information, so we handle it as
* fixed 1 to (cluster / cores).

View File

@@ -7,6 +7,9 @@
#include <cpuinfo/internal-api.h>
#include <cpuinfo/log.h>
#include <arm/api.h>
#include <arm/midr.h>
#include "windows-arm-init.h"
struct cpuinfo_arm_isa cpuinfo_isa;
@@ -14,62 +17,7 @@ struct cpuinfo_arm_isa cpuinfo_isa;
static void set_cpuinfo_isa_fields(void);
static struct woa_chip_info* get_system_info_from_registry(void);
static struct woa_chip_info woa_chip_unknown = {
L"Unknown",
woa_chip_name_unknown,
{{cpuinfo_vendor_unknown, cpuinfo_uarch_unknown, 0}}};
/* Please add new SoC/chip info here! */
static struct woa_chip_info woa_chips[woa_chip_name_last] = {
/* Microsoft SQ1 Kryo 495 4 + 4 cores (3 GHz + 1.80 GHz) */
[woa_chip_name_microsoft_sq_1] =
{L"Microsoft SQ1",
woa_chip_name_microsoft_sq_1,
{{
cpuinfo_vendor_arm,
cpuinfo_uarch_cortex_a55,
1800000000,
},
{
cpuinfo_vendor_arm,
cpuinfo_uarch_cortex_a76,
3000000000,
}}},
/* Microsoft SQ2 Kryo 495 4 + 4 cores (3.15 GHz + 2.42 GHz) */
[woa_chip_name_microsoft_sq_2] =
{L"Microsoft SQ2",
woa_chip_name_microsoft_sq_2,
{{
cpuinfo_vendor_arm,
cpuinfo_uarch_cortex_a55,
2420000000,
},
{cpuinfo_vendor_arm, cpuinfo_uarch_cortex_a76, 3150000000}}},
/* Snapdragon (TM) 8cx Gen 3 @ 3.0 GHz */
[woa_chip_name_microsoft_sq_3] =
{L"Snapdragon (TM) 8cx Gen 3",
woa_chip_name_microsoft_sq_3,
{{
cpuinfo_vendor_arm,
cpuinfo_uarch_cortex_a78,
2420000000,
},
{cpuinfo_vendor_arm, cpuinfo_uarch_cortex_x1, 3000000000}}},
/* Microsoft Windows Dev Kit 2023 */
[woa_chip_name_microsoft_sq_3_devkit] =
{L"Snapdragon Compute Platform",
woa_chip_name_microsoft_sq_3_devkit,
{{
cpuinfo_vendor_arm,
cpuinfo_uarch_cortex_a78,
2420000000,
},
{cpuinfo_vendor_arm, cpuinfo_uarch_cortex_x1, 3000000000}}},
/* Ampere Altra */
[woa_chip_name_ampere_altra] = {
L"Ampere(R) Altra(R) Processor",
woa_chip_name_ampere_altra,
{{cpuinfo_vendor_arm, cpuinfo_uarch_neoverse_n1, 3000000000}}}};
static struct woa_chip_info woa_chip_unknown = {L"Unknown", {{cpuinfo_vendor_unknown, cpuinfo_uarch_unknown, 0}}};
BOOL CALLBACK cpuinfo_arm_windows_init(PINIT_ONCE init_once, PVOID parameter, PVOID* context) {
struct woa_chip_info* chip_info = NULL;
@@ -87,23 +35,6 @@ BOOL CALLBACK cpuinfo_arm_windows_init(PINIT_ONCE init_once, PVOID parameter, PV
return true;
}
bool get_core_uarch_for_efficiency(
enum woa_chip_name chip,
BYTE EfficiencyClass,
enum cpuinfo_uarch* uarch,
uint64_t* frequency) {
/* For currently supported WoA chips, the Efficiency class selects
* the pre-defined little and big core.
* Any further supported SoC's logic should be implemented here.
*/
if (uarch && frequency && chip < woa_chip_name_last && EfficiencyClass < MAX_WOA_VALID_EFFICIENCY_CLASSES) {
*uarch = woa_chips[chip].uarchs[EfficiencyClass].uarch;
*frequency = woa_chips[chip].uarchs[EfficiencyClass].frequency;
return true;
}
return false;
}
/* Static helper functions */
static wchar_t* read_registry(LPCWSTR subkey, LPCWSTR value) {
@@ -149,40 +80,112 @@ static wchar_t* read_registry(LPCWSTR subkey, LPCWSTR value) {
return text_buffer;
}
static uint64_t read_registry_qword(LPCWSTR subkey, LPCWSTR value) {
DWORD key_type = 0;
DWORD data_size = sizeof(uint64_t);
const DWORD flags = RRF_RT_REG_QWORD; /* Only read QWORD (REG_QWORD) values */
uint64_t qword_value = 0;
LSTATUS result = RegGetValueW(HKEY_LOCAL_MACHINE, subkey, value, flags, &key_type, &qword_value, &data_size);
if (result != ERROR_SUCCESS || data_size != sizeof(uint64_t)) {
cpuinfo_log_error("Registry QWORD read error");
return 0;
}
return qword_value;
}
static uint64_t read_registry_dword(LPCWSTR subkey, LPCWSTR value) {
DWORD key_type = 0;
DWORD data_size = sizeof(DWORD);
DWORD dword_value = 0;
LSTATUS result =
RegGetValueW(HKEY_LOCAL_MACHINE, subkey, value, RRF_RT_REG_DWORD, &key_type, &dword_value, &data_size);
if (result != ERROR_SUCCESS || data_size != sizeof(DWORD)) {
cpuinfo_log_error("Registry DWORD read error");
return 0;
}
return (uint64_t)dword_value;
}
static wchar_t* wcsndup(const wchar_t* src, size_t n) {
size_t len = wcsnlen(src, n);
wchar_t* dup = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (len + 1) * sizeof(wchar_t));
if (dup) {
wcsncpy_s(dup, len + 1, src, len);
dup[len] = L'\0';
}
return dup;
}
static struct core_info_by_chip_name get_core_info_from_midr(uint32_t midr, uint64_t frequency) {
struct core_info_by_chip_name info;
enum cpuinfo_vendor vendor;
enum cpuinfo_uarch uarch;
#if CPUINFO_ARCH_ARM
bool has_vfpv4 = false;
cpuinfo_arm_decode_vendor_uarch(midr, has_vfpv4, &vendor, &uarch);
#else
cpuinfo_arm_decode_vendor_uarch(midr, &vendor, &uarch);
#endif
info.vendor = vendor;
info.uarch = uarch;
info.frequency = frequency;
return info;
}
static struct woa_chip_info* get_system_info_from_registry(void) {
wchar_t* text_buffer = NULL;
LPCWSTR cpu0_subkey = L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
LPCWSTR chip_name_value = L"ProcessorNameString";
LPCWSTR chip_midr_value = L"CP 4000";
LPCWSTR chip_mhz_value = L"~MHz";
struct woa_chip_info* chip_info = NULL;
HANDLE heap = GetProcessHeap();
/* Read processor model name from registry and find in the hard-coded
* list. */
text_buffer = read_registry(cpu0_subkey, chip_name_value);
if (text_buffer == NULL) {
cpuinfo_log_error("Registry read error");
cpuinfo_log_error("Registry read error for processor name");
return NULL;
}
for (uint32_t i = 0; i < (uint32_t)woa_chip_name_last; i++) {
size_t compare_length = wcsnlen(woa_chips[i].chip_name_string, CPUINFO_PACKAGE_NAME_MAX);
int compare_result = wcsncmp(text_buffer, woa_chips[i].chip_name_string, compare_length);
if (compare_result == 0) {
chip_info = woa_chips + i;
break;
}
/*
* https://developer.arm.com/documentation/100442/0100/register-descriptions/aarch32-system-registers/midr--main-id-register
* Regedit for MIDR :
*HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0\CP 4000
*/
uint64_t midr_qword = (uint32_t)read_registry_qword(cpu0_subkey, chip_midr_value);
if (midr_qword == 0) {
cpuinfo_log_error("Registry read error for MIDR value");
return NULL;
}
// MIDR is only 32 bits, so we need to cast it to uint32_t
uint32_t midr_value = (uint32_t)midr_qword;
/* Read the frequency from the registry
* The value is in MHz, so we need to convert it to Hz */
uint64_t frequency_mhz = read_registry_dword(cpu0_subkey, chip_mhz_value);
if (frequency_mhz == 0) {
cpuinfo_log_error("Registry read error for frequency value");
return NULL;
}
// Convert MHz to Hz
uint64_t frequency_hz = frequency_mhz * 1000000;
// Allocate chip_info before using it.
chip_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct woa_chip_info));
if (chip_info == NULL) {
/* No match was found, so print a warning and assign the unknown
* case. */
cpuinfo_log_error(
"Unknown chip model name '%ls'.\nPlease add new Windows on Arm SoC/chip support to arm/windows/init.c!",
text_buffer);
} else {
cpuinfo_log_debug("detected chip model name: %s", chip_info->chip_name_string);
cpuinfo_log_error("Heap allocation error for chip_info");
return NULL;
}
HeapFree(heap, 0, text_buffer);
// set chip_info fields
chip_info->chip_name_string = wcsndup(text_buffer, CPUINFO_PACKAGE_NAME_MAX - 1);
chip_info->uarchs[0] = get_core_info_from_midr(midr_value, frequency_hz);
cpuinfo_log_debug("detected chip model name: %ls", chip_info->chip_name_string);
return chip_info;
}
@@ -216,4 +219,4 @@ static void set_cpuinfo_isa_fields(void) {
cpuinfo_isa.pmull = crypto;
cpuinfo_isa.crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) != 0;
}
}

View File

@@ -3,17 +3,6 @@
/* Efficiency class = 0 means little core, while 1 means big core for now. */
#define MAX_WOA_VALID_EFFICIENCY_CLASSES 2
/* List of known and supported Windows on Arm SoCs/chips. */
enum woa_chip_name {
woa_chip_name_microsoft_sq_1 = 0,
woa_chip_name_microsoft_sq_2 = 1,
woa_chip_name_microsoft_sq_3 = 2,
woa_chip_name_microsoft_sq_3_devkit = 3,
woa_chip_name_ampere_altra = 4,
woa_chip_name_unknown = 5,
woa_chip_name_last = woa_chip_name_unknown
};
/* Topology information hard-coded by SoC/chip name */
struct core_info_by_chip_name {
enum cpuinfo_vendor vendor;
@@ -26,14 +15,7 @@ struct core_info_by_chip_name {
*/
struct woa_chip_info {
wchar_t* chip_name_string;
enum woa_chip_name chip_name;
struct core_info_by_chip_name uarchs[MAX_WOA_VALID_EFFICIENCY_CLASSES];
};
bool get_core_uarch_for_efficiency(
enum woa_chip_name chip,
BYTE EfficiencyClass,
enum cpuinfo_uarch* uarch,
uint64_t* frequency);
bool cpu_info_init_by_logical_sys_info(const struct woa_chip_info* chip_info, enum cpuinfo_vendor vendor);

View File

@@ -46,6 +46,8 @@ struct cpuinfo_x86_isa cpuinfo_x86_detect_isa(
(max_base_index >= 7) ? cpuidex(7, 0) : (struct cpuid_regs){0, 0, 0, 0};
const struct cpuid_regs structured_feature_info1 =
(max_base_index >= 7) ? cpuidex(7, 1) : (struct cpuid_regs){0, 0, 0, 0};
const struct cpuid_regs structured_feature_info2 =
(max_base_index >= 7) ? cpuidex(0x24, 0) : (struct cpuid_regs){0, 0, 0, 0};
const uint32_t processor_capacity_info_index = UINT32_C(0x80000008);
const struct cpuid_regs processor_capacity_info = (max_extended_index >= processor_capacity_info_index)
@@ -430,10 +432,17 @@ struct cpuinfo_x86_isa cpuinfo_x86_detect_isa(
isa.avx512f = avx512_regs && !!(structured_feature_info0.ebx & UINT32_C(0x00010000));
/*
* AVX 10.1 instructions:
* AVX 10.1 instructions: avx 10 isa supported.
* - Intel: edx[bit 19] in structured feature info (ecx = 1).
*/
isa.avx10_1 = avx512_regs && !!(structured_feature_info1.edx & UINT32_C(0x00080000));
/*
* AVX 10.2 instructions: avx 10 version information.
* - Intel: ebx[bits 0-7] in structured features info (eax = 24 ecx = 0).
*/
isa.avx10_2 = ((structured_feature_info2.ebx & UINT32_C(0x000000FF)) >= 2) && isa.avx10_1;
/*
* AVX512PF instructions:
* - Intel: ebx[bit 26] in structured feature info (ecx = 0).

View File

@@ -83,8 +83,9 @@ struct proc_cpuinfo_parser_state {
static bool parse_line(
const char* line_start,
const char* line_end,
struct proc_cpuinfo_parser_state state[restrict static 1],
void* context,
uint64_t line_number) {
struct proc_cpuinfo_parser_state* restrict state = context;
/* Empty line. Skip. */
if (line_start == line_end) {
return true;
@@ -215,5 +216,5 @@ bool cpuinfo_x86_linux_parse_proc_cpuinfo(
.processors = processors,
};
return cpuinfo_linux_parse_multiline_file(
"/proc/cpuinfo", BUFFER_SIZE, (cpuinfo_line_callback)parse_line, &state);
"/proc/cpuinfo", BUFFER_SIZE, parse_line, &state);
}

View File

@@ -23409,7 +23409,7 @@ SLES-53702:
region: "PAL-M5"
compat: 5
gsHWFixes:
halfPixelOffset: 2 # Fixes blurriness.
halfPixelOffset: 5 # Fixes blurriness.
SLES-53703:
name: "Peter Jackson's King Kong - The Official Game of the Movie"
name-sort: "King Kong, Peter Jackson's - The Official Game of the Movie"
@@ -23643,7 +23643,7 @@ SLES-53756:
name: "Resident Evil 4"
region: "PAL-M5"
gsHWFixes:
halfPixelOffset: 2 # Fixes blurriness.
halfPixelOffset: 5 # Fixes blurriness.
SLES-53758:
name: "Sniper Elite [Pre-Production]"
region: "PAL-E"
@@ -31588,7 +31588,7 @@ SLKA-25410:
gameFixes:
- BlitInternalFPSHack # Fixes internal FPS detection.
gsHWFixes:
halfPixelOffset: 2 # Fixes blurriness.
halfPixelOffset: 5 # Fixes blurriness.
SLKA-25411:
name: "Need for Speed - ProStreet"
region: "NTSC-K"
@@ -67457,7 +67457,7 @@ SLUS-21134:
gameFixes:
- BlitInternalFPSHack # Fixes internal FPS detection.
gsHWFixes:
halfPixelOffset: 2 # Fixes blurriness.
halfPixelOffset: 5 # Fixes blurriness.
SLUS-21135:
name: "MVP Baseball 2005"
region: "NTSC-U"
@@ -73016,7 +73016,7 @@ SLUS-29169:
gameFixes:
- BlitInternalFPSHack # Fixes internal FPS detection.
gsHWFixes:
halfPixelOffset: 2 # Fixes blurriness.
halfPixelOffset: 5 # Fixes blurriness.
SLUS-29170:
name: "Total Overdose - A Gunslinger's Tale in Mexico [Demo]"
region: "NTSC-U"

View File

@@ -610,6 +610,7 @@
03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows,
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
03000000632500007805000000000000,Retro Fighters Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,
03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
@@ -757,8 +758,8 @@
03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000882800000305000000000000,V5 Game Pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,x:b2,y:b3,platform:Windows,
03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
03000000790000001a18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000790000001b18000000000000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows,
@@ -1288,7 +1289,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
190000004b4800000010000000010000,GO-Advance Controller,a:b1,b:b0,back:b10,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b13,start:b15,x:b2,y:b3,platform:Linux,
190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,platform:Linux,
190000004b4800000011000000010000,GO-Super Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b2,y:b3,platform:Linux,
190000004b4800000011000000010000,GO-Super Gamepad,a:b0,b:b1,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b3,y:b2,platform:Linux,
03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d11800000094000011010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
05000000d11800000094000000010000,Google Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
@@ -1425,6 +1426,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000dd02000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000ea0200000f050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1432,7 +1434,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b000001050000,Microsoft Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b000001050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000016050000,Microsoft Xbox Series Controller,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Linux,
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
@@ -1452,6 +1455,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
0300000085320000170d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000085320000190d000011010000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
05000000853200000503000000010000,Nacon MG-X Pro,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Linux,
030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux,
@@ -1494,7 +1498,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00008501000011010000,PDP Fightpad Pro Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1509,7 +1513,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000540000001010000,PowerA Advantage Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000540000001010000,PowerA Advantage Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -1525,8 +1529,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000520000050010000,PowerA Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000b20000001010000,PowerA Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000520000050010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000000b20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000250900000017000010010000,PS/SS/N64 Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b5,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2~,righty:a3,start:b8,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
@@ -1718,6 +1722,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux,
03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux,
03000000790000001a18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000790000001b18000011010000,Venom PS4 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
@@ -1771,10 +1777,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000014050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000130b000017050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000011050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e040000120b000014050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000130b000017050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,

View File

@@ -25,7 +25,8 @@
#define SW_AD_TO_HW (PS_BLEND_C == 1 && PS_A_MASKED)
#define PS_PRIMID_INIT (PS_DATE == 1 || PS_DATE == 2)
#define NEEDS_RT_EARLY (PS_TEX_IS_FB == 1 || PS_DATE >= 5)
#define NEEDS_RT (NEEDS_RT_EARLY || (!PS_PRIMID_INIT && (PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW)))
#define NEEDS_RT_FOR_AFAIL (PS_AFAIL == 3 && PS_NO_COLOR1)
#define NEEDS_RT (NEEDS_RT_EARLY || NEEDS_RT_FOR_AFAIL || (!PS_PRIMID_INIT && (PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW)))
#define NEEDS_TEX (PS_TFX != 4)
layout(std140, binding = 0) uniform cb21
@@ -1114,7 +1115,7 @@ void ps_main()
ps_fbmask(C);
#if PS_AFAIL == 3 // RGB_ONLY
#if PS_AFAIL == 3 && !PS_NO_COLOR1 // RGB_ONLY
// Use alpha blend factor to determine whether to update A.
alpha_blend.a = float(atst_pass);
#endif
@@ -1130,6 +1131,10 @@ void ps_main()
#else
SV_Target0.rgb = C.rgb / 255.0f;
#endif
#if PS_AFAIL == 3 && !PS_NO_COLOR1 // RGB_ONLY, no dual src blend
if (!atst_pass)
SV_Target0.a = sample_from_rt().a;
#endif
#if !PS_NO_COLOR1
SV_Target1 = alpha_blend;
#endif

View File

@@ -299,8 +299,9 @@ void main()
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
#define SW_BLEND_NEEDS_RT (SW_BLEND && (PS_BLEND_A == 1 || PS_BLEND_B == 1 || PS_BLEND_C == 1 || PS_BLEND_D == 1))
#define SW_AD_TO_HW (PS_BLEND_C == 1 && PS_A_MASKED)
#define AFAIL_NEEDS_RT (PS_AFAIL == 3 && PS_NO_COLOR1)
#define PS_FEEDBACK_LOOP_IS_NEEDED (PS_TEX_IS_FB == 1 || PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW || (PS_DATE >= 5))
#define PS_FEEDBACK_LOOP_IS_NEEDED (PS_TEX_IS_FB == 1 || AFAIL_NEEDS_RT || PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW || (PS_DATE >= 5))
#define NEEDS_TEX (PS_TFX != 4)
@@ -1381,7 +1382,7 @@ void main()
ps_fbmask(C);
#if PS_AFAIL == 3 // RGB_ONLY
#if PS_AFAIL == 3 && !PS_NO_COLOR1 // RGB_ONLY
// Use alpha blend factor to determine whether to update A.
alpha_blend.a = float(atst_pass);
#endif
@@ -1400,6 +1401,10 @@ void main()
#if !PS_NO_COLOR1
o_col1 = alpha_blend;
#endif
#if PS_AFAIL == 3 && PS_NO_COLOR1 // RGB_ONLY, no dual src blend
if (!atst_pass)
o_col0.a = sample_from_rt().a;
#endif
#endif
#if PS_ZCLAMP

View File

@@ -19,6 +19,8 @@ namespace CocoaTools
void AddThemeChangeHandler(void* ctx, void(handler)(void* ctx));
/// Remove a handler previously added using AddThemeChangeHandler with the given context
void RemoveThemeChangeHandler(void* ctx);
/// Mark an NSMenu as the help menu
void MarkHelpMenu(void* menu);
/// Returns the bundle path.
std::optional<std::string> GetBundlePath();
/// Get the bundle path to the actual application without any translocation fun

View File

@@ -143,6 +143,11 @@ void CocoaTools::RemoveThemeChangeHandler(void* ctx)
[s_themeChangeHandler removeCallback:ctx];
}
void CocoaTools::MarkHelpMenu(void* menu)
{
[NSApp setHelpMenu:(__bridge NSMenu*)menu];
}
// MARK: - Sound playback
bool Common::PlaySoundAsync(const char* path)

View File

@@ -196,6 +196,8 @@ target_sources(pcsx2-qt PRIVATE
Debugger/Docking/DockLayout.h
Debugger/Docking/DockManager.cpp
Debugger/Docking/DockManager.h
Debugger/Docking/DockMenuBar.cpp
Debugger/Docking/DockMenuBar.h
Debugger/Docking/DockTables.cpp
Debugger/Docking/DockTables.h
Debugger/Docking/DockUtils.cpp

View File

@@ -112,7 +112,9 @@ DebuggerWindow::DebuggerWindow(QWidget* parent)
QMenuBar* menu_bar = menuBar();
setMenuWidget(m_dock_manager->createLayoutSwitcher(menu_bar));
setMenuWidget(m_dock_manager->createMenuBar(menu_bar));
updateTheme();
Host::RunOnCPUThread([]() {
R5900SymbolImporter.OnDebuggerOpened();
@@ -193,7 +195,7 @@ void DebuggerWindow::setupFonts()
m_font_size++;
updateFontActions();
updateStyleSheets();
updateTheme();
saveFontSize();
});
@@ -205,7 +207,7 @@ void DebuggerWindow::setupFonts()
m_font_size--;
updateFontActions();
updateStyleSheets();
updateTheme();
saveFontSize();
});
@@ -213,12 +215,11 @@ void DebuggerWindow::setupFonts()
m_font_size = DEFAULT_FONT_SIZE;
updateFontActions();
updateStyleSheets();
updateTheme();
saveFontSize();
});
updateFontActions();
updateStyleSheets();
}
void DebuggerWindow::updateFontActions()
@@ -239,7 +240,7 @@ int DebuggerWindow::fontSize()
return m_font_size;
}
void DebuggerWindow::updateStyleSheets()
void DebuggerWindow::updateTheme()
{
// TODO: Migrate away from stylesheets to improve performance.
if (m_font_size != DEFAULT_FONT_SIZE)
@@ -252,7 +253,7 @@ void DebuggerWindow::updateStyleSheets()
setStyleSheet(QString());
}
dockManager().updateStyleSheets();
dockManager().updateTheme();
}
void DebuggerWindow::saveWindowGeometry()

View File

@@ -31,7 +31,7 @@ public:
void updateFontActions();
void saveFontSize();
int fontSize();
void updateStyleSheets();
void updateTheme();
void saveWindowGeometry();
void restoreWindowGeometry();

View File

@@ -25,7 +25,8 @@
#include <QtCore/QTimer>
#include <QtCore/QtTranslation>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QProxyStyle>
#include <QtWidgets/QStyleFactory>
DockManager::DockManager(QObject* parent)
: QObject(parent)
@@ -33,9 +34,6 @@ DockManager::DockManager(QObject* parent)
QTimer* autosave_timer = new QTimer(this);
connect(autosave_timer, &QTimer::timeout, this, &DockManager::saveCurrentLayout);
autosave_timer->start(60 * 1000);
m_blink_timer = new QTimer(this);
connect(m_blink_timer, &QTimer::timeout, this, &DockManager::layoutSwitcherUpdateBlink);
}
void DockManager::configureDockingSystem()
@@ -144,17 +142,13 @@ void DockManager::switchToLayout(DockLayout::Index layout_index, bool blink_tab)
layout.thaw();
int tab_index = static_cast<int>(layout_index);
if (m_switcher && tab_index >= 0 && tab_index < m_plus_tab_index)
{
m_ignore_current_tab_changed = true;
m_switcher->setCurrentIndex(tab_index);
m_ignore_current_tab_changed = false;
}
if (m_menu_bar && tab_index >= 0)
m_menu_bar->onCurrentLayoutChanged(layout_index);
}
}
if (blink_tab)
layoutSwitcherStartBlink();
m_menu_bar->startBlink(m_current_layout);
}
bool DockManager::switchToLayoutWithCPU(BreakPointCpu cpu, bool blink_tab)
@@ -476,168 +470,195 @@ void DockManager::createWindowsMenu(QMenu* menu)
menu->addAction(toggle.action);
}
QWidget* DockManager::createLayoutSwitcher(QWidget* menu_bar)
QWidget* DockManager::createMenuBar(QWidget* original_menu_bar)
{
QWidget* container = new QWidget;
pxAssert(!m_menu_bar);
QHBoxLayout* layout = new QHBoxLayout;
layout->setContentsMargins(0, 2, 2, 0);
container->setLayout(layout);
m_menu_bar = new DockMenuBar(original_menu_bar);
QWidget* menu_wrapper = new QWidget;
menu_wrapper->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
layout->addWidget(menu_wrapper);
connect(m_menu_bar, &DockMenuBar::currentLayoutChanged, this, [this](DockLayout::Index layout_index) {
if (layout_index >= m_layouts.size())
return;
QHBoxLayout* menu_layout = new QHBoxLayout;
menu_layout->setContentsMargins(0, 4, 0, 4);
menu_wrapper->setLayout(menu_layout);
menu_layout->addWidget(menu_bar);
m_switcher = new QTabBar;
m_switcher->setContentsMargins(0, 0, 0, 0);
m_switcher->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
m_switcher->setContextMenuPolicy(Qt::CustomContextMenu);
m_switcher->setMovable(true);
layout->addWidget(m_switcher);
switchToLayout(layout_index);
});
connect(m_menu_bar, &DockMenuBar::newButtonClicked, this, &DockManager::newLayoutClicked);
connect(m_menu_bar, &DockMenuBar::layoutMoved, this, &DockManager::layoutSwitcherTabMoved);
connect(m_menu_bar, &DockMenuBar::lockButtonToggled, this, &DockManager::setLayoutLockedAndSaveSetting);
connect(m_menu_bar, &DockMenuBar::layoutSwitcherContextMenuRequested,
this, &DockManager::openLayoutSwitcherContextMenu);
updateLayoutSwitcher();
connect(m_switcher, &QTabBar::tabMoved, this, &DockManager::layoutSwitcherTabMoved);
connect(m_switcher, &QTabBar::customContextMenuRequested, this, &DockManager::layoutSwitcherContextMenu);
QWidget* spacer = new QWidget;
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
layout->addWidget(spacer);
bool layout_locked = Host::GetBaseBoolSettingValue("Debugger/UserInterface", "LayoutLocked", true);
setLayoutLocked(layout_locked, false);
QPushButton* lock_layout_toggle = new QPushButton;
lock_layout_toggle->setCheckable(true);
lock_layout_toggle->setChecked(layout_locked);
lock_layout_toggle->setFlat(true);
connect(lock_layout_toggle, &QPushButton::toggled, this, [this, lock_layout_toggle](bool checked) {
setLayoutLocked(checked, lock_layout_toggle, true);
});
layout->addWidget(lock_layout_toggle);
setLayoutLocked(layout_locked, lock_layout_toggle, false);
return container;
return m_menu_bar;
}
void DockManager::updateLayoutSwitcher()
{
if (!m_switcher)
return;
disconnect(m_tab_connection);
for (int i = m_switcher->count(); i > 0; i--)
m_switcher->removeTab(i - 1);
for (DockLayout& layout : m_layouts)
{
const char* cpu_name = DebugInterface::cpuName(layout.cpu());
QString tab_name = QString("%1 (%2)").arg(layout.name()).arg(cpu_name);
m_switcher->addTab(tab_name);
}
m_plus_tab_index = m_switcher->addTab("+");
m_current_tab_index = m_current_layout;
if (m_current_layout != DockLayout::INVALID_INDEX)
m_switcher->setCurrentIndex(m_current_layout);
// If we don't have any layouts, the currently selected tab will never be
// changed, so we respond to all clicks instead.
if (!m_layouts.empty())
m_tab_connection = connect(m_switcher, &QTabBar::currentChanged, this, &DockManager::layoutSwitcherTabChanged);
else
m_tab_connection = connect(m_switcher, &QTabBar::tabBarClicked, this, &DockManager::layoutSwitcherTabChanged);
layoutSwitcherStopBlink();
if (m_menu_bar)
m_menu_bar->updateLayoutSwitcher(m_current_layout, m_layouts);
}
void DockManager::layoutSwitcherTabChanged(int index)
void DockManager::newLayoutClicked()
{
// Prevent recursion.
if (m_ignore_current_tab_changed)
return;
// The plus button has just been made the current tab, so set it back to the
// one corresponding to the current layout again.
m_menu_bar->onCurrentLayoutChanged(m_current_layout);
if (index == m_plus_tab_index)
auto name_validator = [this](const QString& name) {
return !hasNameConflict(name, DockLayout::INVALID_INDEX);
};
bool can_clone_current_layout = m_current_layout != DockLayout::INVALID_INDEX;
QPointer<LayoutEditorDialog> dialog = new LayoutEditorDialog(
name_validator, can_clone_current_layout, g_debugger_window);
if (dialog->exec() == QDialog::Accepted && name_validator(dialog->name()))
{
if (m_current_tab_index >= 0 && m_current_tab_index < m_plus_tab_index)
DockLayout::Index new_layout = DockLayout::INVALID_INDEX;
const auto [mode, index] = dialog->initialState();
switch (mode)
{
m_ignore_current_tab_changed = true;
m_switcher->setCurrentIndex(m_current_tab_index);
m_ignore_current_tab_changed = false;
case LayoutEditorDialog::DEFAULT_LAYOUT:
{
const DockTables::DefaultDockLayout& default_layout = DockTables::DEFAULT_DOCK_LAYOUTS.at(index);
new_layout = createLayout(dialog->name(), dialog->cpu(), false, default_layout.name);
break;
}
case LayoutEditorDialog::BLANK_LAYOUT:
{
new_layout = createLayout(dialog->name(), dialog->cpu(), false);
break;
}
case LayoutEditorDialog::CLONE_LAYOUT:
{
if (m_current_layout == DockLayout::INVALID_INDEX)
break;
DockLayout::Index old_layout = m_current_layout;
// Freeze the current layout so we can copy the geometry.
switchToLayout(DockLayout::INVALID_INDEX);
new_layout = createLayout(dialog->name(), dialog->cpu(), false, m_layouts.at(old_layout));
break;
}
}
auto name_validator = [this](const QString& name) {
return !hasNameConflict(name, DockLayout::INVALID_INDEX);
};
bool can_clone_current_layout = m_current_layout != DockLayout::INVALID_INDEX;
QPointer<LayoutEditorDialog> dialog = new LayoutEditorDialog(
name_validator, can_clone_current_layout, g_debugger_window);
if (dialog->exec() == QDialog::Accepted && name_validator(dialog->name()))
if (new_layout != DockLayout::INVALID_INDEX)
{
DockLayout::Index new_layout = DockLayout::INVALID_INDEX;
const auto [mode, index] = dialog->initialState();
switch (mode)
{
case LayoutEditorDialog::DEFAULT_LAYOUT:
{
const DockTables::DefaultDockLayout& default_layout = DockTables::DEFAULT_DOCK_LAYOUTS.at(index);
new_layout = createLayout(dialog->name(), dialog->cpu(), false, default_layout.name);
break;
}
case LayoutEditorDialog::BLANK_LAYOUT:
{
new_layout = createLayout(dialog->name(), dialog->cpu(), false);
break;
}
case LayoutEditorDialog::CLONE_LAYOUT:
{
if (m_current_layout == DockLayout::INVALID_INDEX)
return;
DockLayout::Index old_layout = m_current_layout;
// Freeze the current layout so we can copy the geometry.
switchToLayout(DockLayout::INVALID_INDEX);
new_layout = createLayout(dialog->name(), dialog->cpu(), false, m_layouts.at(old_layout));
break;
}
}
updateLayoutSwitcher();
switchToLayout(new_layout);
}
delete dialog.get();
}
else
{
DockLayout::Index layout_index = static_cast<DockLayout::Index>(index);
if (layout_index < 0 || layout_index >= m_layouts.size())
return;
switchToLayout(layout_index);
m_current_tab_index = index;
}
delete dialog.get();
}
void DockManager::layoutSwitcherTabMoved(int from, int to)
void DockManager::openLayoutSwitcherContextMenu(const QPoint& pos, QTabBar* layout_switcher)
{
DockLayout::Index from_index = static_cast<DockLayout::Index>(from);
DockLayout::Index to_index = static_cast<DockLayout::Index>(to);
DockLayout::Index layout_index = static_cast<DockLayout::Index>(layout_switcher->tabAt(pos));
if (layout_index >= m_layouts.size())
return;
DockLayout& layout = m_layouts[layout_index];
QMenu* menu = new QMenu(layout_switcher);
menu->setAttribute(Qt::WA_DeleteOnClose);
QAction* edit_action = menu->addAction(tr("Edit Layout"));
connect(edit_action, &QAction::triggered, [this, layout_index]() {
editLayoutClicked(layout_index);
});
QAction* reset_action = menu->addAction(tr("Reset Layout"));
reset_action->setEnabled(layout.canReset());
reset_action->connect(reset_action, &QAction::triggered, [this, layout_index]() {
resetLayoutClicked(layout_index);
});
QAction* delete_action = menu->addAction(tr("Delete Layout"));
connect(delete_action, &QAction::triggered, [this, layout_index]() {
deleteLayoutClicked(layout_index);
});
menu->popup(layout_switcher->mapToGlobal(pos));
}
void DockManager::editLayoutClicked(DockLayout::Index layout_index)
{
if (layout_index >= m_layouts.size())
return;
DockLayout& layout = m_layouts[layout_index];
auto name_validator = [this, layout_index](const QString& name) {
return !hasNameConflict(name, layout_index);
};
QPointer<LayoutEditorDialog> dialog = new LayoutEditorDialog(
layout.name(), layout.cpu(), name_validator, g_debugger_window);
if (dialog->exec() != QDialog::Accepted || !name_validator(dialog->name()))
return;
layout.setName(dialog->name());
layout.setCpu(dialog->cpu());
layout.save(layout_index);
delete dialog.get();
updateLayoutSwitcher();
}
void DockManager::resetLayoutClicked(DockLayout::Index layout_index)
{
if (layout_index >= m_layouts.size())
return;
DockLayout& layout = m_layouts[layout_index];
if (!layout.canReset())
return;
QString text = tr("Are you sure you want to reset layout '%1'?").arg(layout.name());
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
return;
bool current_layout = layout_index == m_current_layout;
if (current_layout)
switchToLayout(DockLayout::INVALID_INDEX);
layout.reset();
layout.save(layout_index);
if (current_layout)
switchToLayout(layout_index);
}
void DockManager::deleteLayoutClicked(DockLayout::Index layout_index)
{
if (layout_index >= m_layouts.size())
return;
DockLayout& layout = m_layouts[layout_index];
QString text = tr("Are you sure you want to delete layout '%1'?").arg(layout.name());
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
return;
deleteLayout(layout_index);
updateLayoutSwitcher();
}
void DockManager::layoutSwitcherTabMoved(DockLayout::Index from_index, DockLayout::Index to_index)
{
if (from_index >= m_layouts.size() || to_index >= m_layouts.size())
{
// This happens when the user tries to move a layout to the right of the
@@ -660,135 +681,6 @@ void DockManager::layoutSwitcherTabMoved(int from, int to)
m_current_layout = from_index;
}
void DockManager::layoutSwitcherContextMenu(QPoint pos)
{
DockLayout::Index layout_index = static_cast<DockLayout::Index>(m_switcher->tabAt(pos));
if (layout_index >= m_layouts.size())
return;
DockLayout& layout = m_layouts[layout_index];
QMenu* menu = new QMenu(m_switcher);
menu->setAttribute(Qt::WA_DeleteOnClose);
QAction* edit_action = menu->addAction(tr("Edit Layout"));
connect(edit_action, &QAction::triggered, [this, layout_index]() {
if (layout_index >= m_layouts.size())
return;
DockLayout& layout = m_layouts[layout_index];
auto name_validator = [this, layout_index](const QString& name) {
return !hasNameConflict(name, layout_index);
};
QPointer<LayoutEditorDialog> dialog = new LayoutEditorDialog(
layout.name(), layout.cpu(), name_validator, g_debugger_window);
if (dialog->exec() != QDialog::Accepted || !name_validator(dialog->name()))
return;
layout.setName(dialog->name());
layout.setCpu(dialog->cpu());
layout.save(layout_index);
delete dialog.get();
updateLayoutSwitcher();
});
QAction* reset_action = menu->addAction(tr("Reset Layout"));
reset_action->setEnabled(layout.canReset());
reset_action->connect(reset_action, &QAction::triggered, [this, layout_index]() {
if (layout_index >= m_layouts.size())
return;
DockLayout& layout = m_layouts[layout_index];
if (!layout.canReset())
return;
QString text = tr("Are you sure you want to reset layout '%1'?").arg(layout.name());
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
return;
bool current_layout = layout_index == m_current_layout;
if (current_layout)
switchToLayout(DockLayout::INVALID_INDEX);
layout.reset();
layout.save(layout_index);
if (current_layout)
switchToLayout(layout_index);
});
QAction* delete_action = menu->addAction(tr("Delete Layout"));
connect(delete_action, &QAction::triggered, [this, layout_index]() {
if (layout_index >= m_layouts.size())
return;
DockLayout& layout = m_layouts[layout_index];
QString text = tr("Are you sure you want to delete layout '%1'?").arg(layout.name());
if (QMessageBox::question(g_debugger_window, tr("Confirmation"), text) != QMessageBox::Yes)
return;
deleteLayout(layout_index);
updateLayoutSwitcher();
});
menu->popup(m_switcher->mapToGlobal(pos));
}
void DockManager::layoutSwitcherStartBlink()
{
if (!m_switcher)
return;
layoutSwitcherStopBlink();
if (m_current_layout == DockLayout::INVALID_INDEX)
return;
m_blink_tab = m_current_layout;
m_blink_stage = 0;
m_blink_timer->start(500);
layoutSwitcherUpdateBlink();
}
void DockManager::layoutSwitcherUpdateBlink()
{
if (!m_switcher)
return;
if (m_blink_tab < m_switcher->count())
{
if (m_blink_stage % 2 == 0)
m_switcher->setTabTextColor(m_blink_tab, Qt::red);
else
m_switcher->setTabTextColor(m_blink_tab, m_switcher->palette().text().color());
}
m_blink_stage++;
if (m_blink_stage > 7)
m_blink_timer->stop();
}
void DockManager::layoutSwitcherStopBlink()
{
if (m_blink_timer->isActive())
{
if (m_blink_tab < m_switcher->count())
m_switcher->setTabTextColor(m_blink_tab, m_switcher->palette().text().color());
m_blink_timer->stop();
}
}
bool DockManager::hasNameConflict(const QString& name, DockLayout::Index layout_index)
{
std::string safe_name = Path::SanitizeFileName(name.toStdString());
@@ -867,11 +759,23 @@ void DockManager::switchToDebuggerWidget(DebuggerWidget* widget)
}
}
void DockManager::updateStyleSheets()
void DockManager::updateTheme()
{
if (m_menu_bar)
m_menu_bar->updateTheme();
for (DockLayout& layout : m_layouts)
for (const auto& [unique_name, widget] : layout.debuggerWidgets())
widget->updateStyleSheet();
// KDDockWidgets::QtWidgets::TabBar sets its own style to a subclass of
// QProxyStyle in its constructor, so we need to update that here.
for (KDDockWidgets::Core::Group* group : KDDockWidgets::DockRegistry::self()->groups())
{
auto tab_bar = static_cast<KDDockWidgets::QtWidgets::TabBar*>(group->tabBar()->view());
if (QProxyStyle* style = qobject_cast<QProxyStyle*>(tab_bar->style()))
style->setBaseStyle(QStyleFactory::create(qApp->style()->name()));
}
}
bool DockManager::isLayoutLocked()
@@ -879,23 +783,17 @@ bool DockManager::isLayoutLocked()
return m_layout_locked;
}
void DockManager::setLayoutLocked(bool locked, QPushButton* lock_layout_toggle, bool write_back)
void DockManager::setLayoutLockedAndSaveSetting(bool locked)
{
setLayoutLocked(locked, true);
}
void DockManager::setLayoutLocked(bool locked, bool save_setting)
{
m_layout_locked = locked;
if (lock_layout_toggle)
{
if (m_layout_locked)
{
lock_layout_toggle->setText(tr("Layout Locked"));
lock_layout_toggle->setIcon(QIcon::fromTheme(QString::fromUtf8("padlock-lock")));
}
else
{
lock_layout_toggle->setText(tr("Layout Unlocked"));
lock_layout_toggle->setIcon(QIcon::fromTheme(QString::fromUtf8("padlock-unlock")));
}
}
if (m_menu_bar)
m_menu_bar->onLockStateChanged(locked);
updateToolBarLockState();
@@ -909,7 +807,7 @@ void DockManager::setLayoutLocked(bool locked, QPushButton* lock_layout_toggle,
stack->tabBar()->setTabText(0, stack->tabBar()->tabText(0));
}
if (write_back)
if (save_setting)
{
Host::SetBaseBoolSettingValue("Debugger/UserInterface", "LayoutLocked", m_layout_locked);
Host::CommitBaseSettingChanges();

View File

@@ -4,6 +4,7 @@
#pragma once
#include "Debugger/Docking/DockLayout.h"
#include "Debugger/Docking/DockMenuBar.h"
#include <kddockwidgets/MainWindow.h>
#include <kddockwidgets/DockWidget.h>
@@ -68,14 +69,14 @@ public:
void createToolsMenu(QMenu* menu);
void createWindowsMenu(QMenu* menu);
QWidget* createLayoutSwitcher(QWidget* menu_bar);
QWidget* createMenuBar(QWidget* original_menu_bar);
void updateLayoutSwitcher();
void layoutSwitcherTabChanged(int index);
void layoutSwitcherTabMoved(int from, int to);
void layoutSwitcherContextMenu(QPoint pos);
void layoutSwitcherStartBlink();
void layoutSwitcherUpdateBlink();
void layoutSwitcherStopBlink();
void newLayoutClicked();
void openLayoutSwitcherContextMenu(const QPoint& pos, QTabBar* layout_switcher);
void editLayoutClicked(DockLayout::Index layout_index);
void resetLayoutClicked(DockLayout::Index layout_index);
void deleteLayoutClicked(DockLayout::Index layout_index);
void layoutSwitcherTabMoved(DockLayout::Index from_index, DockLayout::Index to_index);
bool hasNameConflict(const QString& name, DockLayout::Index layout_index);
@@ -88,10 +89,11 @@ public:
void setPrimaryDebuggerWidget(DebuggerWidget* widget, bool is_primary);
void switchToDebuggerWidget(DebuggerWidget* widget);
void updateStyleSheets();
void updateTheme();
bool isLayoutLocked();
void setLayoutLocked(bool locked, QPushButton* lock_layout_toggle, bool write_back);
void setLayoutLockedAndSaveSetting(bool locked);
void setLayoutLocked(bool locked, bool save_setting);
void updateToolBarLockState();
std::optional<BreakPointCpu> cpu();
@@ -103,16 +105,7 @@ private:
std::vector<DockLayout> m_layouts;
DockLayout::Index m_current_layout = DockLayout::INVALID_INDEX;
QTabBar* m_switcher = nullptr;
int m_plus_tab_index = -1;
int m_current_tab_index = -1;
bool m_ignore_current_tab_changed = false;
QMetaObject::Connection m_tab_connection;
DockMenuBar* m_menu_bar = nullptr;
bool m_layout_locked = true;
QTimer* m_blink_timer = nullptr;
int m_blink_tab = 0;
int m_blink_stage = 0;
};

View File

@@ -0,0 +1,342 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#include "DockMenuBar.h"
#include <QtCore/QTimer>
#include <QtGui/QPainter>
#include <QtGui/QPaintEvent>
#include <QtWidgets/QBoxLayout>
#include <QtWidgets/QStyleFactory>
#include <QtWidgets/QStyleOption>
static const int OUTER_MENU_MARGIN = 2;
static const int INNER_MENU_MARGIN = 4;
DockMenuBar::DockMenuBar(QWidget* original_menu_bar, QWidget* parent)
: QWidget(parent)
, m_original_menu_bar(original_menu_bar)
{
QHBoxLayout* layout = new QHBoxLayout;
layout->setContentsMargins(0, OUTER_MENU_MARGIN, OUTER_MENU_MARGIN, 0);
setLayout(layout);
QWidget* menu_wrapper = new QWidget;
menu_wrapper->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
layout->addWidget(menu_wrapper);
QHBoxLayout* menu_layout = new QHBoxLayout;
menu_layout->setContentsMargins(0, INNER_MENU_MARGIN, 0, INNER_MENU_MARGIN);
menu_wrapper->setLayout(menu_layout);
menu_layout->addWidget(original_menu_bar);
m_layout_switcher = new QTabBar;
m_layout_switcher->setContentsMargins(0, 0, 0, 0);
m_layout_switcher->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
m_layout_switcher->setContextMenuPolicy(Qt::CustomContextMenu);
m_layout_switcher->setDrawBase(false);
m_layout_switcher->setExpanding(false);
m_layout_switcher->setMovable(true);
layout->addWidget(m_layout_switcher);
connect(m_layout_switcher, &QTabBar::tabMoved, this, [this](int from, int to) {
DockLayout::Index from_index = static_cast<DockLayout::Index>(from);
DockLayout::Index to_index = static_cast<DockLayout::Index>(to);
emit layoutMoved(from_index, to_index);
});
connect(m_layout_switcher, &QTabBar::customContextMenuRequested, this, [this](const QPoint& pos) {
emit layoutSwitcherContextMenuRequested(pos, m_layout_switcher);
});
m_blink_timer = new QTimer(this);
connect(m_blink_timer, &QTimer::timeout, this, &DockMenuBar::updateBlink);
m_layout_locked_toggle = new QPushButton;
m_layout_locked_toggle->setCheckable(true);
connect(m_layout_locked_toggle, &QPushButton::clicked, this, [this](bool checked) {
if (m_ignore_lock_state_changed)
return;
emit lockButtonToggled(checked);
});
layout->addWidget(m_layout_locked_toggle);
updateTheme();
}
void DockMenuBar::updateTheme()
{
DockMenuBarStyle* style = new DockMenuBarStyle(m_layout_switcher);
m_original_menu_bar->setStyle(style);
m_layout_switcher->setStyle(style);
m_layout_locked_toggle->setStyle(style);
delete m_style;
m_style = style;
}
void DockMenuBar::updateLayoutSwitcher(DockLayout::Index current_index, const std::vector<DockLayout>& layouts)
{
disconnect(m_tab_connection);
for (int i = m_layout_switcher->count(); i > 0; i--)
m_layout_switcher->removeTab(i - 1);
for (const DockLayout& layout : layouts)
{
const char* cpu_name = DebugInterface::cpuName(layout.cpu());
QString tab_name = QString("%1 (%2)").arg(layout.name()).arg(cpu_name);
m_layout_switcher->addTab(tab_name);
}
m_plus_tab_index = m_layout_switcher->addTab("+");
m_current_tab_index = current_index;
if (current_index != DockLayout::INVALID_INDEX)
m_layout_switcher->setCurrentIndex(current_index);
else
m_layout_switcher->setCurrentIndex(m_plus_tab_index);
// If we don't have any layouts, the currently selected tab will never be
// changed, so we respond to all clicks instead.
if (m_plus_tab_index > 0)
m_tab_connection = connect(m_layout_switcher, &QTabBar::currentChanged, this, &DockMenuBar::tabChanged);
else
m_tab_connection = connect(m_layout_switcher, &QTabBar::tabBarClicked, this, &DockMenuBar::tabChanged);
stopBlink();
}
void DockMenuBar::onCurrentLayoutChanged(DockLayout::Index current_index)
{
m_ignore_current_tab_changed = true;
if (current_index != DockLayout::INVALID_INDEX)
m_layout_switcher->setCurrentIndex(current_index);
else
m_layout_switcher->setCurrentIndex(m_plus_tab_index);
m_ignore_current_tab_changed = false;
}
void DockMenuBar::onLockStateChanged(bool layout_locked)
{
m_ignore_lock_state_changed = true;
m_layout_locked_toggle->setChecked(layout_locked);
if (layout_locked)
{
m_layout_locked_toggle->setText(tr("Layout Locked"));
m_layout_locked_toggle->setIcon(QIcon::fromTheme(QString::fromUtf8("padlock-lock")));
}
else
{
m_layout_locked_toggle->setText(tr("Layout Unlocked"));
m_layout_locked_toggle->setIcon(QIcon::fromTheme(QString::fromUtf8("padlock-unlock")));
}
m_ignore_lock_state_changed = false;
}
void DockMenuBar::startBlink(DockLayout::Index layout_index)
{
stopBlink();
if (layout_index == DockLayout::INVALID_INDEX)
return;
m_blink_tab = static_cast<int>(layout_index);
m_blink_stage = 0;
m_blink_timer->start(500);
updateBlink();
}
void DockMenuBar::updateBlink()
{
if (m_blink_tab < m_layout_switcher->count())
{
if (m_blink_stage % 2 == 0)
m_layout_switcher->setTabTextColor(m_blink_tab, Qt::red);
else
m_layout_switcher->setTabTextColor(m_blink_tab, m_layout_switcher->palette().text().color());
}
m_blink_stage++;
if (m_blink_stage > 7)
m_blink_timer->stop();
}
void DockMenuBar::stopBlink()
{
if (m_blink_timer->isActive())
{
if (m_blink_tab < m_layout_switcher->count())
m_layout_switcher->setTabTextColor(m_blink_tab, m_layout_switcher->palette().text().color());
m_blink_timer->stop();
}
}
int DockMenuBar::innerHeight() const
{
return m_original_menu_bar->sizeHint().height() + INNER_MENU_MARGIN * 2;
}
void DockMenuBar::paintEvent(QPaintEvent* event)
{
QPainter painter(this);
// This fixes the background colour of the menu bar when using the Windows
// Vista style.
QStyleOptionMenuItem menu_option;
menu_option.palette = palette();
menu_option.state = QStyle::State_None;
menu_option.menuItemType = QStyleOptionMenuItem::EmptyArea;
menu_option.checkType = QStyleOptionMenuItem::NotCheckable;
menu_option.rect = rect();
menu_option.menuRect = rect();
style()->drawControl(QStyle::CE_MenuBarEmptyArea, &menu_option, &painter, this);
}
void DockMenuBar::tabChanged(int index)
{
// Prevent recursion.
if (m_ignore_current_tab_changed)
return;
if (index < m_plus_tab_index)
{
DockLayout::Index layout_index = static_cast<DockLayout::Index>(index);
emit currentLayoutChanged(layout_index);
}
else if (index == m_plus_tab_index)
{
emit newButtonClicked();
}
}
// *****************************************************************************
DockMenuBarStyle::DockMenuBarStyle(QObject* parent)
: QProxyStyle(QStyleFactory::create(qApp->style()->name()))
{
setParent(parent);
}
void DockMenuBarStyle::drawControl(
ControlElement element,
const QStyleOption* option,
QPainter* painter,
const QWidget* widget) const
{
switch (element)
{
case CE_MenuBarItem:
{
const QStyleOptionMenuItem* opt = qstyleoption_cast<const QStyleOptionMenuItem*>(option);
if (!opt)
break;
QWidget* menu_wrapper = widget->parentWidget();
if (!menu_wrapper)
break;
const DockMenuBar* menu_bar = qobject_cast<const DockMenuBar*>(menu_wrapper->parentWidget());
if (!menu_bar)
break;
if (baseStyle()->name() != "fusion")
break;
// This mirrors a check in QFusionStyle::drawControl. If act is
// false, QFusionStyle will try to draw a border along the bottom.
bool act = opt->state & State_Selected && opt->state & State_Sunken;
if (act)
break;
// Extend the menu item to the bottom of the menu bar to fix the
// position in which it draws its bottom border. We also need to
// extend it up by the same amount so that the text isn't moved.
QStyleOptionMenuItem menu_opt = *opt;
int difference = (menu_bar->innerHeight() - option->rect.top()) - menu_opt.rect.height();
menu_opt.rect.adjust(0, -difference, 0, difference);
QProxyStyle::drawControl(element, &menu_opt, painter, widget);
return;
}
case CE_TabBarTab:
{
QProxyStyle::drawControl(element, option, painter, widget);
// Draw a slick-looking highlight under the currently selected tab.
if (baseStyle()->name() == "fusion")
{
const QStyleOptionTab* tab = qstyleoption_cast<const QStyleOptionTab*>(option);
if (tab && (tab->state & State_Selected))
{
painter->setPen(tab->palette.highlight().color());
painter->drawLine(tab->rect.bottomLeft(), tab->rect.bottomRight());
}
}
return;
}
case CE_MenuBarEmptyArea:
{
// Prevent it from drawing a border in the wrong position.
return;
}
default:
{
break;
}
}
QProxyStyle::drawControl(element, option, painter, widget);
}
QSize DockMenuBarStyle::sizeFromContents(
QStyle::ContentsType type, const QStyleOption* option, const QSize& contents_size, const QWidget* widget) const
{
QSize size = QProxyStyle::sizeFromContents(type, option, contents_size, widget);
#ifdef Q_OS_WIN32
// Adjust the sizes of the layout switcher tabs depending on the theme.
if (type == CT_TabBarTab)
{
const QStyleOptionTab* opt = qstyleoption_cast<const QStyleOptionTab*>(option);
if (!opt)
return size;
const QTabBar* tab_bar = qobject_cast<const QTabBar*>(widget);
if (!tab_bar)
return size;
const DockMenuBar* menu_bar = qobject_cast<const DockMenuBar*>(tab_bar->parentWidget());
if (!menu_bar)
return size;
if (baseStyle()->name() == "fusion" || baseStyle()->name() == "windowsvista")
{
// Make sure the tab extends to the bottom of the widget.
size.setHeight(menu_bar->innerHeight() - opt->rect.top());
}
else if (baseStyle()->name() == "windows11")
{
// Adjust the size of the tab such that it is vertically centred.
size.setHeight(menu_bar->innerHeight() - opt->rect.top() * 2 - OUTER_MENU_MARGIN);
// Make the plus button square.
if (opt->tabIndex + 1 == tab_bar->count())
size.setWidth(size.height());
}
}
#endif
return size;
}

View File

@@ -0,0 +1,93 @@
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#pragma once
#include "Debugger/Docking/DockLayout.h"
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QProxyStyle>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QTabBar>
#include <QtWidgets/QWidget>
class DockMenuBarStyle;
// The widget that replaces the normal menu bar. This contains the original menu
// bar, the layout switcher and the layout locked/unlocked toggle button.
class DockMenuBar : public QWidget
{
Q_OBJECT
public:
DockMenuBar(QWidget* original_menu_bar, QWidget* parent = nullptr);
void updateLayoutSwitcher(DockLayout::Index current_index, const std::vector<DockLayout>& layouts);
void updateTheme();
// Notify the menu bar that a new layout has been selected.
void onCurrentLayoutChanged(DockLayout::Index current_index);
// Notify the menu bar that the layout has been locked/unlocked.
void onLockStateChanged(bool layout_locked);
void startBlink(DockLayout::Index layout_index);
void updateBlink();
void stopBlink();
int innerHeight() const;
Q_SIGNALS:
void currentLayoutChanged(DockLayout::Index layout_index);
void newButtonClicked();
void layoutMoved(DockLayout::Index from_index, DockLayout::Index to_index);
void lockButtonToggled(bool locked);
void layoutSwitcherContextMenuRequested(const QPoint& pos, QTabBar* layout_switcher);
protected:
void paintEvent(QPaintEvent* event) override;
private:
void tabChanged(int index);
QWidget* m_original_menu_bar;
QTabBar* m_layout_switcher;
QMetaObject::Connection m_tab_connection;
int m_plus_tab_index = -1;
int m_current_tab_index = -1;
bool m_ignore_current_tab_changed = false;
QTimer* m_blink_timer = nullptr;
int m_blink_tab = 0;
int m_blink_stage = 0;
QPushButton* m_layout_locked_toggle;
bool m_ignore_lock_state_changed = false;
DockMenuBarStyle* m_style = nullptr;
};
// Fixes some theming issues relating to the menu bar, the layout switcher and
// the layout locked/unlocked toggle button.
class DockMenuBarStyle : public QProxyStyle
{
Q_OBJECT
public:
DockMenuBarStyle(QObject* parent = nullptr);
void drawControl(
ControlElement element,
const QStyleOption* option,
QPainter* painter,
const QWidget* widget = nullptr) const override;
QSize sizeFromContents(
QStyle::ContentsType type,
const QStyleOption* option,
const QSize& contents_size,
const QWidget* widget = nullptr) const override;
};

View File

@@ -20,6 +20,7 @@
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QMenu>
#include <QtWidgets/QStyleFactory>
KDDockWidgets::Core::View* DockViewFactory::createDockWidget(
const QString& unique_name,
@@ -143,6 +144,14 @@ DockTabBar::DockTabBar(KDDockWidgets::Core::TabBar* controller, QWidget* parent)
{
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &DockTabBar::customContextMenuRequested, this, &DockTabBar::openContextMenu);
// The constructor of KDDockWidgets::QtWidgets::TabBar makes a QProxyStyle
// that ends up taking ownerhsip of the style for the entire application!
if (QProxyStyle* proxy_style = qobject_cast<QProxyStyle*>(style()))
{
proxy_style->baseStyle()->setParent(qApp);
proxy_style->setBaseStyle(QStyleFactory::create(qApp->style()->name()));
}
}
void DockTabBar::openContextMenu(QPoint pos)

View File

@@ -151,6 +151,10 @@ void MainWindow::initialize()
ctx->updateTheme(); // Qt won't notice the style change without us touching the palette in some way
});
});
// The cocoa backing isn't initialized yet, delay this until stuff is set up with a `RunOnUIThread` call
QtHost::RunOnUIThread([this]{
CocoaTools::MarkHelpMenu(m_ui.menuHelp->toNSMenu());
});
#endif
m_ui.setupUi(this);
setupAdditionalUi();
@@ -1781,7 +1785,7 @@ void MainWindow::updateTheme()
reloadThemeSpecificImages();
if (g_debugger_window)
g_debugger_window->updateStyleSheets();
g_debugger_window->updateTheme();
}
void MainWindow::reloadThemeSpecificImages()

View File

@@ -19,10 +19,14 @@ DebugAnalysisSettingsWidget::DebugAnalysisSettingsWidget(QWidget* parent)
setupSymbolSourceGrid();
m_ui.importFromElf->setChecked(Host::GetBoolSettingValue("Debugger/Analysis", "ImportSymbolsFromELF", true));
m_ui.importSymFileFromDefaultLocation->setChecked(Host::GetBoolSettingValue("Debugger/Analysis", "ImportSymFileFromDefaultLocation", true));
m_ui.demangleSymbols->setChecked(Host::GetBoolSettingValue("Debugger/Analysis", "DemangleSymbols", true));
m_ui.demangleParameters->setChecked(Host::GetBoolSettingValue("Debugger/Analysis", "DemangleParameters", true));
m_ui.importFromElf->setChecked(
Host::GetBoolSettingValue("Debugger/Analysis", "ImportSymbolsFromELF", true));
m_ui.importSymFileFromDefaultLocation->setChecked(
Host::GetBoolSettingValue("Debugger/Analysis", "ImportSymFileFromDefaultLocation", true));
m_ui.demangleSymbols->setChecked(
Host::GetBoolSettingValue("Debugger/Analysis", "DemangleSymbols", true));
m_ui.demangleParameters->setChecked(
Host::GetBoolSettingValue("Debugger/Analysis", "DemangleParameters", true));
setupSymbolFileList();
@@ -36,15 +40,22 @@ DebugAnalysisSettingsWidget::DebugAnalysisSettingsWidget(QWidget* parent)
m_ui.functionScanMode->setCurrentIndex(i);
}
m_ui.customAddressRange->setChecked(Host::GetBoolSettingValue("Debugger/Analysis", "CustomFunctionScanRange", false));
m_ui.addressRangeStart->setText(QString::fromStdString(Host::GetStringSettingValue("Debugger/Analysis", "FunctionScanStartAddress", "")));
m_ui.addressRangeEnd->setText(QString::fromStdString(Host::GetStringSettingValue("Debugger/Analysis", "FunctionScanEndAddress", "")));
m_ui.customAddressRange->setChecked(
Host::GetBoolSettingValue("Debugger/Analysis", "CustomFunctionScanRange", false));
m_ui.addressRangeStart->setText(QString::fromStdString(
Host::GetStringSettingValue("Debugger/Analysis", "FunctionScanStartAddress", "")));
m_ui.addressRangeEnd->setText(QString::fromStdString(
Host::GetStringSettingValue("Debugger/Analysis", "FunctionScanEndAddress", "")));
m_ui.grayOutOverwrittenFunctions->setChecked(Host::GetBoolSettingValue("Debugger/Analysis", "GenerateFunctionHashes", true));
m_ui.grayOutOverwrittenFunctions->setChecked(
Host::GetBoolSettingValue("Debugger/Analysis", "GenerateFunctionHashes", true));
connect(m_ui.automaticallyClearSymbols, &QCheckBox::checkStateChanged, this, &DebugAnalysisSettingsWidget::updateEnabledStates);
connect(m_ui.demangleSymbols, &QCheckBox::checkStateChanged, this, &DebugAnalysisSettingsWidget::updateEnabledStates);
connect(m_ui.customAddressRange, &QCheckBox::checkStateChanged, this, &DebugAnalysisSettingsWidget::updateEnabledStates);
connect(m_ui.automaticallyClearSymbols, &QCheckBox::checkStateChanged,
this, &DebugAnalysisSettingsWidget::updateEnabledStates);
connect(m_ui.demangleSymbols, &QCheckBox::checkStateChanged,
this, &DebugAnalysisSettingsWidget::updateEnabledStates);
connect(m_ui.customAddressRange, &QCheckBox::checkStateChanged,
this, &DebugAnalysisSettingsWidget::updateEnabledStates);
updateEnabledStates();
}
@@ -122,8 +133,16 @@ DebugAnalysisSettingsWidget::DebugAnalysisSettingsWidget(SettingsWindow* dialog,
{
SettingWidgetBinder::BindWidgetToBoolSetting(
sif, m_ui.customAddressRange, "Debugger/Analysis", "CustomFunctionScanRange", false);
connect(m_ui.addressRangeStart, &QLineEdit::textChanged, this, &DebugAnalysisSettingsWidget::functionScanRangeChanged);
connect(m_ui.addressRangeEnd, &QLineEdit::textChanged, this, &DebugAnalysisSettingsWidget::functionScanRangeChanged);
m_ui.addressRangeStart->setText(QString::fromStdString(
getStringSettingValue("Debugger/Analysis", "FunctionScanStartAddress", "")));
m_ui.addressRangeEnd->setText(QString::fromStdString(
getStringSettingValue("Debugger/Analysis", "FunctionScanEndAddress", "")));
connect(m_ui.addressRangeStart, &QLineEdit::textChanged,
this, &DebugAnalysisSettingsWidget::saveFunctionScanRange);
connect(m_ui.addressRangeEnd, &QLineEdit::textChanged,
this, &DebugAnalysisSettingsWidget::saveFunctionScanRange);
m_dialog->registerWidgetHelp(m_ui.customAddressRange, tr("Custom Address Range"), tr("Unchecked"),
tr("Whether to look for functions from the address range specified (Checked), or from the ELF segment "
@@ -302,6 +321,9 @@ void DebugAnalysisSettingsWidget::saveSymbolSources()
i++;
}
QtHost::SaveGameSettings(sif, true);
g_emu_thread->reloadGameSettings();
}
void DebugAnalysisSettingsWidget::setupSymbolFileList()
@@ -445,7 +467,7 @@ void DebugAnalysisSettingsWidget::saveSymbolFiles()
g_emu_thread->reloadGameSettings();
}
void DebugAnalysisSettingsWidget::functionScanRangeChanged()
void DebugAnalysisSettingsWidget::saveFunctionScanRange()
{
if (!m_dialog)
return;
@@ -457,13 +479,11 @@ void DebugAnalysisSettingsWidget::functionScanRangeChanged()
QString start_address = m_ui.addressRangeStart->text();
QString end_address = m_ui.addressRangeEnd->text();
bool ok;
sif->SetStringValue("Debugger/Analysis", "FunctionScanStartAddress", start_address.toStdString().c_str());
sif->SetStringValue("Debugger/Analysis", "FunctionScanEndAddress", end_address.toStdString().c_str());
if (start_address.toUInt(&ok, 16), ok)
sif->SetStringValue("Debugger/Analysis", "FunctionScanStartAddress", start_address.toStdString().c_str());
if (end_address.toUInt(&ok, 16), ok)
sif->SetStringValue("Debugger/Analysis", "FunctionScanEndAddress", end_address.toStdString().c_str());
QtHost::SaveGameSettings(sif, true);
g_emu_thread->reloadGameSettings();
}
void DebugAnalysisSettingsWidget::updateEnabledStates()

View File

@@ -38,7 +38,7 @@ protected:
void removeSymbolFile();
void saveSymbolFiles();
void functionScanRangeChanged();
void saveFunctionScanRange();
void updateEnabledStates();

File diff suppressed because it is too large Load Diff

View File

@@ -126,6 +126,7 @@
<ClCompile Include="Debugger\Breakpoints\BreakpointWidget.cpp" />
<ClCompile Include="Debugger\Docking\DockLayout.cpp" />
<ClCompile Include="Debugger\Docking\DockManager.cpp" />
<ClCompile Include="Debugger\Docking\DockMenuBar.cpp" />
<ClCompile Include="Debugger\Docking\DockTables.cpp" />
<ClCompile Include="Debugger\Docking\DockUtils.cpp" />
<ClCompile Include="Debugger\Docking\DockViews.cpp" />
@@ -242,6 +243,7 @@
<QtMoc Include="Debugger\Breakpoints\BreakpointWidget.h" />
<QtMoc Include="Debugger\Docking\DockLayout.h" />
<QtMoc Include="Debugger\Docking\DockManager.h" />
<QtMoc Include="Debugger\Docking\DockMenuBar.h" />
<QtMoc Include="Debugger\Docking\DockTables.h" />
<QtMoc Include="Debugger\Docking\DockUtils.h" />
<QtMoc Include="Debugger\Docking\DockViews.h" />
@@ -313,6 +315,7 @@
<ClCompile Include="$(IntDir)Debugger\Breakpoints\moc_BreakpointModel.cpp" />
<ClCompile Include="$(IntDir)Debugger\Breakpoints\moc_BreakpointWidget.cpp" />
<ClCompile Include="$(IntDir)Debugger\Docking\moc_DockManager.cpp" />
<ClCompile Include="$(IntDir)Debugger\Docking\moc_DockMenuBar.cpp" />
<ClCompile Include="$(IntDir)Debugger\Docking\moc_DockViews.cpp" />
<ClCompile Include="$(IntDir)Debugger\Docking\moc_DropIndicators.cpp" />
<ClCompile Include="$(IntDir)Debugger\Docking\moc_LayoutEditorDialog.cpp" />

View File

@@ -22,15 +22,21 @@
<Filter Include="Debugger">
<UniqueIdentifier>{ddb40cc4-9996-4ade-b647-eb549063553c}</UniqueIdentifier>
</Filter>
<Filter Include="Debugger\Models">
<UniqueIdentifier>{f4084ca0-d9d5-4584-b9d2-063db9f67de2}</UniqueIdentifier>
</Filter>
<Filter Include="Translations">
<UniqueIdentifier>{ad04f939-64a0-4039-97aa-a38b8aa46855}</UniqueIdentifier>
</Filter>
<Filter Include="Debugger\SymbolTree">
<UniqueIdentifier>{a622b871-62ae-4b70-b9b2-6ee30ce7fa7a}</UniqueIdentifier>
</Filter>
<Filter Include="Debugger\Breakpoints">
<UniqueIdentifier>{694f359a-dd3c-4e05-b000-684acb0fe0b0}</UniqueIdentifier>
</Filter>
<Filter Include="Debugger\Docking">
<UniqueIdentifier>{669ad4fe-0b5a-4722-946c-9e0742cebbca}</UniqueIdentifier>
</Filter>
<Filter Include="Debugger\Memory">
<UniqueIdentifier>{63790c94-0680-417d-926c-a8b74118f80f}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\pcsx2\windows\PCSX2.rc" />
@@ -302,51 +308,6 @@
<ClCompile Include="Debugger\ThreadWidget.cpp">
<Filter>Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\Breakpoints\BreakpointDialog.cpp">
<Filter>Debugger\Breakpoints</Filter>
</ClCompile>
<ClCompile Include="Debugger\Breakpoints\BreakpointModel.cpp">
<Filter>Debugger\Breakpoints</Filter>
</ClCompile>
<ClCompile Include="Debugger\Breakpoints\BreakpointWidget.cpp">
<Filter>Debugger\Breakpoints</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockLayout.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockManager.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockTables.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockUtils.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockViews.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DropIndicators.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\LayoutEditorDialog.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\NoLayoutsWidget.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Memory\MemorySearchWidget.cpp">
<Filter>Debugger\Memory</Filter>
</ClCompile>
<ClCompile Include="Debugger\Memory\MemoryViewWidget.cpp">
<Filter>Debugger\Memory</Filter>
</ClCompile>
<ClCompile Include="Debugger\Memory\SavedAddressesModel.cpp">
<Filter>Debugger\Memory</Filter>
</ClCompile>
<ClCompile Include="Debugger\Memory\SavedAddressesWidget.cpp">
<Filter>Debugger\Memory</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\moc_AnalysisOptionsDialog.cpp">
<Filter>moc</Filter>
</ClCompile>
@@ -461,6 +422,78 @@
<Filter>Debugger\SymbolTree</Filter>
</ClCompile>
<ClCompile Include="VCRuntimeChecker.cpp" />
<ClCompile Include="Debugger\Breakpoints\BreakpointDialog.cpp">
<Filter>Debugger\Breakpoints</Filter>
</ClCompile>
<ClCompile Include="Debugger\Breakpoints\BreakpointModel.cpp">
<Filter>Debugger\Breakpoints</Filter>
</ClCompile>
<ClCompile Include="Debugger\Breakpoints\BreakpointWidget.cpp">
<Filter>Debugger\Breakpoints</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockLayout.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockManager.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockTables.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockUtils.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockViews.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DropIndicators.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Memory\SavedAddressesModel.cpp">
<Filter>Debugger\Memory</Filter>
</ClCompile>
<ClCompile Include="Debugger\Memory\SavedAddressesWidget.cpp">
<Filter>Debugger\Memory</Filter>
</ClCompile>
<ClCompile Include="Debugger\Memory\MemorySearchWidget.cpp">
<Filter>Debugger\Memory</Filter>
</ClCompile>
<ClCompile Include="Debugger\Memory\MemoryViewWidget.cpp">
<Filter>Debugger\Memory</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\LayoutEditorDialog.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\NoLayoutsWidget.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\SymbolTree\moc_NewSymbolDialogs.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\SymbolTree\moc_SymbolTreeDelegates.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\SymbolTree\moc_SymbolTreeLocation.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\SymbolTree\moc_SymbolTreeModel.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\SymbolTree\moc_SymbolTreeNode.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\SymbolTree\moc_SymbolTreeWidgets.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\SymbolTree\moc_TypeString.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)Debugger\Docking\moc_DockMenuBar.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="Debugger\Docking\DockMenuBar.cpp">
<Filter>Debugger\Docking</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
@@ -483,27 +516,6 @@
<ClInclude Include="Debugger\DebuggerSettingsManager.h">
<Filter>Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\SymbolTree\NewSymbolDialogs.h">
<Filter>Debugger\SymbolTree</Filter>
</ClInclude>
<ClInclude Include="Debugger\SymbolTree\SymbolTreeDelegates.h">
<Filter>Debugger\SymbolTree</Filter>
</ClInclude>
<ClInclude Include="Debugger\SymbolTree\SymbolTreeLocation.h">
<Filter>Debugger\SymbolTree</Filter>
</ClInclude>
<ClInclude Include="Debugger\SymbolTree\SymbolTreeModel.h">
<Filter>Debugger\SymbolTree</Filter>
</ClInclude>
<ClInclude Include="Debugger\SymbolTree\SymbolTreeNode.h">
<Filter>Debugger\SymbolTree</Filter>
</ClInclude>
<ClInclude Include="Debugger\SymbolTree\SymbolTreeWidgets.h">
<Filter>Debugger\SymbolTree</Filter>
</ClInclude>
<ClInclude Include="Debugger\SymbolTree\TypeString.h">
<Filter>Debugger\SymbolTree</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<QtMoc Include="MainWindow.h" />
@@ -640,6 +652,16 @@
<QtMoc Include="Debugger\ThreadWidget.h">
<Filter>Debugger</Filter>
</QtMoc>
<QtMoc Include="ColorPickerButton.h" />
<QtMoc Include="SetupWizardDialog.h" />
<QtMoc Include="Settings\GameCheatSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="Settings\GamePatchSettingsWidget.h">
<Filter>Settings</Filter>
</QtMoc>
<QtMoc Include="LogWindow.h" />
<QtMoc Include="Debugger\SymbolTree\TypeString.h" />
<QtMoc Include="Debugger\Breakpoints\BreakpointDialog.h">
<Filter>Debugger\Breakpoints</Filter>
</QtMoc>
@@ -667,17 +689,20 @@
<QtMoc Include="Debugger\Docking\DropIndicators.h">
<Filter>Debugger\Docking</Filter>
</QtMoc>
<QtMoc Include="Debugger\Docking\LayoutEditorDialog.h">
<Filter>Debugger\Docking</Filter>
<QtMoc Include="Debugger\SymbolTree\SymbolTreeWidgets.h">
<Filter>Debugger\SymbolTree</Filter>
</QtMoc>
<QtMoc Include="Debugger\Docking\NoLayoutsWidget.h">
<Filter>Debugger\Docking</Filter>
<QtMoc Include="Debugger\SymbolTree\SymbolTreeDelegates.h">
<Filter>Debugger\SymbolTree</Filter>
</QtMoc>
<QtMoc Include="Debugger\Memory\MemorySearchWidget.h">
<Filter>Debugger\Memory</Filter>
<QtMoc Include="Debugger\SymbolTree\SymbolTreeLocation.h">
<Filter>Debugger\SymbolTree</Filter>
</QtMoc>
<QtMoc Include="Debugger\Memory\MemoryViewWidget.h">
<Filter>Debugger\Memory</Filter>
<QtMoc Include="Debugger\SymbolTree\SymbolTreeModel.h">
<Filter>Debugger\SymbolTree</Filter>
</QtMoc>
<QtMoc Include="Debugger\SymbolTree\SymbolTreeNode.h">
<Filter>Debugger\SymbolTree</Filter>
</QtMoc>
<QtMoc Include="Debugger\Memory\SavedAddressesModel.h">
<Filter>Debugger\Memory</Filter>
@@ -685,15 +710,24 @@
<QtMoc Include="Debugger\Memory\SavedAddressesWidget.h">
<Filter>Debugger\Memory</Filter>
</QtMoc>
<QtMoc Include="ColorPickerButton.h" />
<QtMoc Include="SetupWizardDialog.h" />
<QtMoc Include="Settings\GameCheatSettingsWidget.h">
<Filter>Settings</Filter>
<QtMoc Include="Debugger\Memory\MemorySearchWidget.h">
<Filter>Debugger\Memory</Filter>
</QtMoc>
<QtMoc Include="Settings\GamePatchSettingsWidget.h">
<Filter>Settings</Filter>
<QtMoc Include="Debugger\Memory\MemoryViewWidget.h">
<Filter>Debugger\Memory</Filter>
</QtMoc>
<QtMoc Include="Debugger\Docking\LayoutEditorDialog.h">
<Filter>Debugger\Docking</Filter>
</QtMoc>
<QtMoc Include="Debugger\Docking\NoLayoutsWidget.h">
<Filter>Debugger\Docking</Filter>
</QtMoc>
<QtMoc Include="Debugger\SymbolTree\NewSymbolDialogs.h">
<Filter>Debugger\SymbolTree</Filter>
</QtMoc>
<QtMoc Include="Debugger\Docking\DockMenuBar.h">
<Filter>Debugger\Docking</Filter>
</QtMoc>
<QtMoc Include="LogWindow.h" />
</ItemGroup>
<ItemGroup>
<QtResource Include="resources\resources.qrc">
@@ -815,27 +849,6 @@
<QtUi Include="Debugger\RegisterWidget.ui">
<Filter>Debugger</Filter>
</QtUi>
<QtUi Include="Debugger\Breakpoints\BreakpointDialog.ui">
<Filter>Debugger\Breakpoints</Filter>
</QtUi>
<QtUi Include="Debugger\Breakpoints\BreakpointWidget.ui">
<Filter>Debugger\Breakpoints</Filter>
</QtUi>
<QtUi Include="Debugger\Docking\LayoutEditorDialog.ui">
<Filter>Debugger\Docking</Filter>
</QtUi>
<QtUi Include="Debugger\Docking\NoLayoutsWidget.ui">
<Filter>Debugger\Docking</Filter>
</QtUi>
<QtUi Include="Debugger\Memory\MemorySearchWidget.ui">
<Filter>Debugger\Memory</Filter>
</QtUi>
<QtUi Include="Debugger\Memory\MemoryViewWidget.ui">
<Filter>Debugger\Memory</Filter>
</QtUi>
<QtUi Include="Debugger\Memory\SavedAddressesWidget.ui">
<Filter>Debugger\Memory</Filter>
</QtUi>
<QtUi Include="Settings\ControllerLEDSettingsDialog.ui">
<Filter>Settings</Filter>
</QtUi>
@@ -885,6 +898,27 @@
<QtUi Include="Settings\AudioStretchSettingsDialog.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Debugger\Breakpoints\BreakpointDialog.ui">
<Filter>Debugger\Breakpoints</Filter>
</QtUi>
<QtUi Include="Debugger\Breakpoints\BreakpointWidget.ui">
<Filter>Debugger\Breakpoints</Filter>
</QtUi>
<QtUi Include="Debugger\Memory\SavedAddressesWidget.ui">
<Filter>Debugger\Memory</Filter>
</QtUi>
<QtUi Include="Debugger\Memory\MemoryViewWidget.ui">
<Filter>Debugger\Memory</Filter>
</QtUi>
<QtUi Include="Debugger\Memory\MemorySearchWidget.ui">
<Filter>Debugger\Memory</Filter>
</QtUi>
<QtUi Include="Debugger\Docking\LayoutEditorDialog.ui">
<Filter>Debugger\Docking</Filter>
</QtUi>
<QtUi Include="Debugger\Docking\NoLayoutsWidget.ui">
<Filter>Debugger\Docking</Filter>
</QtUi>
</ItemGroup>
<ItemGroup>
<None Include="Settings\FolderSettingsWidget.ui">
@@ -908,4 +942,4 @@
<Filter>Translations</Filter>
</QtTs>
</ItemGroup>
</Project>
</Project>

View File

@@ -212,7 +212,7 @@ bool GSHwHack::GSC_Tekken5(GSRendererHW& r, int& skip)
{
if (skip == 0)
{
if (r.IsPossibleChannelShuffle() && (RTBP0 & 31))
if (r.IsPossibleChannelShuffle() && !(RTBP0 & 31))
{
GSVertex* v = &r.m_vertex.buff[0];

View File

@@ -4259,14 +4259,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
m_conf.ps.blend_d = 2;
}
}
// When AA1 is enabled and Alpha Blending is disabled, alpha blending done with coverage instead of alpha.
// We use a COV value of 128 (full coverage) in triangles (except the edge geometry, which we can't do easily).
if (IsCoverageAlpha())
{
m_conf.ps.fixed_one_a = 1;
m_conf.ps.blend_c = 0;
}
else if (m_conf.ps.blend_c == 1)
if (m_conf.ps.blend_c == 1)
{
// When both rt alpha min and max are equal replace Ad with Af, easier to manage.
if (rt_alpha_min == rt_alpha_max)
@@ -6169,6 +6162,9 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
new_scale_rt_alpha = rt->m_rt_alpha_scale;
}
// AA1: Set alpha source to coverage 128 when there is no alpha blending.
m_conf.ps.fixed_one_a = IsCoverageAlpha();
if ((!IsOpaque() || m_context->ALPHA.IsBlack()) && rt && ((m_conf.colormask.wrgba & 0x7) || (m_texture_shuffle && !m_copy_16bit_to_target_shuffle && !m_same_group_texture_shuffle)))
{
EmulateBlending(blend_alpha_min, blend_alpha_max, DATE, DATE_PRIMID, DATE_BARRIER, rt, can_scale_rt_alpha, new_scale_rt_alpha);
@@ -6177,7 +6173,6 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
{
m_conf.blend = {}; // No blending please
m_conf.ps.no_color1 = true;
m_conf.ps.fixed_one_a = IsCoverageAlpha();
if (can_scale_rt_alpha && !new_scale_rt_alpha && m_conf.colormask.wa)
{
@@ -6240,23 +6235,32 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
// Blending might be off, ensure it's enabled.
// We write the alpha pass/fail to SRC1_ALPHA, which is used to update A.
m_conf.ps.afail = AFAIL_RGB_ONLY;
m_conf.ps.no_color1 = false;
if (!m_conf.blend.enable)
if ((features.framebuffer_fetch && m_conf.require_one_barrier) || m_conf.require_full_barrier)
{
m_conf.blend = GSHWDrawConfig::BlendState(true, GSDevice::CONST_ONE, GSDevice::CONST_ZERO,
GSDevice::OP_ADD, GSDevice::SRC1_ALPHA, GSDevice::INV_SRC1_ALPHA, false, 0);
// We're reading the rt anyways, use it for AFAIL
// This ensures we don't attempt to use fbfetch + blend, which breaks Intel GPUs on Metal
// Setting afail to RGB_ONLY without enabling color1 will enable this mode in the shader, so nothing more to do here.
}
else
{
if (m_conf.blend_multi_pass.enable)
m_conf.ps.no_color1 = false;
if (!m_conf.blend.enable)
{
m_conf.blend_multi_pass.blend.src_factor_alpha = GSDevice::SRC1_ALPHA;
m_conf.blend_multi_pass.blend.dst_factor_alpha = GSDevice::INV_SRC1_ALPHA;
m_conf.blend = GSHWDrawConfig::BlendState(true, GSDevice::CONST_ONE, GSDevice::CONST_ZERO,
GSDevice::OP_ADD, GSDevice::SRC1_ALPHA, GSDevice::INV_SRC1_ALPHA, false, 0);
}
else
{
m_conf.blend.src_factor_alpha = GSDevice::SRC1_ALPHA;
m_conf.blend.dst_factor_alpha = GSDevice::INV_SRC1_ALPHA;
if (m_conf.blend_multi_pass.enable)
{
m_conf.blend_multi_pass.blend.src_factor_alpha = GSDevice::SRC1_ALPHA;
m_conf.blend_multi_pass.blend.dst_factor_alpha = GSDevice::INV_SRC1_ALPHA;
}
else
{
m_conf.blend.src_factor_alpha = GSDevice::SRC1_ALPHA;
m_conf.blend.dst_factor_alpha = GSDevice::INV_SRC1_ALPHA;
}
}
}

View File

@@ -219,6 +219,7 @@ public:
MRCOwned<id<MTLFence>> m_draw_sync_fence;
MRCOwned<MTLFunctionConstantValues*> m_fn_constants;
MRCOwned<MTLVertexDescriptor*> m_hw_vertex;
MTLResourceOptions m_resource_options_shared_wc;
// Previously in MetalHostDisplay.
MRCOwned<NSView*> m_view;

View File

@@ -10,6 +10,7 @@
#include "common/Console.h"
#include "common/HostSys.h"
#include "cpuinfo.h"
#include "imgui.h"
#ifdef __APPLE__
@@ -90,6 +91,12 @@ GSDeviceMTL::GSDeviceMTL()
, m_dev(nil)
{
m_backref->second = this;
m_resource_options_shared_wc = MTLResourceStorageModeShared | MTLResourceCPUCacheModeWriteCombined;
#ifdef _M_X86
// WC memory doesn't work properly on AMD hackintoshes, and ends up being horribly slow even when only writing
if (cpuinfo_get_core(0)->vendor == cpuinfo_vendor_amd)
m_resource_options_shared_wc = MTLResourceStorageModeShared;
#endif
}
GSDeviceMTL::~GSDeviceMTL()
@@ -107,7 +114,7 @@ GSDeviceMTL::Map GSDeviceMTL::Allocate(UploadBuffer& buffer, size_t amt)
size_t newsize = std::max<size_t>(buffer.usage.Size() * 2, 4096);
while (newsize < amt)
newsize *= 2;
MTLResourceOptions options = MTLResourceStorageModeShared | MTLResourceCPUCacheModeWriteCombined;
MTLResourceOptions options = m_resource_options_shared_wc;
buffer.mtlbuffer = MRCTransfer([m_dev.dev newBufferWithLength:newsize options:options]);
pxAssertRel(buffer.mtlbuffer, "Failed to allocate MTLBuffer (out of memory?)");
buffer.buffer = [buffer.mtlbuffer contents];
@@ -148,7 +155,7 @@ GSDeviceMTL::Map GSDeviceMTL::Allocate(BufferPair& buffer, size_t amt)
size_t newsize = std::max<size_t>(buffer.usage.Size() * 2, 4096);
while (newsize < amt)
newsize *= 2;
MTLResourceOptions options = MTLResourceStorageModeShared | MTLResourceCPUCacheModeWriteCombined;
MTLResourceOptions options = m_resource_options_shared_wc;
buffer.cpubuffer = MRCTransfer([m_dev.dev newBufferWithLength:newsize options:options]);
pxAssertRel(buffer.cpubuffer, "Failed to allocate MTLBuffer (out of memory?)");
buffer.buffer = [buffer.cpubuffer contents];
@@ -1277,7 +1284,7 @@ void GSDeviceMTL::UpdateTexture(id<MTLTexture> texture, u32 x, u32 y, u32 width,
id<MTLCommandBuffer> cmdbuf = [m_queue commandBuffer];
id<MTLBlitCommandEncoder> enc = [cmdbuf blitCommandEncoder];
size_t bytes = data_stride * height;
MRCOwned<id<MTLBuffer>> buf = MRCTransfer([m_dev.dev newBufferWithLength:bytes options:MTLResourceStorageModeShared | MTLResourceCPUCacheModeWriteCombined]);
MRCOwned<id<MTLBuffer>> buf = MRCTransfer([m_dev.dev newBufferWithLength:bytes options:m_resource_options_shared_wc]);
memcpy([buf contents], data, bytes);
[enc copyFromBuffer:buf
sourceOffset:0

View File

@@ -97,7 +97,8 @@ constant bool SW_BLEND = (PS_BLEND_A != PS_BLEND_B) || PS_BLEND_D;
constant bool SW_AD_TO_HW = (PS_BLEND_C == 1 && PS_A_MASKED);
constant bool NEEDS_RT_FOR_BLEND = (((PS_BLEND_A != PS_BLEND_B) && (PS_BLEND_A == 1 || PS_BLEND_B == 1 || PS_BLEND_C == 1)) || PS_BLEND_D == 1 || SW_AD_TO_HW);
constant bool NEEDS_RT_EARLY = PS_TEX_IS_FB || PS_DATE >= 5;
constant bool NEEDS_RT = NEEDS_RT_EARLY || (!PS_PRIM_CHECKING_INIT && (PS_FBMASK || NEEDS_RT_FOR_BLEND));
constant bool NEEDS_RT_FOR_AFAIL = PS_AFAIL == 3 && PS_NO_COLOR1;
constant bool NEEDS_RT = NEEDS_RT_FOR_AFAIL || NEEDS_RT_EARLY || (!PS_PRIM_CHECKING_INIT && (PS_FBMASK || NEEDS_RT_FOR_BLEND));
constant bool PS_COLOR0 = !PS_NO_COLOR;
constant bool PS_COLOR1 = !PS_NO_COLOR1;
@@ -1202,8 +1203,12 @@ struct PSMain
alpha_blend.a = float(atst_pass);
if (PS_COLOR0)
{
out.c0.a = PS_RTA_CORRECTION ? C.a / 128.f : C.a / 255.f;
out.c0.rgb = PS_HDR ? float3(C.rgb / 65535.f) : C.rgb / 255.f;
if (PS_AFAIL == 3 && !PS_COLOR1 && !atst_pass) // Doing RGB_ONLY without COLOR1
out.c0.a = current_color.a;
}
if (PS_COLOR1)
out.c1 = alpha_blend;
if (PS_ZCLAMP)

View File

@@ -4091,6 +4091,12 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
FSUI_NSTR("Enabled (All Primitives)"),
};
static constexpr const char* s_gpu_clut_options[] = {
FSUI_NSTR("Disabled (Default)"),
FSUI_NSTR("Enabled (Exact Match)"),
FSUI_NSTR("Enabled (Check Inside Target)"),
};
DrawIntListSetting(bsi, FSUI_CSTR("CPU Sprite Render Size"),
FSUI_CSTR("Uses software renderer to draw texture decompression-like sprites."), "EmuCore/GS",
"UserHacks_CPUSpriteRenderBW", 0, s_cpu_sprite_render_bw_options, std::size(s_cpu_sprite_render_bw_options), true);
@@ -4100,6 +4106,9 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
DrawIntListSetting(bsi, FSUI_CSTR("Software CLUT Render"),
FSUI_CSTR("Uses software renderer to draw texture CLUT points/sprites."), "EmuCore/GS", "UserHacks_CPUCLUTRender", 0,
s_cpu_clut_render_options, std::size(s_cpu_clut_render_options), true);
DrawIntListSetting(bsi, FSUI_CSTR("GPU Target CLUT"),
FSUI_CSTR("Try to detect when a game is drawing its own color palette and then renders it on the GPU with special handling."), "EmuCore/GS", "UserHacks_GPUTargetCLUTMode",
0, s_gpu_clut_options, std::size(s_gpu_clut_options), true, 0, manual_hw_fixes);
DrawIntSpinBoxSetting(bsi, FSUI_CSTR("Skip Draw Start"), FSUI_CSTR("Object range to skip drawing."), "EmuCore/GS",
"UserHacks_SkipDraw_Start", 0, 0, 5000, 1);
DrawIntSpinBoxSetting(bsi, FSUI_CSTR("Skip Draw End"), FSUI_CSTR("Object range to skip drawing."), "EmuCore/GS",
@@ -7391,6 +7400,8 @@ TRANSLATE_NOOP("FullscreenUI", "CPU Sprite Render Level");
TRANSLATE_NOOP("FullscreenUI", "Determines filter level for CPU sprite render.");
TRANSLATE_NOOP("FullscreenUI", "Software CLUT Render");
TRANSLATE_NOOP("FullscreenUI", "Uses software renderer to draw texture CLUT points/sprites.");
TRANSLATE_NOOP("FullscreenUI", "GPU Target CLUT");
TRANSLATE_NOOP("FullscreenUI", "Try to detect when a game is drawing its own color palette and then renders it on the GPU with special handling.");
TRANSLATE_NOOP("FullscreenUI", "Skip Draw Start");
TRANSLATE_NOOP("FullscreenUI", "Object range to skip drawing.");
TRANSLATE_NOOP("FullscreenUI", "Skip Draw End");
@@ -7865,6 +7876,8 @@ TRANSLATE_NOOP("FullscreenUI", "Force Nearest");
TRANSLATE_NOOP("FullscreenUI", "Disabled (Default)");
TRANSLATE_NOOP("FullscreenUI", "Enabled (Sprites Only)");
TRANSLATE_NOOP("FullscreenUI", "Enabled (All Primitives)");
TRANSLATE_NOOP("FullscreenUI", "Enabled (Exact Match)");
TRANSLATE_NOOP("FullscreenUI", "Enabled (Check Inside Target)");
TRANSLATE_NOOP("FullscreenUI", "None (Default)");
TRANSLATE_NOOP("FullscreenUI", "Sharpen Only (Internal Resolution)");
TRANSLATE_NOOP("FullscreenUI", "Sharpen and Resize (Display Resolution)");

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 = 59;
static constexpr u32 SHADER_CACHE_VERSION = 60;

View File

@@ -1736,7 +1736,7 @@ StartRecomp:
}
}
pxAssert(xGetPtr() < recPtrEnd);
pxAssert(xGetPtr() < SysMemory::GetIOPRecEnd());
pxAssert(xGetPtr() - recPtr < _64kb);
s_pCurBlockEx->x86size = xGetPtr() - recPtr;

View File

@@ -900,7 +900,7 @@ u8* recEndThunk()
{
u8* block_end = x86Ptr;
pxAssert(block_end < recPtrEnd);
pxAssert(block_end < SysMemory::GetEERecEnd());
recPtr = block_end;
return block_end;
}
@@ -2698,7 +2698,7 @@ StartRecomp:
}
}
pxAssert(xGetPtr() < recPtrEnd);
pxAssert(xGetPtr() < SysMemory::GetEERecEnd());
s_pCurBlockEx->x86size = static_cast<u32>(xGetPtr() - recPtr);