mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-17 04:25:40 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86d76bbf59 | ||
|
|
45fa6a8bb5 | ||
|
|
223c2cba9a | ||
|
|
562c32cd15 | ||
|
|
876a0bfbd7 | ||
|
|
81558dc9c4 | ||
|
|
2d62078b04 | ||
|
|
474ad59818 | ||
|
|
d75c8b1edc | ||
|
|
d89b4b6fa1 | ||
|
|
afb875f2c6 | ||
|
|
f24d44d470 | ||
|
|
4918b0aa09 | ||
|
|
a50ed4d05a | ||
|
|
19d08ba94f | ||
|
|
a80b3144bb | ||
|
|
9f0206966b | ||
|
|
dcae14398a | ||
|
|
14164e6592 | ||
|
|
873977d0b8 | ||
|
|
78319ef0ba | ||
|
|
d1beb6be9a | ||
|
|
5df1662c1b | ||
|
|
45b8338f6d | ||
|
|
92914cee40 | ||
|
|
44079ebbe2 | ||
|
|
8d2d9ebb1d | ||
|
|
4f62bff866 | ||
|
|
8510ec29ba | ||
|
|
cde272055f | ||
|
|
5e3ad282a8 | ||
|
|
091b3a8694 | ||
|
|
42ce97aca5 | ||
|
|
a4df5c300e | ||
|
|
4bf51e735a | ||
|
|
d7e7c8164c | ||
|
|
eb5e3fcd13 | ||
|
|
8f8968cbb1 | ||
|
|
ac83e93426 | ||
|
|
78d0cf4a4f |
@@ -6,6 +6,9 @@ updates:
|
||||
schedule:
|
||||
# Check for updates to GitHub Actions every week
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
# Prefix all commit messages with "Deps/gha: "
|
||||
prefix: "Deps/gha"
|
||||
groups:
|
||||
ci-deps:
|
||||
patterns:
|
||||
|
||||
@@ -92,7 +92,7 @@ jobs:
|
||||
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: ccache cache files
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: .ccache
|
||||
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||
@@ -114,7 +114,7 @@ jobs:
|
||||
|
||||
- name: Cache Dependencies
|
||||
id: cache-deps
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/deps
|
||||
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/linux/build-dependencies-qt.sh', '.github/workflows/scripts/common/*.patch') }}
|
||||
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
|
||||
- name: Cache Dependencies
|
||||
id: cache-deps
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: ~/deps
|
||||
key: ${{ inputs.os }} ${{ inputs.arch }} deps ${{ hashFiles('.github/workflows/scripts/macos/*', '.github/workflows/scripts/common/*.patch') }}
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
run: echo "timestamp=$(date -u "+%Y-%m-%d-%H;%M;%S")" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache ccache cache
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: .ccache
|
||||
key: ${{ inputs.os }} ${{ inputs.arch }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||
@@ -176,7 +176,7 @@ jobs:
|
||||
|
||||
- name: Sign the Application
|
||||
if: ${{ inputs.sign_and_notarize == true && env.SIGN_KEY }}
|
||||
uses: indygreg/apple-code-sign-action@44d0985b7f4363198e80b6fea63ac3e9dd3e9957
|
||||
uses: indygreg/apple-code-sign-action@5e7a4a01fe4dffe948ef3bcf1f4538d963cb0c72
|
||||
with:
|
||||
input_path: 'PCSX2.app'
|
||||
p12_file: cert.p12
|
||||
|
||||
@@ -3,7 +3,7 @@ Version=1.0
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Name=PCSX2
|
||||
StartupWMClass=PCSX2
|
||||
StartupWMClass=pcsx2-qt
|
||||
GenericName=PlayStation 2 Emulator
|
||||
Comment=Sony PlayStation 2 emulator
|
||||
Exec=pcsx2-qt
|
||||
|
||||
@@ -471,7 +471,6 @@ echo "Building PlutoVG..."
|
||||
rmdir /S /Q "plutovg-%PLUTOVG%"
|
||||
%SEVENZIP% x "plutovg-%PLUTOVG%.zip" || goto error
|
||||
cd "plutovg-%PLUTOVG%" || goto error
|
||||
%PATCH% -p1 < "%SCRIPTDIR%\plutovg-workaround-msvc-ice.patch" || goto error
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DPLUTOVG_BUILD_EXAMPLES=OFF -B build -G Ninja || goto error
|
||||
cmake --build build --parallel || goto error
|
||||
ninja -C build install || goto error
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
diff --git a/source/plutovg-font.c b/source/plutovg-font.c
|
||||
index 0ad89b1..110de7f 100644
|
||||
--- a/source/plutovg-font.c
|
||||
+++ b/source/plutovg-font.c
|
||||
@@ -836,7 +836,8 @@ int plutovg_font_face_cache_load_file(plutovg_font_face_cache_t* cache, const ch
|
||||
size_t family_index = 0;
|
||||
if(unicode_family_name) {
|
||||
const stbtt_uint8* family_name = unicode_family_name;
|
||||
- while(family_length) {
|
||||
+ //while(family_length) {
|
||||
+ for (int i = family_length; i > 0; i -= 2) {
|
||||
stbtt_uint16 ch = family_name[0] * 256 + family_name[1];
|
||||
if(ch < 0x80) {
|
||||
entry->family[family_index++] = ch;
|
||||
@@ -853,7 +854,8 @@ int plutovg_font_face_cache_load_file(plutovg_font_face_cache_t* cache, const ch
|
||||
entry->family[family_index++] = (0x80 + ((c) & 0x3f));
|
||||
|
||||
family_name += 2;
|
||||
- family_length -= 2;
|
||||
+ //family_length -= 2;
|
||||
+ i -= 2;
|
||||
} else {
|
||||
entry->family[family_index++] = (0xe0 + (ch >> 12));
|
||||
entry->family[family_index++] = (0x80 + ((ch >> 6) & 0x3f));
|
||||
@@ -861,7 +863,7 @@ int plutovg_font_face_cache_load_file(plutovg_font_face_cache_t* cache, const ch
|
||||
}
|
||||
|
||||
family_name += 2;
|
||||
- family_length -= 2;
|
||||
+ //family_length -= 2;
|
||||
}
|
||||
|
||||
entry->family[family_index] = '\0';
|
||||
@@ -902,7 +904,8 @@ int plutovg_font_face_cache_load_file(plutovg_font_face_cache_t* cache, const ch
|
||||
};
|
||||
|
||||
const stbtt_uint8* family_name = roman_family_name;
|
||||
- while(family_length) {
|
||||
+ //while(family_length) {
|
||||
+ for (int i2 = family_length; i2 > 0; i2--) {
|
||||
stbtt_uint16 ch = MAC_ROMAN_TABLE[family_name[0]];
|
||||
if(ch < 0x80) {
|
||||
entry->family[family_index++] = ch;
|
||||
@@ -916,7 +919,7 @@ int plutovg_font_face_cache_load_file(plutovg_font_face_cache_t* cache, const ch
|
||||
}
|
||||
|
||||
family_name += 1;
|
||||
- family_length -= 1;
|
||||
+ //family_length -= 1;
|
||||
}
|
||||
|
||||
entry->family[family_index] = '\0';
|
||||
@@ -122,7 +122,7 @@ jobs:
|
||||
|
||||
- name: Cache Dependencies
|
||||
id: cache-deps
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v6
|
||||
with:
|
||||
path: deps
|
||||
key: ${{ inputs.os }} ${{ inputs.platform }} deps ${{ hashFiles('.github/workflows/scripts/windows/build-dependencies.bat', '.github/workflows/scripts/common/*.patch') }}
|
||||
|
||||
@@ -63,6 +63,9 @@ oprofile_data/
|
||||
*.kdev4
|
||||
/.kdev4*
|
||||
|
||||
# Kate Projects
|
||||
.kateproject*
|
||||
|
||||
# Resources and docs in /bin are tracked
|
||||
/bin/**/*.dll
|
||||
/bin/**/*.dmp
|
||||
|
||||
+112
-370
@@ -200,7 +200,7 @@ PAPX-90203:
|
||||
name-sort: "ぐらんつーりすも 2000 [たいけんばん]"
|
||||
name-en: "Gran Turismo 2000 [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
gsHWFixes: &gran-turismo-3-gs-fixes
|
||||
halfPixelOffset: 5 # Fixes edge bleed and lines.
|
||||
autoFlush: 1 # Fixes missing lens flare and intensity.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
@@ -226,28 +226,19 @@ PAPX-90207:
|
||||
name-sort: "ぐらんつーりすも 3 A-Spec おーとばっくすげんていりぷれいしあたー"
|
||||
name-en: "Gran Turismo 3 - A-Spec - Autobacs Gentei Replay Theater"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes edge bleed and lines.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PAPX-90208:
|
||||
name: "GRAN TURISMO 3 - A-Spec - リプレイシアター"
|
||||
name-sort: "ぐらんつーりすも 3 A-Spec りぷれいしあたー"
|
||||
name-en: "Gran Turismo 3 - A-Spec - Replay Theater"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes edge bleed and lines.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PAPX-90209:
|
||||
name: "GRAN TURISMO 3 - A-Spec - Netz TOYOTA - リプレイシアターディスク"
|
||||
name-sort: "ぐらんつーりすも 3 A-Spec ねっつとよたりぷれいしあたーでぃすく"
|
||||
name-en: "Gran Turismo 3 - A-Spec - Netz TOYOTA - Replay Theater Disc"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes edge bleed and lines.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PAPX-90210:
|
||||
name: "やっぱ RPGでしょ。 [オリジナルムービーディスク]"
|
||||
name-sort: "やっぱ あーるぴーじーでしょ [おりじなるむーびーでぃすく]"
|
||||
@@ -421,10 +412,7 @@ PAPX-90504:
|
||||
name-sort: "ぐらんつーりすも こんせぷと えあとれっく たーぼ すぺしゃるえでぃしょん [たいけんばん]"
|
||||
name-en: "Gran Turismo Concept - Airtrek Turbo Special Edition [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PAPX-90505:
|
||||
name: "2002 夏のオススメソフト おためしDisc"
|
||||
name-sort: "2002 なつのおすすめそふと おためしでぃすく"
|
||||
@@ -454,19 +442,13 @@ PAPX-90508:
|
||||
name-sort: "ぐらんつーりすも こんせぷと るぽ かっぷ とれいにんぐ ばーじょん"
|
||||
name-en: "Gran Turismo Concept - LUPO CUP Training Version"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PAPX-90509:
|
||||
name: "GRAN TURISMO Concept - LUPO CUP Training Version 2"
|
||||
name-sort: "ぐらんつーりすも こんせぷと るぽ かっぷ とれいにんぐ ばーじょん 2"
|
||||
name-en: "Gran Turismo Concept - LUPO CUP Training Version 2"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PAPX-90511:
|
||||
name: "SIREN [体験版]"
|
||||
name-sort: "さいれん [たいけんばん]"
|
||||
@@ -481,11 +463,9 @@ PAPX-90512:
|
||||
name-sort: "ぐらんつーりすも 4 - とよた ぷりうす [たいけんばん]"
|
||||
name-en: "Gran Turismo 4 - TOYOTA Prius [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
gsHWFixes: &gran-turismo-4-prologue-gs-fixes
|
||||
<<: *gran-turismo-3-gs-fixes
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
PAPX-90514:
|
||||
name: "冬のオススメソフト おためしDISC"
|
||||
name-sort: "ふゆのおすすめそふとおためしでぃすく"
|
||||
@@ -538,13 +518,11 @@ PAPX-90523:
|
||||
name-sort: "ぐらんつーりすも 4 - おんらいんじっけんばーじょん"
|
||||
name-en: "Gran Turismo 4 - Online Test Version"
|
||||
region: "NTSC-J"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
clampModes: &gran-turismo-4-clamp-modes
|
||||
vuClampMode: 2 # In GT4, text in GT mode works. In TT, fixes SPS in TT Mode menu caused by the moving tooltips.
|
||||
gsHWFixes: &gran-turismo-4-gs-fixes
|
||||
<<: *gran-turismo-4-prologue-gs-fixes
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
PAPX-90524:
|
||||
name: "ワイルドアームズ ザ フィフスヴァンガード [体験版]"
|
||||
name-sort: "わいるどあーむず ざ ふぃふすゔぁんがーど [たいけんばん]"
|
||||
@@ -691,20 +669,14 @@ PBPX-95502:
|
||||
name-sort: "ぐらんつーりすも 3 - A-Spec [ほんたいどうこんばん]"
|
||||
name-en: "Gran Turismo 3 - A-Spec [PS2 Bundle]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95502"
|
||||
- "SCPS-15009"
|
||||
PBPX-95503:
|
||||
name: "Gran Turismo 3 - A-Spec [PS2 Bundle]"
|
||||
region: "NTSC-U"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95503"
|
||||
- "SCUS-97102"
|
||||
@@ -765,20 +737,12 @@ PBPX-95523:
|
||||
name-sort: "ぐらんつーりすも 4 ぷろろーぐ [ほんたいどうこんばん]"
|
||||
name-en: "Gran Turismo 4 Prologue [PS2 Bundle]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-prologue-gs-fixes
|
||||
PBPX-95524:
|
||||
name: "Gran Turismo 4 Prologue [PlayStation 2 Racing Pack]"
|
||||
region: "NTSC-C"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-prologue-gs-fixes
|
||||
PBPX-95525:
|
||||
name: "ファイナルファンタジーⅫ [本体同梱版]"
|
||||
name-sort: "ふぁいなるふぁんたじー 12 [ほんたいどうこんばん]"
|
||||
@@ -790,13 +754,8 @@ PBPX-95601:
|
||||
name-en: "Gran Turismo 4 [PS2 Bundle]"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95502"
|
||||
- "SCAJ-20066"
|
||||
@@ -844,10 +803,7 @@ PCPX-96309:
|
||||
name-sort: "ぐらんつーりすも 3 ねっつ とよた [Demo]"
|
||||
name-en: "Gran Turismo 3 Netz TOYOTA [Demo]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes edge bleed and lines.
|
||||
autoFlush: 1 # Fixes missing lens flare and intensity.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PCPX-96310:
|
||||
name: "エクストリーム・レーシング SSX [体験版]"
|
||||
name-sort: "えくすとりーむ れーしんぐ SSX [たいけんばん]"
|
||||
@@ -862,19 +818,13 @@ PCPX-96311:
|
||||
name-sort: "ぐらんつーりすも 3 てんとうしゆうでぃすくVol.1"
|
||||
name-en: "Gran Turismo 3 Trial Disk Volume 1"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes edge bleed and lines.
|
||||
autoFlush: 1 # Fixes missing lens flare and intensity.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PCPX-96312:
|
||||
name: "GRAN TURISMO 3 - A-Spec - [オートバックス店頭試遊ディスク]"
|
||||
name-sort: "ぐらんつーりすも 3 A-Spec おーとばっくすてんとうしゆうでぃすく"
|
||||
name-en: "Gran Turismo 3 - A-Spec - Autobacs Tentou Shiyuu Disc"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes edge bleed and lines.
|
||||
autoFlush: 1 # Fixes missing lens flare and intensity.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PCPX-96314:
|
||||
name: "スカイオデッセイ [体験版]"
|
||||
name-sort: "すかいおでっせい [たいけんばん]"
|
||||
@@ -1005,10 +955,7 @@ PCPX-96609:
|
||||
name-sort: "ぐらんつーりすも 3 - A-Spec - てんとうしゆう Disc Vol. 2"
|
||||
name-en: "Gran Turismo 3 - A-Spec - Tentou Shiyuu Disc Vol. 2"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PCPX-96610:
|
||||
name: "見る見る 2001年2月度受注号"
|
||||
name-sort: "みるみる 2001ねん 2がつどじゅちゅうごう"
|
||||
@@ -1082,10 +1029,7 @@ PCPX-96624:
|
||||
name-sort: "ぐらんつーりすも こんせぷと 2001 Tokyo"
|
||||
name-en: "Gran Turismo - Concept 2001 Tokyo"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PCPX-96625:
|
||||
name: "プレプレ2 VOLUME.4"
|
||||
name-sort: "ぷれぷれ2 VOLUME. 4"
|
||||
@@ -1136,10 +1080,7 @@ PCPX-96634:
|
||||
name-sort: "ぐらんつーりすも すばるどらいびんぐしみゅれーたーばーじょん"
|
||||
name-en: "Gran Turismo - SUBARU Driving Simulator Version"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
PCPX-96635:
|
||||
name: "プレプレ2 VOLUME.8"
|
||||
name-sort: "ぷれぷれ2 VOLUME. 8"
|
||||
@@ -1176,13 +1117,8 @@ PCPX-96649:
|
||||
name-en: "Gran Turismo 4 [Trial]"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
PCPX-96653:
|
||||
name: "ラチェット&クランク3 突撃!ガラクチック★レンジャーズ [店頭体験版]"
|
||||
name-sort: "らちぇっとあんどくらんく3 とつげき!がらくちっくれんじゃーず [てんとうたいけんばん]"
|
||||
@@ -1223,13 +1159,8 @@ PCPX-96660:
|
||||
name-sort: "つーりすと とろふぃー [Demo]"
|
||||
name-en: "Tourist Trophy [Demo]"
|
||||
region: "NTSC-J"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
PCPX-98017:
|
||||
name: "ラチェット&クランク4th ギリギリ銀河のギガバトル [体験版]"
|
||||
name-sort: "らちぇっとあんどくらんく4th ぎりぎりぎんがのぎがばとる [たいけんばん]"
|
||||
@@ -1691,11 +1622,7 @@ SCAJ-20066:
|
||||
name: "Gran Turismo 4 Prologue"
|
||||
region: "NTSC-Unk"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-prologue-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95502"
|
||||
- "SCAJ-20066"
|
||||
@@ -1708,7 +1635,6 @@ SCAJ-20066:
|
||||
- "SCPS-19304"
|
||||
- "SCPS-15009"
|
||||
- "SCPS-55007"
|
||||
# vuClampMode = 2 Text in GT mode works.
|
||||
SCAJ-20067:
|
||||
name: "Gungrave O.D."
|
||||
region: "NTSC-Unk"
|
||||
@@ -2446,13 +2372,8 @@ SCAJ-20170:
|
||||
name: "Tourist Trophy"
|
||||
region: "NTSC-C"
|
||||
compat: 5
|
||||
clampModes:
|
||||
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCAJ-20171:
|
||||
name: "絶体絶命都市2 - 凍てついた記憶たち"
|
||||
name-sort: "ぜったいぜつめいとし いてついたきおくたち"
|
||||
@@ -2743,14 +2664,11 @@ SCAJ-30006:
|
||||
name-sort: "ぐらんつーりすも 4"
|
||||
name-en: "Gran Turismo 4"
|
||||
region: "NTSC-J"
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Using chop for both normal+div fixes crash in B5 license test.
|
||||
eeDivRoundMode: 3 # See above.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95502"
|
||||
- "SCAJ-20066"
|
||||
@@ -2767,25 +2685,19 @@ SCAJ-30007:
|
||||
name: "Gran Turismo 4"
|
||||
region: "NTSC-C"
|
||||
compat: 5
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Using chop for both normal+div fixes crash in B5 license test.
|
||||
eeDivRoundMode: 3 # See above.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCAJ-30008:
|
||||
name: "Gran Turismo 4 [PlayStation2 the Best]"
|
||||
region: "NTSC-C"
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Using chop for both normal+div fixes crash in B5 license test.
|
||||
eeDivRoundMode: 3 # See above.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95502"
|
||||
- "SCAJ-20066"
|
||||
@@ -2949,11 +2861,8 @@ SCCS-60002:
|
||||
name-sort: "Paoche Langmanlu 4"
|
||||
name-en: "Gran Turismo 4 [Review Copy]"
|
||||
region: "NTSC-C"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCED-50041:
|
||||
name: "Tekken Tag Tournament [Demo]"
|
||||
region: "PAL-E"
|
||||
@@ -3353,10 +3262,7 @@ SCED-51351:
|
||||
SCED-51352:
|
||||
name: "Gran Turismo - Nissan Micra Edition [Demo]"
|
||||
region: "PAL-E"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCED-51359:
|
||||
name: "Official PlayStation 2 Magazine Demo 27"
|
||||
region: "PAL-M5"
|
||||
@@ -3920,11 +3826,7 @@ SCED-52452:
|
||||
SCED-52455:
|
||||
name: "Gran Turismo Special Edition 2004 Geneva Version"
|
||||
region: "PAL-E"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-prologue-gs-fixes
|
||||
SCED-52461:
|
||||
name: "SingStar [Press Kit]"
|
||||
region: "PAL-E"
|
||||
@@ -3947,11 +3849,7 @@ SCED-52549:
|
||||
SCED-52578:
|
||||
name: "Gran Turismo 4 BMW 1 Series Virtual Drive Dealership [Demo]"
|
||||
region: "PAL-M5"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCED-52580:
|
||||
name: "Magazine Ufficiale PlayStation 2 Italia 06/04"
|
||||
region: "PAL-I"
|
||||
@@ -3964,11 +3862,7 @@ SCED-52619:
|
||||
SCED-52681:
|
||||
name: "Gran Turismo 4 BMW 1 Series Virtual Drive [Demo]"
|
||||
region: "PAL-M11"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCED-52687:
|
||||
name: "Formula One 04 [Demo]"
|
||||
region: "PAL-M11"
|
||||
@@ -4903,10 +4797,7 @@ SCES-50294:
|
||||
name: "Gran Turismo 3 - A-Spec"
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCES-50295:
|
||||
name: "Dark Cloud"
|
||||
region: "PAL-M5"
|
||||
@@ -5174,10 +5065,7 @@ SCES-50858:
|
||||
name: "Gran Turismo - Concept 2002 Tokyo-Geneva"
|
||||
region: "PAL-M6"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
memcardFilters:
|
||||
- "SCES-50858"
|
||||
- "SCES-50294"
|
||||
@@ -5607,13 +5495,8 @@ SCES-51719:
|
||||
name: "Gran Turismo 4"
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
memcardFilters:
|
||||
- "SCES-51719"
|
||||
- "SCES-52438"
|
||||
@@ -5871,16 +5754,11 @@ SCES-52438:
|
||||
name: "Gran Turismo 4 Prologue"
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-prologue-gs-fixes
|
||||
memcardFilters:
|
||||
- "SCES-51719"
|
||||
- "SCES-52438"
|
||||
- "SCES-50294"
|
||||
# vuClampMode = 2 Text in GT mode works.
|
||||
SCES-52456:
|
||||
name: "Ratchet & Clank 3"
|
||||
region: "PAL-M5"
|
||||
@@ -6229,13 +6107,8 @@ SCES-53372:
|
||||
name: "Tourist Trophy - The Real Riding Simulator"
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
clampModes:
|
||||
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCES-53397:
|
||||
name: "SingStar - Popworld Events Code"
|
||||
region: "PAL-Unk"
|
||||
@@ -7418,11 +7291,7 @@ SCKA-20020:
|
||||
SCKA-20022:
|
||||
name: "Gran Turismo 4 - Prologue" # No listed Korean name on ReDump
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
# vuClampMode = 2 Text in GT mode works.
|
||||
gsHWFixes: *gran-turismo-4-prologue-gs-fixes
|
||||
SCKA-20023:
|
||||
name: "제로 ~붉은 나비~"
|
||||
name-sort: "Zero: Bulgeun Nabi"
|
||||
@@ -7481,10 +7350,7 @@ SCKA-20028:
|
||||
SCKA-20029:
|
||||
name: "Gran Turismo Concept - 2002 Tokyo-Seoul [PlayStation 2 BigHit Series]" # No listed Korean name on ReDump
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCKA-20030:
|
||||
name: "슬라이 쿠퍼 - 전설의 비법서를 찾아서 [PlayStation 2 BigHit Series]"
|
||||
name-sort: "Sly Cooper - Jeonseolui Bibeobseoreul Chajaseo [PlayStation 2 BigHit Series]"
|
||||
@@ -8355,13 +8221,8 @@ SCKA-24012:
|
||||
SCKA-30001:
|
||||
name: "Gran Turismo 4" # No listed Korean name on ReDump
|
||||
region: "NTSC-K"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCKA-30002:
|
||||
name: "GOD OF WAR 영혼의 반역자"
|
||||
name-sort: "God of War: Yeonghonui Banyeokja"
|
||||
@@ -8382,13 +8243,8 @@ SCKA-30003:
|
||||
SCKA-30004:
|
||||
name: "Gran Turismo 4 [PlayStation 2 BigHit Series]" # No listed Korean name on ReDump
|
||||
region: "NTSC-K"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCKA-30005:
|
||||
name: "로그 갤럭시"
|
||||
name-en: "Rogue Galaxy"
|
||||
@@ -8488,10 +8344,7 @@ SCPM-85301:
|
||||
name-sort: "ぐらんつーりすも こんせぷと こぺん すぺしゃるえでぃしょん [Demo]"
|
||||
name-en: "Gran Turismo Concept - Copen Special Edition [Demo]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCPM-85302:
|
||||
name: "みんなのGOLF オンライン"
|
||||
name-sort: "みんなのごるふ おんらいん"
|
||||
@@ -8507,11 +8360,7 @@ SCPM-85304:
|
||||
name-sort: "ぐらんつーりすも 4 ふぁーすとぷれびゅー"
|
||||
name-en: "Gran Turismo 4 - First Preview -"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCPN-60101:
|
||||
name: "PlayStation BB Navigator - Version 0.10 [Prerelease] [Disc 1]"
|
||||
name-sort: "ぷれいすてーしょん BB なびげーたー - Version 0.10 [Prerelease] [Disc 1]"
|
||||
@@ -8824,10 +8673,7 @@ SCPS-15009:
|
||||
name-sort: "ぐらんつーりすも3 A-spec"
|
||||
name-en: "Gran Turismo 3 - A-Spec"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95502"
|
||||
- "SCPS-15009"
|
||||
@@ -8837,10 +8683,7 @@ SCPS-15010:
|
||||
name-en: "Gran Turismo - Concept 2001 Tokyo"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCPS-15011:
|
||||
name: "EXTERMINATION"
|
||||
name-sort: "エクスターミネーション"
|
||||
@@ -9177,11 +9020,7 @@ SCPS-15055:
|
||||
name-sort: "ぐらんつーりすも 4 ぷろろーぐ"
|
||||
name-en: "Gran Turismo 4 Prologue"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-prologue-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95502"
|
||||
- "SCAJ-20066"
|
||||
@@ -9194,7 +9033,6 @@ SCPS-15055:
|
||||
- "SCPS-19304"
|
||||
- "SCPS-15009"
|
||||
- "SCPS-55007"
|
||||
# vuClampMode = 2 Text in GT mode works.
|
||||
SCPS-15056:
|
||||
name: "ラチェット&クランク2 ガガガ!銀河のコマンドーっす"
|
||||
name-sort: "らちぇっとあんどくらんく2 ががが!ぎんがのこまんどーっす"
|
||||
@@ -9650,13 +9488,8 @@ SCPS-15105:
|
||||
name-sort: "つーりすと とろふぃー"
|
||||
name-en: "Tourist Trophy - The Real Riding Simulator"
|
||||
region: "NTSC-J"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCPS-15106:
|
||||
name: "SIREN2"
|
||||
name-sort: "さいれん2"
|
||||
@@ -9811,16 +9644,11 @@ SCPS-17001:
|
||||
name-en: "Gran Turismo 4"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
roundModes:
|
||||
eeRoundMode: 3 # Using chop for both normal+div fixes crash in B5 license test.
|
||||
eeDivRoundMode: 3 # See above.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95502"
|
||||
- "SCAJ-20066"
|
||||
@@ -9847,41 +9675,29 @@ SCPS-17008:
|
||||
name-sort: "ぐらんつーりすも ないき りみてっどえでぃしょん [8inch]"
|
||||
name-en: "Nike - Gran Turismo [Limited Edition - 8 inch]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCPS-17009:
|
||||
name: "NIKE/ GRAN TURISMO Limited Edition [9inch]"
|
||||
name-sort: "ぐらんつーりすも ないき りみてっどえでぃしょん [9inch]"
|
||||
name-en: "Nike - Gran Turismo [Limited Edition - 9 inch]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCPS-17010:
|
||||
name: "NIKE/ GRAN TURISMO Limited Edition [10inch]"
|
||||
name-sort: "ぐらんつーりすも ないき りみてっどえでぃしょん [10inch]"
|
||||
name-en: "Nike - Gran Turismo [Limited Edition - 10 inch]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCPS-17011:
|
||||
name: "NIKE/ GRAN TURISMO Limited Edition [11inch]"
|
||||
name-sort: "ぐらんつーりすも ないき りみてっどえでぃしょん [11inch]"
|
||||
name-en: "Nike - Gran Turismo [Limited Edition - 11 inch]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCPS-17013:
|
||||
name: "ローグギャラクシー ディレクターズカット"
|
||||
name-sort: "ろーぐぎゃらくしー でぃれくたーずかっと"
|
||||
@@ -10037,10 +9853,7 @@ SCPS-19208:
|
||||
name-sort: "ぐらんつーりすも Concept 2001 Tokyo [PlayStation2 the Best]"
|
||||
name-en: "Gran Turismo - Concept 2001 Tokyo [PlayStation2 the Best]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCPS-19209:
|
||||
name: "ぼくのなつやすみ2 海の冒険篇 [PlayStation2 the Best]"
|
||||
name-sort: "ぼくのなつやすみ2 うみのぼうけんへん [PlayStation2 the Best]"
|
||||
@@ -10107,13 +9920,8 @@ SCPS-19252:
|
||||
name-sort: "ぐらんつーりすも 4 [PlayStation2 the Best]"
|
||||
name-en: "Gran Turismo 4 [PlayStation2 the Best]"
|
||||
region: "NTSC-J"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95502"
|
||||
- "SCAJ-20066"
|
||||
@@ -10178,11 +9986,7 @@ SCPS-19304:
|
||||
name-sort: "ぐらんつーりすも 4 ぷろろーぐ [PlayStation2 the Best]"
|
||||
name-en: "Gran Turismo 4 Prologue [PlayStation2 the Best]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-prologue-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95502"
|
||||
- "SCAJ-20066"
|
||||
@@ -10195,7 +9999,6 @@ SCPS-19304:
|
||||
- "SCPS-19304"
|
||||
- "SCPS-15009"
|
||||
- "SCPS-55007"
|
||||
# vuClampMode = 2 Text in GT mode works.
|
||||
SCPS-19305:
|
||||
name: "SIREN [PlayStation2 the Best]"
|
||||
name-sort: "さいれん [PlayStation2 the Best]"
|
||||
@@ -10424,13 +10227,8 @@ SCPS-19324:
|
||||
name-sort: "つーりすと とろふぃー [PlayStation2 the Best]"
|
||||
name-en: "Tourist Trophy - The Real Riding Simulator [PlayStation2 the Best]"
|
||||
region: "NTSC-J"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCPS-19325:
|
||||
name: "サルゲッチュ ミリオンモンキーズ [PlayStation2 the Best]"
|
||||
name-sort: "さるげっちゅ みりおんもんきーず [PlayStation2 the Best]"
|
||||
@@ -10650,10 +10448,7 @@ SCPS-55005:
|
||||
name-sort: "ぐらんつーりすも こんせぷと 2001 Tokyo"
|
||||
name-en: "Gran Turismo - Concept 2001 Tokyo"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCPS-55006:
|
||||
name: "ワイルドアームズ アドヴァンスドサード"
|
||||
name-sort: "わいるどあーむず あどゔぁんすどさーど"
|
||||
@@ -10667,10 +10462,7 @@ SCPS-55007:
|
||||
name-sort: "ぐらんつーりすも 3 - A-Spec"
|
||||
name-en: "Gran Turismo 3 - A-Spec"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCPS-55008:
|
||||
name: "サンダーストライカー"
|
||||
name-sort: "さんだーすとらいかー"
|
||||
@@ -11001,19 +10793,13 @@ SCPS-55902:
|
||||
name-sort: "ぐらんつーりすも - こんせぷと 2002 Tokyo-Geneva"
|
||||
name-en: "Gran Turismo - Concept 2002 Tokyo-Geneva"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCPS-55903:
|
||||
name: "GRAN TURISMO - Concept 2002 Tokyo-Geneva"
|
||||
name-sort: "ぐらんつーりすも - こんせぷと 2002 Tokyo-Geneva"
|
||||
name-en: "Gran Turismo - Concept 2002 Tokyo-Geneva"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCPS-56001:
|
||||
name: "이코"
|
||||
name-en: "Ico"
|
||||
@@ -11049,10 +10835,7 @@ SCPS-56004:
|
||||
SCPS-56005:
|
||||
name: "Gran Turismo Concept - 2002 Tokyo-Seoul" # No listed Korean name on ReDump
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCPS-56006:
|
||||
name: "철권 4"
|
||||
name-en: "Tekken 4"
|
||||
@@ -11131,10 +10914,7 @@ SCPS-72001:
|
||||
name-sort: "ぐらんつーりすも3 A-spec [MEGA HITS!]"
|
||||
name-en: "Gran Turismo 3 - A-Spec [MEGA HITS!]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCPS-72002:
|
||||
name: "みんなのGOLF 3 [MEGA HITS!]"
|
||||
name-sort: "みんなのごるふ 3 [MEGA HITS!]"
|
||||
@@ -11170,13 +10950,8 @@ SCUS-90174:
|
||||
SCUS-90682:
|
||||
name: "Gran Turismo 4"
|
||||
region: "NTSC-U"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCUS-94346:
|
||||
name: "SingStar - Latino"
|
||||
region: "NTSC-U"
|
||||
@@ -11200,10 +10975,7 @@ SCUS-97102:
|
||||
name: "Gran Turismo 3 - A-Spec"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95503"
|
||||
- "SCUS-97102"
|
||||
@@ -11267,10 +11039,7 @@ SCUS-97114:
|
||||
SCUS-97115:
|
||||
name: "Gran Turismo 3 - A-Spec [Demo]"
|
||||
region: "NTSC-U"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCUS-97116:
|
||||
name: "Kiosk Disc 2.1"
|
||||
region: "NTSC-U"
|
||||
@@ -11701,12 +11470,9 @@ SCUS-97218:
|
||||
name: "Kiosk Demo Disc 2.6"
|
||||
region: "NTSC-U"
|
||||
SCUS-97219:
|
||||
name: "Gran Turismo 3 - A-Spec - Nissan 350Z Edition"
|
||||
name: "Gran Turismo Concept - Nissan 350Z Edition"
|
||||
region: "NTSC-U"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
memcardFilters:
|
||||
- "SCUS-97219"
|
||||
- "SCUS-97102"
|
||||
@@ -12063,13 +11829,8 @@ SCUS-97328:
|
||||
name: "Gran Turismo 4"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
memcardFilters: # Allows car imports from GT3 or something.
|
||||
- "PBPX-95503"
|
||||
- "SCUS-97328"
|
||||
@@ -12274,11 +12035,7 @@ SCUS-97383:
|
||||
SCUS-97384:
|
||||
name: "Gran Turismo Special Edition 2004 Toyota [Demo]"
|
||||
region: "NTSC-U"
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-4-prologue-gs-fixes
|
||||
SCUS-97392:
|
||||
name: "NBA '06 featuring The Life Vol.1 [Demo]"
|
||||
region: "NTSC-U"
|
||||
@@ -12507,13 +12264,8 @@ SCUS-97432:
|
||||
SCUS-97436:
|
||||
name: "Gran Turismo 4 [Online Public Beta]"
|
||||
region: "NTSC-U"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
memcardFilters:
|
||||
- "PBPX-95503"
|
||||
- "SCUS-97328"
|
||||
@@ -12731,13 +12483,8 @@ SCUS-97482:
|
||||
SCUS-97483:
|
||||
name: "Gran Turismo 4 MX-5 Edition [Demo]"
|
||||
region: "NTSC-U"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCUS-97484:
|
||||
name: "Sly 3 - Honor Among Thieves [E3 Demo]"
|
||||
region: "NTSC-U"
|
||||
@@ -12860,13 +12607,8 @@ SCUS-97502:
|
||||
name: "Tourist Trophy"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
clampModes:
|
||||
vuClampMode: 2 # Fixes SPS in TT Mode menu caused by the moving tooltips.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCUS-97503:
|
||||
name: "MLB '06 - The Show [Demo]"
|
||||
region: "NTSC-U"
|
||||
@@ -12920,10 +12662,7 @@ SCUS-97512:
|
||||
- "PBPX-95503"
|
||||
- "SCUS-97102"
|
||||
- "SCUS-97512"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 5 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Partially fixes the sun occlusion and lens flare.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
gsHWFixes: *gran-turismo-3-gs-fixes
|
||||
SCUS-97513:
|
||||
name: "Ratchet & Clank 2 - Going Commando [Greatest Hits]"
|
||||
region: "NTSC-U"
|
||||
@@ -13126,13 +12865,8 @@ SCUS-97560:
|
||||
SCUS-97563:
|
||||
name: "Gran Turismo 4"
|
||||
region: "NTSC-U"
|
||||
clampModes:
|
||||
vuClampMode: 2 # Text in GT mode works.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 3 # Improves banding in car showcase as well as car brightness and sheen.
|
||||
halfPixelOffset: 4 # Fixes weird edge shadows and depth bleed which happens on the edge as well.
|
||||
autoFlush: 1 # Helps lens flare and sun occlusion somewhat but doesn't full fix it.
|
||||
getSkipCount: "GSC_PolyphonyDigitalGames" # Fixes post-processing.
|
||||
clampModes: *gran-turismo-4-clamp-modes
|
||||
gsHWFixes: *gran-turismo-4-gs-fixes
|
||||
SCUS-97564:
|
||||
name: "Jampack Demo Disc Vol.15 [T-Rated]"
|
||||
region: "NTSC-U"
|
||||
@@ -15400,6 +15134,14 @@ SLES-50276:
|
||||
name: "The Gift"
|
||||
name-sort: "Gift, The"
|
||||
region: "PAL-E"
|
||||
patches:
|
||||
CC76CD02:
|
||||
content: |-
|
||||
// Sound RPC races because of shared send/receive buffers with badly
|
||||
// placed wait loop, fix by forcing all sound rpc to be synchronous.
|
||||
// Ideal fix would be moving the rpc wait loop though.
|
||||
author=Ziemas
|
||||
patch=0,EE,002159e0,word,00000000
|
||||
SLES-50277:
|
||||
name: "Red Faction"
|
||||
region: "PAL-E"
|
||||
|
||||
@@ -198,7 +198,7 @@ struct PS_OUTPUT
|
||||
|
||||
#if PS_RETURN_COLOR
|
||||
#if PS_DATE == 1 || PS_DATE == 2
|
||||
float c : SV_Target;
|
||||
float c0 : SV_Target;
|
||||
#else
|
||||
|
||||
float4 c0 : SV_Target0;
|
||||
@@ -2014,11 +2014,6 @@ VS_OUTPUT vs_main_expand(uint vid : SV_VertexID)
|
||||
vtx.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none.
|
||||
|
||||
vtx.interior = 0;
|
||||
|
||||
#if !VS_IIP
|
||||
// Get the provoking vertex color (first vertex in DX)
|
||||
vtx.c = i0 == 0 ? vtx.c : (i1 == 0 ? other.c : opposite.c);
|
||||
#endif
|
||||
}
|
||||
|
||||
return vtx;
|
||||
|
||||
@@ -455,11 +455,6 @@ void main()
|
||||
VSout.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none.
|
||||
|
||||
VSout.interior = 0;
|
||||
|
||||
#if !VS_IIP
|
||||
// Get the provoking vertex color (last vertex in GL)
|
||||
vtx.c = i0 == 2 ? vtx.c : (i1 == 2 ? other.c : opposite.c);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -450,11 +450,6 @@ void main()
|
||||
vsOut.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none.
|
||||
|
||||
vsOut.interior = 0;
|
||||
|
||||
#if !VS_IIP
|
||||
// Get the provoking vertex color (last vertex in VK)
|
||||
vtx.c = i0 == 2 ? vtx.c : (i1 == 2 ? other.c : opposite.c);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+102
-30
@@ -17,7 +17,7 @@ struct RapidYAMLContext
|
||||
Error* error = nullptr;
|
||||
};
|
||||
|
||||
std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr file_name, Error* error)
|
||||
std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr file_name, Error* error, bool resolve_anchors)
|
||||
{
|
||||
RapidYAMLContext context;
|
||||
context.error = error;
|
||||
@@ -28,63 +28,135 @@ std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr
|
||||
callbacks.set_user_data(static_cast<void*>(&context));
|
||||
|
||||
callbacks.set_error_basic([](ryml::csubstr msg, const ryml::ErrorDataBasic& errdata, void* user_data) {
|
||||
std::string description;
|
||||
auto callback = [&description](ryml::csubstr string) {
|
||||
description.append(string.str, string.len);
|
||||
};
|
||||
ryml::err_basic_format(std::move(callback), msg, errdata);
|
||||
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
|
||||
// This scope needs to stay, so all objects destruct before std::longjump
|
||||
{
|
||||
std::string description;
|
||||
auto callback = [&description](ryml::csubstr string) {
|
||||
description.append(string.str, string.len);
|
||||
};
|
||||
ryml::err_basic_format(std::move(callback), msg, errdata);
|
||||
|
||||
// We might have already returned, so don't try to recover.
|
||||
pxFailRel(description.c_str());
|
||||
std::abort();
|
||||
if (context != nullptr)
|
||||
{
|
||||
Error::SetString(context->error, std::move(description));
|
||||
}
|
||||
else
|
||||
{
|
||||
pxFailRel(description.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (context != nullptr)
|
||||
{
|
||||
std::longjmp(context->env, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
});
|
||||
|
||||
callbacks.set_error_parse([](ryml::csubstr msg, const ryml::ErrorDataParse& errdata, void* user_data) {
|
||||
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
|
||||
// This scope needs to stay, so all objects destruct before std::longjump
|
||||
{
|
||||
std::string description;
|
||||
auto callback = [&description](ryml::csubstr string) {
|
||||
description.append(string.str, string.len);
|
||||
};
|
||||
ryml::err_parse_format(std::move(callback), msg, errdata);
|
||||
|
||||
std::string description;
|
||||
auto callback = [&description](ryml::csubstr string) {
|
||||
description.append(string.str, string.len);
|
||||
};
|
||||
ryml::err_parse_format(std::move(callback), msg, errdata);
|
||||
if (context != nullptr)
|
||||
{
|
||||
Error::SetString(context->error, std::move(description));
|
||||
}
|
||||
else
|
||||
{
|
||||
pxFailRel(description.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Error::SetString(context->error, std::move(description));
|
||||
std::longjmp(context->env, 1);
|
||||
if (context != nullptr)
|
||||
{
|
||||
std::longjmp(context->env, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
});
|
||||
|
||||
callbacks.set_error_visit([](ryml::csubstr msg, const ryml::ErrorDataVisit& errdata, void* user_data) {
|
||||
std::string description;
|
||||
auto callback = [&description](ryml::csubstr string) {
|
||||
description.append(string.str, string.len);
|
||||
};
|
||||
ryml::err_visit_format(std::move(callback), msg, errdata);
|
||||
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
|
||||
// This scope needs to stay, so all objects destruct before std::longjump
|
||||
{
|
||||
std::string description;
|
||||
auto callback = [&description](ryml::csubstr string) {
|
||||
description.append(string.str, string.len);
|
||||
};
|
||||
ryml::err_visit_format(std::move(callback), msg, errdata);
|
||||
|
||||
// We've probably already returned, so don't try to recover.
|
||||
pxFailRel(description.c_str());
|
||||
std::abort();
|
||||
if (context != nullptr)
|
||||
{
|
||||
Error::SetString(context->error, std::move(description));
|
||||
}
|
||||
else
|
||||
{
|
||||
pxFailRel(description.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (context != nullptr)
|
||||
{
|
||||
std::longjmp(context->env, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
});
|
||||
#else
|
||||
callbacks.m_user_data = static_cast<void*>(&context);
|
||||
callbacks.m_error = [](const char* msg, size_t msg_len, ryml::Location location, void* user_data) {
|
||||
RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data);
|
||||
|
||||
Error::SetString(context->error, std::string(msg, msg_len));
|
||||
std::longjmp(context->env, 1);
|
||||
if (RapidYAMLContext* context = static_cast<RapidYAMLContext*>(user_data))
|
||||
{
|
||||
Error::SetString(context->error, std::string(msg, msg_len));
|
||||
std::longjmp(context->env, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string description(msg, msg_len);
|
||||
pxFailRel(description.c_str());
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
ryml::EventHandlerTree event_handler(callbacks);
|
||||
ryml::Parser parser(&event_handler);
|
||||
|
||||
ryml::Tree tree;
|
||||
ryml::Tree tree(callbacks);
|
||||
|
||||
// The only options RapidYAML provides for recovering from errors are
|
||||
// throwing an exception or using setjmp/longjmp. Since we have exceptions
|
||||
// disabled we have to use the latter option.
|
||||
if (setjmp(context.env))
|
||||
if (setjmp(context.env) != 0)
|
||||
return std::nullopt;
|
||||
|
||||
ryml::parse_in_arena(&parser, file_name, yaml, &tree);
|
||||
if (resolve_anchors)
|
||||
{
|
||||
tree.resolve();
|
||||
}
|
||||
|
||||
// Callbacks passed to ryml::Tree are used for value parsing errors later,
|
||||
// so we need to clear the context before it goes out of scope.
|
||||
#if RYML_VERSION_MAJOR > 0 || RYML_VERSION_MINOR >= 11
|
||||
callbacks.set_user_data(nullptr);
|
||||
#else
|
||||
callbacks.m_user_data = nullptr;
|
||||
#endif
|
||||
tree.callbacks(callbacks);
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
+3
-1
@@ -14,4 +14,6 @@
|
||||
/// parsing errors (as is recommended by the documentation for cases where
|
||||
/// exceptions are disabled). The file_name parameter is only used for error
|
||||
/// messages, which are returned via the error parameter.
|
||||
std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr file_name, Error* error);
|
||||
/// If resolve_anchors is set to true, YAML anchors and aliases will be resolved.
|
||||
/// It's a potentially slow operation, so it's opt-in.
|
||||
std::optional<ryml::Tree> ParseYAMLFromString(ryml::csubstr yaml, ryml::csubstr file_name, Error* error, bool resolve_anchors = false);
|
||||
|
||||
@@ -196,6 +196,7 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Debugger/ModuleModel.h
|
||||
Debugger/ModuleView.cpp
|
||||
Debugger/ModuleView.h
|
||||
Debugger/NavigationHistoryStack.h
|
||||
Debugger/RegisterView.cpp
|
||||
Debugger/RegisterView.h
|
||||
Debugger/RegisterView.ui
|
||||
|
||||
@@ -206,6 +206,29 @@ void DebuggerView::updateStyleSheet()
|
||||
setStyleSheet(stylesheet);
|
||||
}
|
||||
|
||||
bool DebuggerView::supportsNavigation()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DebuggerView::canNavigateBack()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DebuggerView::canNavigateForward()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void DebuggerView::navigateBack()
|
||||
{
|
||||
}
|
||||
|
||||
void DebuggerView::navigateForward()
|
||||
{
|
||||
}
|
||||
|
||||
void DebuggerView::goToInDisassembler(u32 address, bool switch_to_tab)
|
||||
{
|
||||
DebuggerEvents::GoToAddress event;
|
||||
@@ -268,7 +291,7 @@ std::vector<QAction*> DebuggerView::createEventActionsImplementation(
|
||||
if (lhs->displayNameWithoutSuffix() == rhs->displayNameWithoutSuffix())
|
||||
return lhs->displayNameSuffixNumber() < rhs->displayNameSuffixNumber();
|
||||
|
||||
return lhs->displayNameWithoutSuffix() < rhs->displayNameWithoutSuffix();
|
||||
return QtHost::LocaleSensitiveCompare(lhs->displayNameWithoutSuffix(), rhs->displayNameWithoutSuffix()) < 0;
|
||||
});
|
||||
|
||||
QMenu* submenu = nullptr;
|
||||
|
||||
@@ -153,6 +153,12 @@ public:
|
||||
|
||||
void updateStyleSheet();
|
||||
|
||||
virtual bool supportsNavigation();
|
||||
virtual bool canNavigateBack();
|
||||
virtual bool canNavigateForward();
|
||||
virtual void navigateBack();
|
||||
virtual void navigateForward();
|
||||
|
||||
static void goToInDisassembler(u32 address, bool switch_to_tab);
|
||||
static void goToInMemoryView(u32 address, bool switch_to_tab);
|
||||
|
||||
|
||||
@@ -115,6 +115,28 @@ DebuggerWindow::DebuggerWindow(QWidget* parent)
|
||||
|
||||
setMenuWidget(m_dock_manager->createMenuBar(menu_bar));
|
||||
|
||||
connect(m_dock_manager, &DockManager::focusedViewForNavigationChanged,
|
||||
this, &DebuggerWindow::updateNavigationButtons);
|
||||
|
||||
m_ui.actionNavigateBack->setEnabled(false);
|
||||
m_ui.actionNavigateForward->setEnabled(false);
|
||||
|
||||
connect(m_ui.actionNavigateBack, &QAction::triggered, this, [this]() {
|
||||
DebuggerView* view = m_dock_manager->focusedViewForNavigation();
|
||||
if (!view)
|
||||
return;
|
||||
|
||||
view->navigateBack();
|
||||
});
|
||||
|
||||
connect(m_ui.actionNavigateForward, &QAction::triggered, this, [this]() {
|
||||
DebuggerView* view = m_dock_manager->focusedViewForNavigation();
|
||||
if (!view)
|
||||
return;
|
||||
|
||||
view->navigateForward();
|
||||
});
|
||||
|
||||
updateTheme();
|
||||
|
||||
Host::RunOnCPUThread([]() {
|
||||
@@ -307,6 +329,21 @@ void DebuggerWindow::updateFromSettings()
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerWindow::updateNavigationButtons()
|
||||
{
|
||||
DebuggerView* view = m_dock_manager->focusedViewForNavigation();
|
||||
if (view)
|
||||
{
|
||||
m_ui.actionNavigateBack->setEnabled(view->canNavigateBack());
|
||||
m_ui.actionNavigateForward->setEnabled(view->canNavigateForward());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.actionNavigateBack->setEnabled(false);
|
||||
m_ui.actionNavigateForward->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerWindow::onVMStarting()
|
||||
{
|
||||
m_ui.actionRun->setEnabled(true);
|
||||
|
||||
@@ -40,7 +40,9 @@ public:
|
||||
|
||||
void updateFromSettings();
|
||||
|
||||
public slots:
|
||||
void updateNavigationButtons();
|
||||
|
||||
private slots:
|
||||
void onVMStarting();
|
||||
void onVMPaused();
|
||||
void onVMResumed();
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1000</width>
|
||||
<height>750</height>
|
||||
<width>1322</width>
|
||||
<height>974</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -23,8 +23,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1000</width>
|
||||
<height>21</height>
|
||||
<width>1322</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
@@ -58,6 +58,9 @@
|
||||
</property>
|
||||
<addaction name="actionOnTop"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionNavigateBack"/>
|
||||
<addaction name="actionNavigateForward"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionIncreaseFontSize"/>
|
||||
<addaction name="actionDecreaseFontSize"/>
|
||||
<addaction name="actionResetFontSize"/>
|
||||
@@ -82,12 +85,25 @@
|
||||
<addaction name="menuWindows"/>
|
||||
<addaction name="menuLayouts"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBarNavigation">
|
||||
<property name="windowTitle">
|
||||
<string>Navigation</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionNavigateBack"/>
|
||||
<addaction name="actionNavigateForward"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBarDebug">
|
||||
<property name="windowTitle">
|
||||
<string>Debug</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
@@ -105,7 +121,7 @@
|
||||
<string>File</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
@@ -122,7 +138,7 @@
|
||||
<string>System</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
@@ -138,7 +154,7 @@
|
||||
<string>View</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
<enum>Qt::ToolButtonStyle::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
@@ -237,7 +253,7 @@
|
||||
<string>Shut Down</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionReset">
|
||||
@@ -248,7 +264,7 @@
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClose">
|
||||
@@ -259,7 +275,7 @@
|
||||
<string>Close</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionIncreaseFontSize">
|
||||
@@ -270,7 +286,7 @@
|
||||
<string>Increase Font Size</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDecreaseFontSize">
|
||||
@@ -284,7 +300,7 @@
|
||||
<string>Ctrl+-</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionResetFontSize">
|
||||
@@ -295,7 +311,7 @@
|
||||
<string>Reset Font Size</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSettings">
|
||||
@@ -306,7 +322,7 @@
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGameSettings">
|
||||
@@ -317,7 +333,7 @@
|
||||
<string>Game Settings</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionToolsDummy">
|
||||
@@ -330,6 +346,37 @@
|
||||
<string/>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNavigateBack">
|
||||
<property name="icon">
|
||||
<iconset theme="arrow-left-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Navigate Back</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Navigate Back</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Alt+Left</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNavigateForward">
|
||||
<property name="icon">
|
||||
<iconset theme="arrow-right-line"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Navigate Forward</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Alt+Right</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -76,7 +76,11 @@ bool DisassemblyView::fromJson(const JsonValueWrapper& json)
|
||||
|
||||
auto start_address = json.value().FindMember("startAddress");
|
||||
if (start_address != json.value().MemberEnd() && start_address->value.IsUint())
|
||||
{
|
||||
m_visibleStart = start_address->value.GetUint() & ~3;
|
||||
m_navigation_history.clear();
|
||||
m_navigation_history.pushInstantly(m_visibleStart);
|
||||
}
|
||||
|
||||
auto go_to_pc_on_pause = json.value().FindMember("goToPCOnPause");
|
||||
if (go_to_pc_on_pause != json.value().MemberEnd() && go_to_pc_on_pause->value.IsBool())
|
||||
@@ -388,6 +392,41 @@ QString DisassemblyView::GetLineDisasm(u32 address)
|
||||
return QString("%1 %2").arg(lineInfo.name.c_str()).arg(lineInfo.params.c_str());
|
||||
};
|
||||
|
||||
bool DisassemblyView::supportsNavigation()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisassemblyView::canNavigateBack()
|
||||
{
|
||||
return m_navigation_history.canGoBack();
|
||||
}
|
||||
|
||||
bool DisassemblyView::canNavigateForward()
|
||||
{
|
||||
return m_navigation_history.canGoForward();
|
||||
}
|
||||
|
||||
void DisassemblyView::navigateBack()
|
||||
{
|
||||
std::optional<u32> address = m_navigation_history.back();
|
||||
if (!address.has_value())
|
||||
return;
|
||||
|
||||
m_visibleStart = *address;
|
||||
update();
|
||||
}
|
||||
|
||||
void DisassemblyView::navigateForward()
|
||||
{
|
||||
std::optional<u32> address = m_navigation_history.forward();
|
||||
if (!address.has_value())
|
||||
return;
|
||||
|
||||
m_visibleStart = *address;
|
||||
update();
|
||||
}
|
||||
|
||||
// Here we go!
|
||||
void DisassemblyView::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
@@ -629,19 +668,21 @@ void DisassemblyView::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
|
||||
void DisassemblyView::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if (event->angleDelta().y() < 0) // todo: max address bounds check?
|
||||
{
|
||||
if (event->angleDelta().y() < 0)
|
||||
m_visibleStart += 4;
|
||||
}
|
||||
else if (event->angleDelta().y() && m_visibleStart > 0)
|
||||
{
|
||||
m_visibleStart -= 4;
|
||||
}
|
||||
|
||||
m_navigation_history.pushWithDelay(m_visibleStart);
|
||||
update();
|
||||
}
|
||||
|
||||
void DisassemblyView::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
// Alt is used for the global navigation shortcuts.
|
||||
if (event->modifiers() & Qt::AltModifier)
|
||||
return;
|
||||
|
||||
switch (event->key())
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
@@ -653,15 +694,19 @@ void DisassemblyView::keyPressEvent(QKeyEvent* event)
|
||||
// Auto scroll
|
||||
if (m_visibleStart > m_selectedAddressStart)
|
||||
m_visibleStart -= 4;
|
||||
|
||||
m_navigation_history.pushWithDelay(m_visibleStart);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Qt::Key_PageUp:
|
||||
{
|
||||
m_selectedAddressStart -= m_visibleRows * 4;
|
||||
m_selectedAddressEnd = m_selectedAddressStart;
|
||||
m_visibleStart -= m_visibleRows * 4;
|
||||
|
||||
m_navigation_history.pushWithDelay(m_visibleStart);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Qt::Key_Down:
|
||||
{
|
||||
m_selectedAddressEnd += 4;
|
||||
@@ -673,6 +718,7 @@ void DisassemblyView::keyPressEvent(QKeyEvent* event)
|
||||
if (m_visibleStart + ((m_visibleRows - 1) * 4) < m_selectedAddressEnd)
|
||||
m_visibleStart += 4;
|
||||
|
||||
m_navigation_history.pushWithDelay(m_visibleStart);
|
||||
break;
|
||||
}
|
||||
case Qt::Key_PageDown:
|
||||
@@ -680,6 +726,7 @@ void DisassemblyView::keyPressEvent(QKeyEvent* event)
|
||||
m_selectedAddressStart += m_visibleRows * 4;
|
||||
m_selectedAddressEnd = m_selectedAddressStart;
|
||||
m_visibleStart += m_visibleRows * 4;
|
||||
m_navigation_history.pushWithDelay(m_visibleStart);
|
||||
break;
|
||||
}
|
||||
case Qt::Key_G:
|
||||
@@ -1014,6 +1061,8 @@ void DisassemblyView::gotoAddress(u32 address, bool should_set_focus)
|
||||
m_selectedAddressStart = destAddress;
|
||||
m_selectedAddressEnd = destAddress;
|
||||
|
||||
m_navigation_history.pushInstantly(m_visibleStart);
|
||||
|
||||
update();
|
||||
if (should_set_focus)
|
||||
setFocus();
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
|
||||
#include "ui_DisassemblyView.h"
|
||||
|
||||
#include "DebuggerView.h"
|
||||
#include "Debugger/DebuggerView.h"
|
||||
#include "Debugger/NavigationHistoryStack.h"
|
||||
|
||||
#include "pcsx2/DebugTools/DisassemblyManager.h"
|
||||
|
||||
@@ -26,6 +27,12 @@ public:
|
||||
// Required for the breakpoint list (ugh wtf)
|
||||
QString GetLineDisasm(u32 address);
|
||||
|
||||
bool supportsNavigation() override;
|
||||
bool canNavigateBack() override;
|
||||
bool canNavigateForward() override;
|
||||
void navigateBack() override;
|
||||
void navigateForward() override;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
@@ -68,7 +75,7 @@ public slots:
|
||||
private:
|
||||
Ui::DisassemblyView m_ui;
|
||||
|
||||
u32 m_visibleStart = 0x100000; // The address of the first instruction shown.
|
||||
u32 m_visibleStart = STARTING_ADDRESS; // The address of the first instruction shown.
|
||||
u32 m_visibleRows;
|
||||
u32 m_selectedAddressStart = 0;
|
||||
u32 m_selectedAddressEnd = 0;
|
||||
@@ -81,6 +88,8 @@ private:
|
||||
bool m_goToProgramCounterOnPause = true;
|
||||
DisassemblyManager m_disassemblyManager;
|
||||
|
||||
NavigationHistoryStack<u32> m_navigation_history{STARTING_ADDRESS};
|
||||
|
||||
QString GetDisassemblyTitleLine();
|
||||
QColor GetDisassemblyTitleLineColor();
|
||||
inline QString DisassemblyStringFromAddress(u32 address, QFont font, u32 pc, bool selected);
|
||||
@@ -96,4 +105,6 @@ private:
|
||||
void setInstructions(u32 start, u32 end, u32 value);
|
||||
bool AddressCanRestore(u32 start, u32 end);
|
||||
bool FunctionCanRestore(u32 address);
|
||||
|
||||
static constexpr u32 STARTING_ADDRESS = 0x100000;
|
||||
};
|
||||
|
||||
@@ -339,15 +339,28 @@ void DockManager::createToolsMenu(QMenu* menu)
|
||||
if (m_current_layout == DockLayout::INVALID_INDEX || !g_debugger_window)
|
||||
return;
|
||||
|
||||
for (QToolBar* widget : g_debugger_window->findChildren<QToolBar*>())
|
||||
std::vector<QToolBar*> toolbars;
|
||||
for (QToolBar* toolbar : g_debugger_window->findChildren<QToolBar*>())
|
||||
toolbars.emplace_back(toolbar);
|
||||
|
||||
std::sort(toolbars.begin(), toolbars.end(), [](QToolBar* lhs, QToolBar* rhs) {
|
||||
return QtHost::LocaleSensitiveCompare(lhs->windowTitle(), rhs->windowTitle()) < 0;
|
||||
});
|
||||
|
||||
for (QToolBar* toolbar : toolbars)
|
||||
{
|
||||
QAction* action = menu->addAction(widget->windowTitle());
|
||||
action->setText(widget->windowTitle());
|
||||
QAction* action = menu->addAction(toolbar->windowTitle());
|
||||
action->setText(toolbar->windowTitle());
|
||||
action->setCheckable(true);
|
||||
action->setChecked(widget->isVisible());
|
||||
connect(action, &QAction::triggered, this, [widget]() {
|
||||
widget->setVisible(!widget->isVisible());
|
||||
action->setChecked(toolbar->isVisible());
|
||||
|
||||
connect(action, &QAction::triggered, this, [toolbar = QPointer<QToolBar>(toolbar)]() {
|
||||
if (!toolbar)
|
||||
return;
|
||||
|
||||
toolbar->setVisible(!toolbar->isVisible());
|
||||
});
|
||||
|
||||
menu->addAction(action);
|
||||
}
|
||||
}
|
||||
@@ -383,7 +396,7 @@ void DockManager::createWindowsMenu(QMenu* menu)
|
||||
if (lhs->displayNameWithoutSuffix() == rhs->displayNameWithoutSuffix())
|
||||
return lhs->displayNameSuffixNumber() < rhs->displayNameSuffixNumber();
|
||||
|
||||
return lhs->displayNameWithoutSuffix() < rhs->displayNameWithoutSuffix();
|
||||
return QtHost::LocaleSensitiveCompare(lhs->displayNameWithoutSuffix(), rhs->displayNameWithoutSuffix()) < 0;
|
||||
});
|
||||
|
||||
for (DebuggerView* widget : add_another_widgets)
|
||||
@@ -472,7 +485,7 @@ void DockManager::createWindowsMenu(QMenu* menu)
|
||||
if (lhs.display_name == rhs.display_name)
|
||||
return lhs.suffix_number < rhs.suffix_number;
|
||||
|
||||
return lhs.display_name < rhs.display_name;
|
||||
return QtHost::LocaleSensitiveCompare(lhs.display_name, rhs.display_name) < 0;
|
||||
});
|
||||
|
||||
for (const DebuggerViewToggle& toggle : toggles)
|
||||
@@ -862,6 +875,24 @@ std::optional<BreakPointCpu> DockManager::cpu()
|
||||
return m_layouts.at(m_current_layout).cpu();
|
||||
}
|
||||
|
||||
DebuggerView* DockManager::focusedViewForNavigation()
|
||||
{
|
||||
if (!m_focused_view_for_navigation)
|
||||
return nullptr;
|
||||
|
||||
return m_focused_view_for_navigation;
|
||||
}
|
||||
|
||||
void DockManager::onFocusedDockWidgetChanged(KDDockWidgets::QtWidgets::DockWidget* widget)
|
||||
{
|
||||
DebuggerView* view = qobject_cast<DebuggerView*>(widget->widget());
|
||||
if (view && view->supportsNavigation() && view != m_focused_view_for_navigation)
|
||||
{
|
||||
m_focused_view_for_navigation = view;
|
||||
emit focusedViewForNavigationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
KDDockWidgets::Core::DockWidget* DockManager::dockWidgetFactory(const QString& name)
|
||||
{
|
||||
if (!g_debugger_window)
|
||||
|
||||
@@ -98,6 +98,14 @@ public:
|
||||
|
||||
std::optional<BreakPointCpu> cpu();
|
||||
|
||||
/// Returns the last focused view that supports back/forward navigation.
|
||||
DebuggerView* focusedViewForNavigation();
|
||||
|
||||
void onFocusedDockWidgetChanged(KDDockWidgets::QtWidgets::DockWidget* widget);
|
||||
|
||||
Q_SIGNALS:
|
||||
void focusedViewForNavigationChanged();
|
||||
|
||||
private:
|
||||
static KDDockWidgets::Core::DockWidget* dockWidgetFactory(const QString& name);
|
||||
static bool dragAboutToStart(KDDockWidgets::Core::Draggable* draggable);
|
||||
@@ -108,4 +116,6 @@ private:
|
||||
DockMenuBar* m_menu_bar = nullptr;
|
||||
|
||||
bool m_layout_locked = true;
|
||||
|
||||
QPointer<DebuggerView> m_focused_view_for_navigation;
|
||||
};
|
||||
|
||||
@@ -82,6 +82,7 @@ const std::vector<DockTables::DefaultDockLayout> DockTables::DEFAULT_DOCK_LAYOUT
|
||||
{"MemorySearchView", DefaultDockGroup::TOP_LEFT},
|
||||
},
|
||||
.toolbars = {
|
||||
"toolBarNavigation",
|
||||
"toolBarDebug",
|
||||
"toolBarFile",
|
||||
},
|
||||
@@ -113,6 +114,7 @@ const std::vector<DockTables::DefaultDockLayout> DockTables::DEFAULT_DOCK_LAYOUT
|
||||
{"MemorySearchView", DefaultDockGroup::TOP_LEFT},
|
||||
},
|
||||
.toolbars = {
|
||||
"toolBarNavigation",
|
||||
"toolBarDebug",
|
||||
"toolBarFile",
|
||||
},
|
||||
|
||||
@@ -82,6 +82,7 @@ DockWidget::DockWidget(
|
||||
: KDDockWidgets::QtWidgets::DockWidget(unique_name, options, layout_saver_options, window_flags)
|
||||
{
|
||||
connect(this, &DockWidget::isOpenChanged, this, &DockWidget::openStateChanged);
|
||||
connect(this, &DockWidget::isFocusedChanged, this, &DockWidget::focusStateChanged);
|
||||
}
|
||||
|
||||
void DockWidget::openStateChanged(bool open)
|
||||
@@ -95,6 +96,12 @@ void DockWidget::openStateChanged(bool open)
|
||||
g_debugger_window->dockManager().destroyDebuggerView(uniqueName());
|
||||
}
|
||||
|
||||
void DockWidget::focusStateChanged(bool focused)
|
||||
{
|
||||
if (focused && g_debugger_window)
|
||||
g_debugger_window->dockManager().onFocusedDockWidgetChanged(this);
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
DockTitleBar::DockTitleBar(KDDockWidgets::Core::TitleBar* controller, KDDockWidgets::Core::View* parent)
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
|
||||
protected:
|
||||
void openStateChanged(bool open);
|
||||
void focusStateChanged(bool focused);
|
||||
};
|
||||
|
||||
class DockTitleBar : public KDDockWidgets::QtWidgets::TitleBar
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
<height>150</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>600</width>
|
||||
<height>300</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string/>
|
||||
</property>
|
||||
@@ -19,7 +25,7 @@
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="nameLabel">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>nameEditor</cstring>
|
||||
@@ -29,7 +35,7 @@
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="cpuLabel">
|
||||
<property name="text">
|
||||
<string>Target</string>
|
||||
<string>Target:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>cpuEditor</cstring>
|
||||
@@ -39,7 +45,7 @@
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="initialStateLabel">
|
||||
<property name="text">
|
||||
<string>Initial State</string>
|
||||
<string>Initial State:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>initialStateEditor</cstring>
|
||||
|
||||
@@ -19,9 +19,11 @@ using namespace QtUtils;
|
||||
/*
|
||||
MemoryViewTable
|
||||
*/
|
||||
void MemoryViewTable::UpdateStartAddress(u32 start)
|
||||
void MemoryViewTable::UpdateStartAddress(u32 start, NavigationHistoryOperation history_operation)
|
||||
{
|
||||
startAddress = start & ~0xF;
|
||||
navigation_history.push(startAddress, history_operation);
|
||||
parent->update();
|
||||
}
|
||||
|
||||
void MemoryViewTable::UpdateSelectedAddress(u32 selected, bool page)
|
||||
@@ -41,6 +43,13 @@ void MemoryViewTable::UpdateSelectedAddress(u32 selected, bool page)
|
||||
else
|
||||
startAddress += 0x10;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
navigation_history.pushWithDelay(startAddress);
|
||||
parent->update();
|
||||
}
|
||||
|
||||
void MemoryViewTable::DrawTable(QPainter& painter, const QPalette& palette, s32 height, DebugInterface& cpu)
|
||||
@@ -684,7 +693,7 @@ MemoryView::MemoryView(const DebuggerViewParameters& parameters)
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(this, &MemoryView::customContextMenuRequested, this, &MemoryView::openContextMenu);
|
||||
|
||||
m_table.UpdateStartAddress(0x100000);
|
||||
m_table.UpdateStartAddress(0x100000, NavigationHistoryOperation::INSTANT_PUSH);
|
||||
|
||||
receiveEvent<DebuggerEvents::Refresh>([this](const DebuggerEvents::Refresh& event) -> bool {
|
||||
update();
|
||||
@@ -723,7 +732,10 @@ bool MemoryView::fromJson(const JsonValueWrapper& json)
|
||||
|
||||
auto start_address = json.value().FindMember("startAddress");
|
||||
if (start_address != json.value().MemberEnd() && start_address->value.IsUint())
|
||||
m_table.UpdateStartAddress(start_address->value.GetUint());
|
||||
{
|
||||
m_table.navigation_history.clear();
|
||||
m_table.UpdateStartAddress(start_address->value.GetUint(), NavigationHistoryOperation::INSTANT_PUSH);
|
||||
}
|
||||
|
||||
auto view_type = json.value().FindMember("viewType");
|
||||
if (view_type != json.value().MemberEnd() && view_type->value.IsInt())
|
||||
@@ -746,6 +758,40 @@ bool MemoryView::fromJson(const JsonValueWrapper& json)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MemoryView::supportsNavigation()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MemoryView::canNavigateBack()
|
||||
{
|
||||
return m_table.navigation_history.canGoBack();
|
||||
}
|
||||
|
||||
bool MemoryView::canNavigateForward()
|
||||
{
|
||||
return m_table.navigation_history.canGoForward();
|
||||
}
|
||||
|
||||
void MemoryView::navigateBack()
|
||||
{
|
||||
std::optional<u32> address = m_table.navigation_history.back();
|
||||
if (!address.has_value())
|
||||
return;
|
||||
|
||||
m_table.UpdateStartAddress(*address, NavigationHistoryOperation::NO_PUSH);
|
||||
}
|
||||
|
||||
void MemoryView::navigateForward()
|
||||
{
|
||||
std::optional<u32> address = m_table.navigation_history.forward();
|
||||
if (!address.has_value())
|
||||
return;
|
||||
|
||||
m_table.UpdateStartAddress(*address, NavigationHistoryOperation::NO_PUSH);
|
||||
}
|
||||
|
||||
|
||||
void MemoryView::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
QPainter painter(this);
|
||||
@@ -928,17 +974,20 @@ void MemoryView::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if (event->angleDelta().y() < 0)
|
||||
{
|
||||
m_table.UpdateStartAddress(m_table.startAddress + 0x10);
|
||||
m_table.UpdateStartAddress(m_table.startAddress + 0x10, NavigationHistoryOperation::DELAYED_PUSH);
|
||||
}
|
||||
else if (event->angleDelta().y() > 0)
|
||||
{
|
||||
m_table.UpdateStartAddress(m_table.startAddress - 0x10);
|
||||
m_table.UpdateStartAddress(m_table.startAddress - 0x10, NavigationHistoryOperation::DELAYED_PUSH);
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void MemoryView::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
// Alt is used for the global navigation shortcuts.
|
||||
if (event->modifiers() & Qt::AltModifier)
|
||||
return;
|
||||
|
||||
if (!m_table.KeyPress(event->key(), event->text().size() ? event->text()[0] : '\0', cpu()))
|
||||
{
|
||||
switch (event->key())
|
||||
@@ -960,9 +1009,8 @@ void MemoryView::keyPressEvent(QKeyEvent* event)
|
||||
|
||||
void MemoryView::gotoAddress(u32 address)
|
||||
{
|
||||
m_table.UpdateStartAddress(address & ~0xF);
|
||||
m_table.UpdateStartAddress(address & ~0xF, NavigationHistoryOperation::INSTANT_PUSH);
|
||||
m_table.selectedAddress = address;
|
||||
update();
|
||||
setFocus();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "ui_MemoryView.h"
|
||||
|
||||
#include "Debugger/DebuggerView.h"
|
||||
#include "Debugger/NavigationHistoryStack.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/DisassemblyManager.h"
|
||||
@@ -93,7 +94,9 @@ public:
|
||||
u32 selectedAddress = 0;
|
||||
s32 selectedIndex = 0;
|
||||
|
||||
void UpdateStartAddress(u32 start);
|
||||
NavigationHistoryStack<u32> navigation_history;
|
||||
|
||||
void UpdateStartAddress(u32 start, NavigationHistoryOperation history_operation);
|
||||
void UpdateSelectedAddress(u32 selected, bool page = false);
|
||||
void DrawTable(QPainter& painter, const QPalette& palette, s32 height, DebugInterface& cpu);
|
||||
void SelectAt(QPoint pos);
|
||||
@@ -136,6 +139,12 @@ public:
|
||||
void toJson(JsonValueWrapper& json) override;
|
||||
bool fromJson(const JsonValueWrapper& json) override;
|
||||
|
||||
bool supportsNavigation() override;
|
||||
bool canNavigateBack() override;
|
||||
bool canNavigateForward() override;
|
||||
void navigateBack() override;
|
||||
void navigateForward() override;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Debugger/DebuggerWindow.h"
|
||||
|
||||
#include <QtCore/QTimer>
|
||||
|
||||
#include <deque>
|
||||
|
||||
enum class NavigationHistoryOperation
|
||||
{
|
||||
INSTANT_PUSH,
|
||||
DELAYED_PUSH,
|
||||
NO_PUSH
|
||||
};
|
||||
|
||||
/// Data structure for storing navigation history, to be used for the back and
|
||||
/// forward buttons.
|
||||
template <typename Element>
|
||||
class NavigationHistoryStack
|
||||
{
|
||||
public:
|
||||
NavigationHistoryStack()
|
||||
: m_position(m_elements.end())
|
||||
{
|
||||
m_timer.setInterval(DELAY_MILLISECONDS);
|
||||
|
||||
QObject::connect(&m_timer, &QTimer::timeout, [this]() {
|
||||
pushInstantly(std::move(m_pending));
|
||||
m_timer.stop();
|
||||
});
|
||||
}
|
||||
|
||||
NavigationHistoryStack(Element element)
|
||||
: NavigationHistoryStack()
|
||||
{
|
||||
pushInstantly(std::move(element));
|
||||
}
|
||||
|
||||
NavigationHistoryStack(const NavigationHistoryStack<Element>&) = delete;
|
||||
NavigationHistoryStack<Element>& operator=(const NavigationHistoryStack<Element>&) = delete;
|
||||
|
||||
NavigationHistoryStack(NavigationHistoryStack<Element>&&) = delete;
|
||||
NavigationHistoryStack<Element>& operator=(NavigationHistoryStack<Element>&&) = delete;
|
||||
|
||||
/// Push an element onto the stack.
|
||||
void push(Element element, NavigationHistoryOperation operation)
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case NavigationHistoryOperation::INSTANT_PUSH:
|
||||
pushInstantly(std::move(element));
|
||||
break;
|
||||
case NavigationHistoryOperation::DELAYED_PUSH:
|
||||
pushWithDelay(std::move(element));
|
||||
break;
|
||||
case NavigationHistoryOperation::NO_PUSH:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait a second, and then push an element onto the stack. If another
|
||||
/// element is pushed, then that will take priority. This is useful if we're
|
||||
/// storing a scroll position, and don't want the stack to be spammed with
|
||||
/// new values when the user scrolls, for example.
|
||||
void pushWithDelay(Element element)
|
||||
{
|
||||
m_pending = std::move(element);
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
/// Push an element onto the stack instantly.
|
||||
void pushInstantly(Element element)
|
||||
{
|
||||
m_timer.stop();
|
||||
|
||||
if (m_position != m_elements.end() && element == *(m_position - 1))
|
||||
return;
|
||||
|
||||
updateNavigationButtons();
|
||||
|
||||
m_elements.erase(m_position, m_elements.end());
|
||||
m_elements.push_back(std::move(element));
|
||||
|
||||
if (m_elements.size() > MAX_ELEMENTS)
|
||||
m_elements.pop_front();
|
||||
|
||||
m_position = m_elements.end();
|
||||
}
|
||||
|
||||
/// Should to user have an option to go back?
|
||||
bool canGoBack() const
|
||||
{
|
||||
return m_elements.begin() != m_elements.end() && m_position > m_elements.begin() + 1;
|
||||
}
|
||||
|
||||
/// Should the user have an option to go forward?
|
||||
bool canGoForward() const
|
||||
{
|
||||
return m_position != m_elements.end();
|
||||
}
|
||||
|
||||
// Retrieve the current element.
|
||||
std::optional<Element> current() const
|
||||
{
|
||||
if (m_position == m_elements.begin())
|
||||
return std::nullopt;
|
||||
|
||||
return *(m_position - 1);
|
||||
}
|
||||
|
||||
/// Go back one.
|
||||
std::optional<Element> back()
|
||||
{
|
||||
updateNavigationButtons();
|
||||
|
||||
if (!canGoBack())
|
||||
return std::nullopt;
|
||||
|
||||
m_position--;
|
||||
return *(m_position - 1);
|
||||
}
|
||||
|
||||
/// Go forward one.
|
||||
std::optional<Element> forward()
|
||||
{
|
||||
updateNavigationButtons();
|
||||
|
||||
if (!canGoForward())
|
||||
return std::nullopt;
|
||||
|
||||
Element element = *m_position;
|
||||
m_position++;
|
||||
return element;
|
||||
}
|
||||
|
||||
/// Remove all elements.
|
||||
void clear()
|
||||
{
|
||||
m_elements.clear();
|
||||
m_position = m_elements.end();
|
||||
m_timer.stop();
|
||||
}
|
||||
|
||||
private:
|
||||
void updateNavigationButtons()
|
||||
{
|
||||
QTimer::singleShot(0, []() {
|
||||
if (g_debugger_window)
|
||||
g_debugger_window->updateNavigationButtons();
|
||||
});
|
||||
}
|
||||
|
||||
std::deque<Element> m_elements;
|
||||
std::deque<Element>::iterator m_position;
|
||||
|
||||
QTimer m_timer;
|
||||
Element m_pending;
|
||||
|
||||
static constexpr int DELAY_MILLISECONDS = 1000;
|
||||
static constexpr size_t MAX_ELEMENTS = 1000;
|
||||
};
|
||||
@@ -216,7 +216,7 @@ void LogWindow::createUi()
|
||||
m_newline_on_enter = state == Qt::CheckState::Checked;
|
||||
});
|
||||
|
||||
m_input_hbox = new QHBoxLayout(this);
|
||||
m_input_hbox = new QHBoxLayout;
|
||||
m_input_hbox->addWidget(m_line_input, 1);
|
||||
m_input_hbox->addWidget(m_local_echo_checkbox);
|
||||
m_input_hbox->addWidget(m_newline_on_enter_checkbox);
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QLocale>
|
||||
#include <QtCore/QtGlobal>
|
||||
#include <QtCore/QMetaObject>
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QtGui/QIcon>
|
||||
@@ -15,6 +17,7 @@
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QHeaderView>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
@@ -27,21 +30,35 @@
|
||||
#include <QtWidgets/QTableView>
|
||||
#include <QtWidgets/QTreeView>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#include <QtGui/private/qtx11extras_p.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
|
||||
#include "common/CocoaTools.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "pcsx2/Config.h"
|
||||
#include "QtHost.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include "common/RedtapeWilCom.h"
|
||||
#include <Shlobj.h>
|
||||
#include <shobjidl.h>
|
||||
#include <comdef.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
namespace QtUtils
|
||||
@@ -549,4 +566,453 @@ namespace QtUtils
|
||||
const QString flag_path = QStringLiteral("%1/icons/flags/%2.svg").arg(QtHost::GetResourcesBasePath()).arg(country_code.toLower());
|
||||
return QIcon(flag_path);
|
||||
}
|
||||
|
||||
bool IsRunningInFlatpak()
|
||||
{
|
||||
// Checks for the existence of the `.flatpak-info` file which seems to be always present inside flatpak sandboxes.
|
||||
return FileSystem::FileExists("/.flatpak-info");
|
||||
}
|
||||
|
||||
bool IsRunningInAppImage()
|
||||
{
|
||||
// The AppImage runtime sets APPIMAGE environment variable so we can check for that.
|
||||
return std::getenv("APPIMAGE") != nullptr;
|
||||
}
|
||||
|
||||
void CreateShortcut(QWidget* parent, const std::string& name, const std::string& game_path,
|
||||
std::vector<std::string> passed_cli_args, const std::string& custom_args,
|
||||
const std::string& icon_path, bool is_desktop, bool prompt_for_destination)
|
||||
{
|
||||
const auto tr_msg = [](const char* str) {
|
||||
return QCoreApplication::translate("CreateShortcut", str);
|
||||
};
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (name.empty())
|
||||
{
|
||||
Console.Error("Cannot create shortcuts without a name.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitize filename
|
||||
const std::string clean_name = Path::SanitizeFileName(name);
|
||||
std::string clean_path = game_path.empty() ? std::string() : Path::ToNativePath(Path::RealPath(game_path));
|
||||
if (!Path::IsValidFileName(clean_name))
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("Filename contains illegal character."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get path to Desktop or per-user Start Menu\Programs directory
|
||||
// https://superuser.com/questions/1489874/how-can-i-get-the-real-path-of-desktop-in-windows-explorer/1789849#1789849
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
|
||||
// https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
|
||||
std::string link_file;
|
||||
if (wil::unique_cotaskmem_string directory; SUCCEEDED(SHGetKnownFolderPath(is_desktop ? FOLDERID_Desktop : FOLDERID_Programs, 0, NULL, &directory)))
|
||||
{
|
||||
std::string directory_utf8 = StringUtil::WideStringToUTF8String(directory.get());
|
||||
|
||||
if (is_desktop)
|
||||
link_file = Path::ToNativePath(fmt::format("{}/{}.lnk", directory_utf8, clean_name));
|
||||
else
|
||||
{
|
||||
const std::string pcsx2_start_menu_dir = Path::ToNativePath(fmt::format("{}/PCSX2", directory_utf8));
|
||||
if (!FileSystem::EnsureDirectoryExists(pcsx2_start_menu_dir.c_str(), false))
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("Could not create start menu directory."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
link_file = Path::ToNativePath(fmt::format("{}/{}.lnk", pcsx2_start_menu_dir, clean_name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), is_desktop ? tr_msg("'Desktop' directory not found") : tr_msg("User's 'Start Menu\\Programs' directory not found"), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the same shortcut already exists
|
||||
if (prompt_for_destination && FileSystem::FileExists(link_file.c_str()))
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("A shortcut with the same name already exists."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Shortcut CmdLine Args
|
||||
bool lossless = true;
|
||||
for (std::string& arg : passed_cli_args)
|
||||
lossless &= EscapeShortcutCommandLine(&arg);
|
||||
if (!clean_path.empty())
|
||||
lossless &= EscapeShortcutCommandLine(&clean_path);
|
||||
|
||||
if (!lossless)
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("File path contains invalid character(s)."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string final_args = StringUtil::JoinString(passed_cli_args.begin(), passed_cli_args.end(), " ");
|
||||
if (!custom_args.empty())
|
||||
{
|
||||
if (!final_args.empty())
|
||||
final_args += ' ';
|
||||
final_args += custom_args;
|
||||
}
|
||||
if (!clean_path.empty())
|
||||
{
|
||||
if (!final_args.empty())
|
||||
final_args += ' ';
|
||||
final_args += fmt::format("-- {}", clean_path);
|
||||
}
|
||||
|
||||
Console.WriteLnFmt("Creating a shortcut '{}' with arguments '{}'", link_file, final_args);
|
||||
|
||||
const auto str_error = [](HRESULT hr) -> std::string {
|
||||
_com_error err(hr);
|
||||
const TCHAR* errMsg = err.ErrorMessage();
|
||||
return fmt::format("{} [{}]", StringUtil::WideStringToUTF8String(errMsg), hr);
|
||||
};
|
||||
|
||||
// Construct the shortcut
|
||||
// https://stackoverflow.com/questions/3906974/how-to-programmatically-create-a-shortcut-using-win32
|
||||
HRESULT res = CoInitialize(NULL);
|
||||
if (FAILED(res))
|
||||
{
|
||||
Console.ErrorFmt("Failed to create shortcut: CoInitialize failed ({})", str_error(res));
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("CoInitialize failed (%1)").arg(QString::fromStdString(str_error(res))), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
wil::unique_couninitialize_call co_cleanup;
|
||||
|
||||
const auto report_error = [&](const QString& reason) {
|
||||
Console.ErrorFmt("Failed to create shortcut: {}", reason.toStdString());
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), reason, QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
};
|
||||
|
||||
wil::com_ptr_nothrow<IShellLink> pShellLink = wil::CoCreateInstanceNoThrow<IShellLink>(CLSID_ShellLink);
|
||||
wil::com_ptr_nothrow<IPersistFile> pPersistFile;
|
||||
|
||||
if (!pShellLink)
|
||||
{
|
||||
report_error(tr_msg("CoCreateInstance failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set path to the executable
|
||||
const std::wstring target_file = StringUtil::UTF8StringToWideString(FileSystem::GetProgramPath());
|
||||
res = pShellLink->SetPath(target_file.c_str());
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr_msg("SetPath failed (%1)").arg(QString::fromStdString(str_error(res))));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the working directory
|
||||
const std::wstring working_dir = StringUtil::UTF8StringToWideString(Path::GetDirectory(FileSystem::GetProgramPath()));
|
||||
res = pShellLink->SetWorkingDirectory(working_dir.c_str());
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr_msg("SetWorkingDirectory failed (%1)").arg(QString::fromStdString(str_error(res))));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the description (shown as the shortcut's tooltip)
|
||||
const std::wstring description = tr_msg("PlayStation 2 Emulator").toStdWString();
|
||||
res = pShellLink->SetDescription(description.c_str());
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr_msg("SetDescription failed (%1)").arg(QString::fromStdString(str_error(res))));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the launch arguments
|
||||
if (!final_args.empty())
|
||||
{
|
||||
const std::wstring target_cli_args = StringUtil::UTF8StringToWideString(final_args);
|
||||
res = pShellLink->SetArguments(target_cli_args.c_str());
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr_msg("SetArguments failed (%1)").arg(QString::fromStdString(str_error(res))));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the icon
|
||||
std::string final_icon_path;
|
||||
if (!icon_path.empty())
|
||||
{
|
||||
final_icon_path = Path::ToNativePath(icon_path);
|
||||
if (!FileSystem::FileExists(final_icon_path.c_str()))
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("The selected icon file does not exist."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
final_icon_path = Path::ToNativePath(Path::Combine(Path::GetDirectory(FileSystem::GetProgramPath()), "resources/icons/AppIconLarge.ico"));
|
||||
}
|
||||
|
||||
const std::wstring w_icon_path = StringUtil::UTF8StringToWideString(final_icon_path);
|
||||
res = pShellLink->SetIconLocation(w_icon_path.c_str(), 0);
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr_msg("SetIconLocation failed (%1)").arg(QString::fromStdString(str_error(res))));
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the IPersistFile object to save the shell link
|
||||
res = pShellLink.query_to(&pPersistFile);
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr_msg("QueryInterface failed (%1)").arg(QString::fromStdString(str_error(res))));
|
||||
return;
|
||||
}
|
||||
|
||||
// Save shortcut link to disk
|
||||
const std::wstring w_link_file = StringUtil::UTF8StringToWideString(link_file);
|
||||
res = pPersistFile->Save(w_link_file.c_str(), TRUE);
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr_msg("Failed to save the shortcut (%1)").arg(QString::fromStdString(str_error(res))));
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (name.empty())
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("Cannot create a shortcut without a title."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_flatpak = IsRunningInFlatpak();
|
||||
|
||||
// Sanitize filename and game path
|
||||
const std::string clean_name = Path::SanitizeFileName(name);
|
||||
std::string clean_path = game_path.empty() ? std::string() : Path::Canonicalize(Path::RealPath(game_path));
|
||||
if (!Path::IsValidFileName(clean_name))
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("Filename contains illegal character."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the executable path
|
||||
std::string executable_path = FileSystem::GetPackagePath();
|
||||
if (executable_path.empty())
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("Executable path is empty."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the destination directory
|
||||
const QString link_dir = QStandardPaths::writableLocation(is_desktop ? QStandardPaths::DesktopLocation : QStandardPaths::ApplicationsLocation);
|
||||
if (link_dir.isEmpty())
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("Could not determine the shortcut destination directory."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
const std::string link_path = fmt::format("{}/{}.desktop", link_dir.toStdString(), clean_name);
|
||||
|
||||
std::string icon_name;
|
||||
if (!icon_path.empty())
|
||||
{
|
||||
if (!FileSystem::FileExists(icon_path.c_str()))
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("The selected icon file does not exist."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
icon_name = icon_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_flatpak) // Flatpak
|
||||
{
|
||||
executable_path = "flatpak run net.pcsx2.PCSX2";
|
||||
icon_name = "net.pcsx2.PCSX2";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy PCSX2 icon
|
||||
icon_name = "PCSX2";
|
||||
const std::string icon_dest = fmt::format("{}/icons/hicolor/512x512/apps/", QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation).toStdString());
|
||||
const std::string icon_path_dest = fmt::format("{}/{}.png", icon_dest, icon_name);
|
||||
if (FileSystem::EnsureDirectoryExists(icon_dest.c_str(), true))
|
||||
FileSystem::CopyFilePath(Path::Combine(EmuFolders::Resources, "icons/AppIconLarge.png").c_str(), icon_path_dest.c_str(), true);
|
||||
}
|
||||
}
|
||||
|
||||
// Shortcut CmdLine Args
|
||||
bool lossless = true;
|
||||
for (std::string& arg : passed_cli_args)
|
||||
lossless &= EscapeShortcutCommandLine(&arg);
|
||||
if (!is_flatpak)
|
||||
lossless &= EscapeShortcutCommandLine(&executable_path);
|
||||
if (!clean_path.empty())
|
||||
lossless &= EscapeShortcutCommandLine(&clean_path);
|
||||
|
||||
if (!lossless)
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("File path contains invalid character(s)."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cmdline = StringUtil::JoinString(passed_cli_args.begin(), passed_cli_args.end(), " ");
|
||||
|
||||
// Assembling the .desktop file
|
||||
std::string final_args = executable_path;
|
||||
if (!cmdline.empty())
|
||||
final_args += fmt::format(" {}", cmdline);
|
||||
if (!custom_args.empty())
|
||||
final_args += fmt::format(" {}", custom_args);
|
||||
if (!clean_path.empty())
|
||||
final_args += fmt::format(" -- {}", clean_path);
|
||||
std::string file_content =
|
||||
"[Desktop Entry]\n"
|
||||
"Version=1.0\n"
|
||||
"Type=Application\n"
|
||||
"Terminal=false\n"
|
||||
"StartupWMClass=pcsx2-qt\n"
|
||||
"Exec=" +
|
||||
final_args + "\n" +
|
||||
"Name=" +
|
||||
name + "\n" +
|
||||
"GenericName=PlayStation 2 Emulator\n"
|
||||
"Icon=" +
|
||||
icon_name + "\n" +
|
||||
"Comment=Sony PlayStation 2 Emulator\n"
|
||||
"Keywords=game;emulator;\n"
|
||||
"Categories=Game;Emulator;\n";
|
||||
std::string_view sv(file_content);
|
||||
|
||||
QString final_path = QString::fromStdString(link_path);
|
||||
if (prompt_for_destination)
|
||||
{
|
||||
const QString filter(tr_msg("Desktop Shortcut Files (*.desktop)"));
|
||||
final_path = QDir::toNativeSeparators(QFileDialog::getSaveFileName(parent, tr_msg("Select Shortcut Save Destination"), final_path, filter));
|
||||
if (final_path.isEmpty())
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string link_dir(Path::GetDirectory(link_path));
|
||||
if (!link_dir.empty() && !FileSystem::EnsureDirectoryExists(link_dir.c_str(), true))
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("Could not create the shortcut directory."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Write to .desktop file
|
||||
if (!FileSystem::WriteStringToFile(final_path.toStdString().c_str(), sv))
|
||||
{
|
||||
QMessageBox::critical(parent, tr_msg("Failed to create shortcut"), tr_msg("Failed to create .desktop file"), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
if (chmod(final_path.toStdString().c_str(), S_IRWXU) != 0) // enables user to execute file
|
||||
Console.ErrorFmt("Failed to change file permissions for .desktop file: {} ({})", strerror(errno), errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool EscapeShortcutCommandLine(std::string* arg)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!arg->empty() && arg->find_first_of(" \t\n\v\"") == std::string::npos)
|
||||
return true;
|
||||
|
||||
std::string temp;
|
||||
temp.reserve(arg->length() + 10);
|
||||
temp += '"';
|
||||
|
||||
for (auto it = arg->begin();; ++it)
|
||||
{
|
||||
int backslash_count = 0;
|
||||
while (it != arg->end() && *it == '\\')
|
||||
{
|
||||
++it;
|
||||
++backslash_count;
|
||||
}
|
||||
|
||||
if (it == arg->end())
|
||||
{
|
||||
temp.append(backslash_count * 2, '\\');
|
||||
break;
|
||||
}
|
||||
|
||||
if (*it == '"')
|
||||
{
|
||||
temp.append(backslash_count * 2 + 1, '\\');
|
||||
temp += '"';
|
||||
}
|
||||
else
|
||||
{
|
||||
temp.append(backslash_count, '\\');
|
||||
temp += *it;
|
||||
}
|
||||
}
|
||||
|
||||
temp += '"';
|
||||
*arg = std::move(temp);
|
||||
return true;
|
||||
#else
|
||||
const char* carg = arg->c_str();
|
||||
const char* cend = carg + arg->size();
|
||||
const char* RESERVED_CHARS = " \t\n\\\"'\\\\><~|%&;$*?#()`"
|
||||
"\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0d\x0e\x0f"
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f";
|
||||
const char* next = carg + std::strcspn(carg, RESERVED_CHARS);
|
||||
|
||||
if (next == cend)
|
||||
return true; // No escaping needed, don't modify
|
||||
|
||||
bool lossless = true;
|
||||
std::string temp = "\"";
|
||||
const char* NOT_VALID_IN_QUOTE = "%`$\"\\\n"
|
||||
"\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0d\x0e\x0f"
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f";
|
||||
|
||||
while (true)
|
||||
{
|
||||
next = carg + std::strcspn(carg, NOT_VALID_IN_QUOTE);
|
||||
temp.append(carg, next);
|
||||
carg = next;
|
||||
|
||||
if (carg == cend)
|
||||
break;
|
||||
|
||||
switch (*carg)
|
||||
{
|
||||
case '"':
|
||||
case '`':
|
||||
temp.push_back('\\');
|
||||
temp.push_back(*carg);
|
||||
break;
|
||||
case '\\':
|
||||
temp.append("\\\\\\\\");
|
||||
break;
|
||||
case '$':
|
||||
temp.push_back('\\');
|
||||
temp.push_back('\\');
|
||||
temp.push_back(*carg);
|
||||
break;
|
||||
case '%':
|
||||
temp.push_back('%');
|
||||
temp.push_back(*carg);
|
||||
break;
|
||||
default:
|
||||
temp.push_back(' ');
|
||||
lossless = false;
|
||||
break;
|
||||
}
|
||||
++carg;
|
||||
}
|
||||
|
||||
temp.push_back('"');
|
||||
*arg = std::move(temp);
|
||||
return lossless;
|
||||
#endif
|
||||
}
|
||||
} // namespace QtUtils
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
#include <QtGui/QScreen>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "common/Console.h"
|
||||
|
||||
@@ -209,4 +211,19 @@ namespace QtUtils
|
||||
/// Gets a flag icon for a given language code
|
||||
/// Returns an empty QIcon if no flag is available for the language
|
||||
QIcon GetFlagIconForLanguage(const QString& language_code);
|
||||
|
||||
/// Returns true if PCSX2 is running inside a Flatpak sandbox.
|
||||
bool IsRunningInFlatpak();
|
||||
|
||||
/// Returns true if PCSX2 is running from an AppImage.
|
||||
bool IsRunningInAppImage();
|
||||
|
||||
/// Creates a desktop or launcher (Start Menu / applications) shortcuts
|
||||
void CreateShortcut(QWidget* parent, const std::string& name, const std::string& game_path,
|
||||
std::vector<std::string> passed_cli_args, const std::string& custom_args,
|
||||
const std::string& icon_path, bool is_desktop, bool prompt_for_destination = true);
|
||||
|
||||
/// Escapes the given string for use as a shortcut command line argument.
|
||||
/// Returns whether the escaping operation was lossless.
|
||||
bool EscapeShortcutCommandLine(std::string* arg);
|
||||
} // namespace QtUtils
|
||||
|
||||
@@ -88,6 +88,11 @@ void SetupWizardDialog::nextPage()
|
||||
const int current_page = m_ui.pages->currentIndex();
|
||||
if (current_page == Page_Complete)
|
||||
{
|
||||
if (m_ui.createDesktopShortcut->isChecked())
|
||||
QtUtils::CreateShortcut(this, "PCSX2", std::string(), {}, std::string(), std::string(), true, false);
|
||||
if (m_ui.addToApplicationMenu->isChecked())
|
||||
QtUtils::CreateShortcut(this, "PCSX2", std::string(), {}, std::string(), std::string(), false, false);
|
||||
|
||||
accept();
|
||||
return;
|
||||
}
|
||||
@@ -177,6 +182,7 @@ void SetupWizardDialog::setupUi()
|
||||
setupGameListPage();
|
||||
setupControllerPage();
|
||||
setupRetroAchievementsPage();
|
||||
setupCompletePage();
|
||||
}
|
||||
|
||||
void SetupWizardDialog::setupLanguagePage()
|
||||
@@ -435,6 +441,22 @@ void SetupWizardDialog::setupRetroAchievementsPage()
|
||||
refreshRetroAchievementsLoginState();
|
||||
}
|
||||
|
||||
void SetupWizardDialog::setupCompletePage()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
const bool can_create_shortcuts = true;
|
||||
m_ui.addToApplicationMenu->setText(tr("Add PCSX2 to the Start Menu"));
|
||||
#elif defined(__linux__)
|
||||
// Only offer shortcuts for the AppImage since Flatpak creates its own launcher, and
|
||||
// third-party builds (AUR, COPR, etc.) ship their own .desktop file.
|
||||
const bool can_create_shortcuts = QtUtils::IsRunningInAppImage();
|
||||
#else
|
||||
const bool can_create_shortcuts = false;
|
||||
#endif
|
||||
m_ui.createDesktopShortcut->setVisible(can_create_shortcuts);
|
||||
m_ui.addToApplicationMenu->setVisible(can_create_shortcuts);
|
||||
}
|
||||
|
||||
void SetupWizardDialog::refreshRetroAchievementsLoginState()
|
||||
{
|
||||
const std::string username(Host::GetBaseStringSettingValue("Achievements", "Username"));
|
||||
|
||||
@@ -66,6 +66,7 @@ private:
|
||||
void setupGameListPage();
|
||||
void setupControllerPage();
|
||||
void setupRetroAchievementsPage();
|
||||
void setupCompletePage();
|
||||
void refreshRetroAchievementsLoginState();
|
||||
|
||||
void pageChangedTo(int page);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<layout class="QVBoxLayout" name="pagesLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="logo">
|
||||
<property name="sizePolicy">
|
||||
@@ -61,7 +61,6 @@
|
||||
<widget class="QLabel" name="labelLanguage">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
@@ -127,7 +126,7 @@
|
||||
<property name="currentIndex">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page">
|
||||
<widget class="QWidget" name="SetupWizardPages">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>4</number>
|
||||
@@ -145,7 +144,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<widget class="QLabel" name="IntroLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><h1 style=" margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:xx-large; font-weight:700;">Welcome to PCSX2!</span></h1><p>This wizard will help guide you through the configuration steps required to use the application. It is recommended if this is your first time installing PCSX2 that you view the setup guide <a href="https://pcsx2.net/docs/">here</a>.</p><p>By default, PCSX2 will connect to the server at <a href="https://pcsx2.net/">pcsx2.net</a> to check for updates, and if available and confirmed, download update packages from <a href="https://github.com/">github.com</a>. If you do not wish for PCSX2 to make any network connections on startup, you should uncheck the Automatic Updates option now. The Automatic Update setting can be changed later at any time in Interface Settings.</p><p>Please choose a language and theme to begin.</p></body></html></string>
|
||||
</property>
|
||||
@@ -164,7 +163,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<layout class="QFormLayout" name="languageLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="languageLabel">
|
||||
<property name="text">
|
||||
@@ -222,7 +221,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_2">
|
||||
<widget class="QWidget" name="pageBios">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
@@ -237,7 +236,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<widget class="QLabel" name="biosIntro">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>PCSX2 requires a PS2 BIOS in order to run.</p><p>For legal reasons, you must obtain a BIOS <strong>from an actual PS2 unit that you own</strong> (borrowing doesn't count).</p><p>Once dumped, this BIOS image should be placed in the bios folder within the data directory shown below, or you can instruct PCSX2 to scan an alternative directory.</p><p>A guide for dumping your BIOS can be found <a href="https://pcsx2.net/docs/setup/bios/">here</a>.</p></body></html></string>
|
||||
</property>
|
||||
@@ -256,7 +255,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<layout class="QHBoxLayout" name="biosPathLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="biosSearchDirectoryLabel">
|
||||
<property name="text">
|
||||
@@ -310,7 +309,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<layout class="QHBoxLayout" name="biosActions">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
@@ -342,7 +341,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_3">
|
||||
<widget class="QWidget" name="pageDumps">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
@@ -357,7 +356,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<widget class="QLabel" name="dumpsIntro">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>PCSX2 will automatically scan and identify games from the selected directories below, and populate the game list.<br>These games should be dumped from discs you own. Guides for dumping discs can be found <a href="https://pcsx2.net/docs/setup/dumping">here</a>.</p><p>Supported formats for dumps include:</p><p><ul><li>.bin/.iso (ISO Disc Images)</li><li>.mdf (Media Descriptor File)</li><li>.chd (Compressed Hunks of Data)</li><li>.cso (Compressed ISO)</li><li>.zso (Compressed ISO)</li><li>.gz (Gzip Compressed ISO)</li></ul></p></p></body></html></string>
|
||||
</property>
|
||||
@@ -376,7 +375,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<layout class="QHBoxLayout" name="dumpsLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="searchDirectoryListLabel">
|
||||
<property name="text">
|
||||
@@ -474,7 +473,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<widget class="QLabel" name="controllerIntro">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>By default, PCSX2 will map your keyboard to the virtual PS2 controller.</p><p><span style=" font-weight:704;">To use an external controller, you must map it first. </span>On this screen, you can automatically map any controller which is currently connected. If your controller is not currently connected, you can plug it in now.</p><p>To change controller bindings in more detail, or use multi-tap, open the Settings menu and choose Controllers once you have completed the Setup Wizard.</p><p>Guides for configuring controllers can be found <a href="https://pcsx2.net/docs/post/controllers/"><span style="">here</span></a>.</p></body></html></string>
|
||||
</property>
|
||||
@@ -487,7 +486,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<widget class="QGroupBox" name="controller1Group">
|
||||
<property name="title">
|
||||
<string>Controller Port 1</string>
|
||||
</property>
|
||||
@@ -496,14 +495,14 @@
|
||||
<widget class="QComboBox" name="controller1Type"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<widget class="QLabel" name="controllerMappedLabel">
|
||||
<property name="text">
|
||||
<string>Controller Mapped To:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<widget class="QLabel" name="controller1Label">
|
||||
<property name="text">
|
||||
<string>Controller Type:</string>
|
||||
</property>
|
||||
@@ -513,12 +512,15 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<layout class="QHBoxLayout" name="controller1MappingLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="controller1Mapping">
|
||||
<property name="text">
|
||||
<string>Default (Keyboard)</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>controller1Type</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -554,13 +556,13 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<widget class="QGroupBox" name="controller2Group">
|
||||
<property name="title">
|
||||
<string>Controller Port 2</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<widget class="QLabel" name="controller2Label">
|
||||
<property name="text">
|
||||
<string>Controller Type:</string>
|
||||
</property>
|
||||
@@ -573,19 +575,22 @@
|
||||
<widget class="QComboBox" name="controller2Type"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<widget class="QLabel" name="controller2MappedLabel">
|
||||
<property name="text">
|
||||
<string>Controller Mapped To:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<layout class="QHBoxLayout" name="controller2MappingLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="controller2Mapping">
|
||||
<property name="text">
|
||||
<string>Default (Keyboard)</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>controller2Type</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -653,7 +658,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<layout class="QHBoxLayout" name="raLogoLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="raLogo">
|
||||
<property name="sizePolicy">
|
||||
@@ -736,6 +741,9 @@
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>raEnableAchievements</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -885,7 +893,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_5">
|
||||
<widget class="QWidget" name="pageComplete">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
@@ -900,7 +908,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9">
|
||||
<widget class="QLabel" name="completeIntro">
|
||||
<property name="text">
|
||||
<string><html><head/><body><h1 style=" margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:xx-large; font-weight:700;">Setup Complete!</span></h1><p>You are now ready to run games.</p><p><span style=" font-weight:700;">Warning: Do not run untrusted programs in PCSX2. It is not a sandbox and cannot protect your computer from malicious software.</span></p><p>Further options are available under the settings menu. You can also use the Big Picture UI for navigation entirely with a gamepad.</p><p>We hope you enjoy using PCSX2.</p></body></html></string>
|
||||
</property>
|
||||
@@ -912,12 +920,26 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="createDesktopShortcut">
|
||||
<property name="text">
|
||||
<string>Create Desktop shortcut</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="addToApplicationMenu">
|
||||
<property name="text">
|
||||
<string>Add PCSX2 to the Application Menu</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QHBoxLayout" name="navigationLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
|
||||
@@ -3,23 +3,14 @@
|
||||
|
||||
#include "ShortcutCreationDialog.h"
|
||||
#include "QtHost.h"
|
||||
#include <fmt/format.h>
|
||||
#include "QtUtils.h"
|
||||
#include <QtWidgets/QButtonGroup>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include "common/Console.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "VMManager.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include "common/RedtapeWilCom.h"
|
||||
#include <shlobj.h>
|
||||
#include <shobjidl.h>
|
||||
#include <comdef.h>
|
||||
#endif
|
||||
|
||||
ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& title, const QString& path)
|
||||
: QDialog(parent)
|
||||
, m_title(title)
|
||||
@@ -100,7 +91,7 @@ ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& t
|
||||
m_ui.resetIconButton->setEnabled(false);
|
||||
});
|
||||
|
||||
if (std::getenv("container"))
|
||||
if (QtUtils::IsRunningInFlatpak())
|
||||
{
|
||||
m_ui.portableModeToggle->setEnabled(false);
|
||||
m_ui.shortcutDesktop->setEnabled(false);
|
||||
@@ -108,7 +99,7 @@ ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& t
|
||||
}
|
||||
|
||||
connect(m_ui.dialogButtons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
connect(m_ui.dialogButtons, &QDialogButtonBox::accepted, this, [&]() {
|
||||
connect(m_ui.dialogButtons, &QDialogButtonBox::accepted, this, [this]() {
|
||||
std::vector<std::string> args;
|
||||
|
||||
if (m_ui.portableModeToggle->isChecked())
|
||||
@@ -162,430 +153,10 @@ ShortcutCreationDialog::ShortcutCreationDialog(QWidget* parent, const QString& t
|
||||
std::string custom_args = m_ui.customArgsInput->text().toStdString();
|
||||
std::string icon_path = m_ui.iconPath->text().toStdString();
|
||||
|
||||
ShortcutCreationDialog::CreateShortcut(title.toStdString(), path.toStdString(), args, custom_args, icon_path, m_ui.shortcutDesktop->isChecked());
|
||||
QtUtils::CreateShortcut(this, m_title.toStdString(), m_path.toStdString(), std::move(args), custom_args, icon_path, m_ui.shortcutDesktop->isChecked());
|
||||
|
||||
accept();
|
||||
});
|
||||
}
|
||||
|
||||
void ShortcutCreationDialog::CreateShortcut(const std::string name, const std::string game_path, std::vector<std::string> passed_cli_args, std::string custom_args, const std::string icon_path, bool is_desktop)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if (name.empty())
|
||||
{
|
||||
Console.Error("Cannot create shortcuts without a name.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitize filename
|
||||
const std::string clean_name = Path::SanitizeFileName(name).c_str();
|
||||
std::string clean_path = Path::ToNativePath(Path::RealPath(game_path)).c_str();
|
||||
if (!Path::IsValidFileName(clean_name))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("Filename contains illegal character."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get path to Desktop or per-user Start Menu\Programs directory
|
||||
// https://superuser.com/questions/1489874/how-can-i-get-the-real-path-of-desktop-in-windows-explorer/1789849#1789849
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath
|
||||
// https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
|
||||
std::string link_file;
|
||||
if (wil::unique_cotaskmem_string directory; SUCCEEDED(SHGetKnownFolderPath(is_desktop ? FOLDERID_Desktop : FOLDERID_Programs, 0, NULL, &directory)))
|
||||
{
|
||||
std::string directory_utf8 = StringUtil::WideStringToUTF8String(directory.get());
|
||||
|
||||
if (is_desktop)
|
||||
link_file = Path::ToNativePath(fmt::format("{}/{}.lnk", directory_utf8, clean_name));
|
||||
else
|
||||
{
|
||||
const std::string pcsx2_start_menu_dir = Path::ToNativePath(fmt::format("{}/PCSX2", directory_utf8));
|
||||
if (!FileSystem::EnsureDirectoryExists(pcsx2_start_menu_dir.c_str(), false))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("Could not create start menu directory."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
link_file = Path::ToNativePath(fmt::format("{}/{}.lnk", pcsx2_start_menu_dir, clean_name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), is_desktop ? tr("'Desktop' directory not found") : tr("User's 'Start Menu\\Programs' directory not found"), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the same shortcut already exists
|
||||
if (FileSystem::FileExists(link_file.c_str()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("A shortcut with the same name already exists."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Shortcut CmdLine Args
|
||||
bool lossless = true;
|
||||
for (std::string& arg : passed_cli_args)
|
||||
lossless &= ShortcutCreationDialog::EscapeShortcutCommandLine(&arg);
|
||||
|
||||
if (!lossless)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("File path contains invalid character(s)."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
ShortcutCreationDialog::EscapeShortcutCommandLine(&clean_path);
|
||||
std::string combined_args = StringUtil::JoinString(passed_cli_args.begin(), passed_cli_args.end(), " ");
|
||||
std::string final_args = fmt::format("{} {} -- {}", combined_args, custom_args, clean_path);
|
||||
|
||||
Console.WriteLnFmt("Creating a shortcut '{}' with arguments '{}'", link_file, final_args);
|
||||
|
||||
const auto str_error = [](HRESULT hr) -> std::string {
|
||||
_com_error err(hr);
|
||||
const TCHAR* errMsg = err.ErrorMessage();
|
||||
return fmt::format("{} [{}]", StringUtil::WideStringToUTF8String(errMsg), hr);
|
||||
};
|
||||
|
||||
// Construct the shortcut
|
||||
// https://stackoverflow.com/questions/3906974/how-to-programmatically-create-a-shortcut-using-win32
|
||||
HRESULT res = CoInitialize(NULL);
|
||||
if (FAILED(res))
|
||||
{
|
||||
Console.ErrorFmt("Failed to create shortcut: CoInitialize failed ({})", str_error(res));
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("CoInitialize failed (%1)").arg(str_error(res)), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
wil::unique_couninitialize_call co_cleanup;
|
||||
|
||||
const auto report_error = [&](const QString& reason) {
|
||||
Console.ErrorFmt("Failed to create shortcut: {}", reason.toStdString());
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), reason, QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
};
|
||||
|
||||
wil::com_ptr_nothrow<IShellLink> pShellLink = wil::CoCreateInstanceNoThrow<IShellLink>(CLSID_ShellLink);
|
||||
wil::com_ptr_nothrow<IPersistFile> pPersistFile;
|
||||
|
||||
if (!pShellLink)
|
||||
{
|
||||
report_error(tr("CoCreateInstance failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set path to the executable
|
||||
const std::wstring target_file = StringUtil::UTF8StringToWideString(FileSystem::GetProgramPath());
|
||||
res = pShellLink->SetPath(target_file.c_str());
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr("SetPath failed (%1)").arg(str_error(res)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the working directory
|
||||
const std::wstring working_dir = StringUtil::UTF8StringToWideString(FileSystem::GetWorkingDirectory());
|
||||
res = pShellLink->SetWorkingDirectory(working_dir.c_str());
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr("SetWorkingDirectory failed (%1)").arg(str_error(res)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the launch arguments
|
||||
if (!final_args.empty())
|
||||
{
|
||||
const std::wstring target_cli_args = StringUtil::UTF8StringToWideString(final_args);
|
||||
res = pShellLink->SetArguments(target_cli_args.c_str());
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr("SetArguments failed (%1)").arg(str_error(res)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the icon
|
||||
std::string final_icon_path;
|
||||
if (!icon_path.empty())
|
||||
{
|
||||
final_icon_path = Path::ToNativePath(icon_path);
|
||||
if (!FileSystem::FileExists(final_icon_path.c_str()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("The selected icon file does not exist."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
final_icon_path = Path::ToNativePath(Path::Combine(Path::GetDirectory(FileSystem::GetProgramPath()), "resources/icons/AppIconLarge.ico"));
|
||||
}
|
||||
|
||||
const std::wstring w_icon_path = StringUtil::UTF8StringToWideString(final_icon_path);
|
||||
res = pShellLink->SetIconLocation(w_icon_path.c_str(), 0);
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr("SetIconLocation failed (%1)").arg(str_error(res)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the IPersistFile object to save the shell link
|
||||
res = pShellLink.query_to(&pPersistFile);
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr("QueryInterface failed (%1)").arg(str_error(res)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Save shortcut link to disk
|
||||
const std::wstring w_link_file = StringUtil::UTF8StringToWideString(link_file);
|
||||
res = pPersistFile->Save(w_link_file.c_str(), TRUE);
|
||||
if (FAILED(res))
|
||||
{
|
||||
report_error(tr("Failed to save the shortcut (%1)").arg(str_error(res)));
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (name.empty())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("Cannot create a shortcut without a title."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
bool is_flatpak = (std::getenv("container"));
|
||||
|
||||
// Sanitize filename and game path
|
||||
const std::string clean_name = Path::SanitizeFileName(name);
|
||||
std::string clean_path = Path::Canonicalize(Path::RealPath(game_path));
|
||||
if (!Path::IsValidFileName(clean_name))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("Filename contains illegal character."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the executable path
|
||||
std::string executable_path = FileSystem::GetPackagePath();
|
||||
if (executable_path.empty())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("Executable path is empty."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find home directory
|
||||
std::string link_path;
|
||||
const char* home = std::getenv("HOME");
|
||||
const char* xdg_desktop_dir = std::getenv("XDG_DESKTOP_DIR");
|
||||
const char* xdg_data_home = std::getenv("XDG_DATA_HOME");
|
||||
if (home)
|
||||
{
|
||||
if (is_desktop)
|
||||
{
|
||||
if (xdg_desktop_dir)
|
||||
link_path = fmt::format("{}/{}.desktop", xdg_desktop_dir, clean_name);
|
||||
else
|
||||
link_path = fmt::format("{}/Desktop/{}.desktop", home, clean_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xdg_data_home)
|
||||
link_path = fmt::format("{}/applications/{}.desktop", xdg_data_home, clean_name);
|
||||
else
|
||||
link_path = fmt::format("{}/.local/share/applications/{}.desktop", home, clean_name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("Path to the Home directory is empty."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string icon_name;
|
||||
if (!icon_path.empty())
|
||||
{
|
||||
if (!FileSystem::FileExists(icon_path.c_str()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("The selected icon file does not exist."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
icon_name = icon_path;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy PCSX2 icon
|
||||
std::string icon_dest;
|
||||
if (xdg_data_home)
|
||||
icon_dest = fmt::format("{}/icons/hicolor/512x512/apps/", xdg_data_home);
|
||||
else
|
||||
icon_dest = fmt::format("{}/.local/share/icons/hicolor/512x512/apps/", home);
|
||||
|
||||
if (is_flatpak) // Flatpak
|
||||
{
|
||||
executable_path = "flatpak run net.pcsx2.PCSX2";
|
||||
icon_name = "net.pcsx2.PCSX2";
|
||||
}
|
||||
else
|
||||
{
|
||||
icon_name = "PCSX2";
|
||||
std::string icon_path_dest = fmt::format("{}/{}.png", icon_dest, icon_name).c_str();
|
||||
if (FileSystem::EnsureDirectoryExists(icon_dest.c_str(), true))
|
||||
if (!FileSystem::FileExists(icon_path_dest.c_str()))
|
||||
FileSystem::CopyFilePath(Path::Combine(EmuFolders::Resources, "icons/AppIconLarge.png").c_str(), icon_path_dest.c_str(), false);
|
||||
}
|
||||
}
|
||||
|
||||
// Shortcut CmdLine Args
|
||||
bool lossless = true;
|
||||
for (std::string& arg : passed_cli_args)
|
||||
lossless &= ShortcutCreationDialog::EscapeShortcutCommandLine(&arg);
|
||||
|
||||
if (!lossless)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("File path contains invalid character(s)."), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cmdline = StringUtil::JoinString(passed_cli_args.begin(), passed_cli_args.end(), " ");
|
||||
|
||||
// Further string sanitization
|
||||
if (!is_flatpak)
|
||||
ShortcutCreationDialog::EscapeShortcutCommandLine(&executable_path);
|
||||
ShortcutCreationDialog::EscapeShortcutCommandLine(&clean_path);
|
||||
|
||||
// Assembling the .desktop file
|
||||
std::string final_args;
|
||||
final_args = fmt::format("{} {} {} -- {}", executable_path, cmdline, custom_args, clean_path);
|
||||
std::string file_content =
|
||||
"[Desktop Entry]\n"
|
||||
"Encoding=UTF-8\n"
|
||||
"Version=1.0\n"
|
||||
"Type=Application\n"
|
||||
"Terminal=false\n"
|
||||
"StartupWMClass=PCSX2\n"
|
||||
"Exec=" +
|
||||
final_args + "\n" +
|
||||
"Name=" +
|
||||
clean_name + "\n" +
|
||||
"Icon=" +
|
||||
icon_name + "\n" +
|
||||
"Categories=Game;Emulator;\n";
|
||||
std::string_view sv(file_content);
|
||||
|
||||
// Prompt user for shortcut saving destination
|
||||
QString final_path(QStringLiteral("%1").arg(QString::fromStdString(link_path)));
|
||||
const QString filter(tr("Desktop Shortcut Files (*.desktop)"));
|
||||
|
||||
final_path = QDir::toNativeSeparators(QFileDialog::getSaveFileName(this, tr("Select Shortcut Save Destination"), final_path, filter));
|
||||
|
||||
if (final_path.isEmpty())
|
||||
return;
|
||||
|
||||
// Write to .desktop file
|
||||
if (!FileSystem::WriteStringToFile(final_path.toStdString().c_str(), sv))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Failed to create shortcut"), tr("Failed to create .desktop file"), QMessageBox::StandardButton::Ok, QMessageBox::StandardButton::Ok);
|
||||
return;
|
||||
}
|
||||
|
||||
if (chmod(final_path.toStdString().c_str(), S_IRWXU) != 0) // enables user to execute file
|
||||
Console.ErrorFmt("Failed to change file permissions for .desktop file: {} ({})", strerror(errno), errno);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ShortcutCreationDialog::EscapeShortcutCommandLine(std::string* arg)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!arg->empty() && arg->find_first_of(" \t\n\v\"") == std::string::npos)
|
||||
return true;
|
||||
|
||||
std::string temp;
|
||||
temp.reserve(arg->length() + 10);
|
||||
temp += '"';
|
||||
|
||||
for (auto it = arg->begin();; ++it)
|
||||
{
|
||||
int backslash_count = 0;
|
||||
while (it != arg->end() && *it == '\\')
|
||||
{
|
||||
++it;
|
||||
++backslash_count;
|
||||
}
|
||||
|
||||
if (it == arg->end())
|
||||
{
|
||||
temp.append(backslash_count * 2, '\\');
|
||||
break;
|
||||
}
|
||||
|
||||
if (*it == '"')
|
||||
{
|
||||
temp.append(backslash_count * 2 + 1, '\\');
|
||||
temp += '"';
|
||||
}
|
||||
else
|
||||
{
|
||||
temp.append(backslash_count, '\\');
|
||||
temp += *it;
|
||||
}
|
||||
}
|
||||
|
||||
temp += '"';
|
||||
*arg = std::move(temp);
|
||||
return true;
|
||||
#else
|
||||
const char* carg = arg->c_str();
|
||||
const char* cend = carg + arg->size();
|
||||
const char* RESERVED_CHARS = " \t\n\\\"'\\\\><~|%&;$*?#()`"
|
||||
"\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0d\x0e\x0f"
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f";
|
||||
const char* next = carg + std::strcspn(carg, RESERVED_CHARS);
|
||||
|
||||
if (next == cend)
|
||||
return true; // No escaping needed, don't modify
|
||||
|
||||
bool lossless = true;
|
||||
std::string temp = "\"";
|
||||
const char* NOT_VALID_IN_QUOTE = "%`$\"\\\n"
|
||||
"\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0d\x0e\x0f"
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x7f";
|
||||
|
||||
while (true)
|
||||
{
|
||||
next = carg + std::strcspn(carg, NOT_VALID_IN_QUOTE);
|
||||
temp.append(carg, next);
|
||||
carg = next;
|
||||
|
||||
if (carg == cend)
|
||||
break;
|
||||
|
||||
switch (*carg)
|
||||
{
|
||||
case '"':
|
||||
case '`':
|
||||
temp.push_back('\\');
|
||||
temp.push_back(*carg);
|
||||
break;
|
||||
case '\\':
|
||||
temp.append("\\\\\\\\");
|
||||
break;
|
||||
case '$':
|
||||
temp.push_back('\\');
|
||||
temp.push_back('\\');
|
||||
temp.push_back(*carg);
|
||||
break;
|
||||
case '%':
|
||||
temp.push_back('%');
|
||||
temp.push_back(*carg);
|
||||
break;
|
||||
default:
|
||||
temp.push_back(' ');
|
||||
lossless = false;
|
||||
break;
|
||||
}
|
||||
++carg;
|
||||
}
|
||||
|
||||
temp.push_back('"');
|
||||
*arg = std::move(temp);
|
||||
return lossless;
|
||||
#endif
|
||||
}
|
||||
|
||||
#include "moc_ShortcutCreationDialog.cpp"
|
||||
|
||||
@@ -14,13 +14,6 @@ public:
|
||||
ShortcutCreationDialog(QWidget* parent, const QString& title, const QString& path);
|
||||
~ShortcutCreationDialog() = default;
|
||||
|
||||
/// Create desktop shortcut for games
|
||||
void CreateShortcut(const std::string name, const std::string game_path, std::vector<std::string> passed_cli_args, std::string custom_args, const std::string icon_path, bool is_desktop);
|
||||
|
||||
/// Escapes the given string for use with command line arguments.
|
||||
/// Returns a bool that indicates whether the escaping operation are lossless or not.
|
||||
bool EscapeShortcutCommandLine(std::string* cmdline);
|
||||
|
||||
protected:
|
||||
const QString m_title;
|
||||
const QString m_path;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -246,6 +246,7 @@
|
||||
<QtMoc Include="Debugger\StackView.h" />
|
||||
<QtMoc Include="Debugger\ModuleModel.h" />
|
||||
<QtMoc Include="Debugger\ModuleView.h" />
|
||||
<QtMoc Include="Debugger\NavigationHistoryStack.h" />
|
||||
<QtMoc Include="Debugger\ThreadModel.h" />
|
||||
<QtMoc Include="Debugger\ThreadView.h" />
|
||||
<ClInclude Include="Debugger\DebuggerSettingsManager.h" />
|
||||
|
||||
@@ -529,6 +529,9 @@
|
||||
<QtMoc Include="Debugger\ModuleView.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Debugger\NavigationHistoryStack.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Debugger\ModuleModel.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtMoc>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000"><path d="M7.82843 10.9999H20V12.9999H7.82843L13.1924 18.3638L11.7782 19.778L4 11.9999L11.7782 4.22168L13.1924 5.63589L7.82843 10.9999Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 222 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#000"><path d="M16.1716 10.9999L10.8076 5.63589L12.2218 4.22168L20 11.9999L12.2218 19.778L10.8076 18.3638L16.1716 12.9999H4V10.9999H16.1716Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 222 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#fff"><path d="M7.82843 10.9999H20V12.9999H7.82843L13.1924 18.3638L11.7782 19.778L4 11.9999L11.7782 4.22168L13.1924 5.63589L7.82843 10.9999Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 222 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#fff"><path d="M16.1716 10.9999L10.8076 5.63589L12.2218 4.22168L20 11.9999L12.2218 19.778L10.8076 18.3638L16.1716 12.9999H4V10.9999H16.1716Z"></path></svg>
|
||||
|
After Width: | Height: | Size: 222 B |
@@ -2,12 +2,14 @@
|
||||
<qresource>
|
||||
<file>icons/AppIcon64.png</file>
|
||||
<file>icons/black/index.theme</file>
|
||||
<file>icons/black/svg/arrow-left-line.svg</file>
|
||||
<file>icons/black/svg/arrow-left-right-line.svg</file>
|
||||
<file>icons/black/svg/arrow-right-line.svg</file>
|
||||
<file>icons/black/svg/artboard-2-line.svg</file>
|
||||
<file>icons/black/svg/at.svg</file>
|
||||
<file>icons/black/svg/band-aid-line.svg</file>
|
||||
<file>icons/black/svg/booklet.svg</file>
|
||||
<file>icons/black/svg/book.svg</file>
|
||||
<file>icons/black/svg/booklet.svg</file>
|
||||
<file>icons/black/svg/brush-line.svg</file>
|
||||
<file>icons/black/svg/bug-line.svg</file>
|
||||
<file>icons/black/svg/buzz-controller-line.svg</file>
|
||||
@@ -113,12 +115,14 @@
|
||||
<file>icons/QT.png</file>
|
||||
<file>icons/update.png</file>
|
||||
<file>icons/white/index.theme</file>
|
||||
<file>icons/white/svg/arrow-left-line.svg</file>
|
||||
<file>icons/white/svg/arrow-left-right-line.svg</file>
|
||||
<file>icons/white/svg/arrow-right-line.svg</file>
|
||||
<file>icons/white/svg/artboard-2-line.svg</file>
|
||||
<file>icons/white/svg/at.svg</file>
|
||||
<file>icons/white/svg/band-aid-line.svg</file>
|
||||
<file>icons/white/svg/booklet.svg</file>
|
||||
<file>icons/white/svg/book.svg</file>
|
||||
<file>icons/white/svg/booklet.svg</file>
|
||||
<file>icons/white/svg/brush-line.svg</file>
|
||||
<file>icons/white/svg/bug-line.svg</file>
|
||||
<file>icons/white/svg/buzz-controller-line.svg</file>
|
||||
|
||||
+28
-1
@@ -385,7 +385,13 @@ void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
|
||||
case PSMT4HH:
|
||||
clut += (TEX0.CSA & 15) << 4;
|
||||
// TODO: merge these functions
|
||||
ReadCLUT_T32_I4(clut, m_buff32);
|
||||
|
||||
// This is for a situation with Breath of Fire Dragon Quarter where it reinterprets the buffer under CSM2 after reading as CSM1.
|
||||
if (TEX0.CSM == 1 && m_write.TEX0.CSM == 0)
|
||||
ReadCLUT_T32_I4_Swizzled(clut, m_buff32);
|
||||
else
|
||||
ReadCLUT_T32_I4(clut, m_buff32);
|
||||
|
||||
ExpandCLUT64_T32_I8(m_buff32, (u64*)m_buff64); // sw renderer does not need m_buff64 anymore
|
||||
break;
|
||||
}
|
||||
@@ -632,6 +638,27 @@ __forceinline void GSClut::WriteCLUT_T16_I4_CSM1(const u16* RESTRICT src, u16* R
|
||||
}
|
||||
}
|
||||
|
||||
// These functions are only used if the CLUT is in 32bit mode and it swaps to CSM2, a very obscure setup used by Breath of Fire Dragon Quarter.
|
||||
// This doesn't handle offsetting the CLUT or anything crazy, that would be a lot more work
|
||||
void GSClut::ReadCLUT_T32_I4_Swizzled(const u16* RESTRICT clut, u32* RESTRICT dst)
|
||||
{
|
||||
// Point to the base of the palette block
|
||||
GSVector4i* s = (GSVector4i*)clut;
|
||||
GSVector4i* d = (GSVector4i*)dst;
|
||||
|
||||
GSVector4i v0 = s[0];
|
||||
GSVector4i v1 = s[2];
|
||||
GSVector4i v2 = s[32];
|
||||
GSVector4i v3 = s[34];
|
||||
|
||||
GSVector4i::sw16(v0, v2, v1, v3);
|
||||
|
||||
d[0] = v0;
|
||||
d[1] = v1;
|
||||
d[2] = v2;
|
||||
d[3] = v3;
|
||||
}
|
||||
|
||||
void GSClut::ReadCLUT_T32_I8(const u16* RESTRICT clut, u32* RESTRICT dst, int offset)
|
||||
{
|
||||
// Okay this deserves a small explanation
|
||||
|
||||
@@ -78,6 +78,7 @@ class alignas(32) GSClut final : public GSAlignedClass<32>
|
||||
static void WriteCLUT_T32_I4_CSM1(const u32* RESTRICT src, u16* RESTRICT clut);
|
||||
static void WriteCLUT_T16_I8_CSM1(const u16* RESTRICT src, u16* RESTRICT clut);
|
||||
static void WriteCLUT_T16_I4_CSM1(const u16* RESTRICT src, u16* RESTRICT clut);
|
||||
static void ReadCLUT_T32_I4_Swizzled(const u16* RESTRICT clut, u32* RESTRICT dst);
|
||||
static void ReadCLUT_T32_I8(const u16* RESTRICT clut, u32* RESTRICT dst, int offset);
|
||||
static void ReadCLUT_T32_I4(const u16* RESTRICT clut, u32* RESTRICT dst);
|
||||
//static void ReadCLUT_T32_I4(const u16* RESTRICT clut, u32* RESTRICT dst32, u64* RESTRICT dst64);
|
||||
|
||||
+11
-11
@@ -5,23 +5,23 @@
|
||||
|
||||
// clang-format off
|
||||
|
||||
#define VM_SIZE 4194304u
|
||||
#define HALF_VM_SIZE (VM_SIZE / 2u)
|
||||
#define GS_PAGE_SIZE 8192u
|
||||
#define GS_BLOCK_SIZE 256u
|
||||
#define GS_COLUMN_SIZE 64u
|
||||
#define GS_BLOCKS_PER_PAGE (GS_PAGE_SIZE / GS_BLOCK_SIZE)
|
||||
|
||||
#define GS_MAX_PAGES (VM_SIZE / GS_PAGE_SIZE)
|
||||
#define GS_MAX_BLOCKS (VM_SIZE / GS_BLOCK_SIZE)
|
||||
#define GS_MAX_COLUMNS (VM_SIZE / GS_COLUMN_SIZE)
|
||||
|
||||
//if defined, will send much info in reply to the API title info queri from PCSX2
|
||||
//default should be undefined
|
||||
//#define GSTITLEINFO_API_FORCE_VERBOSE
|
||||
|
||||
#include "GSVector.h"
|
||||
|
||||
constexpr u32 VM_SIZE = 4194304u;
|
||||
constexpr u32 HALF_VM_SIZE = (VM_SIZE / 2u);
|
||||
constexpr u32 GS_PAGE_SIZE = 8192u;
|
||||
constexpr u32 GS_BLOCK_SIZE = 256u;
|
||||
constexpr u32 GS_COLUMN_SIZE = 64u;
|
||||
constexpr u32 GS_BLOCKS_PER_PAGE = (GS_PAGE_SIZE / GS_BLOCK_SIZE);
|
||||
|
||||
constexpr u32 GS_MAX_PAGES = (VM_SIZE / GS_PAGE_SIZE);
|
||||
constexpr u32 GS_MAX_BLOCKS = (VM_SIZE / GS_BLOCK_SIZE);
|
||||
constexpr u32 GS_MAX_COLUMNS = (VM_SIZE / GS_COLUMN_SIZE);
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
enum GS_PRIM
|
||||
|
||||
@@ -2976,7 +2976,7 @@ void GSState::InitReadFIFO(u8* mem, int len)
|
||||
// Read the image all in one go.
|
||||
m_mem.ReadImageX(m_tr.x, m_tr.y, m_tr.buff, m_tr.total, m_env.BITBLTBUF, m_env.TRXPOS, m_env.TRXREG);
|
||||
|
||||
if (GSConfig.SaveRT && GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
|
||||
if (GSConfig.SaveTransferImages && GSConfig.ShouldDump(s_n, g_perfmon.GetFrame()))
|
||||
{
|
||||
const std::string s(GetDrawDumpPath(
|
||||
"%05lld_read_%05x_%d_%s_%d_%d_%d_%d.bmp",
|
||||
|
||||
@@ -805,7 +805,7 @@ GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::F
|
||||
{
|
||||
pxAssert(mipmap_levels != 0 && (mipmap_levels < 0 || mipmap_levels <= GetMipmapLevelsForSize(w, h)));
|
||||
const int levels = mipmap_levels < 0 ? GetMipmapLevelsForSize(w, h) : mipmap_levels;
|
||||
return FetchSurface(GSTexture::Texture, w, h, levels, format, false, m_features.prefer_new_textures && prefer_reuse);
|
||||
return FetchSurface(GSTexture::Texture, w, h, levels, format, false, !m_features.prefer_new_textures || prefer_reuse);
|
||||
}
|
||||
|
||||
GSTexture* GSDevice::CreateTexture(const GSVector2i& size, int mipmap_levels, GSTexture::Format format, bool prefer_reuse)
|
||||
|
||||
@@ -603,7 +603,7 @@ bool GSDevice11::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
}
|
||||
|
||||
// 1x1 dummy texture.
|
||||
const GSTexture::Usage null_usage = m_features.rov ? GSTexture::ShaderWriteTarget : GSTexture::Feedback;
|
||||
const GSTexture::Usage null_usage = m_uav_texture ? GSTexture::ShaderWriteTarget : GSTexture::Feedback;
|
||||
m_null_texture = CreateSurface(null_usage, 1, 1, 1, GSTexture::Format::Color);
|
||||
if (!m_null_texture)
|
||||
return false;
|
||||
|
||||
@@ -2719,11 +2719,9 @@ GSDevice12::ComPtr<ID3DBlob> GSDevice12::GetUtilityPixelShader(const std::string
|
||||
|
||||
bool GSDevice12::CreateNullTexture()
|
||||
{
|
||||
const GSTexture::Usage null_access = m_features.rov ? GSTexture::ShaderWriteTarget : GSTexture::FeedbackTarget;
|
||||
const DXGI_FORMAT null_uav_format = m_features.rov ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_UNKNOWN;
|
||||
m_null_texture =
|
||||
GSTexture12::Create(null_access, GSTexture::Format::Color, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, null_uav_format);
|
||||
GSTexture12::Create(GSTexture::ShaderWriteTarget, GSTexture::Format::Color, 1, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
if (!m_null_texture)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -3225,8 +3225,10 @@ void GSRendererHW::Draw()
|
||||
|
||||
// Be careful of being 1 pixel from filled.
|
||||
const bool page_aligned = (m_r.w % pgs.y) == (pgs.y - 1) || (m_r.w % pgs.y) == 0;
|
||||
const bool is_zero_color_clear = (GetConstantDirectWriteMemClearColor() == 0 && !preserve_rt_color && page_aligned);
|
||||
const bool is_zero_depth_clear = (GetConstantDirectWriteMemClearDepth() == 0 && !preserve_depth && page_aligned);
|
||||
const bool is_full_color_cover = !preserve_rt_color && page_aligned;
|
||||
const bool is_full_depth_cover = !preserve_depth && page_aligned;
|
||||
const bool is_zero_color_clear = (GetConstantDirectWriteMemClearColor() == 0 && is_full_color_cover);
|
||||
const bool is_zero_depth_clear = (GetConstantDirectWriteMemClearDepth() == 0 && is_full_depth_cover);
|
||||
bool gs_mem_cleared = false;
|
||||
// If it's an invalid-sized draw, do the mem clear on the CPU, we don't want to create huge targets.
|
||||
// If clearing to zero, don't bother creating the target. Games tend to clear more than they use, wasting VRAM/bandwidth.
|
||||
@@ -3261,8 +3263,8 @@ void GSRendererHW::Draw()
|
||||
}
|
||||
gs_mem_cleared |= overwriting_whole_rt && overwriting_whole_ds && (!no_rt || !no_ds);
|
||||
if (overwriting_whole_rt && overwriting_whole_ds &&
|
||||
TryGSMemClear(no_rt, preserve_rt_color, is_zero_color_clear, rt_end_bp,
|
||||
no_ds, preserve_depth, is_zero_depth_clear, ds_end_bp))
|
||||
TryGSMemClear(no_rt, preserve_rt_color, is_full_color_cover, rt_end_bp,
|
||||
no_ds, preserve_depth, is_full_depth_cover, ds_end_bp))
|
||||
{
|
||||
GL_INS("HW: Skipping (%d,%d=>%d,%d) draw at FBP %x/ZBP %x due to invalid height or zero clear.", m_r.x, m_r.y,
|
||||
m_r.z, m_r.w, m_cached_ctx.FRAME.Block(), m_cached_ctx.ZBUF.Block());
|
||||
@@ -3285,8 +3287,14 @@ void GSRendererHW::Draw()
|
||||
}
|
||||
}
|
||||
|
||||
CleanupDraw(false);
|
||||
return;
|
||||
no_rt |= is_zero_color_clear;
|
||||
no_ds |= is_zero_depth_clear;
|
||||
|
||||
if (no_rt && no_ds)
|
||||
{
|
||||
CleanupDraw(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3435,7 +3443,7 @@ void GSRendererHW::Draw()
|
||||
bool shuffle_target = false;
|
||||
const u32 page_alignment = GSLocalMemory::IsPageAlignedMasked(m_cached_ctx.TEX0.PSM, m_r);
|
||||
const bool page_aligned = (page_alignment & 0xF0F0) != 0; // Make sure Y is page aligned.
|
||||
if (!no_rt && page_aligned && m_cached_ctx.ZBUF.ZMSK && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp >= 16 &&
|
||||
if (!no_rt && page_aligned && m_cached_ctx.ZBUF.ZMSK && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 16 &&
|
||||
(m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index->tail % 6) == 0 && TrianglesAreQuads(true) && m_index->tail > 6)))
|
||||
{
|
||||
// Tail check is to make sure we have enough strips to go all the way across the page, or if it's using a region clamp could be used to draw strips.
|
||||
@@ -5331,31 +5339,36 @@ bool GSRendererHW::VerifyIndices()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fix the colors in vertices in case the API only supports "provoking first vertex"
|
||||
// (i.e., when using flat shading the color comes from the first vertex, unlike PS2
|
||||
// which is "provoking last vertex").
|
||||
void GSRendererHW::HandleProvokingVertexFirst()
|
||||
void GSRendererHW::HandleFlatShadedVertices()
|
||||
{
|
||||
// Early exit conditions:
|
||||
if (g_gs_device->Features().provoking_vertex_last || // device supports provoking last vertex
|
||||
m_conf.vs.iip || // we are doing Gouraud shading
|
||||
m_vt.m_primclass == GS_POINT_CLASS || // drawing points (one vertex per primitive; color is unambiguous)
|
||||
m_vt.m_primclass == GS_SPRITE_CLASS) // drawing sprites (handled by the sprites -> triangles expand shader)
|
||||
// These cases might need fixing.
|
||||
const bool maybe_fix_vertices = !m_conf.vs.iip &&
|
||||
(!g_gs_device->Features().provoking_vertex_last || IsCoverageAlphaSupported());
|
||||
|
||||
// These cases definitely don't need fixing.
|
||||
const bool dont_fix_vertices = m_vt.m_primclass == GS_POINT_CLASS || m_vt.m_primclass == GS_SPRITE_CLASS;
|
||||
|
||||
if (!maybe_fix_vertices || dont_fix_vertices)
|
||||
return;
|
||||
|
||||
const int n = GSUtil::GetClassVertexCount(m_vt.m_primclass);
|
||||
|
||||
// If all first/last vertices have the same color there is nothing to do.
|
||||
bool first_eq_last = true;
|
||||
// If all vertices of each prim have the same color there is nothing to do.
|
||||
bool prims_flat = true;
|
||||
for (u32 i = 0; i < m_index->tail; i += n)
|
||||
{
|
||||
if (m_vertex->buff[m_index->buff[i]].RGBAQ.U32[0] != m_vertex->buff[m_index->buff[i + n - 1]].RGBAQ.U32[0])
|
||||
for (u32 j = 0; j < n - 1; j++)
|
||||
{
|
||||
first_eq_last = false;
|
||||
break;
|
||||
if (m_vertex->buff[m_index->buff[i + j]].RGBAQ.U32[0] != m_vertex->buff[m_index->buff[i + n - 1]].RGBAQ.U32[0])
|
||||
{
|
||||
prims_flat = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!prims_flat)
|
||||
break;
|
||||
}
|
||||
if (first_eq_last)
|
||||
if (prims_flat)
|
||||
return;
|
||||
|
||||
// De-index the vertices using the copy buffer
|
||||
@@ -5369,11 +5382,11 @@ void GSRendererHW::HandleProvokingVertexFirst()
|
||||
std::swap(m_vertex->buff, m_vertex->buff_copy);
|
||||
m_vertex->head = m_vertex->next = m_vertex->tail = m_index->tail;
|
||||
|
||||
// Put correct color in the first vertex
|
||||
// Make all vertices the same color to simplify handling in expand shaders.
|
||||
for (u32 i = 0; i < m_index->tail; i += n)
|
||||
{
|
||||
m_vertex->buff[i].RGBAQ.U32[0] = m_vertex->buff[i + n - 1].RGBAQ.U32[0];
|
||||
m_vertex->buff[i + n - 1].RGBAQ.U32[0] = 0xff; // Make last vertex red for debugging if used improperly
|
||||
for (u32 j = 0; j < n - 1; j++)
|
||||
m_vertex->buff[i + j].RGBAQ.U32[0] = m_vertex->buff[i + n - 1].RGBAQ.U32[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7833,7 +7846,7 @@ void GSRendererHW::ConvertTextureTypeROVSingle(GSTextureCache::Target* tgt, bool
|
||||
}
|
||||
|
||||
#if PCSX2_DEVBUILD
|
||||
new_tex->SetDebugName(tgt->m_texture->GetDebugName());
|
||||
new_tex->SetDebugName(old_tex->GetDebugName());
|
||||
#endif
|
||||
|
||||
if (tgt->m_texture == old_tex)
|
||||
@@ -7864,12 +7877,13 @@ void GSRendererHW::ConvertTextureTypeROV(GSTextureCache::Target* rt, GSTextureCa
|
||||
// Convert depth to the proper type/format.
|
||||
if (ds)
|
||||
{
|
||||
if (m_conf.ps.HasDepthROV() && !ds->m_texture->IsShaderWrite())
|
||||
// Note: we must use m_conf.ds because it might be the temporary Z texture.
|
||||
if (m_conf.ps.HasDepthROV() && !m_conf.ds->IsShaderWrite())
|
||||
{
|
||||
GL_PUSH("HW: Convert DepthStencil -> DepthColor for ROV.");
|
||||
ConvertTextureTypeROVSingle(ds, true);
|
||||
}
|
||||
else if (!m_conf.ps.HasDepthROV() && !ds->m_texture->IsDepthStencil())
|
||||
else if (!m_conf.ps.HasDepthROV() && !m_conf.ds->IsDepthStencil())
|
||||
{
|
||||
GL_PUSH("HW: Convert DepthColor -> DepthStencil for non-ROV.");
|
||||
ConvertTextureTypeROVSingle(ds, false);
|
||||
@@ -9450,7 +9464,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
DetermineROVUsage(rt, ds);
|
||||
ConvertTextureTypeROV(rt, ds);
|
||||
|
||||
// Barriers must be determined before indices are modified via HandleProvokingVertexFirst/SetupIA.
|
||||
// Barriers must be determined before indices are modified via HandleFlatShadedVertices/SetupIA.
|
||||
// This also computes the drawlist if needed.
|
||||
DetermineBarriers(rt, tex);
|
||||
|
||||
@@ -9475,7 +9489,7 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
|
||||
m_conf.scissor = (date_options.enabled && !date_options.barrier) ? m_conf.drawarea : scissor;
|
||||
|
||||
HandleProvokingVertexFirst();
|
||||
HandleFlatShadedVertices();
|
||||
|
||||
SetupIA(rtscale, vs_scale_x, vs_scale_y, m_channel_shuffle_width != 0, no_rt);
|
||||
|
||||
@@ -9970,9 +9984,11 @@ bool GSRendererHW::DetectDoubleHalfClear(bool& no_rt, bool& no_ds)
|
||||
// path write out FRAME and Z separately, with their associated masks. Limit it to black to avoid false positives.
|
||||
if (write_color == 0)
|
||||
{
|
||||
// Don't check the *entire* size for the end, as some games (X-Men) decide it's done with Z and starts overwriting
|
||||
// the end with other things, which causes a resize, so the end point is no longer in the right place.
|
||||
// So let's just check there's at least one page over the half way point, at worst it means 2 targets overlap.
|
||||
const GSTextureCache::Target* base_tgt = g_texture_cache->GetExactTarget(base * GS_BLOCKS_PER_PAGE,
|
||||
m_cached_ctx.FRAME.FBW, clear_depth ? GSTextureCache::DepthStencil : GSTextureCache::RenderTarget,
|
||||
GSLocalMemory::GetEndBlockAddress(half * GS_BLOCKS_PER_PAGE, m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r));
|
||||
m_cached_ctx.FRAME.FBW, clear_depth ? GSTextureCache::DepthStencil : GSTextureCache::RenderTarget, (half + 1) * GS_BLOCKS_PER_PAGE);
|
||||
if (base_tgt)
|
||||
{
|
||||
GL_INS("HW: DetectDoubleHalfClear(): Invalidating targets at 0x%x/0x%x due to different formats, and clear to black.",
|
||||
|
||||
@@ -215,7 +215,7 @@ private:
|
||||
void DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Target* ds, GSTextureCache::Source* tex, const TextureMinMaxResult& tmm);
|
||||
|
||||
void ResetStates();
|
||||
void HandleProvokingVertexFirst();
|
||||
void HandleFlatShadedVertices();
|
||||
void SetupIA(float target_scale, float sx, float sy, bool req_vert_backup, const bool no_rt);
|
||||
void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GSTextureCache::Source* tex);
|
||||
u32 EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt = nullptr);
|
||||
|
||||
@@ -3565,16 +3565,62 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
|
||||
// Make sure there's sufficient compatibility/overlap between the old target and the new target
|
||||
// to warrant loading from the old target.
|
||||
const u32 old_buffer_width = std::max(1U, old_dst->m_TEX0.TBW);
|
||||
|
||||
if (old_dst->m_TEX0.PSM != dst->m_TEX0.PSM ||
|
||||
!old_dst->Overlaps(dst->m_TEX0.TBP0, dst->m_TEX0.TBW, dst->m_TEX0.PSM, dst_valid))
|
||||
{
|
||||
if (old_dst->m_TEX0.TBP0 == dst->m_TEX0.TBP0 && dst_end_block >= old_dst->m_end_block && (!src || !src->m_target || src->m_from_target != old_dst))
|
||||
{
|
||||
InvalidateSourcesFromTarget(old_dst);
|
||||
i = list.erase(j);
|
||||
delete old_dst;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (old_dst->Overlaps(dst->m_TEX0.TBP0, dst->m_TEX0.TBW, dst->m_TEX0.PSM, dst_valid))
|
||||
{
|
||||
const GSLocalMemory::psm_t& psm_o = GSLocalMemory::m_psm[old_dst->m_TEX0.PSM];
|
||||
if (dst->m_TEX0.TBP0 > old_dst->m_TEX0.TBP0)
|
||||
{
|
||||
const int block_diff = dst->m_TEX0.TBP0 - old_dst->m_TEX0.TBP0;
|
||||
const u32 old_pages_wide = old_buffer_width * 64 / psm_o.pgs.x;
|
||||
if ((block_diff % (GS_BLOCKS_PER_PAGE * old_pages_wide)) == 0) // Check for left alignment.
|
||||
{
|
||||
const int new_height = block_diff / (GS_BLOCKS_PER_PAGE * old_pages_wide) * psm_o.pgs.y;
|
||||
old_dst->m_valid = old_dst->m_valid.rintersect(GSVector4i(old_dst->m_valid.x, old_dst->m_valid.y, old_dst->m_valid.z, new_height));
|
||||
old_dst->ResizeValidity(old_dst->m_valid);
|
||||
}
|
||||
}
|
||||
else // new target is behind the old one, so need to move the start of the old one to the end block of the new.
|
||||
{
|
||||
const int block_diff = dst_end_block - old_dst->m_TEX0.TBP0;
|
||||
const u32 old_pages_wide = old_buffer_width * 64 / psm_o.pgs.x;
|
||||
|
||||
if ((block_diff % (GS_BLOCKS_PER_PAGE * old_pages_wide)) == 0) // Check for left alignment.
|
||||
{
|
||||
const int change_height = block_diff / (GS_BLOCKS_PER_PAGE * old_pages_wide) * psm_o.pgs.y;
|
||||
old_dst->m_valid = old_dst->m_valid.rintersect(GSVector4i(old_dst->m_valid.x, old_dst->m_valid.y, old_dst->m_valid.z, old_dst->m_valid.w - change_height));
|
||||
old_dst->m_TEX0.TBP0 += block_diff;
|
||||
|
||||
const GSVector2i new_scaled_size = GSVector2i(old_dst->m_unscaled_size * old_dst->m_scale);
|
||||
if (GSTexture* tex = g_gs_device->CreateCompatible(dst->m_texture, new_scaled_size, true))
|
||||
{
|
||||
const int height_offset = change_height * old_dst->m_scale;
|
||||
g_gs_device->CopyRect(old_dst->m_texture, tex, GSVector4i(0, height_offset, old_dst->GetUnscaledWidth() * old_dst->m_scale, old_dst->GetUnscaledHeight() * old_dst->m_scale), 0, 0);
|
||||
|
||||
g_gs_device->Recycle(old_dst->m_texture);
|
||||
old_dst->m_texture = tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const int page_diff = std::abs(static_cast<int>(old_dst->m_TEX0.TBP0 - dst->m_TEX0.TBP0)) >> 5;
|
||||
const u32 new_buffer_width = std::max(1U, dst->m_TEX0.TBW);
|
||||
const u32 old_buffer_width = std::max(1U, old_dst->m_TEX0.TBW);
|
||||
|
||||
// Handle cases where the buffer widths don't match.
|
||||
if (new_buffer_width != old_buffer_width)
|
||||
@@ -3592,7 +3638,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
const u32 old_pages_wide = old_buffer_width * 64 / psm_s.pgs.x;
|
||||
if ((block_diff % (32 * old_pages_wide)) == 0) // Check for left alignment.
|
||||
{
|
||||
const int new_height = block_diff / (32 * old_pages_wide) * psm_s.pgs.y;
|
||||
const int new_height = block_diff / (GS_BLOCKS_PER_PAGE * old_pages_wide) * psm_s.pgs.y;
|
||||
old_dst->m_valid = old_dst->m_valid.rintersect(GSVector4i(0, 0, old_dst->GetUnscaledWidth(), new_height));
|
||||
if (old_dst->m_valid.rempty())
|
||||
{
|
||||
@@ -4543,10 +4589,14 @@ void GSTextureCache::InvalidateContainedTargets(u32 start_bp, u32 end_bp, u32 wr
|
||||
|
||||
InvalidateSourcesFromTarget(t);
|
||||
|
||||
t->m_valid_alpha_low &= preserve_alpha;
|
||||
t->m_valid_alpha_high &= preserve_alpha;
|
||||
t->m_valid_rgb &= (fb_mask & 0x00FFFFFF) != 0;
|
||||
t->m_was_dst_matched = false;
|
||||
if (type == DepthStencil || start_bp == t->m_TEX0.TBP0 || (start_bp < t->m_TEX0.TBP0 && t->UnwrappedEndBlock() <= end_bp))
|
||||
{
|
||||
const bool compatible_channel_swizzle = GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == GSLocalMemory::m_psm[write_psm].bpp;
|
||||
t->m_valid_alpha_low &= preserve_alpha && compatible_channel_swizzle;
|
||||
t->m_valid_alpha_high &= preserve_alpha && compatible_channel_swizzle;
|
||||
t->m_valid_rgb &= (fb_mask & 0x00FFFFFF) != 0 && compatible_channel_swizzle;
|
||||
t->m_was_dst_matched = false;
|
||||
}
|
||||
|
||||
// Don't keep partial depth buffers around.
|
||||
if ((!t->m_valid_alpha_low && !t->m_valid_alpha_high && !t->m_valid_rgb) || type == DepthStencil)
|
||||
@@ -8178,8 +8228,9 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca
|
||||
{
|
||||
// Can't do partial copies in DirectX for depth textures, and it's probably not ideal in other
|
||||
// APIs either. So use a fullscreen quad setting depth instead.
|
||||
// Use bilinear to avoid artifacts with upscaling. At native this is equivalent to nearest.
|
||||
g_gs_device->StretchRectAuto(m_texture, tex, GSVector4(rc), Biln);
|
||||
// Use bilinear to avoid artifacts with upscaling during native scaling.
|
||||
const bool req_bilinear = m_downscaled && m_scale < g_gs_renderer->GetUpscaleMultiplier();
|
||||
g_gs_device->StretchRectAuto(m_texture, tex, GSVector4(rc), req_bilinear ? Biln : Nearest);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -555,12 +555,6 @@ vertex MainVSOut vs_main_expand(
|
||||
out.inv_cov = is_near_corner ? 0.0f : 1.0f; // Full coverage at near corner, otherwise none.
|
||||
|
||||
out.interior = 0;
|
||||
|
||||
if (NOT_IIP)
|
||||
{
|
||||
// Get the provoking vertex color (first vertex in Metal)
|
||||
out.fc = i0 == 0 ? out.fc : (i1 == 0 ? other.fc : opposite.fc);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
|
||||
@@ -128,12 +128,13 @@ public:
|
||||
{
|
||||
PSSelector ps;
|
||||
VSSelector vs;
|
||||
u8 pad[3];
|
||||
u8 pad[15];
|
||||
|
||||
__fi bool operator==(const ProgramSelector& p) const { return BitEqual(*this, p); }
|
||||
__fi bool operator!=(const ProgramSelector& p) const { return !BitEqual(*this, p); }
|
||||
};
|
||||
static_assert(sizeof(ProgramSelector) == 32, "Program selector is 32 bytes");
|
||||
static_assert(offsetof(ProgramSelector, pad) + sizeof(ProgramSelector::pad) == sizeof(ProgramSelector));
|
||||
|
||||
struct ProgramSelectorHash
|
||||
{
|
||||
|
||||
@@ -3906,8 +3906,7 @@ VkShaderModule GSDeviceVK::GetUtilityFragmentShader(const std::string& source, c
|
||||
|
||||
bool GSDeviceVK::CreateNullTexture()
|
||||
{
|
||||
GSTexture::Usage null_usage = m_features.rov ? GSTexture::ShaderWriteTarget : GSTexture::FeedbackTarget;
|
||||
m_null_texture = GSTextureVK::Create(null_usage, GSTexture::Format::Color, 1, 1, 1);
|
||||
m_null_texture = GSTextureVK::Create(GSTexture::ShaderWriteTarget, GSTexture::Format::Color, 1, 1, 1);
|
||||
if (!m_null_texture)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -1030,7 +1030,7 @@ void GameDatabase::initDatabase()
|
||||
const ryml::csubstr yaml = ryml::to_csubstr(*buffer);
|
||||
|
||||
Error error;
|
||||
std::optional<ryml::Tree> tree = ParseYAMLFromString(yaml, ryml::to_csubstr(name), &error);
|
||||
std::optional<ryml::Tree> tree = ParseYAMLFromString(yaml, ryml::to_csubstr(name), &error, true);
|
||||
if (!tree.has_value())
|
||||
{
|
||||
Console.ErrorFmt("GameDB: Failed to parse game database file {}:", path);
|
||||
|
||||
@@ -380,8 +380,8 @@ bool FullscreenUI::HasActiveWindow()
|
||||
bool FullscreenUI::AreAnyDialogsOpen()
|
||||
{
|
||||
return (s_save_state_selector_open || s_about_window_open || s_cover_downloader_open ||
|
||||
s_input_binding_type != InputBindingInfo::Type::Unknown || ImGuiFullscreen::IsChoiceDialogOpen() ||
|
||||
ImGuiFullscreen::IsFileSelectorOpen());
|
||||
s_achievements_login_open || s_input_binding_type != InputBindingInfo::Type::Unknown ||
|
||||
ImGuiFullscreen::IsChoiceDialogOpen() || ImGuiFullscreen::IsFileSelectorOpen());
|
||||
}
|
||||
|
||||
void FullscreenUI::CheckForConfigChanges(const Pcsx2Config& old_config)
|
||||
|
||||
@@ -4349,6 +4349,8 @@ void FullscreenUI::DrawAchievementsLoginWindow()
|
||||
|
||||
if (ImGui::BeginPopupModal("RetroAchievements", &s_achievements_login_open, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ResetFocusHere();
|
||||
|
||||
const float content_width = ImGui::GetContentRegionAvail().x;
|
||||
|
||||
ImGui::PushFont(g_large_font.first, g_large_font.second);
|
||||
@@ -4448,6 +4450,8 @@ void FullscreenUI::DrawAchievementsLoginWindow()
|
||||
|
||||
s_achievements_login_username[0] = '\0';
|
||||
s_achievements_login_password[0] = '\0';
|
||||
|
||||
QueueResetFocus(FocusResetType::PopupClosed);
|
||||
};
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(ImGuiFullscreen::LAYOUT_FRAME_ROUNDING));
|
||||
@@ -4463,7 +4467,7 @@ void FullscreenUI::DrawAchievementsLoginWindow()
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.3f, 0.6f, 1.0f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.1f, 0.4f, 0.8f, 1.0f));
|
||||
|
||||
if (ImGui::Button(FSUI_CSTR("Dismiss"), ImVec2(button_width, button_height)) && !s_achievements_login_logging_in)
|
||||
if ((ImGui::Button(FSUI_CSTR("Dismiss"), ImVec2(button_width, button_height)) || WantsToCloseMenu()) && !s_achievements_login_logging_in)
|
||||
CloseLoginPopup();
|
||||
|
||||
ImGui::PopStyleColor(3);
|
||||
@@ -4580,7 +4584,7 @@ void FullscreenUI::DrawAchievementsLoginWindow()
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.5f, 0.5f, 0.5f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f));
|
||||
|
||||
if (ImGui::Button(FSUI_CSTR("Cancel"), ImVec2(button_width, button_height)) && !s_achievements_login_logging_in)
|
||||
if ((ImGui::Button(FSUI_CSTR("Cancel"), ImVec2(button_width, button_height)) || WantsToCloseMenu()) && !s_achievements_login_logging_in)
|
||||
{
|
||||
if (s_achievements_login_reason == Achievements::LoginRequestReason::TokenInvalid)
|
||||
{
|
||||
@@ -4803,6 +4807,7 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock<std::mutex>& se
|
||||
s_achievements_login_reason = Achievements::LoginRequestReason::UserInitiated;
|
||||
s_achievements_login_show_dismiss = false;
|
||||
s_achievements_login_open = true;
|
||||
QueueResetFocus(FocusResetType::PopupOpened);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1635,8 +1635,8 @@ void SaveStateSelectorUI::Draw()
|
||||
ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoScrollbar))
|
||||
{
|
||||
// Leave 2 lines for the legend
|
||||
const float legend_margin = ImGui::GetFontSize() * 3.0f + ImGui::GetStyle().ItemSpacing.y * 3.0f;
|
||||
// Leave room for the legend.
|
||||
const float legend_margin = ImGui::GetTextLineHeightWithSpacing() * 4.0f;
|
||||
const float padding = 10.0f * scale;
|
||||
|
||||
ImGui::BeginChild("##item_list", ImVec2(0, -legend_margin), false,
|
||||
|
||||
@@ -555,7 +555,7 @@ const Pad::ControllerInfo& PadDualshock2::GetInfo() const
|
||||
|
||||
void PadDualshock2::Set(u32 index, float value)
|
||||
{
|
||||
if (index > Inputs::LENGTH)
|
||||
if (index >= Inputs::LENGTH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -258,7 +258,7 @@ const Pad::ControllerInfo& PadGuitar::GetInfo() const
|
||||
|
||||
void PadGuitar::Set(u32 index, float value)
|
||||
{
|
||||
if (index > Inputs::LENGTH)
|
||||
if (index >= Inputs::LENGTH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -324,7 +324,7 @@ const Pad::ControllerInfo& PadJogcon::GetInfo() const
|
||||
|
||||
void PadJogcon::Set(u32 index, float value)
|
||||
{
|
||||
if (index > Inputs::LENGTH)
|
||||
if (index >= Inputs::LENGTH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ const Pad::ControllerInfo& PadNegcon::GetInfo() const
|
||||
|
||||
void PadNegcon::Set(u32 index, float value)
|
||||
{
|
||||
if (index > Inputs::LENGTH)
|
||||
if (index >= Inputs::LENGTH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ const Pad::ControllerInfo& PadPopn::GetInfo() const
|
||||
|
||||
void PadPopn::Set(u32 index, float value)
|
||||
{
|
||||
if (index > Inputs::LENGTH)
|
||||
if (index >= Inputs::LENGTH)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -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 = 106; // Last changed in PR 14643
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 108; // Last changed in PR 14688
|
||||
|
||||
@@ -80,6 +80,8 @@ namespace usb_lightgun
|
||||
{"SLUS-20669", 90.25f, 93.5f, 420, 132, 640, 240}, // Resident Evil - Dead Aim (U)
|
||||
{"SLUS-20619", 90.25f, 91.75f, 453, 154, 640, 256}, // Starsky & Hutch (U)
|
||||
{"SCES-50300", 90.25f, 102.75f, 390, 138, 640, 256}, // Time Crisis II (E)
|
||||
{"SLPS-20122", 90.25f, 97.5f, 390, 154, 640, 240}, // Time Crisis II (J)
|
||||
{"SLPS-20113", 90.25f, 97.5f, 390, 154, 640, 240}, // Time Crisis II (with GunCon 2) (J)
|
||||
{"SLUS-20219", 90.25f, 97.5f, 390, 154, 640, 240}, // Time Crisis 2 (U)
|
||||
{"SCES-51844", 90.25f, 102.75f, 390, 138, 640, 256}, // Time Crisis 3 (E)
|
||||
{"SLUS-20645", 90.25f, 97.5f, 390, 154, 640, 240}, // Time Crisis 3 (U)
|
||||
@@ -90,6 +92,7 @@ namespace usb_lightgun
|
||||
{"SLPS-25077", 90.0f, 97.5f, 422, 118, 640, 240}, // Vampire Night (J)
|
||||
{"SLUS-20221", 89.8f, 102.5f, 422, 124, 640, 228}, // Vampire Night (U)
|
||||
{"SLES-51229", 110.15f, 100.0f, 433, 159, 512, 256}, // Virtua Cop - Elite Edition (E,J) (480i)
|
||||
{"SLPM-62205", 110.15f, 100.0f, 433, 159, 512, 256}, // Virtua Cop Re-Birth (J) (480i)
|
||||
// {"SLES-51229", 85.75f, 92.0f, 456, 164, 640, 256}, // Virtua Cop - Elite Edition (E,J) (480p)
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user