Compare commits

..
40 Commits
Author SHA1 Message Date
Ziemasandlightningterror 86d76bbf59 GameDB: Patch The Gift to fix sound RPC 2026-07-16 16:45:38 +02:00
refractionpcsx2andlightningterror 45fa6a8bb5 GS: Add special case CSM2 read for Breath of Fire Dragon Quarter 2026-07-16 16:44:29 +02:00
SternXDandlightningterror 223c2cba9a ImGui: Fix cut off legend in save state overlay 2026-07-16 16:42:02 +02:00
TJnotJTandlightningterror 562c32cd15 GS:HW: Fix ROV texture type conversion for temporary Z. 2026-07-16 16:41:31 +02:00
SternXDandlightningterror 876a0bfbd7 FullscreenUI: Fix nav loss after logging in to RA 2026-07-16 16:40:36 +02:00
chaoticgdandlightningterror 81558dc9c4 Qt: Silence warning when opening log window 2026-07-16 16:39:57 +02:00
PCSX2 BotandTy 2d62078b04 [ci skip] Qt: Update Base Translation. 2026-07-15 20:29:09 -04:00
RedPanda4552andlightningterror 474ad59818 USB: Copy Virtua Cop offsets to Re-Birth JP version 2026-07-15 16:23:29 +02:00
refractionpcsx2andlightningterror d75c8b1edc GS/TC: Invalidate rgb + alpha on contained target swizzle mismatch 2026-07-15 14:35:47 +02:00
refractionpcsx2andlightningterror d89b4b6fa1 GS/TC: Improve handling of different format overlap in preload 2026-07-15 14:35:47 +02:00
refractionpcsx2andlightningterror afb875f2c6 GS/HW: Improve clears when half is zero + alter mismatched DHC lookup
- DHC is double half clear :)
2026-07-15 14:35:47 +02:00
refractionpcsx2andlightningterror f24d44d470 GS: Make size macros const expressions 2026-07-15 14:35:47 +02:00
refractionpcsx2andlightningterror 4918b0aa09 GS/TC: Don't clear valid flags if render target is only partially cleared 2026-07-15 14:35:47 +02:00
a50ed4d05a GS:HW: Fix regression with prefer_reuse texture fetching flag.
Boolean value of the flag was not properly inverted in a refactor.

Co-authored-by: t654132
2026-07-15 14:34:40 +02:00
refractionpcsx2andlightningterror 19d08ba94f GS/TC: Only bilinear resize depth if downscaled 2026-07-15 14:34:02 +02:00
PCSX2 BotandTy a80b3144bb [ci skip] Qt: Update Base Translation. 2026-07-14 20:35:45 -04:00
chaoticgdandlightningterror 9f0206966b Debugger: Add navigation history with back and forward buttons 2026-07-15 00:29:33 +02:00
chaoticgdandlightningterror dcae14398a Debugger: Improve menu item sorting 2026-07-15 00:29:33 +02:00
TheLastRarandlightningterror 14164e6592 GS/OGL: Increase padding to fill ProgramSelector size 2026-07-15 00:27:42 +02:00
chaoticgdandGovanifY 873977d0b8 Debugger: Improve layout editor dialog 2026-07-14 20:00:52 +02:00
TundrakandGovanifY 78319ef0ba Pad: Fix enum entries check 2026-07-14 18:10:25 +02:00
Bobby SmithandTy d1beb6be9a USB: Add GunCon 2 values for the Japanese versions of Time Crisis II 2026-07-14 08:36:28 -04:00
PCSX2 Botandlightningterror 5df1662c1b [ci skip] Qt: Update Base Translation. 2026-07-13 23:45:30 +02:00
refractionpcsx2andlightningterror 45b8338f6d GS/HW: Adjust shuffle predetect for only texture formats under 32bit 2026-07-13 23:45:15 +02:00
lightningterror 92914cee40 GS: Bump shader cache version. 2026-07-12 21:43:59 +02:00
RedPanda4552andlightningterror 44079ebbe2 [ci skip] GitIgnore: Ignore Kate project files 2026-07-12 21:28:21 +02:00
refractionpcsx2andlightningterror 8d2d9ebb1d GS: Move readback image dump to Transfer Images parameter from Save RT 2026-07-12 21:27:13 +02:00
TJnotJTandlightningterror 4f62bff866 GS:DX:VK: Always make null texture with UAV usage. 2026-07-12 21:25:53 +02:00
TJnotJTandlightningterror 8510ec29ba GS/DX: Fix typo with primid init output. 2026-07-12 21:20:28 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
cde272055f Deps/gha: Bump the ci-deps group across 1 directory with 2 updates (#14644)
Bumps the ci-deps group with 2 updates in the / directory:
[actions/cache](https://github.com/actions/cache) and
[indygreg/apple-code-sign-action](https://github.com/indygreg/apple-code-sign-action).

Updates `actions/cache` from 5 to 6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/releases">actions/cache's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update packages, migrate to ESM by <a
href="https://github.com/Samirat"><code>@​Samirat</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1760">actions/cache#1760</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v6.0.0">https://github.com/actions/cache/compare/v5...v6.0.0</a></p>
<h2>v5.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@​actions/cache</code> to v5.1.0 - handle read-only cache
access by <a
href="https://github.com/jasongin"><code>@​jasongin</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1775">actions/cache#1775</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.1.0">https://github.com/actions/cache/compare/v5...v5.1.0</a></p>
<h2>v5.0.5</h2>
<h2>What's Changed</h2>
<ul>
<li>Update ts-http-runtime dependency by <a
href="https://github.com/yacaovsnc"><code>@​yacaovsnc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1747">actions/cache#1747</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.5">https://github.com/actions/cache/compare/v5...v5.0.5</a></p>
<h2>v5.0.4</h2>
<h2>What's Changed</h2>
<ul>
<li>Add release instructions and update maintainer docs by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1696">actions/cache#1696</a></li>
<li>Potential fix for code scanning alert no. 52: Workflow does not
contain permissions by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1697">actions/cache#1697</a></li>
<li>Fix workflow permissions and cleanup workflow names / formatting by
<a href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1699">actions/cache#1699</a></li>
<li>docs: Update examples to use the latest version by <a
href="https://github.com/XZTDean"><code>@​XZTDean</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1690">actions/cache#1690</a></li>
<li>Fix proxy integration tests by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1701">actions/cache#1701</a></li>
<li>Fix cache key in examples.md for bun.lock by <a
href="https://github.com/RyPeck"><code>@​RyPeck</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1722">actions/cache#1722</a></li>
<li>Update dependencies &amp; patch security vulnerabilities by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/cache/pull/1738">actions/cache#1738</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/XZTDean"><code>@​XZTDean</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1690">actions/cache#1690</a></li>
<li><a href="https://github.com/RyPeck"><code>@​RyPeck</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/cache/pull/1722">actions/cache#1722</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.4">https://github.com/actions/cache/compare/v5...v5.0.4</a></p>
<h2>v5.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a
href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li>
<li>Bump <code>@actions/core</code> to v2.0.3</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.3">https://github.com/actions/cache/compare/v5...v5.0.3</a></p>
<h2>v.5.0.2</h2>
<h1>v5.0.2</h1>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/blob/main/RELEASES.md">actions/cache's
changelog</a>.</em></p>
<blockquote>
<h1>Releases</h1>
<h2>How to prepare a release</h2>
<blockquote>
<p>[!NOTE]
Relevant for maintainers with write access only.</p>
</blockquote>
<ol>
<li>Switch to a new branch from <code>main</code>.</li>
<li>Run <code>npm test</code> to ensure all tests are passing.</li>
<li>Update the version in <a
href="https://github.com/actions/cache/blob/main/package.json"><code>https://github.com/actions/cache/blob/main/package.json</code></a>.</li>
<li>Run <code>npm run build</code> to update the compiled files.</li>
<li>Update this <a
href="https://github.com/actions/cache/blob/main/RELEASES.md"><code>https://github.com/actions/cache/blob/main/RELEASES.md</code></a>
with the new version and changes in the <code>## Changelog</code>
section.</li>
<li>Run <code>licensed cache</code> to update the license report.</li>
<li>Run <code>licensed status</code> and resolve any warnings by
updating the <a
href="https://github.com/actions/cache/blob/main/.licensed.yml"><code>https://github.com/actions/cache/blob/main/.licensed.yml</code></a>
file with the exceptions.</li>
<li>Commit your changes and push your branch upstream.</li>
<li>Open a pull request against <code>main</code> and get it reviewed
and merged.</li>
<li>Draft a new release <a
href="https://github.com/actions/cache/releases">https://github.com/actions/cache/releases</a>
use the same version number used in <code>package.json</code>
<ol>
<li>Create a new tag with the version number.</li>
<li>Auto generate release notes and update them to match the changes you
made in <code>RELEASES.md</code>.</li>
<li>Toggle the set as the latest release option.</li>
<li>Publish the release.</li>
</ol>
</li>
<li>Navigate to <a
href="https://github.com/actions/cache/actions/workflows/release-new-action-version.yml">https://github.com/actions/cache/actions/workflows/release-new-action-version.yml</a>
<ol>
<li>There should be a workflow run queued with the same version
number.</li>
<li>Approve the run to publish the new version and update the major tags
for this action.</li>
</ol>
</li>
</ol>
<h2>Changelog</h2>
<h3>6.1.0</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v6.1.0 to pick up <a
href="https://redirect.github.com/actions/toolkit/pull/2435">actions/toolkit#2435
Handle cache write error due to read-only token</a></li>
<li>Switch redundant &quot;Cache save failed&quot; warning to debug log
in save-only</li>
</ul>
<h3>6.0.0</h3>
<ul>
<li>Updated <code>@actions/cache</code> to ^6.0.1,
<code>@actions/core</code> to ^3.0.1, <code>@actions/exec</code> to
^3.0.0, <code>@actions/io</code> to ^3.0.2</li>
<li>Migrated to ESM module system</li>
<li>Upgraded Jest to v30 and test infrastructure to be ESM
compatible</li>
</ul>
<h3>5.0.4</h3>
<ul>
<li>Bump <code>minimatch</code> to v3.1.5 (fixes ReDoS via globstar
patterns)</li>
<li>Bump <code>undici</code> to v6.24.1 (WebSocket decompression bomb
protection, header validation fixes)</li>
<li>Bump <code>fast-xml-parser</code> to v5.5.6</li>
</ul>
<h3>5.0.3</h3>
<ul>
<li>Bump <code>@actions/cache</code> to v5.0.5 (Resolves: <a
href="https://github.com/actions/cache/security/dependabot/33">https://github.com/actions/cache/security/dependabot/33</a>)</li>
<li>Bump <code>@actions/core</code> to v2.0.3</li>
</ul>
<h3>5.0.2</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/cache/commit/55cc8345863c7cc4c66a329aec7e433d2d1c52a9"><code>55cc834</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1768">#1768</a>
from jasongin/readonly-cache</li>
<li><a
href="https://github.com/actions/cache/commit/d8cd72f230726cdf4457ebb61ec1b593a8d12337"><code>d8cd72f</code></a>
Bump <code>@​actions/cache</code> to v6.1.0 - handle cache write error
due to RO token</li>
<li><a
href="https://github.com/actions/cache/commit/2c8a9bd7457de244a408f35966fab2fb45fda9c8"><code>2c8a9bd</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1760">#1760</a>
from actions/samirat/esm_migration_and_package_update</li>
<li><a
href="https://github.com/actions/cache/commit/e9b91fdc3fea7d79165fceb79042ef45c2d51023"><code>e9b91fd</code></a>
Prettier fixes</li>
<li><a
href="https://github.com/actions/cache/commit/e4884b8ff7f92ef6b52c79eda480bbc86e685adb"><code>e4884b8</code></a>
Rebuild dist</li>
<li><a
href="https://github.com/actions/cache/commit/10baf0191a3c426ea0fa4a3253a5c04233b6e18f"><code>10baf01</code></a>
Fixed licenses</li>
<li><a
href="https://github.com/actions/cache/commit/e39b386c9004d72a15d864ade8c0b3a702d47a37"><code>e39b386</code></a>
Fix test mock return order</li>
<li><a
href="https://github.com/actions/cache/commit/b6928203372a8571ff984c0c883ef3a1adfb0c06"><code>b692820</code></a>
PR feedback</li>
<li><a
href="https://github.com/actions/cache/commit/60749128a44d25d3c520a489e576380cf00ff3f1"><code>6074912</code></a>
Rebuild dist bundles as ESM to match type:module</li>
<li><a
href="https://github.com/actions/cache/commit/5a912e8b4af820fa082a0e75cfd2c782f8fbfe0e"><code>5a912e8</code></a>
Fix lint and jest issues</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/cache/compare/v5...v6">compare
view</a></li>
</ul>
</details>
<br />

Updates `indygreg/apple-code-sign-action` from 1.1 to 1.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/indygreg/apple-code-sign-action/releases">indygreg/apple-code-sign-action's
releases</a>.</em></p>
<blockquote>
<h2>v1.2</h2>
<ul>
<li>Use Node 24</li>
<li>Upgraded a bunch of JS packages and GitHub Actions to newer
versions.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/indygreg/apple-code-sign-action/commit/5e7a4a01fe4dffe948ef3bcf1f4538d963cb0c72"><code>5e7a4a0</code></a>
ci: try to get superlint working</li>
<li><a
href="https://github.com/indygreg/apple-code-sign-action/commit/7f0907c84f8b68c8f1984ff263d324c1cce7d5fe"><code>7f0907c</code></a>
Sync linter CI job with reference repo</li>
<li><a
href="https://github.com/indygreg/apple-code-sign-action/commit/ff12e78172ee6d6ef5795e283781716beafa3218"><code>ff12e78</code></a>
Remove exports from index.js</li>
<li><a
href="https://github.com/indygreg/apple-code-sign-action/commit/770da749199c68745f62c806c8f124d9a2460b18"><code>770da74</code></a>
More export fixes</li>
<li><a
href="https://github.com/indygreg/apple-code-sign-action/commit/d518541e903902dbfbbad25890ec19b27dffea15"><code>d518541</code></a>
Fix import in index.js</li>
<li><a
href="https://github.com/indygreg/apple-code-sign-action/commit/438214a5fbcb443aefaa10b3c9224f872cfe27fd"><code>438214a</code></a>
use <code>import</code> instead of <code>require</code></li>
<li><a
href="https://github.com/indygreg/apple-code-sign-action/commit/264357680eaff3f84804a0f31edb9137b57bcc34"><code>2643576</code></a>
Modernize action</li>
<li><a
href="https://github.com/indygreg/apple-code-sign-action/commit/7c7d8b0a07e0a8550c0785566284e4acda0cf836"><code>7c7d8b0</code></a>
node: upgrade vercel/ncc to latest</li>
<li><a
href="https://github.com/indygreg/apple-code-sign-action/commit/36ea96e14b7799106808f4e2e6811b84482faa64"><code>36ea96e</code></a>
node: make semver compatible package updates</li>
<li><a
href="https://github.com/indygreg/apple-code-sign-action/commit/379f0ae50edc7e725f0a29cb6e5c9d90f911124a"><code>379f0ae</code></a>
build(deps): bump actions/checkout from 6 to 7 (<a
href="https://redirect.github.com/indygreg/apple-code-sign-action/issues/79">#79</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/indygreg/apple-code-sign-action/compare/44d0985b7f4363198e80b6fea63ac3e9dd3e9957...5e7a4a01fe4dffe948ef3bcf1f4538d963cb0c72">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-12 14:02:45 -04:00
TellowKrinkleandGitHub 5e3ad282a8 common: Fix build on ryml < 0.11 2026-07-11 23:13:53 -05:00
PCSX2 Botandlightningterror 091b3a8694 [ci skip] Qt: Update Base Translation. 2026-07-12 02:18:27 +02:00
KamFretoZandlightningterror 42ce97aca5 Qt: Clean up Setup Wizard's labels 2026-07-11 15:41:27 +02:00
KamFretoZandlightningterror a4df5c300e Qt/Launcher: Fix StartupWMClass Value 2026-07-11 15:41:27 +02:00
KamFretoZandlightningterror 4bf51e735a Qt: Add Create PCSX2 shortcut option to setup wizard 2026-07-11 15:41:27 +02:00
KamFretoZandlightningterror d7e7c8164c Qt: Decouple CreateShortcut from the ShortcutCreationDialog 2026-07-11 15:41:27 +02:00
TJnotJTandlightningterror eb5e3fcd13 GS/HW: Make all vertices the same color in certain flat shading cases.
Fixes issues with AA1 with flat shading.
2026-07-10 10:16:51 +02:00
TheLastRarandTy 8f8968cbb1 Deps: Revert workaround for MSVC ICE with PlutoVG
This reverts commit 7ade24fc77.
2026-07-09 18:40:47 -04:00
SilentandTy ac83e93426 GameDB: Update Gran Turismo entries to use anchors and overrides 2026-07-09 15:53:38 -04:00
SilentandTy 78d0cf4a4f YAML: Add support for resolving anchors, and use it for GameDB 2026-07-09 15:53:38 -04:00
71 changed files with 1776 additions and 1455 deletions
+3
View File
@@ -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:
+2 -2
View File
@@ -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') }}
+3 -3
View File
@@ -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';
+1 -1
View File
@@ -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') }}
+3
View File
@@ -63,6 +63,9 @@ oprofile_data/
*.kdev4
/.kdev4*
# Kate Projects
.kateproject*
# Resources and docs in /bin are tracked
/bin/**/*.dll
/bin/**/*.dmp
+112 -370
View File
@@ -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: "철권 "
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"
+1 -6
View File
@@ -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
-5
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -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
+24 -1
View File
@@ -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;
+6
View File
@@ -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);
+37
View File
@@ -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);
+3 -1
View File
@@ -40,7 +40,9 @@ public:
void updateFromSettings();
public slots:
void updateNavigationButtons();
private slots:
void onVMStarting();
void onVMPaused();
void onVMResumed();
+63 -16
View File
@@ -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/>
+56 -7
View File
@@ -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();
+13 -2
View File
@@ -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;
};
+39 -8
View File
@@ -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)
+10
View File
@@ -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;
};
+2
View File
@@ -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",
},
+7
View File
@@ -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)
+1
View File
@@ -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>
+56 -8
View File
@@ -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();
}
+10 -1
View File
@@ -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;
+164
View File
@@ -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;
};
+1 -1
View File
@@ -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);
+466
View File
@@ -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
View File
@@ -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
+22
View File
@@ -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"));
+1
View File
@@ -66,6 +66,7 @@ private:
void setupGameListPage();
void setupControllerPage();
void setupRetroAchievementsPage();
void setupCompletePage();
void refreshRetroAchievementsLoginState();
void pageChangedTo(int page);
+47 -25
View File
@@ -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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;h1 style=&quot; margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:xx-large; font-weight:700;&quot;&gt;Welcome to PCSX2!&lt;/span&gt;&lt;/h1&gt;&lt;p&gt;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 &lt;a href=&quot;https://pcsx2.net/docs/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;By default, PCSX2 will connect to the server at &lt;a href=&quot;https://pcsx2.net/&quot;&gt;pcsx2.net&lt;/a&gt; to check for updates, and if available and confirmed, download update packages from &lt;a href=&quot;https://github.com/&quot;&gt;github.com&lt;/a&gt;. 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.&lt;/p&gt;&lt;p&gt;Please choose a language and theme to begin.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;PCSX2 requires a PS2 BIOS in order to run.&lt;/p&gt;&lt;p&gt;For legal reasons, you must obtain a BIOS &lt;strong&gt;from an actual PS2 unit that you own&lt;/strong&gt; (borrowing doesn't count).&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;A guide for dumping your BIOS can be found &lt;a href=&quot;https://pcsx2.net/docs/setup/bios/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;PCSX2 will automatically scan and identify games from the selected directories below, and populate the game list.&lt;br&gt;These games should be dumped from discs you own. Guides for dumping discs can be found &lt;a href=&quot;https://pcsx2.net/docs/setup/dumping&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Supported formats for dumps include:&lt;/p&gt;&lt;p&gt;&lt;ul&gt;&lt;li&gt;.bin/.iso (ISO Disc Images)&lt;/li&gt;&lt;li&gt;.mdf (Media Descriptor File)&lt;/li&gt;&lt;li&gt;.chd (Compressed Hunks of Data)&lt;/li&gt;&lt;li&gt;.cso (Compressed ISO)&lt;/li&gt;&lt;li&gt;.zso (Compressed ISO)&lt;/li&gt;&lt;li&gt;.gz (Gzip Compressed ISO)&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;By default, PCSX2 will map your keyboard to the virtual PS2 controller.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:704;&quot;&gt;To use an external controller, you must map it first. &lt;/span&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;Guides for configuring controllers can be found &lt;a href=&quot;https://pcsx2.net/docs/post/controllers/&quot;&gt;&lt;span style=&quot;&quot;&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;h1 style=&quot; margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:xx-large; font-weight:700;&quot;&gt;Setup Complete!&lt;/span&gt;&lt;/h1&gt;&lt;p&gt;You are now ready to run games.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:700;&quot;&gt;Warning: Do not run untrusted programs in PCSX2. It is not a sandbox and cannot protect your computer from malicious software.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Further options are available under the settings menu. You can also use the Big Picture UI for navigation entirely with a gamepad.&lt;/p&gt;&lt;p&gt;We hope you enjoy using PCSX2.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>
+4 -433
View File
@@ -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"
-7
View File
@@ -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
+1
View File
@@ -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" />
+3
View File
@@ -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

+6 -2
View File
@@ -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
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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",
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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;
+2 -4
View File
@@ -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;
+48 -32
View File
@@ -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.",
+1 -1
View File
@@ -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);
+59 -8
View File
@@ -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
{
-6
View File
@@ -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;
+2 -1
View File
@@ -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
{
+1 -2
View File
@@ -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;
+1 -1
View File
@@ -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);
+2 -2
View File
@@ -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)
+7 -2
View File
@@ -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);
}
}
+2 -2
View File
@@ -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,
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -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;
}
+1 -1
View File
@@ -3,4 +3,4 @@
/// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 106; // Last changed in PR 14643
static constexpr u32 SHADER_CACHE_VERSION = 108; // Last changed in PR 14688
+3
View File
@@ -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)
};