mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-31 11:18:41 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c77d8b3709 | ||
|
|
7b428bb6b0 | ||
|
|
6986030cd9 | ||
|
|
cc9b9a1935 | ||
|
|
2b7eeba55c | ||
|
|
c87dd99824 | ||
|
|
fbd837eadb | ||
|
|
7c9c8e197c | ||
|
|
0366929231 | ||
|
|
10d5261153 | ||
|
|
3278856764 | ||
|
|
ff5a9e0ea1 | ||
|
|
59b0c09443 | ||
|
|
ae772e6a74 | ||
|
|
0a58783a86 | ||
|
|
6f6de13fd4 | ||
|
|
89dcb78efa | ||
|
|
703c02c32c | ||
|
|
adcfca4db3 | ||
|
|
c359223fd4 | ||
|
|
c4c7d26bb3 | ||
|
|
c06bc16b22 | ||
|
|
f7bc05c735 | ||
|
|
ff02d41992 | ||
|
|
ec180e2771 | ||
|
|
dffa9e0b8c | ||
|
|
497e06bcd9 | ||
|
|
4c67c165fa | ||
|
|
2c175c0c7e | ||
|
|
6babbc1ff9 | ||
|
|
8af9aace3c | ||
|
|
601b75b611 | ||
|
|
350037fc75 | ||
|
|
f6bcfc3abd | ||
|
|
a480c972f7 | ||
|
|
581ded2c93 | ||
|
|
06176e291a | ||
|
|
14ee1b40d0 | ||
|
|
9acb98a2c8 | ||
|
|
daf50df337 | ||
|
|
c4d136383c | ||
|
|
5b5016bfd4 | ||
|
|
02352ab231 | ||
|
|
a4909d3575 | ||
|
|
fbb50e2895 | ||
|
|
0e4bf501f1 | ||
|
|
89b97456b7 | ||
|
|
fc4112c459 | ||
|
|
b6923f49b1 |
@@ -2,8 +2,8 @@ name: 📝 Validate GameDB
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
branches-ignore:
|
||||
- "l10n_master"
|
||||
paths:
|
||||
- '**/GameIndex.yaml'
|
||||
pull_request:
|
||||
|
||||
@@ -83,8 +83,14 @@ jobs:
|
||||
arch: x86_64
|
||||
build-bundle: true
|
||||
verbose: true
|
||||
mirror-screenshots-url: https://dl.flathub.org/repo/screenshots
|
||||
branch: stable
|
||||
cache: true
|
||||
restore-cache: true
|
||||
cache-key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} flatpak ${{ hashFiles('.github/workflows/scripts/linux/flatpak/**/*.json') }}
|
||||
|
||||
- name: Commit screenshots to OSTree
|
||||
run: |
|
||||
ostree commit --repo=repo --canonical-permissions --branch=screenshots/x86_64 .github/workflows/scripts/linux/flatpak/screenshots
|
||||
|
||||
# TODO: Push to flathub
|
||||
|
||||
@@ -2,8 +2,8 @@ name: 🐧 Linux Builds
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
branches-ignore:
|
||||
- "l10n_master"
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
@@ -2,8 +2,8 @@ name: 🍎 MacOS Builds
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
branches-ignore:
|
||||
- "l10n_master"
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 136 KiB |
@@ -13,6 +13,14 @@
|
||||
</description>
|
||||
<url type="homepage">https://pcsx2.net/</url>
|
||||
<url type="bugtracker">https://github.com/PCSX2/pcsx2/issues</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://raw.githubusercontent.com/PCSX2/pcsx2/master/.github/workflows/scripts/linux/flatpak/screenshots/screenshot1.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://raw.githubusercontent.com/PCSX2/pcsx2/master/.github/workflows/scripts/linux/flatpak/screenshots/screenshot2.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<content_rating type="oars-1.1"/>
|
||||
<update_contact>pcsx2_AT_pcsx2.net</update_contact>
|
||||
<releases>
|
||||
|
||||
@@ -2,8 +2,8 @@ name: 🖥️ Windows Builds
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
branches-ignore:
|
||||
- "l10n_master"
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
@@ -4984,6 +4984,8 @@ SCES-55571:
|
||||
SCES-55573:
|
||||
name: "MotorStorm - Arctic Edge"
|
||||
region: "PAL-M14"
|
||||
clampModes:
|
||||
vu1ClampMode: 3 # Fixes bad polys in menu.
|
||||
SCES-55591:
|
||||
name: "Street Cricket Champions"
|
||||
region: "PAL-IN"
|
||||
@@ -9330,9 +9332,11 @@ SCUS-97653:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
SCUS-97654:
|
||||
name: "MotorStorm Arctic Edge"
|
||||
name: "MotorStorm - Arctic Edge"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
clampModes:
|
||||
vu1ClampMode: 3 # Fixes bad polys in menu.
|
||||
SCUS-97657:
|
||||
name: "MLB 11 - The Show"
|
||||
region: "NTSC-U"
|
||||
@@ -9527,6 +9531,7 @@ SLAJ-25072:
|
||||
mipmap: 2 # Mipmap + trilinear, improves ground textures to match sw renderer.
|
||||
trilinearFiltering: 1
|
||||
halfPixelOffset: 2 # Fix effects upscaling.
|
||||
autoFlush: 1 # Fixes broken post processing.
|
||||
SLAJ-25073:
|
||||
name: "Resident Evil 4"
|
||||
region: "NTSC-J"
|
||||
@@ -9981,6 +9986,7 @@ SLED-53845:
|
||||
mipmap: 2 # Mipmap + trilinear, improves ground textures to match sw renderer.
|
||||
trilinearFiltering: 1
|
||||
halfPixelOffset: 2 # Fix effects upscaling.
|
||||
autoFlush: 1 # Fixes broken post processing.
|
||||
SLED-53937:
|
||||
name: "Black [Demo]"
|
||||
region: "PAL-M5"
|
||||
@@ -18135,6 +18141,7 @@ SLES-53462:
|
||||
mipmap: 2 # Mipmap + trilinear, improves ground textures to match sw renderer.
|
||||
trilinearFiltering: 1
|
||||
halfPixelOffset: 2 # Fix effects upscaling.
|
||||
autoFlush: 1 # Fixes broken post processing.
|
||||
SLES-53463:
|
||||
name: "NHL '06"
|
||||
region: "PAL-E"
|
||||
@@ -19191,6 +19198,7 @@ SLES-53759:
|
||||
mipmap: 2 # Mipmap + trilinear, improves ground textures to match sw renderer.
|
||||
trilinearFiltering: 1
|
||||
halfPixelOffset: 2 # Fix effects upscaling.
|
||||
autoFlush: 1 # Fixes broken post processing.
|
||||
SLES-53760:
|
||||
name: "Rugby Challenge 2006"
|
||||
region: "PAL-M5"
|
||||
@@ -19280,6 +19288,7 @@ SLES-53799:
|
||||
mipmap: 2 # Mipmap + trilinear, improves ground textures to match sw renderer.
|
||||
trilinearFiltering: 1
|
||||
halfPixelOffset: 2 # Fix effects upscaling.
|
||||
autoFlush: 1 # Fixes broken post processing.
|
||||
SLES-53800:
|
||||
name: "Rampage - Total Destruction"
|
||||
region: "PAL-M5"
|
||||
@@ -23757,8 +23766,10 @@ SLES-55572:
|
||||
gameFixes:
|
||||
- EETimingHack # Broken textures.
|
||||
SLES-55573:
|
||||
name: "MotorStorm Arctic Edge"
|
||||
name: "MotorStorm - Arctic Edge"
|
||||
region: "PAL-M14"
|
||||
clampModes:
|
||||
vu1ClampMode: 3 # Fixes bad polys in menu.
|
||||
SLES-55574:
|
||||
name: "Lord of the Rings, The - Aragorn's Quest"
|
||||
region: "PAL-M6"
|
||||
@@ -24014,6 +24025,7 @@ SLES-82013:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes blurry characters.
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLES-82018:
|
||||
name: "Cy Girls [Ice Disc]"
|
||||
region: "PAL-E-F-S"
|
||||
@@ -24038,6 +24050,7 @@ SLES-82024:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes blurry characters.
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLES-82026:
|
||||
name: "Metal Gear Solid 3 - Snake Eater"
|
||||
region: "PAL-S"
|
||||
@@ -24046,6 +24059,7 @@ SLES-82026:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes blurry characters.
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLES-82028:
|
||||
name: "Star Ocean 3 - Till the End of Time [Disc 1 of 2]"
|
||||
region: "PAL-E"
|
||||
@@ -24094,6 +24108,7 @@ SLES-82032:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes blurry characters.
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLES-82034:
|
||||
name: "Xenosaga Episode II [Disc 1 of 2]"
|
||||
region: "PAL-M3"
|
||||
@@ -24157,6 +24172,7 @@ SLES-82042:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLES-82043:
|
||||
name: "Metal Gear Solid 3 - Subsistence [Disc 2 of 3]"
|
||||
region: "PAL-E-F"
|
||||
@@ -24166,6 +24182,7 @@ SLES-82043:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLES-82042"
|
||||
SLES-82044:
|
||||
@@ -24177,6 +24194,7 @@ SLES-82044:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLES-82045:
|
||||
name: "Metal Gear Solid 3 - Subsistence [Disc 2 of 3]"
|
||||
region: "PAL-I"
|
||||
@@ -24186,6 +24204,7 @@ SLES-82045:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLES-82044"
|
||||
SLES-82046:
|
||||
@@ -24197,6 +24216,7 @@ SLES-82046:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLES-82047:
|
||||
name: "Metal Gear Solid 3 - Subsistence [Disc 2 of 3]"
|
||||
region: "PAL-G"
|
||||
@@ -24206,6 +24226,7 @@ SLES-82047:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLES-82046"
|
||||
SLES-82048:
|
||||
@@ -24217,6 +24238,7 @@ SLES-82048:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLES-82049:
|
||||
name: "Metal Gear Solid 3 - Subsistence [Disc 2 of 3]"
|
||||
region: "PAL-S"
|
||||
@@ -24226,6 +24248,7 @@ SLES-82049:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLES-82048"
|
||||
SLES-82050:
|
||||
@@ -24237,6 +24260,7 @@ SLES-82050:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLES-82042"
|
||||
SLES-82051:
|
||||
@@ -24248,6 +24272,7 @@ SLES-82051:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLES-82044"
|
||||
SLES-82052:
|
||||
@@ -24259,6 +24284,7 @@ SLES-82052:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLES-82046"
|
||||
SLES-82053:
|
||||
@@ -24270,6 +24296,7 @@ SLES-82053:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLES-82048"
|
||||
SLKA-15002:
|
||||
@@ -25116,6 +25143,7 @@ SLKA-25251:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLKA-25252:
|
||||
name: "Forgotten Realms - Demon Stone"
|
||||
region: "NTSC-K"
|
||||
@@ -25274,6 +25302,7 @@ SLKA-25303:
|
||||
mipmap: 2 # Mipmap + trilinear, improves ground textures to match sw renderer.
|
||||
trilinearFiltering: 1
|
||||
halfPixelOffset: 2 # Fix effects upscaling.
|
||||
autoFlush: 1 # Fixes broken post processing.
|
||||
SLKA-25304:
|
||||
name: "Burnout Revenge"
|
||||
region: "NTSC-K"
|
||||
@@ -25433,6 +25462,7 @@ SLKA-25353:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLKA-25354:
|
||||
name: "Metal Gear Solid 3 - Subsistence [Limited Edition] [Disc 2 of 3]"
|
||||
region: "NTSC-K"
|
||||
@@ -25443,6 +25473,7 @@ SLKA-25354:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLKA-25353"
|
||||
SLKA-25355:
|
||||
@@ -25455,6 +25486,7 @@ SLKA-25355:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLKA-25353"
|
||||
SLKA-25359:
|
||||
@@ -31610,6 +31642,7 @@ SLPM-65789:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLPM-65790:
|
||||
name: "Metal Gear Solid 3 - Snake Eater"
|
||||
region: "NTSC-J"
|
||||
@@ -31618,6 +31651,7 @@ SLPM-65790:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLPM-65791:
|
||||
name: "S.L.A.I. - Steel Lancer Arena International"
|
||||
region: "NTSC-J"
|
||||
@@ -32827,6 +32861,7 @@ SLPM-66117:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLPM-66118:
|
||||
name: "Metal Gear Solid 3 - Subsistence [with Headset] [Disc 2 of 3]"
|
||||
region: "NTSC-J"
|
||||
@@ -32836,6 +32871,7 @@ SLPM-66118:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLPM-66119:
|
||||
name: "Metal Gear Solid 3 - Subsistence [with Headset] [Disc 3 of 3]"
|
||||
region: "NTSC-J"
|
||||
@@ -32845,6 +32881,7 @@ SLPM-66119:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLPM-66121:
|
||||
name: "Spider-Man 2 [Taito Best]"
|
||||
region: "NTSC-J"
|
||||
@@ -33068,6 +33105,7 @@ SLPM-66177:
|
||||
mipmap: 2 # Mipmap + trilinear, improves ground textures to match sw renderer.
|
||||
trilinearFiltering: 1
|
||||
halfPixelOffset: 2 # Fix effects upscaling.
|
||||
autoFlush: 1 # Fixes broken post processing.
|
||||
SLPM-66178:
|
||||
name: "pop'n music 7 [Konami The Best]"
|
||||
region: "NTSC-J"
|
||||
@@ -33240,6 +33278,7 @@ SLPM-66220:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLPM-66117"
|
||||
SLPM-66221:
|
||||
@@ -33251,6 +33290,7 @@ SLPM-66221:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLPM-66117"
|
||||
SLPM-66222:
|
||||
@@ -33262,6 +33302,7 @@ SLPM-66222:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLPM-66117"
|
||||
SLPM-66223:
|
||||
@@ -33273,6 +33314,7 @@ SLPM-66223:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLPM-66117"
|
||||
SLPM-66224:
|
||||
@@ -33284,6 +33326,7 @@ SLPM-66224:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLPM-66117"
|
||||
SLPM-66225:
|
||||
@@ -35560,6 +35603,7 @@ SLPM-66794:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLPM-66796:
|
||||
name: "Metal Gear Solid - 20th Anniversary Collection"
|
||||
region: "NTSC-J"
|
||||
@@ -36488,6 +36532,7 @@ SLPM-68516:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLPM-68520:
|
||||
name: "Armored Core - Last Raven [Monthly Champion magazine Special Edition]"
|
||||
region: "NTSC-J"
|
||||
@@ -46721,6 +46766,7 @@ SLUS-20915:
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLUS-20916:
|
||||
name: "Dance Dance Revolution EXTREME"
|
||||
region: "NTSC-U"
|
||||
@@ -48540,6 +48586,7 @@ SLUS-21243:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLUS-21359"
|
||||
SLUS-21244:
|
||||
@@ -48739,6 +48786,7 @@ SLUS-21273:
|
||||
mipmap: 2 # Mipmap + trilinear, improves ground textures to match sw renderer.
|
||||
trilinearFiltering: 1
|
||||
halfPixelOffset: 2 # Fix effects upscaling.
|
||||
autoFlush: 1 # Fixes broken post processing.
|
||||
SLUS-21274:
|
||||
name: "OutRun 2006 - Coast 2 Coast"
|
||||
region: "NTSC-U"
|
||||
@@ -49263,6 +49311,7 @@ SLUS-21359:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
SLUS-21360:
|
||||
name: "Metal Gear Solid 3 - Subsistence [Disc 3 of 3]"
|
||||
region: "NTSC-U"
|
||||
@@ -49272,6 +49321,7 @@ SLUS-21360:
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes lens flare.
|
||||
halfPixelOffset: 2 # Fixes blurriness.
|
||||
getSkipCount: "GSC_MetalGearSolid3" # Fixes depth of field blur.
|
||||
memcardFilters:
|
||||
- "SLUS-21359"
|
||||
SLUS-21361:
|
||||
|
||||
@@ -1294,7 +1294,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,paddle1:b12,paddle3:b13,paddle2,b14,paddle4:b15,platform:Linux,
|
||||
030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,paddle1:b12,paddle3:b13,paddle2,b14,paddle4:b15,platform:Linux,
|
||||
050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
|
||||
@@ -1368,6 +1369,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000666600006706000000010000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
|
||||
030000004c050000da0c000011010000,PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000d9040000160f000000010000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
|
||||
|
||||
@@ -81,7 +81,6 @@ target_sources(common PRIVATE
|
||||
HeapArray.h
|
||||
HTTPDownloader.h
|
||||
MemorySettingsInterface.h
|
||||
MemsetFast.inl
|
||||
MD5Digest.h
|
||||
MRCHelpers.h
|
||||
Path.h
|
||||
|
||||
@@ -198,24 +198,6 @@ private:
|
||||
#define SafeSysMunmap(ptr, size) \
|
||||
((void)(HostSys::Munmap(ptr, size), (ptr) = 0))
|
||||
|
||||
// This method can clear any object-like entity -- which is anything that is not a pointer.
|
||||
// Structures, static arrays, etc. No need to include sizeof() crap, this does it automatically
|
||||
// for you!
|
||||
template <typename T>
|
||||
static __fi void memzero(T& object)
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
std::memset(&object, 0, sizeof(T));
|
||||
}
|
||||
|
||||
// This method clears an object with the given 8 bit value.
|
||||
template <u8 data, typename T>
|
||||
static __fi void memset8(T& object)
|
||||
{
|
||||
static_assert(std::is_trivially_copyable_v<T>);
|
||||
std::memset(&object, data, sizeof(T));
|
||||
}
|
||||
|
||||
extern u64 GetTickFrequency();
|
||||
extern u64 GetCPUTicks();
|
||||
extern u64 GetPhysicalMemory();
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <xmmintrin.h>
|
||||
|
||||
template <u8 data>
|
||||
__noinline void memset_sse_a(void* dest, const size_t size)
|
||||
{
|
||||
const uint MZFqwc = size / 16;
|
||||
|
||||
pxAssert((size & 0xf) == 0);
|
||||
|
||||
__m128 srcreg;
|
||||
|
||||
if (data != 0)
|
||||
{
|
||||
alignas(16) static const u8 loadval[8] = {data, data, data, data, data, data, data, data};
|
||||
srcreg = _mm_loadh_pi(_mm_load_ps((float*)loadval), (__m64*)loadval);
|
||||
}
|
||||
else
|
||||
srcreg = _mm_setzero_ps();
|
||||
|
||||
float(*destxmm)[4] = (float(*)[4])dest;
|
||||
|
||||
switch (MZFqwc & 0x07)
|
||||
{
|
||||
case 0x07:
|
||||
_mm_store_ps(&destxmm[0x07 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x06:
|
||||
_mm_store_ps(&destxmm[0x06 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x05:
|
||||
_mm_store_ps(&destxmm[0x05 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x04:
|
||||
_mm_store_ps(&destxmm[0x04 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x03:
|
||||
_mm_store_ps(&destxmm[0x03 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x02:
|
||||
_mm_store_ps(&destxmm[0x02 - 1][0], srcreg);
|
||||
// Fall through
|
||||
case 0x01:
|
||||
_mm_store_ps(&destxmm[0x01 - 1][0], srcreg);
|
||||
// Fall through
|
||||
}
|
||||
|
||||
destxmm += (MZFqwc & 0x07);
|
||||
for (uint i = 0; i < MZFqwc / 8; ++i, destxmm += 8)
|
||||
{
|
||||
_mm_store_ps(&destxmm[0][0], srcreg);
|
||||
_mm_store_ps(&destxmm[1][0], srcreg);
|
||||
_mm_store_ps(&destxmm[2][0], srcreg);
|
||||
_mm_store_ps(&destxmm[3][0], srcreg);
|
||||
_mm_store_ps(&destxmm[4][0], srcreg);
|
||||
_mm_store_ps(&destxmm[5][0], srcreg);
|
||||
_mm_store_ps(&destxmm[6][0], srcreg);
|
||||
_mm_store_ps(&destxmm[7][0], srcreg);
|
||||
}
|
||||
};
|
||||
|
||||
static __fi void memzero_sse_a(void* dest, const size_t size)
|
||||
{
|
||||
memset_sse_a<0>(dest, size);
|
||||
}
|
||||
|
||||
template <u8 data, typename T>
|
||||
__noinline void memset_sse_a(T& dest)
|
||||
{
|
||||
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
|
||||
memset_sse_a<data>(&dest, sizeof(dest));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void memzero_sse_a(T& dest)
|
||||
{
|
||||
static_assert((sizeof(dest) & 0xf) == 0, "Bad size for SSE memset");
|
||||
memset_sse_a<0>(&dest, sizeof(dest));
|
||||
}
|
||||
@@ -180,4 +180,4 @@
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -66,8 +66,6 @@ x86capabilities::x86capabilities()
|
||||
, PhysicalCores(0)
|
||||
, LogicalCores(0)
|
||||
{
|
||||
memzero(VendorName);
|
||||
memzero(FamilyName);
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma optimize("", on)
|
||||
@@ -148,7 +146,6 @@ void x86capabilities::Identify()
|
||||
s32 regs[4];
|
||||
u32 cmds;
|
||||
|
||||
memzero(VendorName);
|
||||
cpuid(regs, 0);
|
||||
|
||||
cmds = regs[0];
|
||||
@@ -201,7 +198,6 @@ void x86capabilities::Identify()
|
||||
EFlags = regs[3];
|
||||
}
|
||||
|
||||
memzero(FamilyName);
|
||||
cpuid((int*)FamilyName, 0x80000002);
|
||||
cpuid((int*)(FamilyName + 16), 0x80000003);
|
||||
cpuid((int*)(FamilyName + 32), 0x80000004);
|
||||
|
||||
@@ -46,8 +46,8 @@ public:
|
||||
u32 EFlags2; // Extended Feature Flags pg2
|
||||
u32 SEFlag; // Structured Extended Feature Flags Enumeration
|
||||
|
||||
char VendorName[16]; // Vendor/Creator ID
|
||||
char FamilyName[50]; // the original cpu name
|
||||
char VendorName[16] = {}; // Vendor/Creator ID
|
||||
char FamilyName[50] = {}; // the original cpu name
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// x86 CPU Capabilities Section (all boolean flags!)
|
||||
@@ -55,6 +55,8 @@ public:
|
||||
|
||||
union
|
||||
{
|
||||
u64 AllCapabilities = 0;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 hasFloatingPointUnit : 1;
|
||||
@@ -101,13 +103,11 @@ public:
|
||||
u32 hasAMD64BitArchitecture : 1;
|
||||
u32 hasStreamingSIMD4ExtensionsA : 1;
|
||||
};
|
||||
|
||||
u64 AllCapabilities;
|
||||
};
|
||||
|
||||
// Core Counts!
|
||||
u32 PhysicalCores;
|
||||
u32 LogicalCores;
|
||||
u32 PhysicalCores = 0;
|
||||
u32 LogicalCores = 0;
|
||||
|
||||
public:
|
||||
x86capabilities();
|
||||
|
||||
@@ -167,20 +167,25 @@
|
||||
/>
|
||||
</Target>
|
||||
|
||||
<!--Copies base translation files-->
|
||||
<!--Copies base translation files, need to rename them from qtbase_ to qt_ -->
|
||||
<ItemGroup>
|
||||
<BaseTsFiles Include="$(QtTranslationsDir)\*.qm" />
|
||||
</ItemGroup>
|
||||
<Target Name="QtCopyBaseTranslations"
|
||||
AfterTargets="Build"
|
||||
Inputs="@(BaseTsFiles)"
|
||||
Outputs="@(BaseTsFiles -> '$(QtTsOutDir)%(RecursiveDir)%(Filename)%(Extension)')">
|
||||
Outputs="@(BaseTsFiles -> '$(QtTsOutDir)%(RecursiveDir)%(Filename.Replace('qtbase_', 'qt_'))%(Extension)')">
|
||||
<!-- https://stackoverflow.com/a/15379344 -->
|
||||
<ItemGroup>
|
||||
<TempItems Include="@(BaseTsFiles->'%(Filename)%(Extension)'->Replace('qtbase_', 'qt_'))">
|
||||
<OriginalPath>%(Identity)</OriginalPath>
|
||||
<SavedRecursiveDir>%(RecursiveDir)</SavedRecursiveDir>
|
||||
</TempItems>
|
||||
</ItemGroup>
|
||||
<Message Text="Copying base translation files" Importance="High" />
|
||||
<Copy
|
||||
SourceFiles="@(BaseTsFiles)"
|
||||
DestinationFolder="$(QtTsOutDir)"
|
||||
SkipUnchangedFiles="true"
|
||||
/>
|
||||
<Copy SourceFiles="@(TempItems->'%(OriginalPath)')"
|
||||
DestinationFiles="@(TempItems->'$(QtTsOutDir)%(SavedRecursiveDir)%(Identity)')"
|
||||
SkipUnchangedFiles="true" />
|
||||
</Target>
|
||||
|
||||
<!--Compiles all translation files-->
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
files:
|
||||
- source: pcsx2-qt/Translations/pcsx2-qt_en.ts
|
||||
translation: '/pcsx2-qt/Translations/pcsx2-qt_%two_letters_code%.ts'
|
||||
translation: '/pcsx2-qt/Translations/pcsx2-qt_%locale%.ts'
|
||||
|
||||
@@ -658,6 +658,18 @@ void Host::VSyncOnCPUThread()
|
||||
GSRunner::PumpPlatformMessages();
|
||||
}
|
||||
|
||||
s32 Host::Internal::GetTranslatedStringImpl(
|
||||
const std::string_view& context, const std::string_view& msg, char* tbuf, size_t tbuf_space)
|
||||
{
|
||||
if (msg.size() > tbuf_space)
|
||||
return -1;
|
||||
else if (msg.empty())
|
||||
return 0;
|
||||
|
||||
std::memcpy(tbuf, msg.data(), msg.size());
|
||||
return static_cast<s32>(msg.size());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Platform specific code
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -26,6 +26,7 @@ target_sources(pcsx2-qt PRIVATE
|
||||
PrecompiledHeader.h
|
||||
SettingWidgetBinder.h
|
||||
Themes.cpp
|
||||
Translations.cpp
|
||||
QtHost.cpp
|
||||
QtHost.h
|
||||
QtKeyCodes.cpp
|
||||
@@ -173,6 +174,10 @@ if(USE_ACHIEVEMENTS)
|
||||
)
|
||||
endif()
|
||||
|
||||
set(TS_FILES
|
||||
Translations/pcsx2-qt_en.ts
|
||||
)
|
||||
|
||||
target_precompile_headers(pcsx2-qt PRIVATE PrecompiledHeader.h)
|
||||
|
||||
target_include_directories(pcsx2-qt PRIVATE
|
||||
@@ -191,6 +196,24 @@ target_link_libraries(pcsx2-qt PRIVATE
|
||||
Qt6::Network
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_SOURCE_DIR}/bin/translations")
|
||||
qt_add_lrelease(pcsx2-qt TS_FILES ${TS_FILES})
|
||||
elseif(APPLE)
|
||||
# Hopefully macdeployqt will pick these up.
|
||||
qt_add_lrelease(pcsx2-qt TS_FILES ${TS_FILES})
|
||||
else()
|
||||
# TODO: Copy base translations.
|
||||
qt_add_lrelease(pcsx2-qt TS_FILES ${TS_FILES} QM_FILES_OUTPUT_VARIABLE QM_FILES)
|
||||
set(QM_OUTPUT_DIR "$<TARGET_FILE_DIR:pcsx2-qt>/translations")
|
||||
add_custom_command(TARGET pcsx2-qt POST_BUILD COMMAND "${CMAKE_COMMAND}" -E make_directory "${QM_OUTPUT_DIR}")
|
||||
foreach (QM_FILE IN LISTS QM_FILES)
|
||||
get_filename_component(QM_FILE_NAME ${QM_FILE} NAME)
|
||||
add_custom_command(TARGET pcsx2-qt POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${QM_FILE}" "${QM_OUTPUT_DIR}/${QM_FILE_NAME}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
||||
# Currently, 7z is only needed for the Windows updater.
|
||||
if(WIN32)
|
||||
target_link_libraries(pcsx2-qt PRIVATE
|
||||
|
||||
+14
-14
@@ -1394,6 +1394,12 @@ void MainWindow::updateTheme()
|
||||
m_game_list_widget->refreshImages();
|
||||
}
|
||||
|
||||
void MainWindow::updateLanguage()
|
||||
{
|
||||
QtHost::InstallTranslator();
|
||||
recreate();
|
||||
}
|
||||
|
||||
void MainWindow::onInputRecNewActionTriggered()
|
||||
{
|
||||
const bool wasPaused = s_vm_paused;
|
||||
@@ -1933,7 +1939,7 @@ void MainWindow::relativeMouseModeRequested(bool enabled)
|
||||
return;
|
||||
|
||||
m_relative_mouse_mode = enabled;
|
||||
if (s_vm_valid && !s_vm_paused)
|
||||
if (m_display_widget && !s_vm_paused)
|
||||
updateDisplayWidgetCursor();
|
||||
}
|
||||
|
||||
@@ -2002,6 +2008,7 @@ void MainWindow::destroyDisplayWidget(bool show_game_list)
|
||||
|
||||
void MainWindow::updateDisplayWidgetCursor()
|
||||
{
|
||||
pxAssertRel(m_display_widget, "Should have a display widget");
|
||||
m_display_widget->updateRelativeMode(s_vm_valid && !s_vm_paused && m_relative_mouse_mode);
|
||||
m_display_widget->updateCursor(s_vm_valid && !s_vm_paused && shouldHideMouseCursor());
|
||||
}
|
||||
@@ -2063,6 +2070,11 @@ SettingsDialog* MainWindow::getSettingsDialog()
|
||||
{
|
||||
m_settings_dialog = new SettingsDialog(this);
|
||||
connect(m_settings_dialog->getInterfaceSettingsWidget(), &InterfaceSettingsWidget::themeChanged, this, &MainWindow::updateTheme);
|
||||
connect(m_settings_dialog->getInterfaceSettingsWidget(), &InterfaceSettingsWidget::languageChanged, this, [this]() {
|
||||
// reopen settings dialog after it applies
|
||||
updateLanguage();
|
||||
g_main_window->doSettings("Interface");
|
||||
});
|
||||
}
|
||||
|
||||
return m_settings_dialog;
|
||||
@@ -2452,20 +2464,8 @@ void MainWindow::doStartFile(std::optional<CDVD_SourceType> source, const QStrin
|
||||
|
||||
void MainWindow::doDiscChange(CDVD_SourceType source, const QString& path)
|
||||
{
|
||||
const bool is_gs_dump = VMManager::IsGSDumpFileName(path.toStdString());
|
||||
if (is_gs_dump != GSDumpReplayer::IsReplayingDump())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Cannot switch from game to GS dump or vice versa."));
|
||||
return;
|
||||
}
|
||||
else if (is_gs_dump)
|
||||
{
|
||||
Host::RunOnCPUThread([path = path.toStdString()]() { GSDumpReplayer::ChangeDump(path.c_str()); });
|
||||
return;
|
||||
}
|
||||
|
||||
bool reset_system = false;
|
||||
if (!m_was_disc_change_request)
|
||||
if (!m_was_disc_change_request && !GSDumpReplayer::IsReplayingDump())
|
||||
{
|
||||
QMessageBox message(QMessageBox::Question, tr("Confirm Disc Change"),
|
||||
tr("Do you want to swap discs or boot the new image (via system reset)?"), QMessageBox::NoButton, this);
|
||||
|
||||
@@ -159,6 +159,7 @@ private Q_SLOTS:
|
||||
void onToolsOpenDataDirectoryTriggered();
|
||||
void onToolsCoverDownloaderTriggered();
|
||||
void updateTheme();
|
||||
void updateLanguage();
|
||||
void onScreenshotActionTriggered();
|
||||
void onSaveGSDumpActionTriggered();
|
||||
void onBlockDumpActionToggled(bool checked);
|
||||
|
||||
@@ -1220,6 +1220,7 @@ bool QtHost::InitializeConfig()
|
||||
|
||||
LogSink::SetBlockSystemConsole(QtHost::InNoGUIMode());
|
||||
VMManager::Internal::LoadStartupSettings();
|
||||
InstallTranslator();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -216,6 +216,9 @@ namespace QtHost
|
||||
/// Default theme name for the platform.
|
||||
const char* GetDefaultThemeName();
|
||||
|
||||
/// Default language for the platform.
|
||||
const char* GetDefaultLanguage();
|
||||
|
||||
/// Sets application theme according to settings.
|
||||
void UpdateApplicationTheme();
|
||||
|
||||
@@ -234,6 +237,12 @@ namespace QtHost
|
||||
/// Executes a function on the UI thread.
|
||||
void RunOnUIThread(const std::function<void()>& func, bool block = false);
|
||||
|
||||
/// Returns a list of supported languages and codes (suffixes for translation files).
|
||||
std::vector<std::pair<QString, QString>> GetAvailableLanguageList();
|
||||
|
||||
/// Call when the language changes.
|
||||
void InstallTranslator();
|
||||
|
||||
/// Returns the application name and version, optionally including debug/devel config indicator.
|
||||
QString GetAppNameAndVersion();
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ QIcon ControllerBindingWidget::getIcon() const
|
||||
void ControllerBindingWidget::populateControllerTypes()
|
||||
{
|
||||
for (const auto& [name, display_name] : PAD::GetControllerTypeNames())
|
||||
m_ui.controllerType->addItem(QString::fromStdString(display_name), QString::fromStdString(name));
|
||||
m_ui.controllerType->addItem(qApp->translate("Pad", display_name), QString::fromStdString(name));
|
||||
}
|
||||
|
||||
void ControllerBindingWidget::onTypeChanged()
|
||||
@@ -116,8 +116,8 @@ void ControllerBindingWidget::onTypeChanged()
|
||||
if (has_settings)
|
||||
{
|
||||
const gsl::span<const SettingInfo> settings(cinfo->settings, cinfo->num_settings);
|
||||
m_settings_widget =
|
||||
new ControllerCustomSettingsWidget(settings, m_config_section, std::string(), cinfo->name, getDialog(), m_ui.stackedWidget);
|
||||
m_settings_widget = new ControllerCustomSettingsWidget(
|
||||
settings, m_config_section, std::string(), "Pad", getDialog(), m_ui.stackedWidget);
|
||||
m_ui.stackedWidget->addWidget(m_settings_widget);
|
||||
}
|
||||
|
||||
@@ -343,7 +343,7 @@ ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* pare
|
||||
continue;
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(QString::fromUtf8(bi.display_name));
|
||||
item->setText(qApp->translate("Pad", bi.display_name));
|
||||
item->setCheckState((std::find(m_binds.begin(), m_binds.end(), &bi) != m_binds.end()) ? Qt::Checked : Qt::Unchecked);
|
||||
m_ui.bindList->addItem(item);
|
||||
}
|
||||
@@ -374,7 +374,7 @@ QString ControllerMacroEditWidget::getSummary() const
|
||||
{
|
||||
if (!str.isEmpty())
|
||||
str += static_cast<QChar>('/');
|
||||
str += QString::fromUtf8(bi->name);
|
||||
str += qApp->translate("Pad", bi->display_name);
|
||||
}
|
||||
return str.isEmpty() ? tr("Not Configured") : str;
|
||||
}
|
||||
@@ -902,7 +902,7 @@ QIcon USBDeviceWidget::getIcon() const
|
||||
void USBDeviceWidget::populateDeviceTypes()
|
||||
{
|
||||
for (const auto& [name, display_name] : USB::GetDeviceTypes())
|
||||
m_ui.deviceType->addItem(QString::fromStdString(display_name), QString::fromStdString(name));
|
||||
m_ui.deviceType->addItem(qApp->translate("USB", display_name), QString::fromUtf8(name));
|
||||
}
|
||||
|
||||
void USBDeviceWidget::populatePages()
|
||||
@@ -950,7 +950,7 @@ void USBDeviceWidget::populatePages()
|
||||
if (!settings.empty())
|
||||
{
|
||||
m_settings_widget = new ControllerCustomSettingsWidget(
|
||||
settings, m_config_section, m_device_type + "_", m_device_type.c_str(), m_dialog, m_ui.stackedWidget);
|
||||
settings, m_config_section, m_device_type + "_", "USB", m_dialog, m_ui.stackedWidget);
|
||||
m_ui.stackedWidget->addWidget(m_settings_widget);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ void ControllerSettingsDialog::onNewProfileClicked()
|
||||
// from global
|
||||
auto lock = Host::GetSettingsLock();
|
||||
PAD::CopyConfiguration(&temp_si, *Host::Internal::GetBaseSettingsLayer(), true, true, false);
|
||||
USB::CopyConfiguration(&temp_si, *Host::Internal::GetBaseSettingsLayer(), true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -135,6 +136,7 @@ void ControllerSettingsDialog::onNewProfileClicked()
|
||||
const bool copy_hotkey_bindings = m_profile_interface->GetBoolValue("Pad", "UseProfileHotkeyBindings", false);
|
||||
temp_si.SetBoolValue("Pad", "UseProfileHotkeyBindings", copy_hotkey_bindings);
|
||||
PAD::CopyConfiguration(&temp_si, *m_profile_interface, true, true, copy_hotkey_bindings);
|
||||
USB::CopyConfiguration(&temp_si, *m_profile_interface, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,6 +165,7 @@ void ControllerSettingsDialog::onLoadProfileClicked()
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
PAD::CopyConfiguration(Host::Internal::GetBaseSettingsLayer(), *m_profile_interface, true, true, false);
|
||||
USB::CopyConfiguration(Host::Internal::GetBaseSettingsLayer(), *m_profile_interface, true, true);
|
||||
}
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
||||
@@ -398,7 +401,7 @@ void ControllerSettingsDialog::createWidgets()
|
||||
m_ui.settingsContainer->addWidget(m_port_bindings[global_slot]);
|
||||
|
||||
const PAD::ControllerInfo* ci = PAD::GetControllerInfo(m_port_bindings[global_slot]->getControllerType());
|
||||
const QString display_name(ci ? QString::fromUtf8(ci->display_name) : QStringLiteral("Unknown"));
|
||||
const QString display_name(ci ? qApp->translate("Pad", ci->display_name) : QStringLiteral("Unknown"));
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
@@ -454,7 +457,7 @@ void ControllerSettingsDialog::updateListDescription(u32 global_slot, Controller
|
||||
const bool mtap_enabled = getBoolValue("Pad", (port == 0) ? "MultitapPort1" : "MultitapPort2", false);
|
||||
|
||||
const PAD::ControllerInfo* ci = PAD::GetControllerInfo(widget->getControllerType());
|
||||
const QString display_name(ci ? QString::fromUtf8(ci->display_name) : QStringLiteral("Unknown"));
|
||||
const QString display_name(ci ? qApp->translate("Pad", ci->display_name) : QStringLiteral("Unknown"));
|
||||
|
||||
//: Controller Port is an official term from Sony. Find the official translation for your language inside the console's manual.
|
||||
item->setText(mtap_enabled ? (tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) :
|
||||
|
||||
@@ -73,7 +73,20 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="currentProfile"/>
|
||||
<widget class="QComboBox" name="currentProfile">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>220</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="newProfile">
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Low compatiblity warning: yes, it's very big, but may not work with many games.</string>
|
||||
<string>Low compatibility warning: yes, it's very big, but may not work with many games.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
|
||||
@@ -678,7 +678,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Displays various settings and the current values of those settings, useful for debugging."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowInputs, tr("Show Inputs"), tr("Unchecked"),
|
||||
tr("Shows the current controler state of the system in the bottom left corner of the display."));
|
||||
tr("Shows the current controller state of the system in the bottom left corner of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"), tr("Displays a graph showing the average frametimes."));
|
||||
|
||||
@@ -237,7 +237,7 @@
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="stretchY">
|
||||
<property name="suffix">
|
||||
<string extracomment="Percentage sign that shows next to a value. You might want to add a space before if you language requires it.">%</string>
|
||||
<string extracomment="Percentage sign that shows next to a value. You might want to add a space before if your language requires it.">%</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
|
||||
@@ -95,6 +95,10 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
QtHost::GetDefaultThemeName());
|
||||
connect(m_ui.theme, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() { emit themeChanged(); });
|
||||
|
||||
populateLanguages();
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.language, "UI", "Language", QtHost::GetDefaultLanguage());
|
||||
connect(m_ui.language, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() { emit languageChanged(); });
|
||||
|
||||
// Per-game settings is special, we don't want to bind it if we're editing per-game settings.
|
||||
m_ui.perGameSettings->setEnabled(!dialog->isPerGameSettings());
|
||||
if (!dialog->isPerGameSettings())
|
||||
@@ -181,9 +185,6 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
m_ui.disableWindowResizing, tr("Disable Window Resizing"), tr("Unchecked"),
|
||||
tr("Prevents the main window from being resized."));
|
||||
|
||||
// Not yet used, disable the options
|
||||
m_ui.language->setDisabled(true);
|
||||
|
||||
onRenderToSeparateWindowChanged();
|
||||
}
|
||||
|
||||
@@ -193,3 +194,9 @@ void InterfaceSettingsWidget::onRenderToSeparateWindowChanged()
|
||||
{
|
||||
m_ui.hideMainWindow->setEnabled(m_ui.renderToSeparateWindow->isChecked());
|
||||
}
|
||||
|
||||
void InterfaceSettingsWidget::populateLanguages()
|
||||
{
|
||||
for (const std::pair<QString, QString>& it : QtHost::GetAvailableLanguageList())
|
||||
m_ui.language->addItem(it.first, it.second);
|
||||
}
|
||||
|
||||
@@ -31,10 +31,13 @@ public:
|
||||
|
||||
Q_SIGNALS:
|
||||
void themeChanged();
|
||||
void languageChanged();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onRenderToSeparateWindowChanged();
|
||||
|
||||
private:
|
||||
void populateLanguages();
|
||||
|
||||
Ui::InterfaceSettingsWidget m_ui;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "QtHost.h"
|
||||
|
||||
#include "common/Console.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include "pcsx2/ImGui/ImGuiManager.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QTranslator>
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include <KnownFolders.h>
|
||||
#include <ShlObj.h>
|
||||
#endif
|
||||
|
||||
namespace QtHost
|
||||
{
|
||||
static const ImWchar* GetGlyphRangesJapanese();
|
||||
static const ImWchar* GetGlyphRangesChinese();
|
||||
static std::string GetFontPath(const char* name);
|
||||
} // namespace QtHost
|
||||
|
||||
static std::vector<QTranslator*> s_translators;
|
||||
|
||||
void QtHost::InstallTranslator()
|
||||
{
|
||||
for (QTranslator* translator : s_translators)
|
||||
{
|
||||
qApp->removeTranslator(translator);
|
||||
translator->deleteLater();
|
||||
}
|
||||
s_translators.clear();
|
||||
|
||||
const QString language =
|
||||
QString::fromStdString(Host::GetBaseStringSettingValue("UI", "Language", GetDefaultLanguage()));
|
||||
|
||||
// Install the base qt translation first.
|
||||
const QString base_dir = QStringLiteral("%1/translations").arg(qApp->applicationDirPath());
|
||||
QString base_path = QStringLiteral("%1/qt_%2.qm").arg(base_dir).arg(language);
|
||||
bool has_base_ts = QFile::exists(base_path);
|
||||
if (!has_base_ts)
|
||||
{
|
||||
// Try without the country suffix.
|
||||
const int index = language.indexOf('-');
|
||||
if (index > 0)
|
||||
{
|
||||
base_path = QStringLiteral("%1/qt_%2.qm").arg(base_dir).arg(language.left(index));
|
||||
has_base_ts = QFile::exists(base_path);
|
||||
}
|
||||
}
|
||||
if (has_base_ts)
|
||||
{
|
||||
QTranslator* base_translator = new QTranslator(qApp);
|
||||
if (!base_translator->load(base_path))
|
||||
{
|
||||
QMessageBox::warning(nullptr, QStringLiteral("Translation Error"),
|
||||
QStringLiteral("Failed to find load base translation file for '%1':\n%2").arg(language).arg(base_path));
|
||||
delete base_translator;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_translators.push_back(base_translator);
|
||||
qApp->installTranslator(base_translator);
|
||||
}
|
||||
}
|
||||
|
||||
const QString path = QStringLiteral("%1/pcsx2-qt_%3.qm").arg(base_dir).arg(language);
|
||||
if (!QFile::exists(path))
|
||||
{
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
// For now, until we're sure this works on all platforms, we won't block users from starting if they're missing.
|
||||
QMessageBox::warning(nullptr, QStringLiteral("Translation Error"),
|
||||
QStringLiteral("Failed to find translation file for language '%1':\n%2").arg(language).arg(path));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
QTranslator* translator = new QTranslator(qApp);
|
||||
if (!translator->load(path))
|
||||
{
|
||||
QMessageBox::warning(nullptr, QStringLiteral("Translation Error"),
|
||||
QStringLiteral("Failed to load translation file for language '%1':\n%2").arg(language).arg(path));
|
||||
delete translator;
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLn(Color_StrongYellow, "Loaded translation file for language %s", language.toUtf8().constData());
|
||||
qApp->installTranslator(translator);
|
||||
s_translators.push_back(translator);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (language == QStringLiteral("ja"))
|
||||
{
|
||||
ImGuiManager::SetFontPath(GetFontPath("msgothic.ttc"));
|
||||
ImGuiManager::SetFontRange(GetGlyphRangesJapanese());
|
||||
}
|
||||
else if (language == QStringLiteral("zh-cn"))
|
||||
{
|
||||
ImGuiManager::SetFontPath(GetFontPath("msyh.ttc"));
|
||||
ImGuiManager::SetFontRange(GetGlyphRangesChinese());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::string QtHost::GetFontPath(const char* name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
PWSTR folder_path;
|
||||
if (FAILED(SHGetKnownFolderPath(FOLDERID_Fonts, 0, nullptr, &folder_path)))
|
||||
return fmt::format("C:\\Windows\\Fonts\\%s", name);
|
||||
|
||||
std::string font_path(StringUtil::WideStringToUTF8String(folder_path));
|
||||
CoTaskMemFree(folder_path);
|
||||
font_path += "\\";
|
||||
font_path += name;
|
||||
return font_path;
|
||||
#else
|
||||
return name;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::pair<QString, QString>> QtHost::GetAvailableLanguageList()
|
||||
{
|
||||
return {
|
||||
{QStringLiteral("English"), QStringLiteral("en")},
|
||||
};
|
||||
}
|
||||
|
||||
const char* QtHost::GetDefaultLanguage()
|
||||
{
|
||||
return "en";
|
||||
}
|
||||
|
||||
s32 Host::Internal::GetTranslatedStringImpl(
|
||||
const std::string_view& context, const std::string_view& msg, char* tbuf, size_t tbuf_space)
|
||||
{
|
||||
// This is really awful. Thankfully we're caching the results...
|
||||
const std::string temp_context(context);
|
||||
const std::string temp_msg(msg);
|
||||
const QString translated_msg = qApp->translate(temp_context.c_str(), temp_msg.c_str());
|
||||
const QByteArray translated_utf8 = translated_msg.toUtf8();
|
||||
const size_t translated_size = translated_utf8.size();
|
||||
if (translated_size > tbuf_space)
|
||||
return -1;
|
||||
else if (translated_size > 0)
|
||||
std::memcpy(tbuf, translated_utf8.constData(), translated_size);
|
||||
|
||||
return static_cast<s32>(translated_size);
|
||||
}
|
||||
|
||||
static const ImWchar* QtHost::GetGlyphRangesJapanese()
|
||||
{
|
||||
// clang-format off
|
||||
// auto update by generate_update_glyph_ranges.py with pcsx2-qt_ja.ts
|
||||
static const char16_t chars[] = u"、。あいかがきこさしすずせたってでとなにのはべまみらりるれをんァィイェエカキクグゲシジスセタダチッデトドバパフブプボポミムメモャュョラリルレロンー一中了今件体使信入出制効動取口可変始定実度強後得態択挿易更有本検無状獲用画的索終績能自行覧解設読起送速選開除難面高";
|
||||
const int chars_length = sizeof(chars) / sizeof(chars[0]);
|
||||
// clang-format on
|
||||
|
||||
static ImWchar base_ranges[] = {
|
||||
0x0020, 0x007E, // Basic Latin
|
||||
};
|
||||
const int base_length = sizeof(base_ranges) / sizeof(base_ranges[0]);
|
||||
|
||||
static ImWchar full_ranges[base_length + chars_length * 2 + 1] = {0};
|
||||
memcpy(full_ranges, base_ranges, sizeof(base_ranges));
|
||||
for (int i = 0; i < chars_length; i++)
|
||||
{
|
||||
full_ranges[base_length + i * 2] = full_ranges[base_length + i * 2 + 1] = chars[i];
|
||||
}
|
||||
return full_ranges;
|
||||
}
|
||||
|
||||
static const ImWchar* QtHost::GetGlyphRangesChinese()
|
||||
{
|
||||
// clang-format off
|
||||
// auto update by generate_update_glyph_ranges.py with pcsx2-qt_zh-cn.ts
|
||||
static const char16_t chars[] = u"";
|
||||
const int chars_length = sizeof(chars) / sizeof(chars[0]);
|
||||
// clang-format on
|
||||
|
||||
static ImWchar base_ranges[] = {
|
||||
0x0020, 0x007E, // Basic Latin
|
||||
};
|
||||
const int base_length = sizeof(base_ranges) / sizeof(base_ranges[0]);
|
||||
|
||||
static ImWchar full_ranges[base_length + chars_length * 2 + 1] = {0};
|
||||
memcpy(full_ranges, base_ranges, sizeof(base_ranges));
|
||||
for (int i = 0; i < chars_length; i++)
|
||||
{
|
||||
full_ranges[base_length + i * 2] = full_ranges[base_length + i * 2 + 1] = chars[i];
|
||||
}
|
||||
return full_ranges;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
src_path = os.path.join(os.path.dirname(__file__), "..", "Translations.cpp")
|
||||
|
||||
def parse_xml(path):
|
||||
translations = ""
|
||||
tree = ET.parse(path)
|
||||
root = tree.getroot()
|
||||
for node in root.findall("context/message/translation"):
|
||||
if node.text:
|
||||
translations += node.text
|
||||
|
||||
chars = list(set([ord(ch) for ch in translations if ord(ch) >= 0x2000]))
|
||||
chars.sort()
|
||||
chars = "".join([chr(ch) for ch in chars])
|
||||
return chars
|
||||
|
||||
def update_src_file(ts_file, chars):
|
||||
ts_name = os.path.basename(ts_file)
|
||||
pattern = re.compile('(// auto update.*' + ts_name + '.*\n[^"]+")[^"]*(".*)')
|
||||
with open(src_path, "r", encoding="utf-8") as f:
|
||||
original = f.read()
|
||||
update = pattern.sub("\\1" + chars + "\\2", original)
|
||||
if original != update:
|
||||
with open(src_path, "w", encoding="utf-8") as f:
|
||||
f.write(update)
|
||||
print("Updated character list.")
|
||||
else:
|
||||
print("Character list is unchanged.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print(f"usage: {sys.argv[0]} <pcsx2-qt_*.ts path>")
|
||||
sys.exit(1)
|
||||
|
||||
chars = parse_xml(sys.argv[1])
|
||||
#print(chars)
|
||||
print(f"{len(chars)} character(s) detected.")
|
||||
update_src_file(sys.argv[1], chars)
|
||||
+4694
-2101
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
|
||||
set QTBIN=..\..\3rdparty\qt\6.5.0\msvc2022_64\bin
|
||||
set SRCDIRS=../ ../../pcsx2/
|
||||
|
||||
set OPTS=-tr-function-alias QT_TRANSLATE_NOOP+=TRANSLATE,QT_TRANSLATE_NOOP+=TRANSLATE_SV,QT_TRANSLATE_NOOP+=TRANSLATE_STR,QT_TRANSLATE_N_NOOP3+=TRANSLATE_FMT,QT_TRANSLATE_NOOP+=TRANSLATE_NOOP
|
||||
|
||||
"%QTBIN%\lupdate.exe" %SRCDIRS% %OPTS% -no-obsolete -source-language en -ts pcsx2-qt_en.ts
|
||||
|
||||
echo.
|
||||
echo ******************************************************************************************************************
|
||||
echo * PLEASE READ *
|
||||
echo ******************************************************************************************************************
|
||||
echo.
|
||||
echo Make sure you have deleted the build (x64) directory from pcsx2-qt, otherwise you will have polluted the .ts file.
|
||||
echo If you did not, then you should reset/checkout the ts file, delete the build directory, and run this script again.
|
||||
echo.
|
||||
echo.
|
||||
pause
|
||||
@@ -39,6 +39,7 @@
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\lzma\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\simpleini\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\imgui\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\demangler\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src\c4\ext\fast_float\include;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\sdl2\include;$(SolutionDir)3rdparty\sdl2\SDL\include</AdditionalIncludeDirectories>
|
||||
@@ -138,6 +139,7 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="QtKeyCodes.cpp" />
|
||||
<ClCompile Include="QtUtils.cpp" />
|
||||
<ClCompile Include="Translations.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="Settings\InterfaceSettingsWidget.h" />
|
||||
@@ -365,6 +367,9 @@
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtTs Include="Translations\pcsx2-qt_en.ts">
|
||||
<FileType>Document</FileType>
|
||||
</QtTs>
|
||||
<QtUi Include="Settings\DebugSettingsWidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
<Filter Include="Debugger\Models">
|
||||
<UniqueIdentifier>{f4084ca0-d9d5-4584-b9d2-063db9f67de2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Translations">
|
||||
<UniqueIdentifier>{ad04f939-64a0-4039-97aa-a38b8aa46855}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\pcsx2\windows\PCSX2.rc" />
|
||||
@@ -328,6 +331,7 @@
|
||||
<ClCompile Include="$(IntDir)Settings\moc_GameCheatSettingsWidget.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Translations.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
|
||||
@@ -619,4 +623,9 @@
|
||||
<Filter>Settings</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtTs Include="Translations\pcsx2-qt_en.ts">
|
||||
<Filter>Translations</Filter>
|
||||
</QtTs>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1053,23 +1053,23 @@ void Achievements::DisplayAchievementSummary()
|
||||
{
|
||||
std::string title = s_game_title;
|
||||
if (ChallengeModeActive())
|
||||
title += " (Hardcore Mode)";
|
||||
title += TRANSLATE_SV("Achievements", " (Hardcore Mode)");
|
||||
|
||||
std::string summary;
|
||||
if (GetAchievementCount() > 0)
|
||||
{
|
||||
summary = StringUtil::StdStringFromFormat("You have earned %u of %u achievements, and %u of %u points.",
|
||||
summary = fmt::format(TRANSLATE_SV("Achievements", "You have earned {0} of {1} achievements, and {2} of {3} points."),
|
||||
GetUnlockedAchiementCount(), GetAchievementCount(), GetCurrentPointsForGame(), GetMaximumPointsForGame());
|
||||
}
|
||||
else
|
||||
{
|
||||
summary = "This game has no achievements.";
|
||||
summary = TRANSLATE_SV("Achievements", "This game has no achievements.");
|
||||
}
|
||||
if (GetLeaderboardCount() > 0)
|
||||
{
|
||||
summary.push_back('\n');
|
||||
if (LeaderboardsActive())
|
||||
summary.append("Leaderboard submission is enabled.");
|
||||
summary.append(TRANSLATE_SV("Achievements", "Leaderboard submission is enabled."));
|
||||
}
|
||||
|
||||
GetMTGS().RunOnGSThread([title = std::move(title), summary = std::move(summary), icon = s_game_icon]() {
|
||||
@@ -1505,7 +1505,8 @@ void Achievements::GameChanged(u32 disc_crc, u32 crc)
|
||||
// when we're booting the bios, or shutting down, this will fail
|
||||
if (disc_crc != 0)
|
||||
{
|
||||
Host::AddKeyedOSDMessage("retroachievements_disc_read_failed", "Failed to read executable from disc. Achievements disabled.",
|
||||
Host::AddKeyedOSDMessage("retroachievements_disc_read_failed",
|
||||
TRANSLATE_STR("Achievements", "Failed to read executable from disc. Achievements disabled."),
|
||||
Host::OSD_CRITICAL_ERROR_DURATION);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -913,7 +913,7 @@ static uint cdvdBlockReadTime(CDVD_MODE_TYPE mode)
|
||||
|
||||
void cdvdReset()
|
||||
{
|
||||
memzero(cdvd);
|
||||
std::memset(&cdvd, 0, sizeof(cdvd));
|
||||
|
||||
cdvd.Type = CDVD_TYPE_NODISC;
|
||||
cdvd.Spinning = false;
|
||||
@@ -1824,7 +1824,7 @@ static void cdvdWrite04(u8 rt)
|
||||
cdvd.SCMDParamC = 0;
|
||||
cdvdUpdateStatus(CDVD_STATUS_STOP);
|
||||
cdvd.Spinning = false;
|
||||
memzero(cdvd.SCMDResult);
|
||||
std::memset(cdvd.SCMDResult, 0, sizeof(cdvd.SCMDResult));
|
||||
cdvdSetIrq();
|
||||
break;
|
||||
|
||||
@@ -2337,7 +2337,7 @@ static void cdvdWrite16(u8 rt) // SCOMMAND
|
||||
CDVD_LOG("cdvdWrite16: SCMD %s (%x) (ParamP = %x)", sCmdName[rt], rt, cdvd.SCMDParamP);
|
||||
|
||||
cdvd.sCommand = rt;
|
||||
memzero(cdvd.SCMDResult);
|
||||
std::memset(cdvd.SCMDResult, 0, sizeof(cdvd.SCMDResult));
|
||||
|
||||
switch (rt)
|
||||
{
|
||||
|
||||
@@ -314,7 +314,10 @@ void CDVDsys_SetFile(CDVD_SourceType srctype, std::string newfile)
|
||||
const auto driveType = GetDriveType(StringUtil::UTF8StringToWideString(root).c_str());
|
||||
if (driveType == DRIVE_REMOVABLE)
|
||||
{
|
||||
Host::AddIconOSDMessage("RemovableDriveWarning", ICON_FA_EXCLAMATION_TRIANGLE, "Game disc location is on a removable drive, performance issues such as jittering and freezing may occur.", Host::OSD_WARNING_DURATION);
|
||||
Host::AddIconOSDMessage("RemovableDriveWarning", ICON_FA_EXCLAMATION_TRIANGLE,
|
||||
TRANSLATE_SV("CDVD", "Game disc location is on a removable drive, performance issues such as jittering "
|
||||
"and freezing may occur."),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -421,7 +424,8 @@ bool DoCDVDopen()
|
||||
cdvdTD td;
|
||||
CDVD->getTD(0, &td);
|
||||
|
||||
Host::AddKeyedOSDMessage("BlockDumpCreate", fmt::format("Saving CDVD block dump to '{}'.", temp), Host::OSD_INFO_DURATION);
|
||||
Host::AddKeyedOSDMessage("BlockDumpCreate",
|
||||
fmt::format(TRANSLATE_SV("CDVD", "Saving CDVD block dump to '{}'."), temp), Host::OSD_INFO_DURATION);
|
||||
|
||||
if (blockDumpFile.Create(std::move(temp), 2))
|
||||
{
|
||||
|
||||
@@ -591,7 +591,7 @@ void cdrReadInterrupt()
|
||||
if (cdr.RErr == -1)
|
||||
{
|
||||
DevCon.Warning("CD err");
|
||||
memzero(cdr.Transfer);
|
||||
std::memset(cdr.Transfer, 0, sizeof(cdr.Transfer));
|
||||
cdr.Stat = DiskError;
|
||||
cdr.StatP |= STATUS_ERROR;
|
||||
cdr.Result[0] = cdr.StatP;
|
||||
@@ -1107,7 +1107,7 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr)
|
||||
|
||||
void cdrReset()
|
||||
{
|
||||
memzero(cdr);
|
||||
std::memset(&cdr, 0, sizeof(cdr));
|
||||
cdr.CurTrack = 1;
|
||||
cdr.File = 1;
|
||||
cdr.Channel = 1;
|
||||
|
||||
+1
-1
@@ -165,7 +165,7 @@ namespace
|
||||
|
||||
void resetCache()
|
||||
{
|
||||
memzero(cache);
|
||||
std::memset(&cache, 0, sizeof(cache));
|
||||
}
|
||||
|
||||
static bool findInCache(const CacheSet& set, uptr ppf, int* way)
|
||||
|
||||
@@ -66,6 +66,10 @@ struct SettingInfo
|
||||
float FloatMinValue() const;
|
||||
float FloatMaxValue() const;
|
||||
float FloatStepValue() const;
|
||||
|
||||
void SetDefaultValue(SettingsInterface* si, const char* section, const char* key) const;
|
||||
void CopyValue(SettingsInterface* dest_si, const SettingsInterface& src_si,
|
||||
const char* section, const char* key) const;
|
||||
};
|
||||
|
||||
enum class GenericInputBinding : u8;
|
||||
|
||||
+1
-1
@@ -164,7 +164,7 @@ void rcntInit()
|
||||
|
||||
g_FrameCount = 0;
|
||||
|
||||
memzero(counters);
|
||||
std::memset(counters, 0, sizeof(counters));
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
counters[i].rate = 2;
|
||||
|
||||
+23
-23
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -46,15 +46,15 @@ void ATA::WritePaddedString(u8* data, int* index, std::string value, u32 len)
|
||||
|
||||
void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
{
|
||||
const u16 sectorSize = 512;
|
||||
constexpr u16 sectorSize = 512;
|
||||
DevCon.WriteLn("DEV9: HddSize : %i", sizeSectors * sectorSize / (1024 * 1024));
|
||||
const u64 nbSectors = sizeSectors;
|
||||
DevCon.WriteLn("DEV9: nbSectors : %i", nbSectors);
|
||||
|
||||
memset(&identifyData, 0, sizeof(identifyData));
|
||||
//Defualt CHS translation
|
||||
const u16 defHeads = 16;
|
||||
const u16 defSectors = 63;
|
||||
constexpr u16 defHeads = 16;
|
||||
constexpr u16 defSectors = 63;
|
||||
u64 cylinderslong = std::min<u64>(nbSectors, 16514064) / defHeads / defSectors;
|
||||
const u16 defCylinders = (u16)std::min<u64>(cylinderslong, UINT16_MAX);
|
||||
|
||||
@@ -94,7 +94,7 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
//Default Num of heads (Retired)
|
||||
WriteUInt16(identifyData, &index, defHeads); //word 3
|
||||
//Number of unformatted bytes per track (Retired)
|
||||
WriteUInt16(identifyData, &index, (u16)(sectorSize * defSectors)); //word 4
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>(sectorSize * defSectors)); //word 4
|
||||
//Number of unformatted bytes per sector (Retired)
|
||||
WriteUInt16(identifyData, &index, sectorSize); //word 5
|
||||
//Default Number of sectors per track (Retired)
|
||||
@@ -133,7 +133,7 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
//Capabilities (0-Shall be set to one to indicate a device specific Standby timer value minimum)
|
||||
index += 1 * 2; //word 50
|
||||
//PIO data transfer cycle timing mode (Obsolete)
|
||||
WriteUInt16(identifyData, &index, (u8)((pioMode > 2 ? pioMode : 2) << 8)); //word 51
|
||||
WriteUInt16(identifyData, &index, static_cast<u8>((pioMode > 2 ? pioMode : 2) << 8)); //word 51
|
||||
//DMA data transfer cycle timing mode (Obsolete)
|
||||
WriteUInt16(identifyData, &index, 0); //word 52
|
||||
//
|
||||
@@ -150,23 +150,23 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
//Number of current sectors per track
|
||||
WriteUInt16(identifyData, &index, curSectors); //word 56
|
||||
//Current capacity in sectors
|
||||
WriteUInt32(identifyData, &index, (u32)curOldsize); //word 57-58
|
||||
WriteUInt32(identifyData, &index, static_cast<u32>(curOldsize)); //word 57-58
|
||||
//PIO READ/WRITE Multiple setting
|
||||
/*
|
||||
* bit 7-0: Current setting for number of logical sectors that shall be transferred per DRQ
|
||||
* data block on READ/WRITE Multiple commands
|
||||
* bit 8: Multiple sector setting is valid
|
||||
*/
|
||||
WriteUInt16(identifyData, &index, (u16)(curMultipleSectorsSetting | (1 << 8))); //word 59
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>(curMultipleSectorsSetting | (1 << 8))); //word 59
|
||||
//Total number of user addressable logical sectors
|
||||
WriteUInt32(identifyData, &index, (u32)(nbSectors < 268435456 ? nbSectors : 268435456)); //word 60-61
|
||||
WriteUInt32(identifyData, &index, static_cast<u32>(nbSectors < 268435456 ? nbSectors : 268435456)); //word 60-61
|
||||
//DMA modes
|
||||
/*
|
||||
* bits 0-7: Singleword modes supported (0,1,2)
|
||||
* bits 8-15: Transfer mode active
|
||||
*/
|
||||
if (sdmaMode > 0)
|
||||
WriteUInt16(identifyData, &index, (u16)(0x07 | (1 << (sdmaMode + 8)))); //word 62
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>(0x07 | (1 << (sdmaMode + 8)))); //word 62
|
||||
else
|
||||
WriteUInt16(identifyData, &index, 0x07); //word 62
|
||||
//DMA Modes
|
||||
@@ -175,7 +175,7 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
* bits 8-15: Transfer mode active
|
||||
*/
|
||||
if (mdmaMode > 0)
|
||||
WriteUInt16(identifyData, &index, (u16)(0x07 | (1 << (mdmaMode + 8)))); //word 63
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>(0x07 | (1 << (mdmaMode + 8)))); //word 63
|
||||
else
|
||||
WriteUInt16(identifyData, &index, 0x07); //word 63
|
||||
//Bit 0-7-PIO modes supported (0,1,2,3,4)
|
||||
@@ -220,7 +220,7 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
* bit 14: NOP
|
||||
* bit 15: (Obsolete)
|
||||
*/
|
||||
WriteUInt16(identifyData, &index, (u16)((1 << 14) | (1 << 5) | /*(1 << 1) | (1 << 10) |*/ 1)); //word 82
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>((1 << 14) | (1 << 5) | /*(1 << 1) | (1 << 10) |*/ 1)); //word 82
|
||||
//Supported Feature Sets (83)
|
||||
/*
|
||||
* bit 0: DOWNLOAD MICROCODE
|
||||
@@ -239,7 +239,7 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
* bit 13: FLUSH CACHE EXT
|
||||
* bit 14: 1
|
||||
*/
|
||||
WriteUInt16(identifyData, &index, (u16)((1 << 14) | (1 << 13) | (1 << 12) /*| (1 << 8)*/ | ((lba48Supported ? 1 : 0) << 10))); //word 83
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>((1 << 14) | (1 << 13) | (1 << 12) /*| (1 << 8)*/ | ((lba48Supported ? 1 : 0) << 10))); //word 83
|
||||
//Supported Feature Sets (84)
|
||||
/*
|
||||
* bit 0: Smart error logging
|
||||
@@ -256,19 +256,19 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
* bit 13: IDLE IMMEDIATE with UNLOAD FEATURE
|
||||
* bit 14: 1
|
||||
*/
|
||||
WriteUInt16(identifyData, &index, (u16)((1 << 14) | (1 << 1) | 1)); //word 84
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>((1 << 14) | (1 << 1) | 1)); //word 84
|
||||
//Command set/feature enabled/supported (See word 82)
|
||||
WriteUInt16(identifyData, &index, (u16)((fetSmartEnabled << 0) | (fetSecurityEnabled << 1) | (fetWriteCacheEnabled << 5) | (fetHostProtectedAreaEnabled << 10) | (1 << 14))); //Fixed //word 85
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>((fetSmartEnabled << 0) | (fetSecurityEnabled << 1) | (fetWriteCacheEnabled << 5) | (fetHostProtectedAreaEnabled << 10) | (1 << 14))); //Fixed //word 85
|
||||
//Command set/feature enabled/supported (See word 83)
|
||||
// clang-format off
|
||||
WriteUInt16(identifyData, &index, (u16)(
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>(
|
||||
/*(1 << 8) | //SET MAX */
|
||||
((lba48Supported ? 1 : 0) << 10) | //Fixed
|
||||
(1 << 12) | //Fixed
|
||||
(1 << 13))); //Fixed //word 86
|
||||
//Command set/feature enabled/supported (See word 84)
|
||||
WriteUInt16(identifyData, &index, (u16)((1 << 14) | (1 << 1) | 1));
|
||||
WriteUInt16(identifyData, &index, (u16)(
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>((1 << 14) | (1 << 1) | 1));
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>(
|
||||
(1) | //Fixed
|
||||
((1) << 1))); //Fixed //word 87
|
||||
// clang-format on
|
||||
@@ -278,7 +278,7 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
* bits 8-15: Transfer mode active
|
||||
*/
|
||||
if (udmaMode > 0)
|
||||
WriteUInt16(identifyData, &index, (u16)(0x7f | (1 << (udmaMode + 8)))); //word 88
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>(0x7f | (1 << (udmaMode + 8)))); //word 88
|
||||
else
|
||||
WriteUInt16(identifyData, &index, 0x7f); //word 88
|
||||
//Time required for security erase unit completion
|
||||
@@ -306,7 +306,7 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
* bit 14: 1
|
||||
*/
|
||||
index = 93 * 2;
|
||||
WriteUInt16(identifyData, &index, (u16)(1 | (1 << 14) | 0x2000)); //word 93
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>(1 | (1 << 14) | 0x2000)); //word 93
|
||||
//Vendor’s recommended acoustic management value.
|
||||
//94
|
||||
//Stream Minimum Request Size
|
||||
@@ -319,7 +319,7 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
//98-99
|
||||
//Total Number of User Addressable Sectors for the 48-bit Address feature set.
|
||||
index = 100 * 2;
|
||||
WriteUInt64(identifyData, &index, (u16)nbSectors);
|
||||
WriteUInt64(identifyData, &index, static_cast<u16>(nbSectors));
|
||||
index -= 2;
|
||||
WriteUInt16(identifyData, &index, 0); //truncate to 48bits
|
||||
//Streaming Transfer Time - PIO
|
||||
@@ -334,7 +334,7 @@ void ATA::CreateHDDinfo(u64 sizeSectors)
|
||||
* bit 14: 1
|
||||
*/
|
||||
index = 106 * 2;
|
||||
WriteUInt16(identifyData, &index, (u16)((1 << 14) | 0));
|
||||
WriteUInt16(identifyData, &index, static_cast<u16>((1 << 14) | 0));
|
||||
//Inter-seek delay for ISO-7779acoustic testing in microseconds
|
||||
//107
|
||||
//WNN
|
||||
@@ -384,7 +384,7 @@ void ATA::CreateHDDinfoCsum() //Is this correct?
|
||||
counter += 0xA5;
|
||||
|
||||
identifyData[510] = 0xA5;
|
||||
identifyData[511] = (u8)(255 - counter + 1);
|
||||
identifyData[511] = static_cast<u8>(255 - counter + 1);
|
||||
counter = 0;
|
||||
|
||||
for (int i = 0; i < (512); i++)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -381,35 +381,35 @@ void ATA::Write16(u32 addr, u16 value)
|
||||
//DevCon.WriteLn("DEV9: *ATA_R_FEATURE 16bit write at address %x, value %x", addr, value);
|
||||
ClearHOB();
|
||||
regFeatureHOB = regFeature;
|
||||
regFeature = (u8)value;
|
||||
regFeature = static_cast<u8>(value);
|
||||
break;
|
||||
case ATA_R_NSECTOR:
|
||||
//DevCon.WriteLn("DEV9: *ATA_R_NSECTOR 16bit write at address %x, value %x", addr, value);
|
||||
ClearHOB();
|
||||
regNsectorHOB = regNsector;
|
||||
regNsector = (u8)value;
|
||||
regNsector = static_cast<u8>(value);
|
||||
break;
|
||||
case ATA_R_SECTOR:
|
||||
//DevCon.WriteLn("DEV9: *ATA_R_SECTOR 16bit write at address %x, value %x", addr, value);
|
||||
ClearHOB();
|
||||
regSectorHOB = regSector;
|
||||
regSector = (u8)value;
|
||||
regSector = static_cast<u8>(value);
|
||||
break;
|
||||
case ATA_R_LCYL:
|
||||
//DevCon.WriteLn("DEV9: *ATA_R_LCYL 16bit write at address %x, value %x", addr, value);
|
||||
ClearHOB();
|
||||
regLcylHOB = regLcyl;
|
||||
regLcyl = (u8)value;
|
||||
regLcyl = static_cast<u8>(value);
|
||||
break;
|
||||
case ATA_R_HCYL:
|
||||
//DevCon.WriteLn("DEV9: *ATA_R_HCYL 16bit write at address %x, value %x", addr, value);
|
||||
ClearHOB();
|
||||
regHcylHOB = regHcyl;
|
||||
regHcyl = (u8)value;
|
||||
regHcyl = static_cast<u8>(value);
|
||||
break;
|
||||
case ATA_R_SELECT:
|
||||
//DevCon.WriteLn("DEV9: *ATA_R_SELECT 16bit write at address %x, value %x", addr, value);
|
||||
regSelect = (u8)value;
|
||||
regSelect = static_cast<u8>(value);
|
||||
//bus->ifs[0].select = (val & ~0x10) | 0xa0;
|
||||
//bus->ifs[1].select = (val | 0x10) | 0xa0;
|
||||
break;
|
||||
@@ -502,18 +502,18 @@ s64 ATA::HDD_GetLBA()
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((s64)regHcylHOB << 40) |
|
||||
((s64)regLcylHOB << 32) |
|
||||
((s64)regSectorHOB << 24) |
|
||||
((s64)regHcyl << 16) |
|
||||
((s64)regLcyl << 8) |
|
||||
return (static_cast<s64>(regHcylHOB) << 40) |
|
||||
(static_cast<s64>(regLcylHOB) << 32) |
|
||||
(static_cast<s64>(regSectorHOB) << 24) |
|
||||
(static_cast<s64>(regHcyl) << 16) |
|
||||
(static_cast<s64>(regLcyl) << 8) |
|
||||
regSector;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
regStatus |= (u8)ATA_STAT_ERR;
|
||||
regError |= (u8)ATA_ERR_ABORT;
|
||||
regStatus |= static_cast<u8>(ATA_STAT_ERR);
|
||||
regError |= static_cast<u8>(ATA_ERR_ABORT);
|
||||
|
||||
Console.Error("DEV9: ATA: Tried to get LBA address while LBA mode disabled");
|
||||
//(c.Nh + h).Ns+(s-1)
|
||||
@@ -528,19 +528,19 @@ void ATA::HDD_SetLBA(s64 sectorNum)
|
||||
{
|
||||
if (!lba48)
|
||||
{
|
||||
regSelect = (u8)((regSelect & 0xf0) | (int)((sectorNum >> 24) & 0x0f));
|
||||
regHcyl = (u8)(sectorNum >> 16);
|
||||
regLcyl = (u8)(sectorNum >> 8);
|
||||
regSector = (u8)(sectorNum);
|
||||
regSelect = static_cast<u8>((regSelect & 0xf0) | static_cast<int>((sectorNum >> 24) & 0x0f));
|
||||
regHcyl = static_cast<u8>(sectorNum >> 16);
|
||||
regLcyl = static_cast<u8>(sectorNum >> 8);
|
||||
regSector = static_cast<u8>(sectorNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
regSector = (u8)sectorNum;
|
||||
regLcyl = (u8)(sectorNum >> 8);
|
||||
regHcyl = (u8)(sectorNum >> 16);
|
||||
regSectorHOB = (u8)(sectorNum >> 24);
|
||||
regLcylHOB = (u8)(sectorNum >> 32);
|
||||
regHcylHOB = (u8)(sectorNum >> 40);
|
||||
regSector = static_cast<u8>(sectorNum);
|
||||
regLcyl = static_cast<u8>(sectorNum >> 8);
|
||||
regHcyl = static_cast<u8>(sectorNum >> 16);
|
||||
regSectorHOB = static_cast<u8>(sectorNum >> 24);
|
||||
regLcylHOB = static_cast<u8>(sectorNum >> 32);
|
||||
regHcylHOB = static_cast<u8>(sectorNum >> 40);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -560,35 +560,27 @@ bool ATA::HDD_CanSeek()
|
||||
|
||||
bool ATA::HDD_CanAccess(int* sectors)
|
||||
{
|
||||
s64 lba;
|
||||
s64 posStart;
|
||||
s64 posEnd;
|
||||
s64 maxLBA;
|
||||
|
||||
maxLBA = std::min<s64>(EmuConfig.DEV9.HddSizeSectors, hddImageSize / 512) - 1;
|
||||
s64 maxLBA = std::min<s64>(EmuConfig.DEV9.HddSizeSectors, hddImageSize / 512) - 1;
|
||||
if ((regSelect & 0x40) == 0) //CHS mode
|
||||
maxLBA = std::min<s64>(maxLBA, curCylinders * curHeads * curSectors);
|
||||
|
||||
lba = HDD_GetLBA();
|
||||
if (lba == -1)
|
||||
const s64 posStart = HDD_GetLBA();
|
||||
if (posStart == -1)
|
||||
return false;
|
||||
|
||||
//DevCon.WriteLn("DEV9: LBA :%i", lba);
|
||||
posStart = lba;
|
||||
|
||||
if (posStart > maxLBA)
|
||||
{
|
||||
*sectors = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
posEnd = posStart + *sectors;
|
||||
|
||||
const s64 posEnd = posStart + *sectors;
|
||||
if (posEnd > maxLBA)
|
||||
{
|
||||
const s64 overshoot = posEnd - maxLBA;
|
||||
s64 space = *sectors - overshoot;
|
||||
*sectors = (int)space;
|
||||
*sectors = static_cast<int>(space);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -105,7 +105,7 @@ bool ATA::IO_Write()
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 imagePos = entry.sector * 512;
|
||||
const u64 imagePos = entry.sector * 512;
|
||||
if (FileSystem::FSeek64(hddImage, imagePos, SEEK_SET) != 0)
|
||||
{
|
||||
Console.Error("DEV9: ATA: File seek error");
|
||||
@@ -209,12 +209,13 @@ void ATA::IO_SparseCacheLoad()
|
||||
memset(&hddSparseBlock[readSize], 0, hddSparseBlockSize - readSize);
|
||||
}
|
||||
|
||||
// Store file pointer.
|
||||
const s64 orgPos = FileSystem::FTell64(hddImage);
|
||||
|
||||
// Flush so that we know what is allocated.
|
||||
std::fflush(hddImage);
|
||||
|
||||
// Store file pointer.
|
||||
const s64 orgPos = FileSystem::FTell64(hddImage);
|
||||
pxAssert(orgPos != -1);
|
||||
|
||||
#ifdef _WIN32
|
||||
// FlushFileBuffers is required, hddSparseBlock differs from actual file without it.
|
||||
FlushFileBuffers(hddNativeHandle);
|
||||
@@ -234,11 +235,6 @@ void ATA::IO_SparseCacheLoad()
|
||||
memset(hddSparseBlock.get(), 0, hddSparseBlockSize);
|
||||
hddSparseBlockValid = true;
|
||||
#if defined(PCSX2_DEBUG) || defined(PCSX2_DEVBUILD)
|
||||
|
||||
// Store file pointer.
|
||||
const s64 orgPos = FileSystem::FTell64(hddImage);
|
||||
pxAssert(orgPos != -1);
|
||||
|
||||
//Load into check buffer.
|
||||
FileSystem::FSeek64(hddImage, HddSparseStart, SEEK_SET);
|
||||
|
||||
@@ -281,11 +277,6 @@ void ATA::IO_SparseCacheLoad()
|
||||
memset(hddSparseBlock.get(), 0, hddSparseBlockSize);
|
||||
hddSparseBlockValid = true;
|
||||
#if defined(PCSX2_DEBUG) || defined(PCSX2_DEVBUILD)
|
||||
|
||||
// Store file pointer.
|
||||
const s64 orgPos = FileSystem::FTell64(hddImage);
|
||||
pxAssert(orgPos != -1);
|
||||
|
||||
// Load into check buffer.
|
||||
FileSystem::FSeek64(hddImage, HddSparseStart, SEEK_SET);
|
||||
|
||||
@@ -512,8 +503,8 @@ bool ATA::HDD_CanAssessOrSetError()
|
||||
if (!HDD_CanAccess(&nsector))
|
||||
{
|
||||
//Read what we can
|
||||
regStatus |= (u8)ATA_STAT_ERR;
|
||||
regError |= (u8)ATA_ERR_ID;
|
||||
regStatus |= static_cast<u8>(ATA_STAT_ERR);
|
||||
regError |= static_cast<u8>(ATA_ERR_ID);
|
||||
if (nsector == -1)
|
||||
{
|
||||
PostCmdNoData();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -53,7 +53,7 @@ void ATA::HDD_InitDevParameters()
|
||||
DevCon.WriteLn("DEV9: HDD_InitDevParameters");
|
||||
|
||||
curSectors = regNsector;
|
||||
curHeads = (u8)((regSelect & 0x7) + 1);
|
||||
curHeads = static_cast<u8>((regSelect & 0x7) + 1);
|
||||
PostCmdNoData();
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ void ATA::HDD_SetFeatures()
|
||||
return;
|
||||
case 0x03: //Set transfer mode
|
||||
{
|
||||
const u16 xferMode = (u16)regNsector; //Set Transfer mode
|
||||
const u16 xferMode = static_cast<u16>(regNsector); //Set Transfer mode
|
||||
|
||||
const int mode = xferMode & 0x07;
|
||||
switch ((xferMode) >> 3)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -42,7 +42,7 @@ void HddCreate::Start()
|
||||
void HddCreate::WriteImage(std::string hddPath, u64 fileBytes, u64 zeroSizeBytes)
|
||||
{
|
||||
constexpr int buffsize = 4 * 1024;
|
||||
u8 buff[buffsize] = {0}; // 4kb.
|
||||
const u8 buff[buffsize] = {0}; // 4kb.
|
||||
|
||||
if (FileSystem::FileExists(hddPath.c_str()))
|
||||
{
|
||||
|
||||
+19
-36
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -171,9 +171,7 @@ s32 DEV9init()
|
||||
}
|
||||
#endif
|
||||
|
||||
int rxbi;
|
||||
|
||||
for (rxbi = 0; rxbi < (SMAP_BD_SIZE / 8); rxbi++)
|
||||
for (int rxbi = 0; rxbi < (SMAP_BD_SIZE / 8); rxbi++)
|
||||
{
|
||||
smap_bd_t* pbd = (smap_bd_t*)&dev9.dev9R[SMAP_BD_RX_BASE & 0xffff];
|
||||
pbd = &pbd[rxbi];
|
||||
@@ -309,7 +307,6 @@ u8 DEV9read8(u32 addr)
|
||||
if (!EmuConfig.DEV9.EthEnable && !EmuConfig.DEV9.HddEnable)
|
||||
return 0;
|
||||
|
||||
u8 hard;
|
||||
if (addr >= ATA_DEV9_HDD_BASE && addr < ATA_DEV9_HDD_END)
|
||||
{
|
||||
Console.Error("DEV9: ATA does not support 8bit reads %lx", addr);
|
||||
@@ -322,9 +319,10 @@ u8 DEV9read8(u32 addr)
|
||||
}
|
||||
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
||||
{
|
||||
return (u8)FLASHread32(addr, 1);
|
||||
return static_cast<u8>(FLASHread32(addr, 1));
|
||||
}
|
||||
|
||||
u8 hard = 0;
|
||||
switch (addr)
|
||||
{
|
||||
case SPD_R_PIO_DATA:
|
||||
@@ -339,9 +337,7 @@ u8 DEV9read8(u32 addr)
|
||||
{
|
||||
if (dev9.eeprom_command == 2) //read
|
||||
{
|
||||
if (dev9.eeprom_bit == 0xFF)
|
||||
hard = 0;
|
||||
else
|
||||
if (dev9.eeprom_bit != 0xFF)
|
||||
hard = ((dev9.eeprom[dev9.eeprom_address] << dev9.eeprom_bit) & 0x8000) >> 11;
|
||||
dev9.eeprom_bit++;
|
||||
if (dev9.eeprom_bit == 16)
|
||||
@@ -350,11 +346,7 @@ u8 DEV9read8(u32 addr)
|
||||
dev9.eeprom_bit = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
hard = 0;
|
||||
}
|
||||
else
|
||||
hard = 0;
|
||||
//DevCon.WriteLn("DEV9: SPD_R_PIO_DATA 8bit read %x", hard);
|
||||
return hard;
|
||||
|
||||
@@ -375,7 +367,6 @@ u16 DEV9read16(u32 addr)
|
||||
if (!EmuConfig.DEV9.EthEnable && !EmuConfig.DEV9.HddEnable)
|
||||
return 0;
|
||||
|
||||
u16 hard;
|
||||
if (addr >= ATA_DEV9_HDD_BASE && addr < ATA_DEV9_HDD_END)
|
||||
{
|
||||
return dev9.ata->Read16(addr);
|
||||
@@ -387,9 +378,10 @@ u16 DEV9read16(u32 addr)
|
||||
}
|
||||
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
||||
{
|
||||
return (u16)FLASHread32(addr, 2);
|
||||
return static_cast<u16>(FLASHread32(addr, 2));
|
||||
}
|
||||
|
||||
u16 hard = 0;
|
||||
switch (addr)
|
||||
{
|
||||
case SPD_R_INTR_STAT:
|
||||
@@ -412,9 +404,7 @@ u16 DEV9read16(u32 addr)
|
||||
{
|
||||
if (dev9.eeprom_command == 2) //read
|
||||
{
|
||||
if (dev9.eeprom_bit == 0xFF)
|
||||
hard = 0;
|
||||
else
|
||||
if (dev9.eeprom_bit != 0xFF)
|
||||
hard = ((dev9.eeprom[dev9.eeprom_address] << dev9.eeprom_bit) & 0x8000) >> 11;
|
||||
dev9.eeprom_bit++;
|
||||
if (dev9.eeprom_bit == 16)
|
||||
@@ -423,11 +413,7 @@ u16 DEV9read16(u32 addr)
|
||||
dev9.eeprom_bit = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
hard = 0;
|
||||
}
|
||||
else
|
||||
hard = 0;
|
||||
//DevCon.WriteLn("DEV9: SPD_R_PIO_DATA 16bit read %x", hard);
|
||||
return hard;
|
||||
|
||||
@@ -447,7 +433,6 @@ u16 DEV9read16(u32 addr)
|
||||
return hard;
|
||||
|
||||
case SPD_R_REV_3:
|
||||
hard = 0;
|
||||
if (EmuConfig.DEV9.HddEnable)
|
||||
hard |= SPD_CAPS_ATA;
|
||||
if (EmuConfig.DEV9.EthEnable)
|
||||
@@ -465,7 +450,6 @@ u16 DEV9read16(u32 addr)
|
||||
return dev9.xfr_ctrl;
|
||||
case SPD_R_DBUF_STAT:
|
||||
{
|
||||
hard = 0;
|
||||
if (dev9.if_ctrl & SPD_IF_READ) //Semi async
|
||||
{
|
||||
HDDWriteFIFO(); //Yes this is not a typo
|
||||
@@ -476,18 +460,18 @@ u16 DEV9read16(u32 addr)
|
||||
}
|
||||
FIFOIntr();
|
||||
|
||||
const u8 count = (u8)((dev9.fifo_bytes_write - dev9.fifo_bytes_read) / 512);
|
||||
const u8 count = static_cast<u8>((dev9.fifo_bytes_write - dev9.fifo_bytes_read) / 512);
|
||||
if (dev9.xfr_ctrl & SPD_XFR_WRITE) //or ifRead?
|
||||
{
|
||||
hard = (u8)(SPD_DBUF_AVAIL_MAX - count);
|
||||
hard |= (count == 0) ? SPD_DBUF_STAT_1 : (u16)0;
|
||||
hard |= (count > 0) ? SPD_DBUF_STAT_2 : (u16)0;
|
||||
hard = static_cast<u8>(SPD_DBUF_AVAIL_MAX - count);
|
||||
hard |= (count == 0) ? SPD_DBUF_STAT_1 : static_cast<u16>(0);
|
||||
hard |= (count > 0) ? SPD_DBUF_STAT_2 : static_cast<u16>(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
hard = count;
|
||||
hard |= (count < SPD_DBUF_AVAIL_MAX) ? SPD_DBUF_STAT_1 : (u16)0;
|
||||
hard |= (count == 0) ? SPD_DBUF_STAT_2 : (u16)0;
|
||||
hard |= (count < SPD_DBUF_AVAIL_MAX) ? SPD_DBUF_STAT_1 : static_cast<u16>(0);
|
||||
hard |= (count == 0) ? SPD_DBUF_STAT_2 : static_cast<u16>(0);
|
||||
//If overflow (HDD->SPEED), set both SPD_DBUF_STAT_2 & SPD_DBUF_STAT_FULL
|
||||
//and overflow INTR set
|
||||
}
|
||||
@@ -515,7 +499,6 @@ u32 DEV9read32(u32 addr)
|
||||
if (!EmuConfig.DEV9.EthEnable && !EmuConfig.DEV9.HddEnable)
|
||||
return 0;
|
||||
|
||||
u32 hard;
|
||||
if (addr >= ATA_DEV9_HDD_BASE && addr < ATA_DEV9_HDD_END)
|
||||
{
|
||||
Console.Error("DEV9: ATA does not support 32bit reads %lx", addr);
|
||||
@@ -528,10 +511,10 @@ u32 DEV9read32(u32 addr)
|
||||
}
|
||||
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
||||
{
|
||||
return (u32)FLASHread32(addr, 4);
|
||||
return static_cast<u32>(FLASHread32(addr, 4));
|
||||
}
|
||||
|
||||
hard = dev9Ru32(addr);
|
||||
const u32 hard = dev9Ru32(addr);
|
||||
Console.Error("DEV9: Unknown 32bit read at address %lx value %x", addr, hard);
|
||||
return hard;
|
||||
}
|
||||
@@ -556,7 +539,7 @@ void DEV9write8(u32 addr, u8 value)
|
||||
}
|
||||
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
||||
{
|
||||
FLASHwrite32(addr, (u32)value, 1);
|
||||
FLASHwrite32(addr, static_cast<u32>(value), 1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -666,7 +649,7 @@ void DEV9write16(u32 addr, u16 value)
|
||||
}
|
||||
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
||||
{
|
||||
FLASHwrite32(addr, (u32)value, 2);
|
||||
FLASHwrite32(addr, static_cast<u32>(value), 2);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -978,7 +961,7 @@ void DEV9write32(u32 addr, u32 value)
|
||||
}
|
||||
if ((addr >= FLASH_REGBASE) && (addr < (FLASH_REGBASE + FLASH_REGSIZE)))
|
||||
{
|
||||
FLASHwrite32(addr, (u32)value, 4);
|
||||
FLASHwrite32(addr, static_cast<u32>(value), 4);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -81,7 +81,7 @@ namespace InternalServers
|
||||
{
|
||||
#ifdef _WIN32
|
||||
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
|
||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
const WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
|
||||
WSADATA wsaData{0};
|
||||
const int err = WSAStartup(wVersionRequested, &wsaData);
|
||||
@@ -162,14 +162,14 @@ namespace InternalServers
|
||||
DNS_Packet* ret = new DNS_Packet();
|
||||
ret->id = dns.id; //TODO, drop duplicate requests based on ID
|
||||
ret->SetQR(true);
|
||||
ret->SetOpCode((u8)DNS_OPCode::Query);
|
||||
ret->SetOpCode(static_cast<u8>(DNS_OPCode::Query));
|
||||
ret->SetAA(false);
|
||||
ret->SetTC(false);
|
||||
ret->SetRD(true);
|
||||
ret->SetRA(true);
|
||||
ret->SetAD(false);
|
||||
ret->SetCD(false);
|
||||
ret->SetRCode((u8)DNS_RCode::NoError);
|
||||
ret->SetRCode(static_cast<u8>(DNS_RCode::NoError));
|
||||
//Counts
|
||||
ret->questions = dns.questions;
|
||||
|
||||
@@ -292,8 +292,7 @@ namespace InternalServers
|
||||
data->session = this;
|
||||
data->url = url;
|
||||
|
||||
int ret = GetAddrInfoEx(converted_string.data(), nullptr, NS_ALL, 0, &hints, (ADDRINFOEX**)&data->result, nullptr, &data->overlapped, &DNS_Server::GetAddrInfoExCallback, &data->cancelHandle);
|
||||
|
||||
const int ret = GetAddrInfoEx(converted_string.data(), nullptr, NS_ALL, 0, &hints, (ADDRINFOEX**)&data->result, nullptr, &data->overlapped, &DNS_Server::GetAddrInfoExCallback, &data->cancelHandle);
|
||||
if (ret == WSA_IO_PENDING)
|
||||
return;
|
||||
else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -77,12 +77,11 @@ bool load_pcap()
|
||||
return true;
|
||||
|
||||
//Store old Search Dir
|
||||
wchar_t* oldDllDir;
|
||||
int len = GetDllDirectory(0, nullptr);
|
||||
if (len == 0)
|
||||
return false;
|
||||
|
||||
oldDllDir = new wchar_t[len];
|
||||
wchar_t* oldDllDir = new wchar_t[len];
|
||||
|
||||
if (len == 1)
|
||||
oldDllDir[0] = 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -253,7 +253,7 @@ HANDLE TAPOpen(const std::string& device_guid)
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
BOOL bret = DeviceIoControl(handle.get(), TAP_IOCTL_GET_VERSION,
|
||||
const BOOL bret = DeviceIoControl(handle.get(), TAP_IOCTL_GET_VERSION,
|
||||
&version, sizeof(version),
|
||||
&version, sizeof(version), (LPDWORD)&version_len, NULL);
|
||||
|
||||
@@ -400,14 +400,13 @@ bool TAPGetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter,
|
||||
//Note that we append to the collection during iteration
|
||||
for (size_t vi = 0; vi < searchList.size(); vi++)
|
||||
{
|
||||
int targetIndex = searchList[vi];
|
||||
|
||||
for (ULONG i = 0; i < table->NumEntries; i++)
|
||||
{
|
||||
int targetIndex = searchList[vi];
|
||||
MIB_IFSTACK_ROW row = table->Table[i];
|
||||
if (row.LowerLayerInterfaceIndex == targetIndex)
|
||||
{
|
||||
PIP_ADAPTER_ADDRESSES potentialAdapter = FindAdapterViaIndex(AdapterInfoReduced.get(), row.HigherLayerInterfaceIndex);
|
||||
const PIP_ADAPTER_ADDRESSES potentialAdapter = FindAdapterViaIndex(AdapterInfoReduced.get(), row.HigherLayerInterfaceIndex);
|
||||
if (potentialAdapter != nullptr)
|
||||
{
|
||||
Console.WriteLn(fmt::format("DEV9: {} is possible bridge (Check 1 passed)", StringUtil::WideStringToUTF8String(potentialAdapter->Description)));
|
||||
@@ -598,7 +597,7 @@ bool TAPAdapter::recv(NetPacket* pkt)
|
||||
|
||||
if (!result)
|
||||
{
|
||||
DWORD dwError = GetLastError();
|
||||
const DWORD dwError = GetLastError();
|
||||
if (dwError == ERROR_IO_PENDING)
|
||||
{
|
||||
HANDLE readHandles[]{read.hEvent, cancel};
|
||||
@@ -639,7 +638,7 @@ bool TAPAdapter::send(NetPacket* pkt)
|
||||
|
||||
if (!result)
|
||||
{
|
||||
DWORD dwError = GetLastError();
|
||||
const DWORD dwError = GetLastError();
|
||||
if (dwError == ERROR_IO_PENDING)
|
||||
{
|
||||
WaitForSingleObject(write.hEvent, INFINITE);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -75,8 +75,6 @@ static const char* getCmdName(u32 cmd)
|
||||
|
||||
void FLASHinit()
|
||||
{
|
||||
FILE* fd;
|
||||
|
||||
id = FLASH_ID_64MBIT;
|
||||
counter = 0;
|
||||
addrbyte = 0;
|
||||
@@ -86,12 +84,10 @@ void FLASHinit()
|
||||
calculateECC(data);
|
||||
ctrl = FLASH_PP_READY;
|
||||
|
||||
fd = fopen("flash.dat", "rb");
|
||||
FILE* fd = fopen("flash.dat", "rb");
|
||||
if (fd != NULL)
|
||||
{
|
||||
size_t ret;
|
||||
|
||||
ret = fread(file, 1, CARD_SIZE_ECC, fd);
|
||||
const size_t ret = fread(file, 1, CARD_SIZE_ECC, fd);
|
||||
if (ret != CARD_SIZE_ECC)
|
||||
{
|
||||
DevCon.WriteLn("DEV9: Reading error.");
|
||||
|
||||
+11
-11
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -70,7 +70,7 @@ bool rx_fifo_can_rx()
|
||||
return false;
|
||||
|
||||
//Check if there is space on fifo
|
||||
int rd_ptr = dev9Ru32(SMAP_R_RXFIFO_RD_PTR);
|
||||
const int rd_ptr = dev9Ru32(SMAP_R_RXFIFO_RD_PTR);
|
||||
int space = sizeof(dev9.rxfifo) -
|
||||
((dev9.rxfifo_wr_ptr - rd_ptr) & 16383);
|
||||
|
||||
@@ -89,7 +89,7 @@ void rx_process(NetPacket* pk)
|
||||
{
|
||||
smap_bd_t* pbd = ((smap_bd_t*)&dev9.dev9R[SMAP_BD_RX_BASE & 0xffff]) + dev9.rxbdi;
|
||||
|
||||
int bytes = (pk->size + 3) & (~3);
|
||||
const int bytes = (pk->size + 3) & (~3);
|
||||
|
||||
if (!(pbd->ctrl_stat & SMAP_BD_RX_EMPTY))
|
||||
{
|
||||
@@ -97,7 +97,7 @@ void rx_process(NetPacket* pk)
|
||||
return;
|
||||
}
|
||||
|
||||
int pstart = (dev9.rxfifo_wr_ptr) & 16383;
|
||||
const int pstart = (dev9.rxfifo_wr_ptr) & 16383;
|
||||
int i = 0;
|
||||
while (i < bytes)
|
||||
{
|
||||
@@ -134,7 +134,7 @@ u32 wswap(u32 d)
|
||||
void tx_process()
|
||||
{
|
||||
//we loop based on count ? or just *use* it ?
|
||||
u32 cnt = dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT);
|
||||
const u32 cnt = dev9Ru8(SMAP_R_TXFIFO_FRAME_CNT);
|
||||
//spams// printf("tx_process : %u cnt frames !\n",cnt);
|
||||
|
||||
NetPacket pk;
|
||||
@@ -159,7 +159,7 @@ void tx_process()
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 base = (pbd->pointer - 0x1000) & 16383;
|
||||
const u32 base = (pbd->pointer - 0x1000) & 16383;
|
||||
DevCon.WriteLn("DEV9: Sending Packet from base %x, size %d", base, pbd->length);
|
||||
|
||||
pk.size = pbd->length;
|
||||
@@ -277,7 +277,7 @@ void emac3_write(u32 addr)
|
||||
if (value & (SMAP_E3_PHY_READ))
|
||||
{
|
||||
value |= SMAP_E3_PHY_OP_COMP;
|
||||
int reg = value & (SMAP_E3_PHY_REG_ADDR_MSK);
|
||||
const int reg = value & (SMAP_E3_PHY_REG_ADDR_MSK);
|
||||
u16 val = dev9.phyregs[reg];
|
||||
switch (reg)
|
||||
{
|
||||
@@ -342,7 +342,7 @@ u8 smap_read8(u32 addr)
|
||||
|
||||
u16 smap_read16(u32 addr)
|
||||
{
|
||||
int rv = dev9Ru16(addr);
|
||||
const int rv = dev9Ru16(addr);
|
||||
if (addr >= SMAP_BD_TX_BASE && addr < (SMAP_BD_TX_BASE + SMAP_BD_SIZE))
|
||||
{
|
||||
if (dev9.bd_swap)
|
||||
@@ -497,8 +497,8 @@ u32 smap_read32(u32 addr)
|
||||
{
|
||||
if (addr >= SMAP_EMAC3_REGBASE && addr < SMAP_EMAC3_REGEND)
|
||||
{
|
||||
u32 hi = smap_read16(addr);
|
||||
u32 lo = smap_read16(addr + 2) << 16;
|
||||
const u32 hi = smap_read16(addr);
|
||||
const u32 lo = smap_read16(addr + 2) << 16;
|
||||
return hi | lo;
|
||||
}
|
||||
switch (addr)
|
||||
@@ -517,7 +517,7 @@ u32 smap_read32(u32 addr)
|
||||
{
|
||||
int rd_ptr = dev9Ru32(SMAP_R_RXFIFO_RD_PTR) & 16383;
|
||||
|
||||
int rv = *((u32*)(dev9.rxfifo + rd_ptr));
|
||||
const int rv = *((u32*)(dev9.rxfifo + rd_ptr));
|
||||
|
||||
dev9Ru32(SMAP_R_RXFIFO_RD_PTR) = ((rd_ptr + 4) & 16383);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2020 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -216,7 +216,7 @@ SocketAdapter::SocketAdapter()
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
|
||||
WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
const WORD wVersionRequested = MAKEWORD(2, 2);
|
||||
|
||||
WSADATA wsaData{0};
|
||||
const int err = WSAStartup(wVersionRequested, &wsaData);
|
||||
@@ -270,7 +270,7 @@ bool SocketAdapter::recv(NetPacket* pkt)
|
||||
EthernetFrame frame(ipPkt);
|
||||
frame.sourceMAC = internalMAC;
|
||||
frame.destinationMAC = ps2MAC;
|
||||
frame.protocol = (u16)EtherType::IPv4;
|
||||
frame.protocol = static_cast<u16>(EtherType::IPv4);
|
||||
|
||||
frame.WritePacket(pkt);
|
||||
InspectRecv(pkt);
|
||||
@@ -295,8 +295,6 @@ bool SocketAdapter::send(NetPacket* pkt)
|
||||
if (NetAdapter::send(pkt))
|
||||
return true;
|
||||
|
||||
bool result = false;
|
||||
|
||||
EthernetFrame frame(pkt);
|
||||
|
||||
switch (frame.protocol)
|
||||
@@ -350,7 +348,7 @@ bool SocketAdapter::send(NetPacket* pkt)
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
|
||||
void SocketAdapter::reset()
|
||||
@@ -464,7 +462,7 @@ bool SocketAdapter::SendTCP(ConnectionKey Key, IP_Packet* ipPkt)
|
||||
Key.ps2Port = tcp.sourcePort;
|
||||
Key.srvPort = tcp.destinationPort;
|
||||
|
||||
int res = SendFromConnection(Key, ipPkt);
|
||||
const int res = SendFromConnection(Key, ipPkt);
|
||||
if (res == 1)
|
||||
return true;
|
||||
else if (res == 0)
|
||||
@@ -561,7 +559,7 @@ int SocketAdapter::SendFromConnection(ConnectionKey Key, IP_Packet* ipPkt)
|
||||
|
||||
void SocketAdapter::HandleConnectionClosed(BaseSession* sender)
|
||||
{
|
||||
ConnectionKey key = sender->key;
|
||||
const ConnectionKey key = sender->key;
|
||||
connections.Remove(key);
|
||||
//Note, we delete something that is calling us
|
||||
//this is probably going to cause issues
|
||||
|
||||
+2
-2
@@ -149,7 +149,7 @@ void ElfObject::initElfHeaders()
|
||||
|
||||
bool ElfObject::hasValidPSXHeader()
|
||||
{
|
||||
if (data.GetSizeInBytes() < sizeof(PSXEXEHeader))
|
||||
if (data.GetSizeInBytes() < static_cast<s64>(sizeof(PSXEXEHeader)))
|
||||
return false;
|
||||
|
||||
const PSXEXEHeader* header = reinterpret_cast<const PSXEXEHeader*>(data.GetPtr());
|
||||
@@ -158,7 +158,7 @@ bool ElfObject::hasValidPSXHeader()
|
||||
if (std::memcmp(header->id, expected_id, sizeof(expected_id)) != 0)
|
||||
return false;
|
||||
|
||||
if ((header->file_size + sizeof(PSXEXEHeader)) > data.GetSizeInBytes())
|
||||
if (static_cast<s64>(header->file_size + sizeof(PSXEXEHeader)) > data.GetSizeInBytes())
|
||||
{
|
||||
Console.Warning("Incorrect file size in PS-EXE header: %u bytes should not be greater than %u bytes",
|
||||
header->file_size, static_cast<unsigned>(data.GetSizeInBytes() - sizeof(PSXEXEHeader)));
|
||||
|
||||
+2
-2
@@ -40,7 +40,7 @@ void gsReset()
|
||||
{
|
||||
GetMTGS().ResetGS(true);
|
||||
gsVideoMode = GS_VideoMode::Uninitialized;
|
||||
memzero(g_RealGSMem);
|
||||
std::memset(g_RealGSMem, 0, sizeof(g_RealGSMem));
|
||||
UpdateVSyncRate(true);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ static __fi void gsCSRwrite( const tGS_CSR& csr )
|
||||
gifUnit.gsSIGNAL.queued = false;
|
||||
gifUnit.gsFINISH.gsFINISHFired = true;
|
||||
// Privilage registers also reset.
|
||||
memzero(g_RealGSMem);
|
||||
std::memset(g_RealGSMem, 0, sizeof(g_RealGSMem));
|
||||
GSIMR.reset();
|
||||
CSRreg.Reset();
|
||||
GetMTGS().SendSimplePacket(GS_RINGTYPE_RESET, 0, 0, 0);
|
||||
|
||||
+162
-130
@@ -265,8 +265,9 @@ bool GSreopen(bool recreate_device, bool recreate_renderer, const Pcsx2Config::G
|
||||
if (!OpenGSDevice(GSConfig.Renderer, false, recreate_window) ||
|
||||
(recreate_renderer && !OpenGSRenderer(GSConfig.Renderer, basemem)))
|
||||
{
|
||||
Host::AddKeyedOSDMessage(
|
||||
"GSReopenFailed", "Failed to reopen, restoring old configuration.", Host::OSD_CRITICAL_ERROR_DURATION);
|
||||
Host::AddKeyedOSDMessage("GSReopenFailed",
|
||||
TRANSLATE_STR("GS", "Failed to reopen, restoring old configuration."),
|
||||
Host::OSD_CRITICAL_ERROR_DURATION);
|
||||
|
||||
CloseGSDevice(false);
|
||||
|
||||
@@ -965,7 +966,8 @@ void GSFreeWrappedMemory(void* ptr, size_t size, size_t repeat)
|
||||
static void HotkeyAdjustUpscaleMultiplier(s32 delta)
|
||||
{
|
||||
const u32 new_multiplier = static_cast<u32>(std::clamp(static_cast<s32>(EmuConfig.GS.UpscaleMultiplier) + delta, 1, 8));
|
||||
Host::AddKeyedFormattedOSDMessage("UpscaleMultiplierChanged", Host::OSD_QUICK_DURATION, "Upscale multiplier set to %ux.", new_multiplier);
|
||||
Host::AddKeyedOSDMessage("UpscaleMultiplierChanged",
|
||||
fmt::format(TRANSLATE_SV("GS", "Upscale multiplier set to {}x."), new_multiplier), Host::OSD_QUICK_DURATION);
|
||||
EmuConfig.GS.UpscaleMultiplier = new_multiplier;
|
||||
|
||||
// this is pretty slow. we only really need to flush the TC and recompile shaders.
|
||||
@@ -973,144 +975,174 @@ static void HotkeyAdjustUpscaleMultiplier(s32 delta)
|
||||
GetMTGS().ApplySettings();
|
||||
}
|
||||
|
||||
BEGIN_HOTKEY_LIST(g_gs_hotkeys)
|
||||
{"Screenshot", "Graphics", "Save Screenshot", [](s32 pressed) {
|
||||
BEGIN_HOTKEY_LIST(g_gs_hotkeys){"Screenshot", TRANSLATE_NOOP("Hotkeys", "Graphics"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Save Screenshot"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
GetMTGS().RunOnGSThread([]() {
|
||||
GSQueueSnapshot(std::string(), 0);
|
||||
});
|
||||
GetMTGS().RunOnGSThread([]() { GSQueueSnapshot(std::string(), 0); });
|
||||
}
|
||||
}},
|
||||
{"ToggleVideoCapture", "Graphics", "Toggle Video Capture", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
if (GSCapture::IsCapturing())
|
||||
{
|
||||
GetMTGS().RunOnGSThread([]() { g_gs_renderer->EndCapture(); });
|
||||
GetMTGS().WaitGS(false, false, false);
|
||||
return;
|
||||
}
|
||||
{"ToggleVideoCapture", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Toggle Video Capture"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
if (GSCapture::IsCapturing())
|
||||
{
|
||||
GetMTGS().RunOnGSThread([]() { g_gs_renderer->EndCapture(); });
|
||||
GetMTGS().WaitGS(false, false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
GetMTGS().RunOnGSThread([]() {
|
||||
std::string filename(fmt::format("{}.{}", GSGetBaseVideoFilename(), GSConfig.CaptureContainer));
|
||||
g_gs_renderer->BeginCapture(std::move(filename));
|
||||
});
|
||||
GetMTGS().RunOnGSThread([]() {
|
||||
std::string filename(fmt::format("{}.{}", GSGetBaseVideoFilename(), GSConfig.CaptureContainer));
|
||||
g_gs_renderer->BeginCapture(std::move(filename));
|
||||
});
|
||||
|
||||
// Sync GS thread. We want to start adding audio at the same time as video.
|
||||
GetMTGS().WaitGS(false, false, false);
|
||||
}
|
||||
}},
|
||||
{"GSDumpSingleFrame", "Graphics", "Save Single Frame GS Dump", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
GetMTGS().RunOnGSThread([]() {
|
||||
GSQueueSnapshot(std::string(), 1);
|
||||
// Sync GS thread. We want to start adding audio at the same time as video.
|
||||
GetMTGS().WaitGS(false, false, false);
|
||||
}
|
||||
}},
|
||||
{"GSDumpSingleFrame", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Save Single Frame GS Dump"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
GetMTGS().RunOnGSThread([]() { GSQueueSnapshot(std::string(), 1); });
|
||||
}
|
||||
}},
|
||||
{"GSDumpMultiFrame", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Save Multi Frame GS Dump"),
|
||||
[](s32 pressed) {
|
||||
GetMTGS().RunOnGSThread([pressed]() {
|
||||
if (pressed > 0)
|
||||
GSQueueSnapshot(std::string(), std::numeric_limits<u32>::max());
|
||||
else
|
||||
GSStopGSDump();
|
||||
});
|
||||
}
|
||||
}},
|
||||
{"GSDumpMultiFrame", "Graphics", "Save Multi Frame GS Dump", [](s32 pressed) {
|
||||
GetMTGS().RunOnGSThread([pressed]() {
|
||||
if (pressed > 0)
|
||||
GSQueueSnapshot(std::string(), std::numeric_limits<u32>::max());
|
||||
else
|
||||
GSStopGSDump();
|
||||
});
|
||||
}},
|
||||
{"ToggleSoftwareRendering", "Graphics", "Toggle Software Rendering", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
GetMTGS().ToggleSoftwareRendering();
|
||||
}},
|
||||
{"IncreaseUpscaleMultiplier", "Graphics", "Increase Upscale Multiplier", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
HotkeyAdjustUpscaleMultiplier(1);
|
||||
}},
|
||||
{"DecreaseUpscaleMultiplier", "Graphics", "Decrease Upscale Multiplier", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
HotkeyAdjustUpscaleMultiplier(-1);
|
||||
}},
|
||||
{"CycleAspectRatio", "Graphics", "Cycle Aspect Ratio", [](s32 pressed) {
|
||||
if (pressed)
|
||||
return;
|
||||
}},
|
||||
{"ToggleSoftwareRendering", TRANSLATE_NOOP("Hotkeys", "Graphics"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Toggle Software Rendering"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed)
|
||||
GetMTGS().ToggleSoftwareRendering();
|
||||
}},
|
||||
{"IncreaseUpscaleMultiplier", TRANSLATE_NOOP("Hotkeys", "Graphics"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Increase Upscale Multiplier"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed)
|
||||
HotkeyAdjustUpscaleMultiplier(1);
|
||||
}},
|
||||
{"DecreaseUpscaleMultiplier", TRANSLATE_NOOP("Hotkeys", "Graphics"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Decrease Upscale Multiplier"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed)
|
||||
HotkeyAdjustUpscaleMultiplier(-1);
|
||||
}},
|
||||
{"CycleAspectRatio", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Cycle Aspect Ratio"),
|
||||
[](s32 pressed) {
|
||||
if (pressed)
|
||||
return;
|
||||
|
||||
// technically this races, but the worst that'll happen is one frame uses the old AR.
|
||||
EmuConfig.CurrentAspectRatio = static_cast<AspectRatioType>((static_cast<int>(EmuConfig.CurrentAspectRatio) + 1) % static_cast<int>(AspectRatioType::MaxCount));
|
||||
Host::AddKeyedFormattedOSDMessage("CycleAspectRatio", Host::OSD_QUICK_DURATION, "Aspect ratio set to '%s'.", Pcsx2Config::GSOptions::AspectRatioNames[static_cast<int>(EmuConfig.CurrentAspectRatio)]);
|
||||
}},
|
||||
{"CycleMipmapMode", "Graphics", "Cycle Hardware Mipmapping", [](s32 pressed) {
|
||||
if (pressed)
|
||||
return;
|
||||
// technically this races, but the worst that'll happen is one frame uses the old AR.
|
||||
EmuConfig.CurrentAspectRatio = static_cast<AspectRatioType>(
|
||||
(static_cast<int>(EmuConfig.CurrentAspectRatio) + 1) % static_cast<int>(AspectRatioType::MaxCount));
|
||||
Host::AddKeyedOSDMessage("CycleAspectRatio",
|
||||
fmt::format(TRANSLATE_SV("Hotkeys", "Aspect ratio set to '{}'."),
|
||||
Pcsx2Config::GSOptions::AspectRatioNames[static_cast<int>(EmuConfig.CurrentAspectRatio)]),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
}},
|
||||
{"CycleMipmapMode", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Cycle Hardware Mipmapping"),
|
||||
[](s32 pressed) {
|
||||
if (pressed)
|
||||
return;
|
||||
|
||||
static constexpr s32 CYCLE_COUNT = 4;
|
||||
static constexpr std::array<const char*, CYCLE_COUNT> option_names = {{"Automatic", "Off", "Basic (Generated)", "Full (PS2)"}};
|
||||
static constexpr s32 CYCLE_COUNT = 4;
|
||||
static constexpr std::array<const char*, CYCLE_COUNT> option_names = {
|
||||
{"Automatic", "Off", "Basic (Generated)", "Full (PS2)"}};
|
||||
|
||||
const HWMipmapLevel new_level = static_cast<HWMipmapLevel>(((static_cast<s32>(EmuConfig.GS.HWMipmap) + 2) % CYCLE_COUNT) - 1);
|
||||
Host::AddKeyedFormattedOSDMessage("CycleMipmapMode", Host::OSD_QUICK_DURATION, "Hardware mipmapping set to '%s'.", option_names[static_cast<s32>(new_level) + 1]);
|
||||
EmuConfig.GS.HWMipmap = new_level;
|
||||
const HWMipmapLevel new_level =
|
||||
static_cast<HWMipmapLevel>(((static_cast<s32>(EmuConfig.GS.HWMipmap) + 2) % CYCLE_COUNT) - 1);
|
||||
Host::AddKeyedOSDMessage("CycleMipmapMode",
|
||||
fmt::format(TRANSLATE_SV("Hotkeys", "Hardware mipmapping set to '{}'."),
|
||||
option_names[static_cast<s32>(new_level) + 1]),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
EmuConfig.GS.HWMipmap = new_level;
|
||||
|
||||
GetMTGS().RunOnGSThread([new_level]() {
|
||||
GSConfig.HWMipmap = new_level;
|
||||
g_gs_renderer->PurgeTextureCache();
|
||||
g_gs_renderer->PurgePool();
|
||||
});
|
||||
}},
|
||||
{"CycleInterlaceMode", "Graphics", "Cycle Deinterlace Mode", [](s32 pressed) {
|
||||
if (pressed)
|
||||
return;
|
||||
GetMTGS().RunOnGSThread([new_level]() {
|
||||
GSConfig.HWMipmap = new_level;
|
||||
g_gs_renderer->PurgeTextureCache();
|
||||
g_gs_renderer->PurgePool();
|
||||
});
|
||||
}},
|
||||
{"CycleInterlaceMode", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Cycle Deinterlace Mode"),
|
||||
[](s32 pressed) {
|
||||
if (pressed)
|
||||
return;
|
||||
|
||||
static constexpr std::array<const char*, static_cast<int>(GSInterlaceMode::Count)> option_names = {{
|
||||
"Automatic",
|
||||
"Off",
|
||||
"Weave (Top Field First)",
|
||||
"Weave (Bottom Field First)",
|
||||
"Bob (Top Field First)",
|
||||
"Bob (Bottom Field First)",
|
||||
"Blend (Top Field First)",
|
||||
"Blend (Bottom Field First)",
|
||||
"Adaptive (Top Field First)",
|
||||
"Adaptive (Bottom Field First)",
|
||||
}};
|
||||
static constexpr std::array<const char*, static_cast<int>(GSInterlaceMode::Count)> option_names = {{
|
||||
"Automatic",
|
||||
"Off",
|
||||
"Weave (Top Field First)",
|
||||
"Weave (Bottom Field First)",
|
||||
"Bob (Top Field First)",
|
||||
"Bob (Bottom Field First)",
|
||||
"Blend (Top Field First)",
|
||||
"Blend (Bottom Field First)",
|
||||
"Adaptive (Top Field First)",
|
||||
"Adaptive (Bottom Field First)",
|
||||
}};
|
||||
|
||||
const GSInterlaceMode new_mode = static_cast<GSInterlaceMode>((static_cast<s32>(EmuConfig.GS.InterlaceMode) + 1) % static_cast<s32>(GSInterlaceMode::Count));
|
||||
Host::AddKeyedFormattedOSDMessage("CycleInterlaceMode", Host::OSD_QUICK_DURATION, "Deinterlace mode set to '%s'.", option_names[static_cast<s32>(new_mode)]);
|
||||
EmuConfig.GS.InterlaceMode = new_mode;
|
||||
const GSInterlaceMode new_mode = static_cast<GSInterlaceMode>(
|
||||
(static_cast<s32>(EmuConfig.GS.InterlaceMode) + 1) % static_cast<s32>(GSInterlaceMode::Count));
|
||||
Host::AddKeyedOSDMessage("CycleInterlaceMode",
|
||||
fmt::format(
|
||||
TRANSLATE_SV("Hotkeys", "Deinterlace mode set to '{}'."), option_names[static_cast<s32>(new_mode)]),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
EmuConfig.GS.InterlaceMode = new_mode;
|
||||
|
||||
GetMTGS().RunOnGSThread([new_mode]() { GSConfig.InterlaceMode = new_mode; });
|
||||
}},
|
||||
{"ToggleTextureDumping", "Graphics", "Toggle Texture Dumping", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
EmuConfig.GS.DumpReplaceableTextures = !EmuConfig.GS.DumpReplaceableTextures;
|
||||
Host::AddKeyedOSDMessage("ToggleTextureReplacements",
|
||||
EmuConfig.GS.DumpReplaceableTextures ? "Texture dumping is now enabled." : "Texture dumping is now disabled.",
|
||||
Host::OSD_INFO_DURATION);
|
||||
GetMTGS().ApplySettings();
|
||||
}
|
||||
}},
|
||||
{"ToggleTextureReplacements", "Graphics", "Toggle Texture Replacements", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
EmuConfig.GS.LoadTextureReplacements = !EmuConfig.GS.LoadTextureReplacements;
|
||||
Host::AddKeyedOSDMessage("ToggleTextureReplacements",
|
||||
EmuConfig.GS.LoadTextureReplacements ? "Texture replacements are now enabled." : "Texture replacements are now disabled.",
|
||||
Host::OSD_INFO_DURATION);
|
||||
GetMTGS().ApplySettings();
|
||||
}
|
||||
}},
|
||||
{"ReloadTextureReplacements", "Graphics", "Reload Texture Replacements", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
if (!EmuConfig.GS.LoadTextureReplacements)
|
||||
{
|
||||
Host::AddKeyedOSDMessage("ReloadTextureReplacements", "Texture replacements are not enabled.", Host::OSD_INFO_DURATION);
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::AddKeyedOSDMessage("ReloadTextureReplacements", "Reloading texture replacements...", Host::OSD_INFO_DURATION);
|
||||
GetMTGS().RunOnGSThread([]() {
|
||||
GSTextureReplacements::ReloadReplacementMap();
|
||||
});
|
||||
}
|
||||
}
|
||||
}},
|
||||
END_HOTKEY_LIST()
|
||||
GetMTGS().RunOnGSThread([new_mode]() { GSConfig.InterlaceMode = new_mode; });
|
||||
}},
|
||||
{"ToggleTextureDumping", TRANSLATE_NOOP("Hotkeys", "Graphics"), TRANSLATE_NOOP("Hotkeys", "Toggle Texture Dumping"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
EmuConfig.GS.DumpReplaceableTextures = !EmuConfig.GS.DumpReplaceableTextures;
|
||||
Host::AddKeyedOSDMessage("ToggleTextureReplacements",
|
||||
EmuConfig.GS.DumpReplaceableTextures ? TRANSLATE_STR("Hotkeys", "Texture dumping is now enabled.") :
|
||||
TRANSLATE_STR("Hotkeys", "Texture dumping is now disabled."),
|
||||
Host::OSD_INFO_DURATION);
|
||||
GetMTGS().ApplySettings();
|
||||
}
|
||||
}},
|
||||
{"ToggleTextureReplacements", TRANSLATE_NOOP("Hotkeys", "Graphics"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Toggle Texture Replacements"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
EmuConfig.GS.LoadTextureReplacements = !EmuConfig.GS.LoadTextureReplacements;
|
||||
Host::AddKeyedOSDMessage("ToggleTextureReplacements",
|
||||
EmuConfig.GS.LoadTextureReplacements ?
|
||||
TRANSLATE_STR("Hotkeys", "Texture replacements are now enabled.") :
|
||||
TRANSLATE_STR("Hotkeys", "Texture replacements are now disabled."),
|
||||
Host::OSD_INFO_DURATION);
|
||||
GetMTGS().ApplySettings();
|
||||
}
|
||||
}},
|
||||
{"ReloadTextureReplacements", TRANSLATE_NOOP("Hotkeys", "Graphics"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Reload Texture Replacements"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
if (!EmuConfig.GS.LoadTextureReplacements)
|
||||
{
|
||||
Host::AddKeyedOSDMessage("ReloadTextureReplacements",
|
||||
TRANSLATE_STR("Hotkeys", "Texture replacements are not enabled."), Host::OSD_INFO_DURATION);
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::AddKeyedOSDMessage("ReloadTextureReplacements",
|
||||
TRANSLATE_STR("Hotkeys", "Reloading texture replacements..."), Host::OSD_INFO_DURATION);
|
||||
GetMTGS().RunOnGSThread([]() { GSTextureReplacements::ReloadReplacementMap(); });
|
||||
}
|
||||
}
|
||||
}},
|
||||
END_HOTKEY_LIST()
|
||||
|
||||
@@ -453,6 +453,22 @@ bool GSLocalMemory::IsPageAligned(u32 psm, const GSVector4i& rc)
|
||||
return (rc & pgmsk).eq(GSVector4i::zero());
|
||||
}
|
||||
|
||||
u32 GSLocalMemory::GetStartBlockAddress(u32 bp, u32 bw, u32 psm, GSVector4i rect)
|
||||
{
|
||||
u32 result = m_psm[psm].info.bn(rect.x, rect.y, bp, bw); // Valid only for color formats
|
||||
|
||||
// If rect is page aligned, we can assume it's the start of the page. Z formats don't place block 0
|
||||
// in the top-left, so we have to round them down.
|
||||
const GSVector2i page_size = GSLocalMemory::m_psm[psm].pgs;
|
||||
if ((rect.x & (page_size.x - 1)) == 0 && (rect.y & (page_size.y - 1)) == 0)
|
||||
{
|
||||
constexpr u32 page_mask = (1 << 5) - 1;
|
||||
result &= ~page_mask;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 GSLocalMemory::GetEndBlockAddress(u32 bp, u32 bw, u32 psm, GSVector4i rect)
|
||||
{
|
||||
u32 result = m_psm[psm].info.bn(rect.z - 1, rect.w - 1, bp, bw); // Valid only for color formats
|
||||
|
||||
@@ -535,6 +535,7 @@ public:
|
||||
GSLocalMemory();
|
||||
~GSLocalMemory();
|
||||
|
||||
__forceinline u8* vm8() const { return m_vm8; }
|
||||
__forceinline u16* vm16() const { return reinterpret_cast<u16*>(m_vm8); }
|
||||
__forceinline u32* vm32() const { return reinterpret_cast<u32*>(m_vm8); }
|
||||
|
||||
@@ -546,6 +547,7 @@ public:
|
||||
GSPixelOffset4* GetPixelOffset4(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF);
|
||||
std::vector<GSVector2i>* GetPage2TileMap(const GIFRegTEX0& TEX0);
|
||||
static bool IsPageAligned(u32 psm, const GSVector4i& rc);
|
||||
static u32 GetStartBlockAddress(u32 bp, u32 bw, u32 psm, GSVector4i rect);
|
||||
static u32 GetEndBlockAddress(u32 bp, u32 bw, u32 psm, GSVector4i rect);
|
||||
|
||||
// address
|
||||
|
||||
@@ -1646,7 +1646,11 @@ void GSState::FlushPrim()
|
||||
|
||||
try
|
||||
{
|
||||
Draw();
|
||||
// Skip draw if Z test is enabled, but set to fail all pixels.
|
||||
const bool skip_draw = (m_context->TEST.ZTE && m_context->TEST.ZTST == ZTST_NEVER);
|
||||
|
||||
if (!skip_draw)
|
||||
Draw();
|
||||
}
|
||||
catch (GSRecoverableError&)
|
||||
{
|
||||
|
||||
@@ -243,6 +243,11 @@ public:
|
||||
return GSVector4(GSVector4i::load((int)rgba).u8to32() << shift);
|
||||
}
|
||||
|
||||
__forceinline static GSVector4 unorm8(u32 rgba)
|
||||
{
|
||||
return rgba32(rgba) * GSVector4::cxpr(1.0f / 255.0f);
|
||||
}
|
||||
|
||||
__forceinline GSVector4 abs() const
|
||||
{
|
||||
return *this & cast(GSVector4i::x7fffffff());
|
||||
|
||||
@@ -323,7 +323,7 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
|
||||
case GSTexture::Type::DepthStencil:
|
||||
{
|
||||
if (clear)
|
||||
ClearDepth(t);
|
||||
ClearDepth(t, 0.0f);
|
||||
else
|
||||
InvalidateRenderTarget(t);
|
||||
}
|
||||
@@ -470,7 +470,7 @@ void GSDevice::ClearCurrent()
|
||||
m_cas = nullptr;
|
||||
}
|
||||
|
||||
void GSDevice::Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c)
|
||||
void GSDevice::Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c)
|
||||
{
|
||||
if (ResizeRenderTarget(&m_merge, fs.x, fs.y, false, false))
|
||||
DoMerge(sTex, sRect, m_merge, dRect, PMODE, EXTBUF, c, GSConfig.PCRTCOffsets);
|
||||
|
||||
@@ -786,7 +786,7 @@ protected:
|
||||
virtual GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) = 0;
|
||||
GSTexture* FetchSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_reuse);
|
||||
|
||||
virtual void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) = 0;
|
||||
virtual void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) = 0;
|
||||
virtual void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) = 0;
|
||||
virtual void DoFXAA(GSTexture* sTex, GSTexture* dTex) = 0;
|
||||
virtual void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) = 0;
|
||||
@@ -877,10 +877,9 @@ public:
|
||||
/// Returns the amount of GPU time utilized since the last time this method was called.
|
||||
virtual float GetAndResetAccumulatedGPUTime() = 0;
|
||||
|
||||
virtual void ClearRenderTarget(GSTexture* t, const GSVector4& c) = 0;
|
||||
virtual void ClearRenderTarget(GSTexture* t, u32 c) = 0;
|
||||
virtual void InvalidateRenderTarget(GSTexture* t) = 0;
|
||||
virtual void ClearDepth(GSTexture* t) = 0;
|
||||
virtual void ClearDepth(GSTexture* t, float d) = 0;
|
||||
|
||||
virtual void PushDebugGroup(const char* fmt, ...) = 0;
|
||||
virtual void PopDebugGroup() = 0;
|
||||
@@ -919,7 +918,7 @@ public:
|
||||
virtual void ClearSamplerCache() = 0;
|
||||
|
||||
void ClearCurrent();
|
||||
void Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c);
|
||||
void Merge(GSTexture* sTex[3], GSVector4* sRect, GSVector4* dRect, const GSVector2i& fs, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c);
|
||||
void Interlace(const GSVector2i& ds, int field, int mode, float yoffset);
|
||||
void FXAA();
|
||||
void ShadeBoost();
|
||||
|
||||
@@ -220,13 +220,7 @@ bool GSRenderer::Merge(int field)
|
||||
tex[0] = nullptr;
|
||||
}
|
||||
|
||||
const GSVector4 c = GSVector4(
|
||||
static_cast<int>(m_regs->BGCOLOR.R),
|
||||
static_cast<int>(m_regs->BGCOLOR.G),
|
||||
static_cast<int>(m_regs->BGCOLOR.B),
|
||||
static_cast<int>(m_regs->PMODE.ALP)) /
|
||||
255;
|
||||
|
||||
const u32 c = (m_regs->BGCOLOR.U32[0] & 0x00FFFFFFu) | (m_regs->PMODE.ALP << 24);
|
||||
g_gs_device->Merge(tex, src_gs_read, dst, fs, m_regs->PMODE, m_regs->EXTBUF, c);
|
||||
|
||||
if (isReallyInterlaced() && GSConfig.InterlaceMode != GSInterlaceMode::Off)
|
||||
@@ -431,22 +425,30 @@ static void CompressAndWriteScreenshot(std::string filename, u32 width, u32 heig
|
||||
|
||||
std::string key(fmt::format("GSScreenshot_{}", filename));
|
||||
|
||||
if(!GSDumpReplayer::IsRunner())
|
||||
Host::AddIconOSDMessage(key, ICON_FA_CAMERA, fmt::format("Saving screenshot to '{}'.", Path::GetFileName(filename)), 60.0f);
|
||||
if (!GSDumpReplayer::IsRunner())
|
||||
{
|
||||
Host::AddIconOSDMessage(key, ICON_FA_CAMERA,
|
||||
fmt::format(TRANSLATE_SV("GS", "Saving screenshot to '{}'."), Path::GetFileName(filename)), 60.0f);
|
||||
}
|
||||
|
||||
// maybe std::async would be better here.. but it's definitely worth threading, large screenshots take a while to compress.
|
||||
std::unique_lock lock(s_screenshot_threads_mutex);
|
||||
s_screenshot_threads.emplace_back([key = std::move(key), filename = std::move(filename), image = std::move(image), quality = GSConfig.ScreenshotQuality]() {
|
||||
s_screenshot_threads.emplace_back([key = std::move(key), filename = std::move(filename), image = std::move(image),
|
||||
quality = GSConfig.ScreenshotQuality]() {
|
||||
if (image.SaveToFile(filename.c_str(), quality))
|
||||
{
|
||||
if(!GSDumpReplayer::IsRunner())
|
||||
if (!GSDumpReplayer::IsRunner())
|
||||
{
|
||||
Host::AddIconOSDMessage(std::move(key), ICON_FA_CAMERA,
|
||||
fmt::format("Saved screenshot to '{}'.", Path::GetFileName(filename)), Host::OSD_INFO_DURATION);
|
||||
fmt::format(TRANSLATE_SV("GS", "Saved screenshot to '{}'."), Path::GetFileName(filename)),
|
||||
Host::OSD_INFO_DURATION);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::AddIconOSDMessage(std::move(key), ICON_FA_CAMERA,
|
||||
fmt::format("Failed to save screenshot to '{}'.", Path::GetFileName(filename), Host::OSD_ERROR_DURATION));
|
||||
fmt::format(TRANSLATE_SV("GS", "Failed to save screenshot to '{}'."), Path::GetFileName(filename),
|
||||
Host::OSD_ERROR_DURATION));
|
||||
}
|
||||
|
||||
// remove ourselves from the list, if the GS thread is waiting for us, we won't be in there
|
||||
@@ -516,7 +518,7 @@ bool GSRenderer::BeginPresentFrame(bool frame_skip)
|
||||
|
||||
// First frame after reopening is definitely going to be trash, so skip it.
|
||||
Host::AddIconOSDMessage("GSDeviceLost", ICON_FA_EXCLAMATION_TRIANGLE,
|
||||
"Host GPU device encountered an error and was recovered. This may have broken rendering.",
|
||||
TRANSLATE_SV("GS", "Host GPU device encountered an error and was recovered. This may have broken rendering."),
|
||||
Host::OSD_CRITICAL_ERROR_DURATION);
|
||||
return false;
|
||||
}
|
||||
@@ -620,7 +622,9 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
else if (!cas_log_once)
|
||||
{
|
||||
Host::AddIconOSDMessage("CASUnsupported", ICON_FA_EXCLAMATION_TRIANGLE,
|
||||
"CAS is not available, your graphics driver does not support the required functionality.", 10.0f);
|
||||
TRANSLATE_SV("GS",
|
||||
"CAS is not available, your graphics driver does not support the required functionality."),
|
||||
10.0f);
|
||||
cas_log_once = true;
|
||||
}
|
||||
}
|
||||
@@ -692,9 +696,11 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
|
||||
delete[] fd.data;
|
||||
|
||||
Host::AddKeyedOSDMessage("GSDump", fmt::format("Saving {0} GS dump {1} to '{2}'",
|
||||
(m_dump_frames == 1) ? "single frame" : "multi-frame", compression_str,
|
||||
Path::GetFileName(m_dump->GetPath())), Host::OSD_INFO_DURATION);
|
||||
Host::AddKeyedOSDMessage("GSDump",
|
||||
fmt::format(TRANSLATE_SV("GS", "Saving {0} GS dump {1} to '{2}'"),
|
||||
(m_dump_frames == 1) ? "single frame" : "multi-frame", compression_str,
|
||||
Path::GetFileName(m_dump->GetPath())),
|
||||
Host::OSD_INFO_DURATION);
|
||||
}
|
||||
|
||||
const bool internal_resolution = (GSConfig.ScreenshotSize >= GSScreenshotSize::InternalResolution);
|
||||
@@ -711,7 +717,8 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::AddIconOSDMessage("GSScreenshot", ICON_FA_CAMERA, "Failed to render/download screenshot.", Host::OSD_ERROR_DURATION);
|
||||
Host::AddIconOSDMessage("GSScreenshot", ICON_FA_CAMERA,
|
||||
TRANSLATE_SV("GS", "Failed to render/download screenshot."), Host::OSD_ERROR_DURATION);
|
||||
}
|
||||
|
||||
m_snapshot = {};
|
||||
@@ -721,7 +728,9 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
const bool last = (m_dump_frames == 0);
|
||||
if (m_dump->VSync(field, last, m_regs))
|
||||
{
|
||||
Host::AddKeyedOSDMessage("GSDump", fmt::format("Saved GS dump to '{}'.", Path::GetFileName(m_dump->GetPath())), Host::OSD_INFO_DURATION);
|
||||
Host::AddKeyedOSDMessage("GSDump",
|
||||
fmt::format(TRANSLATE_SV("GS", "Saved GS dump to '{}'."), Path::GetFileName(m_dump->GetPath())),
|
||||
Host::OSD_INFO_DURATION);
|
||||
m_dump.reset();
|
||||
}
|
||||
else if (!last)
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
|
||||
union alignas(16) ClearValue
|
||||
{
|
||||
float color[4];
|
||||
u32 color;
|
||||
float depth;
|
||||
};
|
||||
|
||||
@@ -139,13 +139,14 @@ public:
|
||||
__fi u32 GetLastFrameUsed() const { return m_last_frame_used; }
|
||||
void SetLastFrameUsed(u32 frame) { m_last_frame_used = frame; }
|
||||
|
||||
__fi GSVector4 GetClearColor() const { return GSVector4::load<false>(m_clear_value.color); }
|
||||
__fi u32 GetClearColor() const { return m_clear_value.color; }
|
||||
__fi float GetClearDepth() const { return m_clear_value.depth; }
|
||||
__fi GSVector4 GetUNormClearColor() const { return GSVector4::unorm8(m_clear_value.color); }
|
||||
|
||||
__fi void SetClearColor(const GSVector4& color)
|
||||
__fi void SetClearColor(u32 color)
|
||||
{
|
||||
m_state = State::Cleared;
|
||||
GSVector4::store<false>(m_clear_value.color, color);
|
||||
m_clear_value.color = color;
|
||||
}
|
||||
__fi void SetClearDepth(float depth)
|
||||
{
|
||||
|
||||
@@ -1057,38 +1057,43 @@ void GSDevice11::DrawIndexedPrimitive(int offset, int count)
|
||||
m_ctx->DrawIndexed(count, m_index.start + offset, m_vertex.start);
|
||||
}
|
||||
|
||||
void GSDevice11::ClearRenderTarget(GSTexture* t, const GSVector4& c)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
m_ctx->ClearRenderTargetView(*(GSTexture11*)t, c.v);
|
||||
}
|
||||
|
||||
void GSDevice11::ClearRenderTarget(GSTexture* t, u32 c)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
const GSVector4 color = GSVector4::rgba32(c) * (1.0f / 255);
|
||||
|
||||
m_ctx->ClearRenderTargetView(*(GSTexture11*)t, color.v);
|
||||
t->SetClearColor(c);
|
||||
}
|
||||
|
||||
void GSDevice11::InvalidateRenderTarget(GSTexture* t)
|
||||
{
|
||||
if (t->IsDepthStencil())
|
||||
m_ctx->DiscardView(static_cast<ID3D11DepthStencilView*>(*static_cast<GSTexture11*>(t)));
|
||||
t->SetState(GSTexture::State::Invalidated);
|
||||
}
|
||||
|
||||
void GSDevice11::ClearDepth(GSTexture* t, float d)
|
||||
{
|
||||
t->SetClearDepth(d);
|
||||
}
|
||||
|
||||
void GSDevice11::CommitClear(GSTexture* t)
|
||||
{
|
||||
GSTexture11* T = static_cast<GSTexture11*>(t);
|
||||
if (!T->IsRenderTargetOrDepthStencil() || T->GetState() == GSTexture::State::Dirty)
|
||||
return;
|
||||
|
||||
if (T->IsDepthStencil())
|
||||
{
|
||||
if (T->GetState() == GSTexture::State::Invalidated)
|
||||
m_ctx->DiscardView(static_cast<ID3D11DepthStencilView*>(*T));
|
||||
else
|
||||
m_ctx->ClearDepthStencilView(*T, D3D11_CLEAR_DEPTH, T->GetClearDepth(), 0);
|
||||
}
|
||||
else
|
||||
m_ctx->DiscardView(static_cast<ID3D11RenderTargetView*>(*static_cast<GSTexture11*>(t)));
|
||||
}
|
||||
{
|
||||
if (T->GetState() == GSTexture::State::Invalidated)
|
||||
m_ctx->DiscardView(static_cast<ID3D11RenderTargetView*>(*T));
|
||||
else
|
||||
m_ctx->ClearRenderTargetView(*T, T->GetUNormClearColor().F32);
|
||||
}
|
||||
|
||||
void GSDevice11::ClearDepth(GSTexture* t)
|
||||
{
|
||||
m_ctx->ClearDepthStencilView(*(GSTexture11*)t, D3D11_CLEAR_DEPTH, 0.0f, 0);
|
||||
}
|
||||
|
||||
void GSDevice11::ClearStencil(GSTexture* t, u8 c)
|
||||
{
|
||||
m_ctx->ClearDepthStencilView(*(GSTexture11*)t, D3D11_CLEAR_STENCIL, 0, c);
|
||||
T->SetState(GSTexture::State::Dirty);
|
||||
}
|
||||
|
||||
void GSDevice11::PushDebugGroup(const char* fmt, ...)
|
||||
@@ -1176,6 +1181,9 @@ std::unique_ptr<GSDownloadTexture> GSDevice11::CreateDownloadTexture(u32 width,
|
||||
|
||||
void GSDevice11::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY)
|
||||
{
|
||||
CommitClear(sTex);
|
||||
CommitClear(dTex);
|
||||
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
D3D11_BOX box = {(UINT)r.left, (UINT)r.top, 0U, (UINT)r.right, (UINT)r.bottom, 1U};
|
||||
@@ -1192,6 +1200,7 @@ void GSDevice11::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
void GSDevice11::CloneTexture(GSTexture* src, GSTexture** dest, const GSVector4i& rect)
|
||||
{
|
||||
pxAssertMsg(src->GetType() == GSTexture::Type::DepthStencil || src->GetType() == GSTexture::Type::RenderTarget, "Source is RT or DS.");
|
||||
CommitClear(src);
|
||||
|
||||
const int w = src->GetWidth();
|
||||
const int h = src->GetHeight();
|
||||
@@ -1231,7 +1240,7 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
|
||||
void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, bool linear)
|
||||
{
|
||||
ASSERT(sTex);
|
||||
CommitClear(sTex);
|
||||
|
||||
const bool draw_in_depth = dTex && dTex->IsDepthStencil();
|
||||
|
||||
@@ -1303,7 +1312,7 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
|
||||
void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear)
|
||||
{
|
||||
ASSERT(sTex);
|
||||
CommitClear(sTex);
|
||||
|
||||
GSVector2i ds;
|
||||
if (dTex)
|
||||
@@ -1480,6 +1489,7 @@ void GSDevice11::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rect
|
||||
IAUnmapIndexBuffer(icount);
|
||||
IASetIndexBuffer(m_ib.get());
|
||||
|
||||
CommitClear(rects[0].src);
|
||||
PSSetShaderResource(0, rects[0].src);
|
||||
PSSetSamplerState(rects[0].linear ? m_convert.ln.get() : m_convert.pt.get());
|
||||
|
||||
@@ -1489,7 +1499,7 @@ void GSDevice11::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rect
|
||||
}
|
||||
|
||||
|
||||
void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear)
|
||||
void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
|
||||
{
|
||||
const GSVector4 full_r(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
const bool feedback_write_2 = PMODE.EN2 && sTex[2] != nullptr && EXTBUF.FBIN == 1;
|
||||
@@ -1504,7 +1514,7 @@ void GSDevice11::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
// Upload constant to select YUV algo, but skip constant buffer update if we don't need it
|
||||
if (feedback_write_2 || feedback_write_1 || sTex[0])
|
||||
{
|
||||
const MergeConstantBuffer cb = {c, EXTBUF.EMODA, EXTBUF.EMODC};
|
||||
const MergeConstantBuffer cb = {GSVector4::unorm8(c), EXTBUF.EMODA, EXTBUF.EMODC};
|
||||
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
|
||||
}
|
||||
|
||||
@@ -1799,7 +1809,7 @@ void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vert
|
||||
{
|
||||
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
|
||||
|
||||
ClearStencil(ds, 0);
|
||||
m_ctx->ClearDepthStencilView(*static_cast<GSTexture11*>(ds), D3D11_CLEAR_STENCIL, 0.0f, 0);
|
||||
|
||||
// om
|
||||
|
||||
@@ -2067,8 +2077,16 @@ void GSDevice11::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector
|
||||
ID3D11RenderTargetView* rtv = nullptr;
|
||||
ID3D11DepthStencilView* dsv = nullptr;
|
||||
|
||||
if (rt) rtv = *(GSTexture11*)rt;
|
||||
if (ds) dsv = *(GSTexture11*)ds;
|
||||
if (rt)
|
||||
{
|
||||
CommitClear(rt);
|
||||
rtv = *static_cast<GSTexture11*>(rt);
|
||||
}
|
||||
if (ds)
|
||||
{
|
||||
CommitClear(ds);
|
||||
dsv = *static_cast<GSTexture11*>(ds);
|
||||
}
|
||||
|
||||
const bool changed = (m_state.rt_view != rtv || m_state.dsv != dsv);
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(changed));
|
||||
|
||||
@@ -129,7 +129,7 @@ private:
|
||||
void PopTimestampQuery();
|
||||
void KickTimestampQuery();
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) override;
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) override;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) override;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) override;
|
||||
@@ -309,11 +309,9 @@ public:
|
||||
void DrawIndexedPrimitive();
|
||||
void DrawIndexedPrimitive(int offset, int count);
|
||||
|
||||
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
|
||||
void ClearRenderTarget(GSTexture* t, u32 c) override;
|
||||
void InvalidateRenderTarget(GSTexture* t) override;
|
||||
void ClearDepth(GSTexture* t) override;
|
||||
void ClearStencil(GSTexture* t, u8 c);
|
||||
void ClearDepth(GSTexture* t, float v) override;
|
||||
|
||||
void PushDebugGroup(const char* fmt, ...) override;
|
||||
void PopDebugGroup() override;
|
||||
@@ -322,6 +320,7 @@ public:
|
||||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override;
|
||||
|
||||
void CommitClear(GSTexture* t);
|
||||
void CloneTexture(GSTexture* src, GSTexture** dest, const GSVector4i& rect);
|
||||
|
||||
void CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY) override;
|
||||
|
||||
@@ -67,6 +67,7 @@ bool GSTexture11::Update(const GSVector4i& r, const void* data, int pitch, int l
|
||||
if (layer >= m_mipmap_levels)
|
||||
return false;
|
||||
|
||||
GSDevice11::GetInstance()->CommitClear(this);
|
||||
g_perfmon.Put(GSPerfMon::TextureUploads, 1);
|
||||
|
||||
const u32 bs = GetCompressedBlockSize();
|
||||
@@ -82,41 +83,19 @@ bool GSTexture11::Update(const GSVector4i& r, const void* data, int pitch, int l
|
||||
|
||||
bool GSTexture11::Map(GSMap& m, const GSVector4i* r, int layer)
|
||||
{
|
||||
if (r != NULL)
|
||||
{
|
||||
// ASSERT(0); // not implemented
|
||||
return false;
|
||||
}
|
||||
|
||||
if (layer >= m_mipmap_levels)
|
||||
return false;
|
||||
|
||||
if (m_texture && m_desc.Usage == D3D11_USAGE_STAGING)
|
||||
{
|
||||
D3D11_MAPPED_SUBRESOURCE map;
|
||||
UINT subresource = layer;
|
||||
|
||||
if (SUCCEEDED(GSDevice11::GetInstance()->GetD3DContext()->Map(m_texture.get(), subresource, D3D11_MAP_READ_WRITE, 0, &map)))
|
||||
{
|
||||
m.bits = (u8*)map.pData;
|
||||
m.pitch = (int)map.RowPitch;
|
||||
m_mapped_subresource = layer;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Not supported
|
||||
return false;
|
||||
}
|
||||
|
||||
void GSTexture11::Unmap()
|
||||
{
|
||||
const UINT subresource = m_mapped_subresource;
|
||||
m_needs_mipmaps_generated |= (m_mapped_subresource == 0);
|
||||
GSDevice11::GetInstance()->GetD3DContext()->Unmap(m_texture.get(), subresource);
|
||||
pxFailRel("Should not be called.");
|
||||
}
|
||||
|
||||
bool GSTexture11::Save(const std::string& fn)
|
||||
{
|
||||
GSDevice11::GetInstance()->CommitClear(this);
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = m_desc;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
@@ -342,6 +321,9 @@ void GSDownloadTexture11::CopyFromTexture(
|
||||
pxAssert(src.z <= stex->GetWidth() && src.w <= stex->GetHeight());
|
||||
pxAssert(static_cast<u32>(drc.z) <= m_width && static_cast<u32>(drc.w) <= m_height);
|
||||
pxAssert(src_level < static_cast<u32>(stex->GetMipmapLevels()));
|
||||
|
||||
GSDevice11::GetInstance()->CommitClear(stex);
|
||||
|
||||
g_perfmon.Put(GSPerfMon::Readbacks, 1);
|
||||
|
||||
if (IsMapped())
|
||||
|
||||
@@ -639,42 +639,28 @@ void GSDevice12::DrawIndexedPrimitive(int offset, int count)
|
||||
g_d3d12_context->GetCommandList()->DrawIndexedInstanced(count, 1, m_index.start + offset, m_vertex.start, 0);
|
||||
}
|
||||
|
||||
void GSDevice12::ClearRenderTarget(GSTexture* t, const GSVector4& c)
|
||||
void GSDevice12::ClearRenderTarget(GSTexture* t, u32 c)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
if (m_current_render_target == t)
|
||||
EndRenderPass();
|
||||
|
||||
static_cast<GSTexture12*>(t)->SetClearColor(c);
|
||||
}
|
||||
|
||||
void GSDevice12::ClearRenderTarget(GSTexture* t, u32 c)
|
||||
{
|
||||
ClearRenderTarget(t, GSVector4::rgba32(c) * (1.0f / 255));
|
||||
t->SetClearColor(c);
|
||||
}
|
||||
|
||||
void GSDevice12::InvalidateRenderTarget(GSTexture* t)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
if (m_current_render_target == t || m_current_depth_target == t)
|
||||
EndRenderPass();
|
||||
|
||||
t->SetState(GSTexture::State::Invalidated);
|
||||
}
|
||||
|
||||
void GSDevice12::ClearDepth(GSTexture* t)
|
||||
void GSDevice12::ClearDepth(GSTexture* t, float d)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
if (m_current_depth_target == t)
|
||||
EndRenderPass();
|
||||
|
||||
static_cast<GSTexture12*>(t)->SetClearDepth(0.0f);
|
||||
t->SetClearDepth(d);
|
||||
}
|
||||
|
||||
void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_format, DXGI_FORMAT* srv_format,
|
||||
@@ -771,7 +757,7 @@ void GSDevice12::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
{
|
||||
dTexVK->TransitionToState(D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
g_d3d12_context->GetCommandList()->ClearRenderTargetView(
|
||||
dTexVK->GetWriteDescriptor(), sTexVK->GetClearColor().v, 0, nullptr);
|
||||
dTexVK->GetWriteDescriptor(), sTexVK->GetUNormClearColor().v, 0, nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1027,19 +1013,17 @@ void GSDevice12::BeginRenderPassForStretchRect(
|
||||
|
||||
if (dTex->GetType() != GSTexture::Type::DepthStencil)
|
||||
{
|
||||
const GSVector4 clear_color(dTex->GetClearColor());
|
||||
BeginRenderPass(load_op, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
clear_color);
|
||||
dTex->GetClearColor());
|
||||
}
|
||||
else
|
||||
{
|
||||
const float clear_depth = dTex->GetClearDepth();
|
||||
BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS, load_op, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
GSVector4::zero(), clear_depth);
|
||||
0, dTex->GetClearDepth());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1103,7 +1087,7 @@ void GSDevice12::DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect,
|
||||
}
|
||||
|
||||
void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect,
|
||||
const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear)
|
||||
const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
|
||||
{
|
||||
GL_PUSH("DoMerge");
|
||||
|
||||
@@ -1126,7 +1110,7 @@ void GSDevice12::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
if (feedback_write_2 || feedback_write_1 || sTex[0])
|
||||
{
|
||||
SetUtilityRootSignature();
|
||||
const MergeConstantBuffer uniforms = {c, EXTBUF.EMODA, EXTBUF.EMODC};
|
||||
const MergeConstantBuffer uniforms = {GSVector4::unorm8(c), EXTBUF.EMODA, EXTBUF.EMODC};
|
||||
SetUtilityPushConstants(&uniforms, sizeof(uniforms));
|
||||
}
|
||||
|
||||
@@ -2711,8 +2695,7 @@ bool GSDevice12::InRenderPass()
|
||||
void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_begin,
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE color_end, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE depth_begin,
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE depth_end, D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE stencil_begin,
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE stencil_end, const GSVector4& clear_color /* = GSVector4::zero() */,
|
||||
float clear_depth /* = 0.0f */, u8 clear_stencil /* = 0 */)
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE stencil_end, u32 clear_color, float clear_depth, u8 clear_stencil)
|
||||
{
|
||||
if (m_in_render_pass)
|
||||
EndRenderPass();
|
||||
@@ -2731,7 +2714,8 @@ void GSDevice12::BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE color_b
|
||||
{
|
||||
LookupNativeFormat(m_current_render_target->GetFormat(), nullptr,
|
||||
&rt.BeginningAccess.Clear.ClearValue.Format, nullptr, nullptr);
|
||||
GSVector4::store<false>(rt.BeginningAccess.Clear.ClearValue.Color, clear_color);
|
||||
GSVector4::store<false>(rt.BeginningAccess.Clear.ClearValue.Color,
|
||||
GSVector4::unorm8(clear_color));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3026,8 +3010,7 @@ void GSDevice12::SetupDATE(GSTexture* rt, GSTexture* ds, bool datm, const GSVect
|
||||
SetStencilRef(1);
|
||||
BeginRenderPass(D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, GSVector4::zero(),
|
||||
0.0f, 0);
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE, 0, 0.0f, 0);
|
||||
if (ApplyUtilityState())
|
||||
DrawPrimitive();
|
||||
|
||||
@@ -3062,7 +3045,7 @@ GSTexture12* GSDevice12::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, Pipe
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
|
||||
config.ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
GSVector4::zero(), config.ds ? static_cast<GSTexture12*>(config.ds)->GetClearDepth() : 0.0f);
|
||||
0, config.ds ? config.ds->GetClearDepth() : 0.0f);
|
||||
|
||||
// draw the quad to prefill the image
|
||||
const GSVector4 src = GSVector4(config.drawarea) / GSVector4(rtsize).xyxy();
|
||||
@@ -3169,7 +3152,6 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
EndRenderPass();
|
||||
|
||||
GL_PUSH_("HDR Render Target Setup");
|
||||
hdr_rt = static_cast<GSTexture12*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
|
||||
if (!hdr_rt)
|
||||
{
|
||||
@@ -3182,11 +3164,12 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
// propagate clear value through if the hdr render is the first
|
||||
if (draw_rt->GetState() == GSTexture::State::Cleared)
|
||||
{
|
||||
hdr_rt->SetState(GSTexture::State::Cleared);
|
||||
hdr_rt->SetClearColor(draw_rt->GetClearColor());
|
||||
}
|
||||
else
|
||||
else if (draw_rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
hdr_rt->SetState(GSTexture::State::Invalidated);
|
||||
GL_PUSH_("HDR Render Target Setup");
|
||||
draw_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
}
|
||||
|
||||
@@ -3252,7 +3235,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
|
||||
stencil_DATE ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD :
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
draw_rt ? draw_rt->GetClearColor() : GSVector4::zero(), draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1);
|
||||
draw_rt ? draw_rt->GetClearColor() : 0, draw_ds ? draw_ds->GetClearDepth() : 0.0f, 1);
|
||||
}
|
||||
|
||||
// rt -> hdr blit if enabled
|
||||
@@ -3322,7 +3305,7 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
|
||||
// now blit the hdr texture back to the original target
|
||||
if (hdr_rt)
|
||||
{
|
||||
GL_INS("Blit HDR back to RT");
|
||||
GL_PUSH("Blit HDR back to RT");
|
||||
|
||||
EndRenderPass();
|
||||
hdr_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
@@ -204,7 +204,7 @@ private:
|
||||
GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
|
||||
const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) final;
|
||||
const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) final;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect,
|
||||
ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) final;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
||||
@@ -279,10 +279,9 @@ public:
|
||||
void DrawIndexedPrimitive();
|
||||
void DrawIndexedPrimitive(int offset, int count);
|
||||
|
||||
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
|
||||
void ClearRenderTarget(GSTexture* t, u32 c) override;
|
||||
void InvalidateRenderTarget(GSTexture* t) override;
|
||||
void ClearDepth(GSTexture* t) override;
|
||||
void ClearDepth(GSTexture* t, float d) override;
|
||||
|
||||
std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override;
|
||||
|
||||
@@ -369,7 +368,7 @@ public:
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE depth_end = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE stencil_begin = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS,
|
||||
D3D12_RENDER_PASS_ENDING_ACCESS_TYPE stencil_end = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
|
||||
const GSVector4& clear_color = GSVector4::zero(), float clear_depth = 0.0f, u8 clear_stencil = 0);
|
||||
const u32 clear_color = 0, float clear_depth = 0.0f, u8 clear_stencil = 0);
|
||||
void EndRenderPass();
|
||||
|
||||
void SetViewport(const D3D12_VIEWPORT& viewport);
|
||||
|
||||
@@ -670,7 +670,7 @@ void GSTexture12::CommitClear(ID3D12GraphicsCommandList* cmdlist)
|
||||
else
|
||||
{
|
||||
TransitionToState(cmdlist, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
cmdlist->ClearRenderTargetView(GetWriteDescriptor(), m_clear_value.color, 0, nullptr);
|
||||
cmdlist->ClearRenderTargetView(GetWriteDescriptor(), GSVector4::unorm8(m_clear_value.color).v, 0, nullptr);
|
||||
}
|
||||
|
||||
SetState(GSTexture::State::Dirty);
|
||||
|
||||
@@ -135,7 +135,7 @@ bool GSHwHack::GSC_SacredBlaze(GSRendererHW& r, int& skip)
|
||||
if ((RFBP == 0x2680 || RFBP == 0x26c0 || RFBP == 0x2780 || RFBP == 0x2880 || RFBP == 0x2a80) && RTPSM == PSMCT32 && RFBW <= 2 &&
|
||||
(!RTME || (RTBP0 == 0x0 || RTBP0 == 0xe00 || RTBP0 == 0x3e00)))
|
||||
{
|
||||
r.SwPrimRender(r, RTBP0 > 0x1000);
|
||||
r.SwPrimRender(r, RTBP0 > 0x1000, false);
|
||||
skip = 1;
|
||||
}
|
||||
}
|
||||
@@ -215,7 +215,7 @@ bool GSHwHack::GSC_Tekken5(GSRendererHW& r, int& skip)
|
||||
|
||||
bool GSHwHack::GSC_BurnoutGames(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (RFBW == 2 && std::abs(static_cast<int>(RFBP) - static_cast<int>(RZBP)) <= static_cast<int>(BLOCKS_PER_PAGE))
|
||||
if (RFBW == 2 && std::abs(static_cast<int>(RFBP) - static_cast<int>(RZBP)) <= static_cast<int>(BLOCKS_PER_PAGE) && (!RTME || RTPSM != PSMT8))
|
||||
{
|
||||
skip = 2;
|
||||
return true;
|
||||
@@ -253,7 +253,7 @@ bool GSHwHack::GSC_BlackAndBurnoutSky(GSRendererHW& r, int& skip)
|
||||
// the clouds on top of the sky at each frame.
|
||||
// Burnout 3 PAL 50Hz: 0x3ba0 => 0x1e80.
|
||||
GL_INS("OO_BurnoutGames - Readback clouds renderered from TEX0.TBP0 = 0x%04x (TEX0.CBP = 0x%04x) to FBP = 0x%04x", TEX0.TBP0, TEX0.CBP, FRAME.Block());
|
||||
r.SwPrimRender(r, true);
|
||||
r.SwPrimRender(r, true, false);
|
||||
skip = 1;
|
||||
}
|
||||
if (TEX0.TBW == 2 && TEX0.TW == 7 && ((TEX0.PSM == PSMT4 && FRAME.FBW == 3) || (TEX0.PSM == PSMT8 && FRAME.FBW == 2)) && TEX0.TH == 6 && (FRAME.FBMSK & 0xFFFFFF) == 0xFFFFFF)
|
||||
@@ -261,7 +261,7 @@ bool GSHwHack::GSC_BlackAndBurnoutSky(GSRendererHW& r, int& skip)
|
||||
// Rendering of the glass smashing effect and some chassis decal in to the alpha channel of the FRAME on boot (before the menu).
|
||||
// This gets ejected from the texture cache due to old age, but never gets written back.
|
||||
GL_INS("OO_BurnoutGames - Render glass smash from TEX0.TBP0 = 0x%04x (TEX0.CBP = 0x%04x) to FBP = 0x%04x", TEX0.TBP0, TEX0.CBP, FRAME.Block());
|
||||
r.SwPrimRender(r, true);
|
||||
r.SwPrimRender(r, true, false);
|
||||
skip = 1;
|
||||
}
|
||||
}
|
||||
@@ -652,7 +652,7 @@ bool GSHwHack::GSC_BlueTongueGames(GSRendererHW& r, int& skip)
|
||||
// Also used for Nicktoons Unite, same engine it appears.
|
||||
if ((context->FRAME.PSM == PSMCT16S || context->FRAME.PSM <= PSMCT24) && context->FRAME.FBW <= 5)
|
||||
{
|
||||
r.SwPrimRender(r, true);
|
||||
r.SwPrimRender(r, true, false);
|
||||
skip = 1;
|
||||
return true;
|
||||
}
|
||||
@@ -661,13 +661,52 @@ bool GSHwHack::GSC_BlueTongueGames(GSRendererHW& r, int& skip)
|
||||
// rendered on both.
|
||||
if (context->FRAME.FBW == 8 && r.m_index.tail == 32 && r.PRIM->TME && context->TEX0.TBW == 1)
|
||||
{
|
||||
r.SwPrimRender(r, false);
|
||||
r.SwPrimRender(r, false, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_MetalGearSolid3(GSRendererHW& r, int& skip)
|
||||
{
|
||||
// MGS3 copies 256x224 in Z24 from 0x2000 to 0x2080 (with a BW of 8, so half the screen), and then uses this as a
|
||||
// Z buffer. So, we effectively have two buffers within one, overlapping, at the 256 pixel point, colour on left,
|
||||
// depth on right. Our texture cache can't handle that, and it thinks it's one big target, so when it does look up
|
||||
// Z at 0x2080, it misses and loads from local memory instead, which of course, is junk. This is for the depth of
|
||||
// field effect (MGS3-DOF.gs).
|
||||
|
||||
// We could fix this up at the time the Z data actually gets used, but that doubles the amount of copies we need to
|
||||
// do, since OI fixes can't access the dirty area. So, instead, we'll just fudge the FBP when it copies 0x2000 to
|
||||
// 0x2080, which normally happens with a 256 pixel offset, so we have to subtract that from the sprite verts too.
|
||||
|
||||
// Drawing with FPSM of Z24 is pretty unlikely, so hopefully this doesn't hit any false positives.
|
||||
if (RFPSM != PSMZ24 || RTPSM != PSMZ24 || !RTME)
|
||||
return false;
|
||||
|
||||
// For some reason, instead of being sensible and masking Z, they set up AFAIL instead.
|
||||
if (!RZMSK)
|
||||
{
|
||||
u32 fm = 0, fm_mask = 0, zm = 0;
|
||||
if (!r.m_cached_ctx.TEST.ATE || !r.TryAlphaTest(fm, fm_mask, zm) || zm == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
const int w_sub = (RFBW / 2) * 64;
|
||||
const u32 w_sub_fp = w_sub << 4;
|
||||
r.m_cached_ctx.FRAME.FBP += RFBW / 2;
|
||||
|
||||
GL_INS("OI_MetalGearSolid3(): %x -> %x, %dx%d, subtract %d", RFBP, RFBP + (RFBW / 2), r.m_r.width(), r.m_r.height(),
|
||||
w_sub);
|
||||
|
||||
for (u32 i = 0; i < r.m_vertex.next; i++)
|
||||
r.m_vertex.buff[i].XYZ.X -= w_sub_fp;
|
||||
|
||||
// No point adjusting the scissor, it just ends up expanding out anyway.. but we do have to fix up the draw rect.
|
||||
r.m_r -= GSVector4i(w_sub);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
const u32 n_vertices = r.m_vertex.next;
|
||||
@@ -698,7 +737,7 @@ bool GSHwHack::OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds
|
||||
{
|
||||
const u32 FBP = r.m_cached_ctx.FRAME.Block();
|
||||
const u32 FBW = r.m_cached_ctx.FRAME.FBW;
|
||||
GL_INS("PointListPalette - m_r = <%d, %d => %d, %d>, n_vertices = %zu, FBP = 0x%x, FBW = %u", r.m_r.x, r.m_r.y, r.m_r.z, r.m_r.w, n_vertices, FBP, FBW);
|
||||
GL_INS("PointListPalette - m_r = <%d, %d => %d, %d>, n_vertices = %u, FBP = 0x%x, FBW = %u", r.m_r.x, r.m_r.y, r.m_r.z, r.m_r.w, n_vertices, FBP, FBW);
|
||||
const GSVertex* RESTRICT v = r.m_vertex.buff;
|
||||
const int ox(r.m_context->XYOFFSET.OFX);
|
||||
const int oy(r.m_context->XYOFFSET.OFY);
|
||||
@@ -775,11 +814,11 @@ bool GSHwHack::OI_FFX(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCa
|
||||
const u32 ZBP = RZBUF.Block();
|
||||
const u32 TBP = RTEX0.TBP0;
|
||||
|
||||
if ((FBP == 0x00d00 || FBP == 0x00000) && ZBP == 0x02100 && RPRIM->TME && TBP == 0x01a00 && RTEX0.PSM == PSMCT16S)
|
||||
if (ds && (FBP == 0x00d00 || FBP == 0x00000) && ZBP == 0x02100 && RPRIM->TME && TBP == 0x01a00 && RTEX0.PSM == PSMCT16S)
|
||||
{
|
||||
// random battle transition (z buffer written directly, clear it now)
|
||||
GL_INS("OI_FFX ZB clear");
|
||||
g_gs_device->ClearDepth(ds);
|
||||
g_gs_device->ClearDepth(ds, 0.0f);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -823,7 +862,7 @@ bool GSHwHack::OI_RozenMaidenGebetGarden(GSRendererHW& r, GSTexture* rt, GSTextu
|
||||
if (GSTextureCache::Target* tmp_ds = g_texture_cache->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil))
|
||||
{
|
||||
GL_INS("OI_RozenMaidenGebetGarden ZB clear");
|
||||
g_gs_device->ClearDepth(tmp_ds->m_texture);
|
||||
g_gs_device->ClearDepth(tmp_ds->m_texture, 0.0f);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -848,13 +887,16 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
||||
Frame.TBP0 = RFRAME.Block();
|
||||
Frame.PSM = RFRAME.PSM;
|
||||
|
||||
if ((!RPRIM->TME) || (GSLocalMemory::m_psm[Texture.PSM].bpp != 16) || (GSLocalMemory::m_psm[Frame.PSM].bpp != 16) || (Texture.TBP0 == Frame.TBP0) || (Frame.TBW != 16 && Texture.TBW != 16))
|
||||
if ((!rt) || (!RPRIM->TME) || (GSLocalMemory::m_psm[Texture.PSM].bpp != 16) || (GSLocalMemory::m_psm[Frame.PSM].bpp != 16) || (Texture.TBP0 == Frame.TBP0) || (Frame.TBW != 16 && Texture.TBW != 16))
|
||||
return true;
|
||||
|
||||
GL_INS("OI_SonicUnleashed replace draw by a copy");
|
||||
|
||||
GSTextureCache::Target* src = g_texture_cache->LookupTarget(Texture, GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget);
|
||||
|
||||
if (!src)
|
||||
return true;
|
||||
|
||||
const GSVector2i src_size(src->m_texture->GetSize());
|
||||
GSVector2i rt_size(rt->GetSize());
|
||||
|
||||
@@ -906,10 +948,10 @@ bool GSHwHack::OI_ArTonelico2(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GST
|
||||
|
||||
const GSVertex* v = &r.m_vertex.buff[0];
|
||||
|
||||
if (r.m_vertex.next == 2 && !RPRIM->TME && RFRAME.FBW == 10 && v->XYZ.Z == 0 && RTEST.ZTST == ZTST_ALWAYS)
|
||||
if (ds && r.m_vertex.next == 2 && !RPRIM->TME && RFRAME.FBW == 10 && v->XYZ.Z == 0 && RTEST.ZTST == ZTST_ALWAYS)
|
||||
{
|
||||
GL_INS("OI_ArTonelico2");
|
||||
g_gs_device->ClearDepth(ds);
|
||||
g_gs_device->ClearDepth(ds, 0.0f);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -946,7 +988,7 @@ bool GSHwHack::GSC_Battlefield2(GSRendererHW& r, int& skip)
|
||||
GSTextureCache::Target* dst = g_texture_cache->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil);
|
||||
if (dst)
|
||||
{
|
||||
g_gs_device->ClearDepth(dst->m_texture);
|
||||
g_gs_device->ClearDepth(dst->m_texture, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1084,6 +1126,7 @@ const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_function
|
||||
CRC_F(GSC_Battlefield2),
|
||||
CRC_F(GSC_NFSUndercover),
|
||||
CRC_F(GSC_PolyphonyDigitalGames),
|
||||
CRC_F(GSC_MetalGearSolid3),
|
||||
|
||||
// Channel Effect
|
||||
CRC_F(GSC_GiTS),
|
||||
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
static bool GSC_Battlefield2(GSRendererHW& r, int& skip);
|
||||
static bool GSC_NFSUndercover(GSRendererHW& r, int& skip);
|
||||
static bool GSC_PolyphonyDigitalGames(GSRendererHW& r, int& skip);
|
||||
static bool GSC_MetalGearSolid3(GSRendererHW& r, int& skip);
|
||||
|
||||
static bool OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_BigMuthaTruckers(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
|
||||
@@ -151,8 +151,10 @@ void GSRendererHW::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
|
||||
if (g_texture_cache->GetHashCacheMemoryUsage() > 1024 * 1024 * 1024)
|
||||
{
|
||||
Host::AddKeyedFormattedOSDMessage("HashCacheOverflow", Host::OSD_ERROR_DURATION, "Hash cache has used %.2f MB of VRAM, disabling.",
|
||||
static_cast<float>(g_texture_cache->GetHashCacheMemoryUsage()) / 1048576.0f);
|
||||
Host::AddKeyedOSDMessage("HashCacheOverflow",
|
||||
fmt::format(TRANSLATE_SV("GS", "Hash cache has used {:.2f} MB of VRAM, disabling."),
|
||||
static_cast<float>(g_texture_cache->GetHashCacheMemoryUsage()) / 1048576.0f),
|
||||
Host::OSD_ERROR_DURATION);
|
||||
g_texture_cache->RemoveAll();
|
||||
g_gs_device->PurgePool();
|
||||
GSConfig.TexturePreloading = TexturePreloadingLevel::Partial;
|
||||
@@ -1522,6 +1524,7 @@ void GSRendererHW::Draw()
|
||||
m_cached_ctx.TEST = context->TEST;
|
||||
m_cached_ctx.FRAME = context->FRAME;
|
||||
m_cached_ctx.ZBUF = context->ZBUF;
|
||||
m_primitive_covers_without_gaps.reset();
|
||||
|
||||
if (IsBadFrame())
|
||||
{
|
||||
@@ -1660,16 +1663,31 @@ void GSRendererHW::Draw()
|
||||
const bool draw_sprite_tex = PRIM->TME && (m_vt.m_primclass == GS_SPRITE_CLASS);
|
||||
|
||||
// We trigger the sw prim render here super early, to avoid creating superfluous render targets.
|
||||
if (CanUseSwPrimRender(no_rt, no_ds, draw_sprite_tex) && SwPrimRender(*this, true))
|
||||
if (CanUseSwPrimRender(no_rt, no_ds, draw_sprite_tex) && SwPrimRender(*this, true, true))
|
||||
{
|
||||
GL_CACHE("Possible texture decompression, drawn with SwPrimRender() (BP %x BW %u TBP0 %x TBW %u)",
|
||||
m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBMSK, m_cached_ctx.TEX0.TBP0, m_cached_ctx.TEX0.TBW);
|
||||
return;
|
||||
}
|
||||
|
||||
// The rectangle of the draw rounded up.
|
||||
const GSVector4 rect = m_vt.m_min.p.upld(m_vt.m_max.p + GSVector4::cxpr(0.5f));
|
||||
m_r = GSVector4i(rect).rintersect(context->scissor.in);
|
||||
// GS doesn't fill the right or bottom edges of sprites/triangles, and for a pixel to be shaded, the vertex
|
||||
// must cross the center. In other words, the range is equal to the floor of coordinates +0.5. Except for
|
||||
// the case where the minimum equals the maximum, because at least one pixel is filled per line.
|
||||
// Test cases for the math:
|
||||
// --------------------------------------
|
||||
// | Position range | Draw Range | Size |
|
||||
// | -0.5,0.0 | 0-0 | 1 |
|
||||
// | -0.5,0.5 | 0-0 | 1 |
|
||||
// | 0,1 | 0-0 | 1 |
|
||||
// | 0,1.5 | 0-1 | 2 |
|
||||
// | 0.5,1.5 | 1-1 | 1 |
|
||||
// | 0.5,1.75 | 1-1 | 1 |
|
||||
// | 0.5,2.25 | 1-1 | 1 |
|
||||
// | 0.5,2.5 | 1-2 | 2 |
|
||||
// --------------------------------------
|
||||
m_r = GSVector4i(m_vt.m_min.p.upld(m_vt.m_max.p) + GSVector4::cxpr(0.5f));
|
||||
m_r = m_r.blend8(m_r + GSVector4i::cxpr(0, 0, 1, 1), (m_r.xyxy() == m_r.zwzw()));
|
||||
m_r = m_r.rintersect(context->scissor.in);
|
||||
|
||||
const bool process_texture = PRIM->TME && !(PRIM->ABE && m_context->ALPHA.IsBlack() && !m_cached_ctx.TEX0.TCC);
|
||||
const u32 frame_end_bp = GSLocalMemory::GetEndBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r);
|
||||
@@ -1682,7 +1700,7 @@ void GSRendererHW::Draw()
|
||||
m_mem.m_clut.ClearDrawInvalidity();
|
||||
if (result == CLUTDrawTestResult::CLUTDrawOnCPU && GSConfig.UserHacks_CPUCLUTRender > 0)
|
||||
{
|
||||
if (SwPrimRender(*this, true))
|
||||
if (SwPrimRender(*this, true, true))
|
||||
{
|
||||
GL_CACHE("Possible clut draw, drawn with SwPrimRender()");
|
||||
return;
|
||||
@@ -1700,7 +1718,8 @@ void GSRendererHW::Draw()
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (((fm & fm_mask) != 0) || // Some channels masked
|
||||
|
||||
if (((fm & fm_mask) != 0) || // Some channels masked
|
||||
!IsDiscardingDstColor() || !PrimitiveCoversWithoutGaps() || // Using Dst Color or draw has gaps
|
||||
(process_texture && m_cached_ctx.TEX0.TBP0 >= m_cached_ctx.FRAME.Block() && m_cached_ctx.TEX0.TBP0 < frame_end_bp)) // Tex is RT
|
||||
{
|
||||
@@ -5146,7 +5165,7 @@ void GSRendererHW::OI_DoubleHalfClear(GSTextureCache::Target*& rt, GSTextureCach
|
||||
{
|
||||
// Only pure clear are supported for depth
|
||||
ASSERT(color == 0);
|
||||
g_gs_device->ClearDepth(tex);
|
||||
g_gs_device->ClearDepth(tex, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5168,7 +5187,7 @@ void GSRendererHW::OI_DoubleHalfClear(GSTextureCache::Target*& rt, GSTextureCach
|
||||
{
|
||||
// Only pure clear are supported for depth
|
||||
ASSERT(color == 0);
|
||||
g_gs_device->ClearDepth(ds->m_texture);
|
||||
g_gs_device->ClearDepth(ds->m_texture, 0.0f);
|
||||
ds->UpdateValidity(ds->GetUnscaledRect());
|
||||
}
|
||||
else
|
||||
@@ -5293,12 +5312,11 @@ void GSRendererHW::OI_DoGsMemClear(const GSOffset& off, const GSVector4i& r, u32
|
||||
{
|
||||
const GSVector4i vcolor = GSVector4i(color);
|
||||
const u32 iterations_per_page = (pages_wide * pixels_per_page) / 4;
|
||||
|
||||
for (; top < page_aligned_bottom; top += pgs.y)
|
||||
pxAssert((off.bp() & (BLOCKS_PER_PAGE - 1)) == 0);
|
||||
for (u32 current_page = off.bp() >> 5; top < page_aligned_bottom; top += pgs.y, current_page += pages_wide)
|
||||
{
|
||||
auto pa = off.assertSizesMatch(GSLocalMemory::swizzle32).paMulti(m_mem.vm32(), 0, top);
|
||||
GSVector4i* ptr = reinterpret_cast<GSVector4i*>(pa.value(0));
|
||||
GSVector4i* const ptr_end = reinterpret_cast<GSVector4i*>(pa.value(0)) + iterations_per_page;
|
||||
GSVector4i* ptr = reinterpret_cast<GSVector4i*>(m_mem.vm8() + current_page * PAGE_SIZE);
|
||||
GSVector4i* const ptr_end = ptr + iterations_per_page;
|
||||
while (ptr != ptr_end)
|
||||
*(ptr++) = vcolor;
|
||||
}
|
||||
@@ -5308,12 +5326,11 @@ void GSRendererHW::OI_DoGsMemClear(const GSOffset& off, const GSVector4i& r, u32
|
||||
const GSVector4i mask = GSVector4i::xff000000();
|
||||
const GSVector4i vcolor = GSVector4i(color & 0x00ffffffu);
|
||||
const u32 iterations_per_page = (pages_wide * pixels_per_page) / 4;
|
||||
|
||||
for (; top < page_aligned_bottom; top += pgs.y)
|
||||
pxAssert((off.bp() & (BLOCKS_PER_PAGE - 1)) == 0);
|
||||
for (u32 current_page = off.bp() >> 5; top < page_aligned_bottom; top += pgs.y, current_page += pages_wide)
|
||||
{
|
||||
auto pa = off.assertSizesMatch(GSLocalMemory::swizzle32).paMulti(m_mem.vm32(), 0, top);
|
||||
GSVector4i* ptr = reinterpret_cast<GSVector4i*>(pa.value(0));
|
||||
GSVector4i* const ptr_end = reinterpret_cast<GSVector4i*>(pa.value(0)) + iterations_per_page;
|
||||
GSVector4i* ptr = reinterpret_cast<GSVector4i*>(m_mem.vm8() + current_page * PAGE_SIZE);
|
||||
GSVector4i* const ptr_end = ptr + iterations_per_page;
|
||||
while (ptr != ptr_end)
|
||||
{
|
||||
*ptr = (*ptr & mask) | vcolor;
|
||||
@@ -5323,16 +5340,15 @@ void GSRendererHW::OI_DoGsMemClear(const GSOffset& off, const GSVector4i& r, u32
|
||||
}
|
||||
else if (format == 2)
|
||||
{
|
||||
const u16 converted_color = ((vert_color >> 16) & 0x8000) | ((vert_color >> 9) & 0x7C00) | ((vert_color >> 6) & 0x7E0) | ((vert_color >> 3) & 0x1F);
|
||||
|
||||
const u16 converted_color = ((vert_color >> 16) & 0x8000) | ((vert_color >> 9) & 0x7C00) |
|
||||
((vert_color >> 6) & 0x7E0) | ((vert_color >> 3) & 0x1F);
|
||||
const GSVector4i vcolor = GSVector4i::broadcast16(converted_color);
|
||||
const u32 iterations_per_page = (pages_wide * pixels_per_page) / 8;
|
||||
|
||||
for (; top < page_aligned_bottom; top += pgs.y)
|
||||
pxAssert((off.bp() & (BLOCKS_PER_PAGE - 1)) == 0);
|
||||
for (u32 current_page = off.bp() >> 5; top < page_aligned_bottom; top += pgs.y, current_page += pages_wide)
|
||||
{
|
||||
auto pa = off.assertSizesMatch(GSLocalMemory::swizzle16).paMulti(m_mem.vm16(), 0, top);
|
||||
GSVector4i* ptr = reinterpret_cast<GSVector4i*>(pa.value(0));
|
||||
GSVector4i* const ptr_end = reinterpret_cast<GSVector4i*>(pa.value(0)) + iterations_per_page;
|
||||
GSVector4i* ptr = reinterpret_cast<GSVector4i*>(m_mem.vm8() + current_page * PAGE_SIZE);
|
||||
GSVector4i* const ptr_end = ptr + iterations_per_page;
|
||||
while (ptr != ptr_end)
|
||||
*(ptr++) = vcolor;
|
||||
}
|
||||
@@ -5451,21 +5467,36 @@ bool GSRendererHW::IsDiscardingDstColor()
|
||||
!m_cached_ctx.TEST.DATE;
|
||||
}
|
||||
|
||||
bool GSRendererHW::PrimitiveCoversWithoutGaps() const
|
||||
bool GSRendererHW::PrimitiveCoversWithoutGaps()
|
||||
{
|
||||
if (m_primitive_covers_without_gaps.has_value())
|
||||
return m_primitive_covers_without_gaps.value();
|
||||
|
||||
// Draw shouldn't be offset.
|
||||
if (((m_r.eq32(GSVector4i::zero())).mask() & 0xff) != 0xff)
|
||||
{
|
||||
m_primitive_covers_without_gaps = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is potentially wrong for fans/strips...
|
||||
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
|
||||
return (m_index.tail == 6);
|
||||
{
|
||||
m_primitive_covers_without_gaps = (m_index.tail == 6);
|
||||
return m_primitive_covers_without_gaps.value();
|
||||
}
|
||||
else if (m_vt.m_primclass != GS_SPRITE_CLASS)
|
||||
{
|
||||
m_primitive_covers_without_gaps = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Simple case: one sprite.
|
||||
if (m_index.tail == 2)
|
||||
{
|
||||
m_primitive_covers_without_gaps = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check that the height matches. Xenosaga 3 draws a letterbox around
|
||||
// the FMV with a sprite at the top and bottom of the framebuffer.
|
||||
@@ -5482,7 +5513,10 @@ bool GSRendererHW::PrimitiveCoversWithoutGaps() const
|
||||
{
|
||||
const u32 dpY = v[i + 1].XYZ.Y - v[i].XYZ.Y;
|
||||
if (dpY != first_dpY || v[i].XYZ.Y != last_pY)
|
||||
{
|
||||
m_primitive_covers_without_gaps = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
last_pY = v[i + 1].XYZ.Y;
|
||||
}
|
||||
@@ -5499,14 +5533,19 @@ bool GSRendererHW::PrimitiveCoversWithoutGaps() const
|
||||
{
|
||||
const u32 dpX = v[i + 1].XYZ.X - v[i].XYZ.X;
|
||||
if (dpX != first_dpX || v[i].XYZ.X != last_pX)
|
||||
{
|
||||
m_primitive_covers_without_gaps = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
last_pX = v[i + 1].XYZ.X;
|
||||
}
|
||||
|
||||
m_primitive_covers_without_gaps = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
m_primitive_covers_without_gaps = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5526,6 +5565,45 @@ bool GSRendererHW::IsConstantDirectWriteMemClear()
|
||||
return false;
|
||||
}
|
||||
|
||||
void GSRendererHW::ReplaceVerticesWithSprite(const GSVector4i& unscaled_rect, const GSVector4i& unscaled_uv_rect,
|
||||
const GSVector2i& unscaled_size, const GSVector4i& scissor)
|
||||
{
|
||||
const GSVector4i fpr = unscaled_rect.sll32(4);
|
||||
const GSVector4i fpuv = unscaled_uv_rect.sll32(4);
|
||||
GSVertex* v = m_vertex.buff;
|
||||
|
||||
v[0].XYZ.X = static_cast<u16>(m_context->XYOFFSET.OFX + fpr.x);
|
||||
v[0].XYZ.Y = static_cast<u16>(m_context->XYOFFSET.OFY + fpr.y);
|
||||
|
||||
v[1].XYZ.X = static_cast<u16>(m_context->XYOFFSET.OFX + fpr.z);
|
||||
v[1].XYZ.Y = static_cast<u16>(m_context->XYOFFSET.OFY + fpr.w);
|
||||
|
||||
if (PRIM->FST)
|
||||
{
|
||||
v[0].U = fpuv.x;
|
||||
v[0].V = fpuv.y;
|
||||
v[1].U = fpuv.z;
|
||||
v[1].V = fpuv.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
const GSVector4 st = GSVector4(unscaled_uv_rect) / GSVector4(GSVector4i(unscaled_size).xyxy());
|
||||
GSVector4::storel(&v[0].ST.S, st);
|
||||
GSVector4::storeh(&v[1].ST.S, st);
|
||||
}
|
||||
|
||||
m_vertex.head = m_vertex.tail = m_vertex.next = 2;
|
||||
m_index.tail = 2;
|
||||
|
||||
m_r = unscaled_rect;
|
||||
m_context->scissor.in = scissor;
|
||||
}
|
||||
|
||||
void GSRendererHW::ReplaceVerticesWithSprite(const GSVector4i& unscaled_rect, const GSVector2i& unscaled_size)
|
||||
{
|
||||
ReplaceVerticesWithSprite(unscaled_rect, unscaled_rect, unscaled_size, unscaled_rect);
|
||||
}
|
||||
|
||||
GSHWDrawConfig& GSRendererHW::BeginHLEHardwareDraw(
|
||||
GSTexture* rt, GSTexture* ds, float rt_scale, GSTexture* tex, float tex_scale, const GSVector4i& unscaled_rect)
|
||||
{
|
||||
|
||||
@@ -55,7 +55,7 @@ private:
|
||||
bool CanUseSwSpriteRender();
|
||||
bool IsConstantDirectWriteMemClear();
|
||||
bool IsDiscardingDstColor();
|
||||
bool PrimitiveCoversWithoutGaps() const;
|
||||
bool PrimitiveCoversWithoutGaps();
|
||||
|
||||
enum class CLUTDrawTestResult
|
||||
{
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
CLUTDrawTestResult PossibleCLUTDraw();
|
||||
CLUTDrawTestResult PossibleCLUTDrawAggressive();
|
||||
bool CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_tex);
|
||||
bool (*SwPrimRender)(GSRendererHW&, bool invalidate_tc);
|
||||
bool (*SwPrimRender)(GSRendererHW&, bool invalidate_tc, bool add_ee_transfer);
|
||||
|
||||
template <bool linear>
|
||||
void RoundSpriteOffset();
|
||||
@@ -147,6 +147,7 @@ private:
|
||||
u32 m_split_clear_pages = 0; // if zero, inactive
|
||||
u32 m_split_clear_color = 0;
|
||||
|
||||
std::optional<bool> m_primitive_covers_without_gaps;
|
||||
bool m_userhacks_tcoffset = false;
|
||||
float m_userhacks_tcoffset_x = 0.0f;
|
||||
float m_userhacks_tcoffset_y = 0.0f;
|
||||
@@ -204,6 +205,11 @@ public:
|
||||
/// Returns true if the specified texture address matches the frame or Z buffer.
|
||||
bool IsTBPFrameOrZ(u32 tbp) const;
|
||||
|
||||
/// Replaces vertices with the specified fullscreen quad.
|
||||
void ReplaceVerticesWithSprite(const GSVector4i& unscaled_rect, const GSVector4i& unscaled_uv_rect,
|
||||
const GSVector2i& unscaled_size, const GSVector4i& scissor);
|
||||
void ReplaceVerticesWithSprite(const GSVector4i& unscaled_rect, const GSVector2i& unscaled_size);
|
||||
|
||||
/// Starts a HLE'ed hardware draw, which can be further customized by the caller.
|
||||
GSHWDrawConfig& BeginHLEHardwareDraw(
|
||||
GSTexture* rt, GSTexture* ds, float rt_scale, GSTexture* tex, float tex_scale, const GSVector4i& unscaled_rect);
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
class CURRENT_ISA::GSRendererHWFunctions
|
||||
{
|
||||
public:
|
||||
static bool SwPrimRender(GSRendererHW& hw, bool invalidate_tc);
|
||||
static bool SwPrimRender(GSRendererHW& hw, bool invalidate_tc, bool add_ee_transfer);
|
||||
|
||||
static void Populate(GSRendererHW& renderer)
|
||||
{
|
||||
@@ -40,7 +40,7 @@ void CURRENT_ISA::GSRendererHWPopulateFunctions(GSRendererHW& renderer)
|
||||
static GSVector4i s_dimx_storage[8];
|
||||
static GIFRegDIMX s_last_dimx;
|
||||
|
||||
bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc)
|
||||
bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc, bool add_ee_transfer)
|
||||
{
|
||||
GSVertexTrace& vt = hw.m_vt;
|
||||
const GIFRegPRIM* PRIM = hw.PRIM;
|
||||
@@ -68,7 +68,7 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc)
|
||||
GSVertexSW::s_cvb[vt.m_primclass][PRIM->TME][PRIM->FST][q_div](context, data.vertex, hw.m_vertex.buff, hw.m_vertex.next);
|
||||
|
||||
GSVector4i scissor = context->scissor.in;
|
||||
GSVector4i bbox = GSVector4i(vt.m_min.p.floor().xyxy(vt.m_max.p.ceil()));
|
||||
GSVector4i bbox = GSVector4i(vt.m_min.p.floor().xyxy(vt.m_max.p.ceil())).rintersect(scissor);
|
||||
|
||||
// Points and lines may have zero area bbox (single line: 0, 0 - 256, 0)
|
||||
|
||||
@@ -557,5 +557,18 @@ bool GSRendererHWFunctions::SwPrimRender(GSRendererHW& hw, bool invalidate_tc)
|
||||
if (invalidate_tc)
|
||||
g_texture_cache->InvalidateVideoMem(context->offset.fb, bbox);
|
||||
|
||||
// Jak does sw prim render, then draws to the same target, and it needs to be uploaded.
|
||||
if (add_ee_transfer)
|
||||
{
|
||||
GSRendererHW::GSUploadQueue uq;
|
||||
uq.blit.U64 = 0;
|
||||
uq.blit.DBP = hw.m_cached_ctx.FRAME.Block();
|
||||
uq.blit.DBW = hw.m_cached_ctx.FRAME.FBW;
|
||||
uq.blit.DPSM = hw.m_cached_ctx.FRAME.PSM;
|
||||
uq.draw = GSState::s_n;
|
||||
uq.rect = bbox;
|
||||
hw.m_draw_transfers.push_back(uq);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1711,9 +1711,9 @@ void GSTextureCache::InvalidateVideoMemType(int type, u32 bp)
|
||||
// Called each time you want to write to the GS memory
|
||||
void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& rect, bool eewrite, bool target)
|
||||
{
|
||||
u32 bp = off.bp();
|
||||
u32 bw = off.bw();
|
||||
u32 psm = off.psm();
|
||||
const u32 bp = off.bp();
|
||||
const u32 bw = off.bw();
|
||||
const u32 psm = off.psm();
|
||||
|
||||
if (!target)
|
||||
{
|
||||
@@ -1823,8 +1823,11 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
// Handle the case where the transfer wrapped around the end of GS memory.
|
||||
const u32 end_bp = off.bnNoWrap(rect.z - 1, rect.w - 1);
|
||||
// Get the bounds that we're invalidating in blocks, so we can remove any targets which are completely contained.
|
||||
// Unfortunately sometimes the draw rect is incorrect, and since the end block gets the rect -1, it'll underflow,
|
||||
// so we need to prevent that from happening. Just make it a single block in that case, and hope for the best.
|
||||
const u32 start_bp = GSLocalMemory::GetStartBlockAddress(off.bp(), off.bw(), off.psm(), rect);
|
||||
const u32 end_bp = rect.rempty() ? start_bp : GSLocalMemory::GetEndBlockAddress(off.bp(), off.bw(), off.psm(), rect);
|
||||
|
||||
// Ideally in the future we can turn this on unconditionally, but for now it breaks too much.
|
||||
const bool check_inside_target = (GSConfig.UserHacks_TargetPartialInvalidation ||
|
||||
@@ -2063,6 +2066,26 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r
|
||||
// TODO Use ComputeSurfaceOffset below.
|
||||
if (GSUtil::HasSharedBits(psm, t->m_TEX0.PSM))
|
||||
{
|
||||
if (t->m_TEX0.TBP0 >= start_bp && t->m_end_block <= end_bp)
|
||||
{
|
||||
// If we're clearing C24 but the target is C32, then we need to dirty instead.
|
||||
if (rgba._u32 != GSUtil::GetChannelMask(t->m_TEX0.PSM))
|
||||
{
|
||||
GL_CACHE("TC: Dirty whole target(%s) (0x%x) due to being contained within the invalidate range",
|
||||
to_string(type), t->m_TEX0.TBP0);
|
||||
AddDirtyRectTarget(t, t->GetUnscaledRect(), t->m_TEX0.PSM, t->m_TEX0.TBW, rgba);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = list.erase(j);
|
||||
GL_CACHE("TC: Remove Target(%s) (0x%x) due to being contained within the invalidate range",
|
||||
to_string(type), t->m_TEX0.TBP0);
|
||||
delete t;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (bp < t->m_TEX0.TBP0)
|
||||
{
|
||||
const u32 rowsize = bw * 8192;
|
||||
@@ -2583,9 +2606,10 @@ void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r
|
||||
bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u32 DBW, u32 DPSM, int dx, int dy, int w, int h)
|
||||
{
|
||||
if (SBP == DBP && SPSM == DPSM && !GSLocalMemory::m_psm[SPSM].depth && ShuffleMove(SBP, SBW, SPSM, sx, sy, dx, dy, w, h))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (SPSM == DPSM && SBW == 1 && SBW == DBW && PageMove(SBP, DBP, SBW, SPSM, sx, sy, dx, dy, w, h))
|
||||
return true;
|
||||
|
||||
// TODO: In theory we could do channel swapping on the GPU, but we haven't found anything which needs it so far.
|
||||
if (SPSM != DPSM)
|
||||
@@ -2797,6 +2821,108 @@ bool GSTextureCache::ShuffleMove(u32 BP, u32 BW, u32 PSM, int sx, int sy, int dx
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSTextureCache::PageMove(u32 SBP, u32 DBP, u32 BW, u32 PSM, int sx, int sy, int dx, int dy, int w, int h)
|
||||
{
|
||||
// Only supports 1-wide at the moment.
|
||||
pxAssert(BW == 1);
|
||||
|
||||
const GSVector4i src = GSVector4i(sx, sy, sx + w, sy + h);
|
||||
const GSVector4i drc = GSVector4i(dx, dy, dx + w, dy + h);
|
||||
if (!GSLocalMemory::IsPageAligned(PSM, src) || !GSLocalMemory::IsPageAligned(PSM, drc))
|
||||
return false;
|
||||
|
||||
// How many pages are we dealing with?
|
||||
const GSVector2i& pgs = GSLocalMemory::m_psm[PSM].pgs;
|
||||
const u32 num_pages = (h / pgs.y) * BW;
|
||||
const u32 src_page_offset = ((sy / pgs.y) * BW) + (sx / pgs.x);
|
||||
const u32 src_block_end = SBP + (((src_page_offset + num_pages) * BLOCKS_PER_PAGE) - 1);
|
||||
const u32 dst_page_offset = ((dy / pgs.y) * BW) + (dx / pgs.x);
|
||||
const u32 dst_block_end = DBP + (((dst_page_offset + num_pages) * BLOCKS_PER_PAGE) - 1);
|
||||
pxAssert(num_pages > 0);
|
||||
GL_PUSH("GSTextureCache::PageMove(): %u pages, with offset of %u src %u dst", num_pages, src_page_offset,
|
||||
dst_page_offset);
|
||||
|
||||
// Find our targets.
|
||||
Target* stgt = nullptr;
|
||||
Target* dtgt = nullptr;
|
||||
for (int type = 0; type < 2; type++)
|
||||
{
|
||||
for (Target* tgt : m_dst[type])
|
||||
{
|
||||
// We _could_ do compatible bits here maybe?
|
||||
if (tgt->m_TEX0.PSM != PSM)
|
||||
continue;
|
||||
|
||||
// Check that the end block is in range. If it's not, we can't do this, and have to fall back to local memory.
|
||||
const u32 tgt_end = tgt->UnwrappedEndBlock();
|
||||
if (tgt->m_TEX0.TBP0 <= SBP && src_block_end <= tgt_end)
|
||||
stgt = tgt;
|
||||
if (tgt->m_TEX0.TBP0 <= DBP && dst_block_end <= tgt_end)
|
||||
dtgt = tgt;
|
||||
|
||||
if (stgt && dtgt)
|
||||
break;
|
||||
}
|
||||
|
||||
if (stgt && dtgt)
|
||||
break;
|
||||
}
|
||||
if (!stgt || !dtgt)
|
||||
{
|
||||
GL_INS("Targets not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Double-check that we're not copying to a non-page-aligned target.
|
||||
if (((SBP - stgt->m_TEX0.TBP0) % BLOCKS_PER_PAGE) != 0 || ((DBP - dtgt->m_TEX0.TBP0) % BLOCKS_PER_PAGE) != 0)
|
||||
{
|
||||
GL_INS("Effective SBP of %x or DBP of %x is not page aligned.", SBP - stgt->m_TEX0.TBP0, DBP - dtgt->m_TEX0.TBP0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Need to offset based on the target's actual BP.
|
||||
const u32 real_src_offset = ((SBP - stgt->m_TEX0.TBP0) / BLOCKS_PER_PAGE) + src_page_offset;
|
||||
const u32 real_dst_offset = ((DBP - dtgt->m_TEX0.TBP0) / BLOCKS_PER_PAGE) + dst_page_offset;
|
||||
CopyPages(stgt, stgt->m_TEX0.TBW, real_src_offset, dtgt, dtgt->m_TEX0.TBW, real_dst_offset, num_pages);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GSTextureCache::CopyPages(Target* src, u32 sbw, u32 src_offset, Target* dst, u32 dbw, u32 dst_offset, u32 num_pages, ShaderConvert shader)
|
||||
{
|
||||
GL_PUSH("GSTextureCache::CopyPages(): %u pages at %x[eff %x] BW %u to %x[eff %x] BW %u", num_pages,
|
||||
src->m_TEX0.TBP0, src->m_TEX0.TBP0 + src_offset, sbw, dst->m_TEX0.TBP0, dst->m_TEX0.TBP0 + dst_offset, dbw);
|
||||
|
||||
// Create rectangles for the pages.
|
||||
const GSVector2i& pgs = GSLocalMemory::m_psm[dst->m_TEX0.PSM].pgs;
|
||||
const GSVector4i page_rc = GSVector4i::loadh(pgs);
|
||||
const GSVector4 src_size = GSVector4(src->GetUnscaledSize()).xyxy();
|
||||
const GSVector4 dst_scale = GSVector4(dst->GetScale());
|
||||
GSDevice::MultiStretchRect* rects = static_cast<GSDevice::MultiStretchRect*>(alloca(sizeof(GSDevice::MultiStretchRect) * num_pages));
|
||||
for (u32 i = 0; i < num_pages; i++)
|
||||
{
|
||||
const u32 src_page_num = src_offset + i;
|
||||
const GSVector2i src_offset = GSVector2i((src_page_num % sbw) * pgs.x, (src_page_num / sbw) * pgs.y);
|
||||
const u32 dst_page_num = dst_offset + i;
|
||||
const GSVector2i dst_offset = GSVector2i((dst_page_num % dbw) * pgs.x, (dst_page_num / dbw) * pgs.y);
|
||||
|
||||
const GSVector4i src_rect = page_rc + GSVector4i(src_offset).xyxy();
|
||||
const GSVector4i dst_rect = page_rc + GSVector4i(dst_offset).xyxy();
|
||||
|
||||
GL_INS("Copy page %u @ <%d,%d=>%d,%d> to %u @ <%d,%d=>%d,%d>", src_page_num, src_rect.x, src_rect.y, src_rect.z,
|
||||
src_rect.w, dst_page_num, dst_rect.x, dst_rect.y, dst_rect.z, dst_rect.w);
|
||||
|
||||
GSDevice::MultiStretchRect& rc = rects[i];
|
||||
rc.src = src->m_texture;
|
||||
rc.src_rect = GSVector4(src_rect) / src_size;
|
||||
rc.dst_rect = GSVector4(dst_rect) * dst_scale;
|
||||
rc.linear = false;
|
||||
rc.wmask.wrgba = 0xf;
|
||||
}
|
||||
|
||||
// No need to sort here, it's all from the same texture.
|
||||
g_gs_device->DrawMultiStretchRects(rects, num_pages, dst->m_texture, shader);
|
||||
}
|
||||
|
||||
GSTextureCache::Target* GSTextureCache::GetExactTarget(u32 BP, u32 BW, int type, u32 end_bp)
|
||||
{
|
||||
auto& rts = m_dst[type];
|
||||
@@ -4765,9 +4891,9 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca
|
||||
{
|
||||
// Otherwise just pass the clear through.
|
||||
if (tex->GetType() != GSTexture::Type::DepthStencil)
|
||||
g_gs_device->ClearRenderTarget(tex, tex->GetClearColor());
|
||||
g_gs_device->ClearRenderTarget(tex, m_texture->GetClearColor());
|
||||
else
|
||||
g_gs_device->ClearDepth(tex/*, tex->GetClearDepth()*/);
|
||||
g_gs_device->ClearDepth(tex, m_texture->GetClearDepth());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -480,6 +480,9 @@ public:
|
||||
|
||||
bool Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u32 DBW, u32 DPSM, int dx, int dy, int w, int h);
|
||||
bool ShuffleMove(u32 BP, u32 BW, u32 PSM, int sx, int sy, int dx, int dy, int w, int h);
|
||||
bool PageMove(u32 SBP, u32 DBP, u32 BW, u32 PSM, int sx, int sy, int dx, int dy, int w, int h);
|
||||
void CopyPages(Target* src, u32 sbw, u32 src_offset, Target* dst, u32 dbw, u32 dst_offset, u32 num_pages,
|
||||
ShaderConvert shader = ShaderConvert::COPY);
|
||||
|
||||
void IncAge();
|
||||
|
||||
|
||||
@@ -575,10 +575,11 @@ GSTexture* GSTextureReplacements::CreateReplacementTexture(const ReplacementText
|
||||
static bool log_once = false;
|
||||
if (!log_once)
|
||||
{
|
||||
static const char* message =
|
||||
"Disabling autogenerated mipmaps on one or more compressed replacement textures. Please generate mipmaps when compressing your textures.";
|
||||
Console.Warning(message);
|
||||
Host::AddIconOSDMessage("DisablingReplacementAutoGeneratedMipmap", ICON_FA_EXCLAMATION_CIRCLE, message, Host::OSD_WARNING_DURATION);
|
||||
Console.Warning("Disabling autogenerated mipmaps on one or more compressed replacement textures.");
|
||||
Host::AddIconOSDMessage("DisablingReplacementAutoGeneratedMipmap", ICON_FA_EXCLAMATION_CIRCLE,
|
||||
TRANSLATE_SV("GS", "Disabling autogenerated mipmaps on one or more compressed replacement textures. "
|
||||
"Please generate mipmaps when compressing your textures."),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
log_once = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -367,7 +367,7 @@ public:
|
||||
|
||||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) override;
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) override;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) override;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) override;
|
||||
@@ -404,9 +404,8 @@ public:
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
void AccumulateCommandBufferTime(id<MTLCommandBuffer> buffer);
|
||||
|
||||
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
|
||||
void ClearRenderTarget(GSTexture* t, u32 c) override;
|
||||
void ClearDepth(GSTexture* t) override;
|
||||
void ClearDepth(GSTexture* t, float d) override;
|
||||
void InvalidateRenderTarget(GSTexture* t) override;
|
||||
|
||||
std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override;
|
||||
|
||||
@@ -410,7 +410,7 @@ void GSDeviceMTL::BeginRenderPass(NSString* name, GSTexture* color, MTLLoadActio
|
||||
} \
|
||||
}
|
||||
|
||||
CHECK_CLEAR(mc, color_load, color_clear, GetClearColor)
|
||||
CHECK_CLEAR(mc, color_load, color_clear, GetUNormClearColor)
|
||||
CHECK_CLEAR(md, depth_load, depth_clear, GetClearDepth)
|
||||
#undef CHECK_CLEAR
|
||||
// Stencil and depth are one texture, stencil clears aren't supported
|
||||
@@ -554,7 +554,7 @@ GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Type type, int width, int heigh
|
||||
ClearRenderTarget(t, 0);
|
||||
break;
|
||||
case GSTexture::Type::DepthStencil:
|
||||
ClearDepth(t);
|
||||
ClearDepth(t, 0.0f);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -567,7 +567,7 @@ GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Type type, int width, int heigh
|
||||
}
|
||||
}}
|
||||
|
||||
void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear)
|
||||
void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
|
||||
{ @autoreleasepool {
|
||||
id<MTLCommandBuffer> cmdbuf = GetRenderCmdBuf();
|
||||
GSScopedDebugGroupMTL dbg(cmdbuf, @"DoMerge");
|
||||
@@ -579,7 +579,8 @@ void GSDeviceMTL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
|
||||
ClearRenderTarget(dTex, c);
|
||||
|
||||
vector_float4 cb_c = { c.r, c.g, c.b, c.a };
|
||||
const GSVector4 unorm_c = GSVector4::unorm8(c);
|
||||
vector_float4 cb_c = { unorm_c.r, unorm_c.g, unorm_c.b, unorm_c.a };
|
||||
GSMTLConvertPSUniform cb_yuv = {};
|
||||
cb_yuv.emoda = EXTBUF.EMODA;
|
||||
cb_yuv.emodc = EXTBUF.EMODC;
|
||||
@@ -1430,27 +1431,18 @@ void GSDeviceMTL::AccumulateCommandBufferTime(id<MTLCommandBuffer> buffer)
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
void GSDeviceMTL::ClearRenderTarget(GSTexture* t, const GSVector4& c)
|
||||
void GSDeviceMTL::ClearRenderTarget(GSTexture* t, uint32 c)
|
||||
{
|
||||
if (!t) return;
|
||||
t->SetClearColor(c);
|
||||
}
|
||||
|
||||
void GSDeviceMTL::ClearRenderTarget(GSTexture* t, uint32 c)
|
||||
void GSDeviceMTL::ClearDepth(GSTexture* t, float d)
|
||||
{
|
||||
GSVector4 color = GSVector4::rgba32(c) * (1.f / 255.f);
|
||||
ClearRenderTarget(t, color);
|
||||
}
|
||||
|
||||
void GSDeviceMTL::ClearDepth(GSTexture* t)
|
||||
{
|
||||
if (!t) return;
|
||||
t->SetClearDepth(0);
|
||||
t->SetClearDepth(d);
|
||||
}
|
||||
|
||||
void GSDeviceMTL::InvalidateRenderTarget(GSTexture* t)
|
||||
{
|
||||
if (!t) return;
|
||||
t->SetState(GSTexture::State::Invalidated);
|
||||
}
|
||||
|
||||
|
||||
@@ -859,133 +859,121 @@ void GSDeviceOGL::DrawIndexedPrimitive(int offset, int count)
|
||||
static_cast<GLint>(m_vertex.start));
|
||||
}
|
||||
|
||||
void GSDeviceOGL::ClearRenderTarget(GSTexture* t, const GSVector4& c)
|
||||
void GSDeviceOGL::CommitClear(GSTexture* t, bool use_write_fbo)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
GSTextureOGL* T = static_cast<GSTextureOGL*>(t);
|
||||
if (T->HasBeenCleaned())
|
||||
if (!T->IsRenderTargetOrDepthStencil() || T->GetState() == GSTexture::State::Dirty)
|
||||
return;
|
||||
|
||||
// Performance note: potentially T->Clear() could be used. Main purpose of
|
||||
// Clear() is to avoid the framebuffer setup cost. However, in this context,
|
||||
// the texture 't' will be set as the render target of the framebuffer and
|
||||
// therefore will require a framebuffer setup.
|
||||
|
||||
// So using the old/standard path is faster/better albeit verbose.
|
||||
|
||||
GL_PUSH("Clear RT %d", T->GetID());
|
||||
|
||||
// TODO: check size of scissor before toggling it
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
const u32 old_color_mask = GLState::wrgba;
|
||||
OMSetColorMaskState();
|
||||
|
||||
OMSetFBO(m_fbo);
|
||||
OMAttachRt(T);
|
||||
|
||||
if (T->IsIntegerFormat())
|
||||
if (use_write_fbo)
|
||||
{
|
||||
if (T->IsUnsignedFormat())
|
||||
glClearBufferuiv(GL_COLOR, 0, c.U32);
|
||||
else
|
||||
glClearBufferiv(GL_COLOR, 0, c.I32);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_write);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
(t->GetType() == GSTexture::Type::RenderTarget) ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
GL_TEXTURE_2D, (t->GetType() == GSTexture::Type::DepthStencil) ? static_cast<GSTextureOGL*>(t)->GetID() : 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glClearBufferfv(GL_COLOR, 0, c.v);
|
||||
OMSetFBO(m_fbo);
|
||||
if (T->GetType() == GSTexture::Type::DepthStencil)
|
||||
{
|
||||
if (GLState::rt && GLState::rt->GetSize() != T->GetSize())
|
||||
OMAttachRt(nullptr);
|
||||
OMAttachDs(T);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GLState::ds && GLState::ds->GetSize() != T->GetSize())
|
||||
OMAttachDs(nullptr);
|
||||
OMAttachRt(T);
|
||||
}
|
||||
}
|
||||
|
||||
OMSetColorMaskState(OMColorMaskSelector(old_color_mask));
|
||||
if (T->GetState() == GSTexture::State::Invalidated)
|
||||
{
|
||||
if (GLAD_GL_VERSION_4_3)
|
||||
{
|
||||
if (T->GetType() == GSTexture::Type::DepthStencil)
|
||||
{
|
||||
const GLenum attachments[] = {GL_DEPTH_STENCIL_ATTACHMENT};
|
||||
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, std::size(attachments), attachments);
|
||||
}
|
||||
else
|
||||
{
|
||||
const GLenum attachments[] = {GL_COLOR_ATTACHMENT0};
|
||||
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, std::size(attachments), attachments);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
if (T->GetType() == GSTexture::Type::DepthStencil)
|
||||
{
|
||||
const float d = T->GetClearDepth();
|
||||
if (GLState::depth_mask)
|
||||
{
|
||||
glClearBufferfv(GL_DEPTH, 0, &d);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDepthMask(true);
|
||||
glClearBufferfv(GL_DEPTH, 0, &d);
|
||||
glDepthMask(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const u32 old_color_mask = GLState::wrgba;
|
||||
OMSetColorMaskState();
|
||||
|
||||
T->WasCleaned();
|
||||
const GSVector4 c_unorm = T->GetUNormClearColor();
|
||||
|
||||
if (T->IsIntegerFormat())
|
||||
{
|
||||
if (T->IsUnsignedFormat())
|
||||
glClearBufferuiv(GL_COLOR, 0, c_unorm.U32);
|
||||
else
|
||||
glClearBufferiv(GL_COLOR, 0, c_unorm.I32);
|
||||
}
|
||||
else
|
||||
{
|
||||
glClearBufferfv(GL_COLOR, 0, c_unorm.v);
|
||||
}
|
||||
|
||||
OMSetColorMaskState(OMColorMaskSelector(old_color_mask));
|
||||
}
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
T->SetState(GSTexture::State::Dirty);
|
||||
|
||||
if (use_write_fbo)
|
||||
{
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
||||
(t->GetType() == GSTexture::Type::RenderTarget) ? GL_COLOR_ATTACHMENT0 :
|
||||
(m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT),
|
||||
GL_TEXTURE_2D, 0, 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLState::fbo);
|
||||
}
|
||||
}
|
||||
|
||||
void GSDeviceOGL::ClearRenderTarget(GSTexture* t, u32 c)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
const GSVector4 color = GSVector4::rgba32(c) * (1.0f / 255);
|
||||
ClearRenderTarget(t, color);
|
||||
t->SetClearColor(c);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::InvalidateRenderTarget(GSTexture* t)
|
||||
{
|
||||
GSTextureOGL* T = static_cast<GSTextureOGL*>(t);
|
||||
if (!T || T->HasBeenCleaned())
|
||||
return;
|
||||
|
||||
if (GLAD_GL_VERSION_4_3 || GLAD_GL_ES_VERSION_3_0)
|
||||
{
|
||||
OMSetFBO(m_fbo);
|
||||
|
||||
if (T->GetType() == GSTexture::Type::DepthStencil)
|
||||
{
|
||||
OMAttachDs(T);
|
||||
const GLenum attachments[] = {GL_DEPTH_STENCIL_ATTACHMENT};
|
||||
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, std::size(attachments), attachments);
|
||||
}
|
||||
else
|
||||
{
|
||||
OMAttachRt(T);
|
||||
const GLenum attachments[] = {GL_COLOR_ATTACHMENT0};
|
||||
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, std::size(attachments), attachments);
|
||||
}
|
||||
}
|
||||
t->SetState(GSTexture::State::Invalidated);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::ClearDepth(GSTexture* t)
|
||||
void GSDeviceOGL::ClearDepth(GSTexture* t, float d)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
GSTextureOGL* T = static_cast<GSTextureOGL*>(t);
|
||||
|
||||
GL_PUSH("Clear Depth %d", T->GetID());
|
||||
|
||||
OMSetFBO(m_fbo);
|
||||
// RT must be detached, if RT is too small, depth won't be fully cleared
|
||||
// AT tolenico 2 map clip bug
|
||||
OMAttachRt(NULL);
|
||||
OMAttachDs(T);
|
||||
|
||||
// TODO: check size of scissor before toggling it
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
const float c = 0.0f;
|
||||
if (GLState::depth_mask)
|
||||
{
|
||||
glClearBufferfv(GL_DEPTH, 0, &c);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDepthMask(true);
|
||||
glClearBufferfv(GL_DEPTH, 0, &c);
|
||||
glDepthMask(false);
|
||||
}
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::ClearStencil(GSTexture* t, u8 c)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
GSTextureOGL* T = static_cast<GSTextureOGL*>(t);
|
||||
|
||||
GL_PUSH("Clear Stencil %d", T->GetID());
|
||||
|
||||
// Keep SCISSOR_TEST enabled on purpose to reduce the size
|
||||
// of clean in DATE (impact big upscaling)
|
||||
OMSetFBO(m_fbo);
|
||||
OMAttachDs(T);
|
||||
const GLint color = c;
|
||||
|
||||
glClearBufferiv(GL_STENCIL, 0, &color);
|
||||
t->SetClearDepth(d);
|
||||
}
|
||||
|
||||
std::unique_ptr<GSDownloadTexture> GSDeviceOGL::CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format)
|
||||
@@ -1230,6 +1218,8 @@ std::string GSDeviceOGL::GetPSSource(const PSSelector& sel)
|
||||
// Copy a sub part of texture (same as below but force a conversion)
|
||||
void GSDeviceOGL::BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, bool linear)
|
||||
{
|
||||
CommitClear(sTex, true);
|
||||
|
||||
GL_PUSH(fmt::format("CopyRectConv from {}", static_cast<GSTextureOGL*>(sTex)->GetID()).c_str());
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
@@ -1259,6 +1249,8 @@ void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r
|
||||
|
||||
const GLuint& sid = static_cast<GSTextureOGL*>(sTex)->GetID();
|
||||
const GLuint& did = static_cast<GSTextureOGL*>(dTex)->GetID();
|
||||
CommitClear(sTex, false);
|
||||
CommitClear(dTex, false);
|
||||
|
||||
GL_PUSH("CopyRect from %d to %d", sid, did);
|
||||
|
||||
@@ -1322,7 +1314,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
|
||||
|
||||
void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GLProgram& ps, bool alpha_blend, OMColorMaskSelector cms, bool linear)
|
||||
{
|
||||
ASSERT(sTex);
|
||||
CommitClear(sTex, true);
|
||||
|
||||
const bool draw_in_depth = dTex->IsDepthStencil();
|
||||
|
||||
@@ -1365,7 +1357,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
|
||||
|
||||
void GSDeviceOGL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear)
|
||||
{
|
||||
ASSERT(sTex);
|
||||
CommitClear(sTex, true);
|
||||
|
||||
const GSVector2i ds(dTex ? dTex->GetSize() : GSVector2i(GetWindowWidth(), GetWindowHeight()));
|
||||
DisplayConstantBuffer cb;
|
||||
@@ -1403,6 +1395,8 @@ void GSDeviceOGL::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
|
||||
|
||||
void GSDeviceOGL::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, GSTexture* dTex, u32 dOffset, u32 dSize)
|
||||
{
|
||||
CommitClear(sTex, false);
|
||||
|
||||
const ShaderConvert shader = (dSize == 16) ? ShaderConvert::CLUT_4 : ShaderConvert::CLUT_8;
|
||||
GLProgram& prog = m_convert.ps[static_cast<int>(shader)];
|
||||
prog.Bind();
|
||||
@@ -1423,6 +1417,8 @@ void GSDeviceOGL::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX,
|
||||
|
||||
void GSDeviceOGL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM)
|
||||
{
|
||||
CommitClear(sTex, false);
|
||||
|
||||
const ShaderConvert shader = ShaderConvert::RGBA_TO_8I;
|
||||
GLProgram& prog = m_convert.ps[static_cast<int>(shader)];
|
||||
prog.Bind();
|
||||
@@ -1562,7 +1558,7 @@ void GSDeviceOGL::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rec
|
||||
DrawIndexedPrimitive();
|
||||
}
|
||||
|
||||
void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear)
|
||||
void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
|
||||
{
|
||||
GL_PUSH("DoMerge");
|
||||
|
||||
@@ -1610,7 +1606,7 @@ void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
{
|
||||
// Blend with a constant alpha
|
||||
m_merge_obj.ps[1].Bind();
|
||||
m_merge_obj.ps[1].Uniform4fv(0, c.v);
|
||||
m_merge_obj.ps[1].Uniform4fv(0, GSVector4::unorm8(c).v);
|
||||
StretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge_obj.ps[1], true, OMColorMaskSelector(), linear);
|
||||
}
|
||||
else
|
||||
@@ -1720,7 +1716,10 @@ void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* ver
|
||||
|
||||
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
|
||||
|
||||
ClearStencil(ds, 0);
|
||||
OMSetRenderTargets(nullptr, ds, &GLState::scissor);
|
||||
|
||||
const GLint clear_color = 0;
|
||||
glClearBufferiv(GL_STENCIL, 0, &clear_color);
|
||||
|
||||
m_convert.ps[static_cast<int>(datm ? ShaderConvert::DATM_1 : ShaderConvert::DATM_0)].Bind();
|
||||
|
||||
@@ -1731,7 +1730,6 @@ void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* ver
|
||||
{
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
OMSetRenderTargets(NULL, ds, &GLState::scissor);
|
||||
|
||||
// ia
|
||||
|
||||
@@ -2015,30 +2013,24 @@ void GSDeviceOGL::RenderBlankFrame()
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::OMAttachRt(GSTextureOGL* rt)
|
||||
void GSDeviceOGL::OMAttachRt(GSTexture* rt)
|
||||
{
|
||||
if (rt)
|
||||
rt->WasAttached();
|
||||
if (GLState::rt == rt)
|
||||
return;
|
||||
|
||||
if (GLState::rt != rt)
|
||||
{
|
||||
GLState::rt = rt;
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt ? rt->GetID() : 0, 0);
|
||||
}
|
||||
GLState::rt = static_cast<GSTextureOGL*>(rt);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt ? static_cast<GSTextureOGL*>(rt)->GetID() : 0, 0);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::OMAttachDs(GSTextureOGL* ds)
|
||||
void GSDeviceOGL::OMAttachDs(GSTexture* ds)
|
||||
{
|
||||
if (ds)
|
||||
ds->WasAttached();
|
||||
if (GLState::ds == ds)
|
||||
return;
|
||||
|
||||
if (GLState::ds != ds)
|
||||
{
|
||||
GLState::ds = ds;
|
||||
GLState::ds = static_cast<GSTextureOGL*>(ds);
|
||||
|
||||
const GLenum target = m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, target, GL_TEXTURE_2D, ds ? ds->GetID() : 0, 0);
|
||||
}
|
||||
const GLenum target = m_features.framebuffer_fetch ? GL_DEPTH_ATTACHMENT : GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, target, GL_TEXTURE_2D, ds ? static_cast<GSTextureOGL*>(ds)->GetID() : 0, 0);
|
||||
}
|
||||
|
||||
void GSDeviceOGL::OMSetFBO(GLuint fbo)
|
||||
@@ -2129,27 +2121,26 @@ void GSDeviceOGL::OMSetBlendState(bool enable, GLenum src_factor, GLenum dst_fac
|
||||
|
||||
void GSDeviceOGL::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor)
|
||||
{
|
||||
GSTextureOGL* RT = static_cast<GSTextureOGL*>(rt);
|
||||
GSTextureOGL* DS = static_cast<GSTextureOGL*>(ds);
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(GLState::rt != rt || GLState::ds != ds));
|
||||
|
||||
g_perfmon.Put(GSPerfMon::RenderPasses, static_cast<double>(GLState::rt != RT || GLState::ds != DS));
|
||||
// Split up to avoid unbind/bind calls when clearing.
|
||||
|
||||
OMSetFBO(m_fbo);
|
||||
if (rt)
|
||||
{
|
||||
OMAttachRt(RT);
|
||||
}
|
||||
OMAttachRt(rt);
|
||||
else
|
||||
{
|
||||
OMAttachRt();
|
||||
}
|
||||
|
||||
// Note: it must be done after OMSetFBO
|
||||
if (ds)
|
||||
OMAttachDs(DS);
|
||||
OMAttachDs(ds);
|
||||
else
|
||||
OMAttachDs();
|
||||
|
||||
if (rt)
|
||||
CommitClear(rt, false);
|
||||
if (ds)
|
||||
CommitClear(ds, false);
|
||||
|
||||
if (rt || ds)
|
||||
{
|
||||
const GSVector2i size = rt ? rt->GetSize() : ds->GetSize();
|
||||
@@ -2254,7 +2245,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
case GSHWDrawConfig::DestinationAlphaMode::StencilOne:
|
||||
if (m_features.texture_barrier)
|
||||
{
|
||||
ClearStencil(config.ds, 1);
|
||||
// Cleared after RT bind.
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
@@ -2419,6 +2410,13 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
OMSetColorMaskState(config.colormask);
|
||||
SetupOM(config.depth);
|
||||
|
||||
// Clear stencil as close as possible to the RT bind, to avoid framebuffer swaps.
|
||||
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne && m_features.texture_barrier)
|
||||
{
|
||||
constexpr GLint clear_color = 1;
|
||||
glClearBufferiv(GL_STENCIL, 0, &clear_color);
|
||||
}
|
||||
|
||||
SendHWDraw(config, psel.ps.IsFeedbackLoop());
|
||||
|
||||
if (config.separate_alpha_pass)
|
||||
|
||||
@@ -250,7 +250,7 @@ private:
|
||||
|
||||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) override;
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) override;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) override;
|
||||
|
||||
bool CompileFXAAProgram();
|
||||
@@ -266,8 +266,8 @@ private:
|
||||
void RenderImGui();
|
||||
void RenderBlankFrame();
|
||||
|
||||
void OMAttachRt(GSTextureOGL* rt = nullptr);
|
||||
void OMAttachDs(GSTextureOGL* ds = nullptr);
|
||||
void OMAttachRt(GSTexture* rt = nullptr);
|
||||
void OMAttachDs(GSTexture* ds = nullptr);
|
||||
void OMSetFBO(GLuint fbo);
|
||||
|
||||
void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds);
|
||||
@@ -285,6 +285,7 @@ public:
|
||||
|
||||
__fi u32 GetFBORead() const { return m_fbo_read; }
|
||||
__fi u32 GetFBOWrite() const { return m_fbo_write; }
|
||||
void CommitClear(GSTexture* t, bool use_write_fbo);
|
||||
|
||||
RenderAPI GetRenderAPI() const override;
|
||||
bool HasSurface() const override;
|
||||
@@ -310,11 +311,9 @@ public:
|
||||
void DrawIndexedPrimitive();
|
||||
void DrawIndexedPrimitive(int offset, int count);
|
||||
|
||||
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
|
||||
void ClearRenderTarget(GSTexture* t, u32 c) override;
|
||||
void InvalidateRenderTarget(GSTexture* t) override;
|
||||
void ClearDepth(GSTexture* t) override;
|
||||
void ClearStencil(GSTexture* t, u8 c);
|
||||
void ClearDepth(GSTexture* t, float d) override;
|
||||
|
||||
std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override;
|
||||
|
||||
|
||||
@@ -183,16 +183,6 @@ void* GSTextureOGL::GetNativeHandle() const
|
||||
return reinterpret_cast<void*>(static_cast<uintptr_t>(m_texture_id));
|
||||
}
|
||||
|
||||
void GSTextureOGL::Clear(const void* data)
|
||||
{
|
||||
glClearTexImage(m_texture_id, 0, m_int_format, m_int_type, data);
|
||||
}
|
||||
|
||||
void GSTextureOGL::Clear(const void* data, const GSVector4i& area)
|
||||
{
|
||||
glClearTexSubImage(m_texture_id, 0, area.x, area.y, 0, area.width(), area.height(), 1, m_int_format, m_int_type, data);
|
||||
}
|
||||
|
||||
bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch, int layer)
|
||||
{
|
||||
ASSERT(m_type != Type::DepthStencil);
|
||||
@@ -205,8 +195,7 @@ bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch, int
|
||||
// overflow the pbo buffer
|
||||
// Data upload is rather small typically 64B or 1024B. So don't bother with PBO
|
||||
// and directly send the data to the GL synchronously
|
||||
|
||||
m_clean = false;
|
||||
GSDeviceOGL::GetInstance()->CommitClear(this, true);
|
||||
|
||||
const u32 preferred_pitch = Common::AlignUpPow2(r.width() << m_int_shift, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
|
||||
const u32 map_size = r.height() * preferred_pitch;
|
||||
@@ -269,6 +258,8 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
|
||||
if (layer >= m_mipmap_levels || IsCompressedFormat())
|
||||
return false;
|
||||
|
||||
GSDeviceOGL::GetInstance()->CommitClear(this, true);
|
||||
|
||||
GSVector4i r = _r ? *_r : GSVector4i(0, 0, m_size.x, m_size.y);
|
||||
// Will need some investigation
|
||||
ASSERT(r.width() != 0);
|
||||
@@ -286,8 +277,6 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
|
||||
GL_PUSH_("Upload Texture %d", m_texture_id); // POP is in Unmap
|
||||
g_perfmon.Put(GSPerfMon::TextureUploads, 1);
|
||||
|
||||
m_clean = false;
|
||||
|
||||
const auto map = GSDeviceOGL::GetTextureUploadBuffer()->Map(TEXTURE_UPLOAD_ALIGNMENT, upload_size);
|
||||
m.bits = static_cast<u8*>(map.pointer);
|
||||
|
||||
@@ -309,6 +298,8 @@ void GSTextureOGL::Unmap()
|
||||
{
|
||||
if (m_type == Type::Texture || m_type == Type::RenderTarget)
|
||||
{
|
||||
GSDeviceOGL::GetInstance()->CommitClear(this, true);
|
||||
|
||||
const u32 pitch = Common::AlignUpPow2(m_r_w << m_int_shift, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
|
||||
const u32 upload_size = pitch * m_r_h;
|
||||
GLStreamBuffer* sb = GSDeviceOGL::GetTextureUploadBuffer();
|
||||
@@ -334,11 +325,14 @@ void GSTextureOGL::Unmap()
|
||||
void GSTextureOGL::GenerateMipmap()
|
||||
{
|
||||
ASSERT(m_mipmap_levels > 1);
|
||||
GSDeviceOGL::GetInstance()->CommitClear(this, true);
|
||||
glGenerateTextureMipmap(m_texture_id);
|
||||
}
|
||||
|
||||
bool GSTextureOGL::Save(const std::string& fn)
|
||||
{
|
||||
GSDeviceOGL::GetInstance()->CommitClear(this, true);
|
||||
|
||||
// Collect the texture data
|
||||
u32 pitch = 4 * m_size.x;
|
||||
u32 buf_size = pitch * m_size.y * 2; // Note *2 for security (depth/stencil)
|
||||
@@ -351,7 +345,7 @@ bool GSTextureOGL::Save(const std::string& fn)
|
||||
|
||||
if (IsDepthStencil())
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, GSDeviceOGL::GetInstance()->GetFBORead());
|
||||
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_texture_id, 0);
|
||||
glReadPixels(0, 0, m_size.x, m_size.y, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image.get());
|
||||
@@ -369,7 +363,7 @@ bool GSTextureOGL::Save(const std::string& fn)
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, GSDeviceOGL::GetInstance()->GetFBORead());
|
||||
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_id, 0);
|
||||
|
||||
@@ -399,8 +393,6 @@ void GSTextureOGL::Swap(GSTexture* tex)
|
||||
GSTexture::Swap(tex);
|
||||
|
||||
std::swap(m_texture_id, static_cast<GSTextureOGL*>(tex)->m_texture_id);
|
||||
std::swap(m_fbo_read, static_cast<GSTextureOGL*>(tex)->m_fbo_read);
|
||||
std::swap(m_clean, static_cast<GSTextureOGL*>(tex)->m_clean);
|
||||
std::swap(m_r_x, static_cast<GSTextureOGL*>(tex)->m_r_x);
|
||||
std::swap(m_r_x, static_cast<GSTextureOGL*>(tex)->m_r_y);
|
||||
std::swap(m_r_w, static_cast<GSTextureOGL*>(tex)->m_r_w);
|
||||
@@ -491,6 +483,7 @@ void GSDownloadTextureOGL::CopyFromTexture(
|
||||
const GSVector4i& drc, GSTexture* stex, const GSVector4i& src, u32 src_level, bool use_transfer_pitch)
|
||||
{
|
||||
GSTextureOGL* const glTex = static_cast<GSTextureOGL*>(stex);
|
||||
GSDeviceOGL::GetInstance()->CommitClear(glTex, true);
|
||||
|
||||
pxAssert(glTex->GetFormat() == m_format);
|
||||
pxAssert(drc.width() == src.width() && drc.height() == src.height());
|
||||
|
||||
@@ -22,8 +22,6 @@ class GSTextureOGL final : public GSTexture
|
||||
{
|
||||
private:
|
||||
GLuint m_texture_id = 0; // the texture id
|
||||
GLuint m_fbo_read = 0;
|
||||
bool m_clean = false;
|
||||
|
||||
// Avoid alignment constrain
|
||||
//GSVector4i m_r;
|
||||
@@ -66,13 +64,7 @@ public:
|
||||
return (m_int_type == GL_UNSIGNED_BYTE || m_int_type == GL_UNSIGNED_SHORT || m_int_type == GL_UNSIGNED_INT);
|
||||
}
|
||||
|
||||
u32 GetID() { return m_texture_id; }
|
||||
bool HasBeenCleaned() { return m_clean; }
|
||||
void WasAttached() { m_clean = false; }
|
||||
void WasCleaned() { m_clean = true; }
|
||||
|
||||
void Clear(const void* data);
|
||||
void Clear(const void* data, const GSVector4i& area);
|
||||
__fi u32 GetID() { return m_texture_id; }
|
||||
};
|
||||
|
||||
class GSDownloadTextureOGL final : public GSDownloadTexture
|
||||
|
||||
@@ -764,7 +764,7 @@ bool GSDeviceVK::CheckFeatures()
|
||||
if (!m_features.texture_barrier && !m_features.stencil_buffer)
|
||||
{
|
||||
Host::AddKeyedOSDMessage("GSDeviceVK_NoTextureBarrierOrStencilBuffer",
|
||||
"Stencil buffers and texture barriers are both unavailable, this will break some graphical effects.",
|
||||
TRANSLATE_STR("GS", "Stencil buffers and texture barriers are both unavailable, this will break some graphical effects."),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
|
||||
@@ -790,39 +790,28 @@ void GSDeviceVK::DrawIndexedPrimitive(int offset, int count)
|
||||
vkCmdDrawIndexed(g_vulkan_context->GetCurrentCommandBuffer(), count, 1, m_index.start + offset, m_vertex.start, 0);
|
||||
}
|
||||
|
||||
void GSDeviceVK::ClearRenderTarget(GSTexture* t, const GSVector4& c)
|
||||
void GSDeviceVK::ClearRenderTarget(GSTexture* t, u32 c)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
if (m_current_render_target == t)
|
||||
EndRenderPass();
|
||||
|
||||
static_cast<GSTextureVK*>(t)->SetClearColor(c);
|
||||
t->SetClearColor(c);
|
||||
}
|
||||
|
||||
void GSDeviceVK::ClearRenderTarget(GSTexture* t, u32 c) { ClearRenderTarget(t, GSVector4::rgba32(c) * (1.0f / 255)); }
|
||||
|
||||
void GSDeviceVK::InvalidateRenderTarget(GSTexture* t)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
if (m_current_render_target == t || m_current_depth_target == t)
|
||||
EndRenderPass();
|
||||
|
||||
t->SetState(GSTexture::State::Invalidated);
|
||||
}
|
||||
|
||||
void GSDeviceVK::ClearDepth(GSTexture* t)
|
||||
void GSDeviceVK::ClearDepth(GSTexture* t, float d)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
if (m_current_depth_target == t)
|
||||
EndRenderPass();
|
||||
|
||||
static_cast<GSTextureVK*>(t)->SetClearDepth(0.0f);
|
||||
static_cast<GSTextureVK*>(t)->SetClearDepth(d);
|
||||
}
|
||||
|
||||
VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const
|
||||
@@ -903,7 +892,7 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((dTexVK->GetClearColor() == (sTexVK->GetClearColor())).alltrue())
|
||||
if (dTexVK->GetClearColor() == sTexVK->GetClearColor())
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -916,7 +905,7 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
|
||||
// so use an attachment clear
|
||||
VkClearAttachment ca;
|
||||
ca.aspectMask = depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
GSVector4::store<false>(ca.clearValue.color.float32, sTexVK->GetClearColor());
|
||||
GSVector4::store<false>(ca.clearValue.color.float32, sTexVK->GetUNormClearColor());
|
||||
ca.clearValue.depthStencil.depth = sTexVK->GetClearDepth();
|
||||
ca.clearValue.depthStencil.stencil = 0;
|
||||
ca.colorAttachment = 0;
|
||||
@@ -1277,12 +1266,13 @@ void GSDeviceVK::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offs
|
||||
}
|
||||
|
||||
void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect,
|
||||
const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear)
|
||||
const GSRegPMODE& PMODE, const GSRegEXTBUF& EXTBUF, u32 c, const bool linear)
|
||||
{
|
||||
GL_PUSH("DoMerge");
|
||||
|
||||
const GSVector4 full_r(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
const u32 yuv_constants[4] = {EXTBUF.EMODA, EXTBUF.EMODC};
|
||||
const GSVector4 bg_color = GSVector4::unorm8(c);
|
||||
const bool feedback_write_2 = PMODE.EN2 && sTex[2] != nullptr && EXTBUF.FBIN == 1;
|
||||
const bool feedback_write_1 = PMODE.EN1 && sTex[2] != nullptr && EXTBUF.FBIN == 0;
|
||||
const bool feedback_write_2_but_blend_bg = feedback_write_2 && PMODE.SLBG == 1;
|
||||
@@ -1362,7 +1352,7 @@ void GSDeviceVK::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
|
||||
// 1st output is enabled. It must be blended
|
||||
SetUtilityTexture(sTex[0], sampler);
|
||||
SetPipeline(m_merge[PMODE.MMOD]);
|
||||
SetUtilityPushConstants(&c, sizeof(c));
|
||||
SetUtilityPushConstants(&bg_color, sizeof(bg_color));
|
||||
DrawStretchRect(sRect[0], dRect[0], dTex->GetSize());
|
||||
}
|
||||
|
||||
@@ -2949,7 +2939,8 @@ void GSDeviceVK::ExecuteCommandBufferForReadback()
|
||||
{
|
||||
m_warned_slow_spin = true;
|
||||
Host::AddKeyedOSDMessage("GSDeviceVK_NoCalibratedTimestamps",
|
||||
"Spin GPU During Readbacks is enabled, but calibrated timestamps are unavailable. This might be really slow.",
|
||||
TRANSLATE_STR("GS", "Spin GPU During Readbacks is enabled, but calibrated timestamps are unavailable. "
|
||||
"This might be really slow."),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
}
|
||||
@@ -3136,10 +3127,10 @@ void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, c
|
||||
vkCmdBeginRenderPass(g_vulkan_context->GetCurrentCommandBuffer(), &begin_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, const GSVector4& clear_color)
|
||||
void GSDeviceVK::BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, u32 clear_color)
|
||||
{
|
||||
alignas(16) VkClearValue cv;
|
||||
GSVector4::store<true>((void*)cv.color.float32, clear_color);
|
||||
GSVector4::store<true>((void*)cv.color.float32, GSVector4::unorm8(clear_color));
|
||||
BeginClearRenderPass(rp, rect, &cv, 1);
|
||||
}
|
||||
|
||||
@@ -3636,24 +3627,25 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
EndRenderPass();
|
||||
|
||||
GL_PUSH_("HDR Render Target Setup");
|
||||
hdr_rt = static_cast<GSTextureVK*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
|
||||
if (!hdr_rt)
|
||||
{
|
||||
Console.WriteLn("Failed to allocate HDR render target, aborting draw.");
|
||||
if (date_image)
|
||||
Recycle(date_image);
|
||||
GL_POP();
|
||||
return;
|
||||
}
|
||||
|
||||
// propagate clear value through if the hdr render is the first
|
||||
if (draw_rt->GetState() == GSTexture::State::Cleared)
|
||||
{
|
||||
hdr_rt->SetState(GSTexture::State::Cleared);
|
||||
hdr_rt->SetClearColor(draw_rt->GetClearColor());
|
||||
}
|
||||
else
|
||||
else if (draw_rt->GetState() == GSTexture::State::Dirty)
|
||||
{
|
||||
hdr_rt->SetState(GSTexture::State::Invalidated);
|
||||
GL_PUSH_("HDR Render Target Setup");
|
||||
draw_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
|
||||
}
|
||||
|
||||
@@ -3742,7 +3734,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
alignas(16) VkClearValue cvs[2];
|
||||
u32 cv_count = 0;
|
||||
if (draw_rt)
|
||||
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetClearColor());
|
||||
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
|
||||
|
||||
// the only time the stencil value is used here is DATE_one, so setting it to 1 is fine (not used otherwise)
|
||||
if (draw_ds)
|
||||
@@ -3834,7 +3826,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
alignas(16) VkClearValue cvs[2];
|
||||
u32 cv_count = 0;
|
||||
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetClearColor());
|
||||
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
|
||||
if (draw_ds)
|
||||
cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1};
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ private:
|
||||
GSTexture* CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format) override;
|
||||
|
||||
void DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, GSVector4* dRect, const GSRegPMODE& PMODE,
|
||||
const GSRegEXTBUF& EXTBUF, const GSVector4& c, const bool linear) final;
|
||||
const GSRegEXTBUF& EXTBUF, u32 c, const bool linear) final;
|
||||
void DoInterlace(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderInterlace shader, bool linear, const InterlaceConstantBuffer& cb) final;
|
||||
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float params[4]) final;
|
||||
void DoFXAA(GSTexture* sTex, GSTexture* dTex) final;
|
||||
@@ -265,10 +265,9 @@ public:
|
||||
void DrawIndexedPrimitive();
|
||||
void DrawIndexedPrimitive(int offset, int count);
|
||||
|
||||
void ClearRenderTarget(GSTexture* t, const GSVector4& c) override;
|
||||
void ClearRenderTarget(GSTexture* t, u32 c) override;
|
||||
void InvalidateRenderTarget(GSTexture* t) override;
|
||||
void ClearDepth(GSTexture* t) override;
|
||||
void ClearDepth(GSTexture* t, float d) override;
|
||||
|
||||
std::unique_ptr<GSDownloadTexture> CreateDownloadTexture(u32 width, u32 height, GSTexture::Format format) override;
|
||||
|
||||
@@ -352,7 +351,7 @@ public:
|
||||
bool InRenderPass();
|
||||
void BeginRenderPass(VkRenderPass rp, const GSVector4i& rect);
|
||||
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, const VkClearValue* cv, u32 cv_count);
|
||||
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, const GSVector4& clear_color);
|
||||
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, u32 clear_color);
|
||||
void BeginClearRenderPass(VkRenderPass rp, const GSVector4i& rect, float depth, u8 stencil);
|
||||
void EndRenderPass();
|
||||
|
||||
|
||||
@@ -547,7 +547,7 @@ void GSTextureVK::CommitClear(VkCommandBuffer cmdbuf)
|
||||
else
|
||||
{
|
||||
alignas(16) VkClearColorValue cv;
|
||||
GSVector4::store<true>(cv.float32, GetClearColor());
|
||||
GSVector4::store<true>(cv.float32, GetUNormClearColor());
|
||||
const VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u};
|
||||
vkCmdClearColorImage(cmdbuf, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cv, 1, &srr);
|
||||
}
|
||||
|
||||
@@ -748,6 +748,41 @@ bool VKContext::CreateAllocator()
|
||||
if (m_optional_extensions.vk_ext_memory_budget)
|
||||
ci.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
|
||||
|
||||
// Limit usage of the DEVICE_LOCAL upload heap when we're using a debug device.
|
||||
// On NVIDIA drivers, it results in frequently running out of device memory when trying to
|
||||
// play back captures in RenderDoc, making life very painful. Re-BAR GPUs should be fine.
|
||||
constexpr VkDeviceSize UPLOAD_HEAP_SIZE_THRESHOLD = 512 * 1024 * 1024;
|
||||
constexpr VkMemoryPropertyFlags UPLOAD_HEAP_PROPERTIES =
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
|
||||
std::array<VkDeviceSize, VK_MAX_MEMORY_HEAPS> heap_size_limits;
|
||||
if (GSConfig.UseDebugDevice)
|
||||
{
|
||||
bool has_upload_heap = false;
|
||||
heap_size_limits.fill(VK_WHOLE_SIZE);
|
||||
for (u32 i = 0; i < m_device_memory_properties.memoryTypeCount; i++)
|
||||
{
|
||||
// Look for any memory types which are upload-like.
|
||||
const VkMemoryType& type = m_device_memory_properties.memoryTypes[i];
|
||||
if ((type.propertyFlags & UPLOAD_HEAP_PROPERTIES) != UPLOAD_HEAP_PROPERTIES)
|
||||
continue;
|
||||
|
||||
const VkMemoryHeap& heap = m_device_memory_properties.memoryHeaps[type.heapIndex];
|
||||
if (heap.size >= UPLOAD_HEAP_SIZE_THRESHOLD)
|
||||
continue;
|
||||
|
||||
if (heap_size_limits[type.heapIndex] == VK_WHOLE_SIZE)
|
||||
{
|
||||
Console.Warning("Disabling allocation from upload heap #%u (%.2f MB) due to debug device.",
|
||||
type.heapIndex, static_cast<float>(heap.size) / 1048576.0f);
|
||||
heap_size_limits[type.heapIndex] = 0;
|
||||
has_upload_heap = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (has_upload_heap)
|
||||
ci.pHeapSizeLimit = heap_size_limits.data();
|
||||
}
|
||||
|
||||
VkResult res = vmaCreateAllocator(&ci, &m_allocator);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
|
||||
@@ -126,6 +126,12 @@ bool GSDumpReplayer::ChangeDump(const char* filename)
|
||||
{
|
||||
Console.WriteLn("(GSDumpReplayer) Switching to '%s'...", filename);
|
||||
|
||||
if (!VMManager::IsGSDumpFileName(filename))
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("GSDumpReplayer", "'%s' is not a GS dump.", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<GSDumpFile> new_dump(GSDumpFile::OpenGSDump(filename));
|
||||
if (!new_dump || !new_dump->ReadFile())
|
||||
{
|
||||
|
||||
+11
-7
@@ -868,11 +868,14 @@ u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
|
||||
if (value >= 0 && value <= static_cast<int>(AccBlendLevel::Maximum) && static_cast<int>(EmuConfig.GS.AccurateBlendingUnit) < value)
|
||||
{
|
||||
Host::AddKeyedOSDMessage("HWBlendingWarning",
|
||||
fmt::format(ICON_FA_PAINT_BRUSH " Current Blending Accuracy is {}.\n"
|
||||
"Recommended Blending Accuracy for this game is {}.\n"
|
||||
"You can adjust the blending level in Game Properties to improve\n"
|
||||
"graphical quality, but this will increase system requirements.",
|
||||
Pcsx2Config::GSOptions::BlendingLevelNames[static_cast<int>(EmuConfig.GS.AccurateBlendingUnit)],
|
||||
fmt::format(TRANSLATE_SV("GameDatabase",
|
||||
"{0} Current Blending Accuracy is {1}.\n"
|
||||
"Recommended Blending Accuracy for this game is {2}.\n"
|
||||
"You can adjust the blending level in Game Properties to improve\n"
|
||||
"graphical quality, but this will increase system requirements."),
|
||||
ICON_FA_PAINT_BRUSH,
|
||||
Pcsx2Config::GSOptions::BlendingLevelNames[static_cast<int>(
|
||||
EmuConfig.GS.AccurateBlendingUnit)],
|
||||
Pcsx2Config::GSOptions::BlendingLevelNames[value]),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
@@ -905,8 +908,9 @@ u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
|
||||
if (!disabled_fixes.empty())
|
||||
{
|
||||
Host::AddKeyedOSDMessage("HWFixesWarning",
|
||||
fmt::format(ICON_FA_MAGIC " Manual GS hardware renderer fixes are enabled, automatic fixes were not applied:\n{}",
|
||||
disabled_fixes),
|
||||
fmt::format(ICON_FA_MAGIC " {}\n{}",
|
||||
TRANSLATE_SV("GameDatabase", "Manual GS hardware renderer fixes are enabled, automatic fixes were not applied:"),
|
||||
disabled_fixes),
|
||||
Host::OSD_ERROR_DURATION);
|
||||
}
|
||||
else
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ bool CheckPaths()
|
||||
|
||||
void GIF_Fifo::init()
|
||||
{
|
||||
memzero(data);
|
||||
std::memset(data, 0, sizeof(data));
|
||||
fifoSize = 0;
|
||||
gifRegs.stat.FQC = 0;
|
||||
|
||||
|
||||
+4
-4
@@ -65,7 +65,7 @@ struct Gif_Tag
|
||||
setTag(pMem, analyze);
|
||||
}
|
||||
|
||||
__ri void Reset() { memzero(*this); }
|
||||
__ri void Reset() { std::memset(this, 0, sizeof(*this)); }
|
||||
__ri u8 curReg() { return regs[nRegIdx & 0xf]; }
|
||||
|
||||
__ri void packedStep()
|
||||
@@ -163,21 +163,21 @@ struct GS_Packet
|
||||
s32 cycles; // EE Cycles taken to process this GS packet
|
||||
s32 readAmount; // Dummy read-amount data needed for proper buffer calculations
|
||||
GS_Packet() { Reset(); }
|
||||
void Reset() { memzero(*this); }
|
||||
void Reset() { std::memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
struct GS_SIGNAL
|
||||
{
|
||||
u32 data[2];
|
||||
bool queued;
|
||||
void Reset() { memzero(*this); }
|
||||
void Reset() { std::memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
struct GS_FINISH
|
||||
{
|
||||
bool gsFINISHFired;
|
||||
|
||||
void Reset() { memzero(*this); }
|
||||
void Reset() { std::memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
static __fi void incTag(u32& offset, u32& size, u32 incAmount)
|
||||
|
||||
+111
-2
@@ -26,13 +26,122 @@
|
||||
#include "common/Assertions.h"
|
||||
#include "common/CrashHandler.h"
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/HeterogeneousContainers.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <shared_mutex>
|
||||
|
||||
static std::mutex s_settings_mutex;
|
||||
static LayeredSettingsInterface s_layered_settings_interface;
|
||||
namespace Host
|
||||
{
|
||||
static std::pair<const char*, u32> LookupTranslationString(
|
||||
const std::string_view& context, const std::string_view& msg);
|
||||
|
||||
static std::mutex s_settings_mutex;
|
||||
static LayeredSettingsInterface s_layered_settings_interface;
|
||||
|
||||
static constexpr u32 TRANSLATION_STRING_CACHE_SIZE = 4 * 1024 * 1024;
|
||||
using TranslationStringMap = UnorderedStringMap<std::pair<u32, u32>>;
|
||||
using TranslationStringContextMap = UnorderedStringMap<TranslationStringMap>;
|
||||
static std::shared_mutex s_translation_string_mutex;
|
||||
static TranslationStringContextMap s_translation_string_map;
|
||||
static std::vector<char> s_translation_string_cache;
|
||||
static u32 s_translation_string_cache_pos;
|
||||
} // namespace Host
|
||||
|
||||
std::pair<const char*, u32> Host::LookupTranslationString(const std::string_view& context, const std::string_view& msg)
|
||||
{
|
||||
// TODO: TranslatableString, compile-time hashing.
|
||||
|
||||
TranslationStringContextMap::iterator ctx_it;
|
||||
TranslationStringMap::iterator msg_it;
|
||||
std::pair<const char*, u32> ret;
|
||||
s32 len;
|
||||
|
||||
// Shouldn't happen, but just in case someone tries to translate an empty string.
|
||||
if (unlikely(msg.empty()))
|
||||
{
|
||||
ret.first = &s_translation_string_cache[0];
|
||||
ret.second = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
s_translation_string_mutex.lock_shared();
|
||||
ctx_it = UnorderedStringMapFind(s_translation_string_map, context);
|
||||
|
||||
if (unlikely(ctx_it == s_translation_string_map.end()))
|
||||
goto add_string;
|
||||
|
||||
msg_it = UnorderedStringMapFind(ctx_it->second, msg);
|
||||
if (unlikely(msg_it == ctx_it->second.end()))
|
||||
goto add_string;
|
||||
|
||||
ret.first = &s_translation_string_cache[msg_it->second.first];
|
||||
ret.second = msg_it->second.second;
|
||||
s_translation_string_mutex.unlock_shared();
|
||||
return ret;
|
||||
|
||||
add_string:
|
||||
s_translation_string_mutex.unlock_shared();
|
||||
s_translation_string_mutex.lock();
|
||||
|
||||
if (unlikely(s_translation_string_cache.empty()))
|
||||
{
|
||||
// First element is always an empty string.
|
||||
s_translation_string_cache.resize(TRANSLATION_STRING_CACHE_SIZE);
|
||||
s_translation_string_cache[0] = '\0';
|
||||
s_translation_string_cache_pos = 0;
|
||||
}
|
||||
|
||||
if ((len = Internal::GetTranslatedStringImpl(context, msg,
|
||||
&s_translation_string_cache[s_translation_string_cache_pos],
|
||||
TRANSLATION_STRING_CACHE_SIZE - 1 - s_translation_string_cache_pos)) < 0)
|
||||
{
|
||||
Console.Error("WARNING: Clearing translation string cache, it might need to be larger.");
|
||||
s_translation_string_cache_pos = 0;
|
||||
if ((len = Internal::GetTranslatedStringImpl(context, msg,
|
||||
&s_translation_string_cache[s_translation_string_cache_pos],
|
||||
TRANSLATION_STRING_CACHE_SIZE - 1 - s_translation_string_cache_pos)) < 0)
|
||||
{
|
||||
pxFailRel("Failed to get translated string after clearing cache.");
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// New context?
|
||||
if (ctx_it == s_translation_string_map.end())
|
||||
ctx_it = s_translation_string_map.emplace(context, TranslationStringMap()).first;
|
||||
|
||||
// Impl doesn't null terminate, we need that for C strings.
|
||||
// TODO: do we want to consider aligning the buffer?
|
||||
const u32 insert_pos = s_translation_string_cache_pos;
|
||||
s_translation_string_cache[insert_pos + static_cast<u32>(len)] = 0;
|
||||
|
||||
ctx_it->second.emplace(msg, std::pair<u32, u32>(insert_pos, static_cast<u32>(len)));
|
||||
s_translation_string_cache_pos = insert_pos + static_cast<u32>(len) + 1;
|
||||
|
||||
ret.first = &s_translation_string_cache[insert_pos];
|
||||
ret.second = static_cast<u32>(len);
|
||||
s_translation_string_mutex.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* Host::TranslateToCString(const std::string_view& context, const std::string_view& msg)
|
||||
{
|
||||
return LookupTranslationString(context, msg).first;
|
||||
}
|
||||
|
||||
std::string_view Host::TranslateToStringView(const std::string_view& context, const std::string_view& msg)
|
||||
{
|
||||
const auto mp = LookupTranslationString(context, msg);
|
||||
return std::string_view(mp.first, mp.second);
|
||||
}
|
||||
|
||||
std::string Host::TranslateToString(const std::string_view& context, const std::string_view& msg)
|
||||
{
|
||||
return std::string(TranslateToStringView(context, msg));
|
||||
}
|
||||
|
||||
void Host::ReportFormattedErrorAsync(const std::string_view& title, const char* format, ...)
|
||||
{
|
||||
|
||||
+31
-2
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "common/Pcsx2Defs.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
@@ -48,12 +50,28 @@ namespace Host
|
||||
/// Returns the modified time of a resource.
|
||||
std::optional<std::time_t> GetResourceFileTimestamp(const char* filename);
|
||||
|
||||
/// Returns a localized version of the specified string within the specified context.
|
||||
/// The pointer is guaranteed to be valid until the next language change.
|
||||
const char* TranslateToCString(const std::string_view& context, const std::string_view& msg);
|
||||
|
||||
/// Returns a localized version of the specified string within the specified context.
|
||||
/// The view is guaranteed to be valid until the next language change.
|
||||
/// NOTE: When passing this to fmt, positional arguments should be used in the base string, as
|
||||
/// not all locales follow the same word ordering.
|
||||
std::string_view TranslateToStringView(const std::string_view& context, const std::string_view& msg);
|
||||
|
||||
/// Returns a localized version of the specified string within the specified context.
|
||||
std::string TranslateToString(const std::string_view& context, const std::string_view& msg);
|
||||
|
||||
/// Returns a localized version of the specified string, after formatting.
|
||||
|
||||
template<typename... T>
|
||||
std::string TranslateAndFmt(const std::string_view& context, const std::string_view& format, T&&... args);
|
||||
|
||||
/// Adds OSD messages, duration is in seconds.
|
||||
void AddOSDMessage(std::string message, float duration = 2.0f);
|
||||
void AddKeyedOSDMessage(std::string key, std::string message, float duration = 2.0f);
|
||||
void AddIconOSDMessage(std::string key, const char* icon, const std::string_view& message, float duration = 2.0f);
|
||||
void AddFormattedOSDMessage(float duration, const char* format, ...);
|
||||
void AddKeyedFormattedOSDMessage(std::string key, float duration, const char* format, ...);
|
||||
void RemoveKeyedOSDMessage(std::string key);
|
||||
void ClearOSDMessages();
|
||||
|
||||
@@ -155,5 +173,16 @@ namespace Host
|
||||
|
||||
/// Sets the input profile settings layer. Called by VMManager when the game changes.
|
||||
void SetInputSettingsLayer(SettingsInterface* sif);
|
||||
|
||||
/// Implementation to retrieve a translated string.
|
||||
s32 GetTranslatedStringImpl(const std::string_view& context, const std::string_view& msg, char* tbuf, size_t tbuf_space);
|
||||
} // namespace Internal
|
||||
} // namespace Host
|
||||
|
||||
// Helper macros for retrieving translated strings.
|
||||
#define TRANSLATE(context, msg) Host::TranslateToCString(context, msg)
|
||||
#define TRANSLATE_SV(context, msg) Host::TranslateToStringView(context, msg)
|
||||
#define TRANSLATE_STR(context, msg) Host::TranslateToString(context, msg)
|
||||
|
||||
// Does not translate the string at runtime, but allows the UI to in its own way.
|
||||
#define TRANSLATE_NOOP(context, msg) msg
|
||||
|
||||
+169
-137
@@ -41,10 +41,13 @@ void VMManager::Internal::ResetVMHotkeyState()
|
||||
static void HotkeyAdjustTargetSpeed(double delta)
|
||||
{
|
||||
const double min_speed = Achievements::ChallengeModeActive() ? 1.0 : 0.1;
|
||||
EmuConfig.Framerate.NominalScalar = std::max(min_speed, EmuConfig.GS.LimitScalar + delta);
|
||||
EmuConfig.Framerate.NominalScalar = std::max(min_speed, EmuConfig.Framerate.NominalScalar + delta);
|
||||
EmuConfig.LimiterMode = LimiterModeType::Unlimited; // force update
|
||||
VMManager::SetLimiterMode(LimiterModeType::Nominal);
|
||||
Host::AddIconOSDMessage("SpeedChanged", ICON_FA_CLOCK,
|
||||
fmt::format("Target speed set to {:.0f}%.", std::round(EmuConfig.Framerate.NominalScalar * 100.0)), Host::OSD_QUICK_DURATION);
|
||||
fmt::format(TRANSLATE_SV("Hotkeys", "Target speed set to {:.0f}%."),
|
||||
std::round(EmuConfig.Framerate.NominalScalar * 100.0)),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
}
|
||||
|
||||
static void HotkeyAdjustVolume(s32 fixed, s32 delta)
|
||||
@@ -53,18 +56,19 @@ static void HotkeyAdjustVolume(s32 fixed, s32 delta)
|
||||
return;
|
||||
|
||||
const s32 current_vol = SPU2::GetOutputVolume();
|
||||
const s32 new_volume = std::clamp((fixed >= 0) ? fixed : (current_vol + delta), 0, Pcsx2Config::SPU2Options::MAX_VOLUME);
|
||||
const s32 new_volume =
|
||||
std::clamp((fixed >= 0) ? fixed : (current_vol + delta), 0, Pcsx2Config::SPU2Options::MAX_VOLUME);
|
||||
if (current_vol != new_volume)
|
||||
SPU2::SetOutputVolume(new_volume);
|
||||
|
||||
if (new_volume == 0)
|
||||
{
|
||||
Host::AddIconOSDMessage("VolumeChanged", ICON_FA_VOLUME_MUTE, "Volume: Muted");
|
||||
Host::AddIconOSDMessage("VolumeChanged", ICON_FA_VOLUME_MUTE, TRANSLATE_STR("Hotkeys", "Volume: Muted"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::AddIconOSDMessage(
|
||||
"VolumeChanged", (current_vol < new_volume) ? ICON_FA_VOLUME_UP : ICON_FA_VOLUME_DOWN, fmt::format("Volume: {}%", new_volume));
|
||||
Host::AddIconOSDMessage("VolumeChanged", (current_vol < new_volume) ? ICON_FA_VOLUME_UP : ICON_FA_VOLUME_DOWN,
|
||||
fmt::format(TRANSLATE_SV("Hotkeys", "Volume: {}%"), new_volume));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,11 +102,14 @@ static void HotkeyCycleSaveSlot(s32 delta)
|
||||
date_buf[len - 1] = 0;
|
||||
|
||||
Host::AddIconOSDMessage("CycleSaveSlot", ICON_FA_SEARCH,
|
||||
fmt::format("Save slot {} selected (last save: {}).", s_current_save_slot, date_buf), Host::OSD_QUICK_DURATION);
|
||||
fmt::format(
|
||||
TRANSLATE_SV("Hotkeys", "Save slot {} selected (last save: {})."), s_current_save_slot, date_buf),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::AddIconOSDMessage("CycleSaveSlot", ICON_FA_SEARCH, fmt::format("Save slot {} selected (no save yet).", s_current_save_slot),
|
||||
Host::AddIconOSDMessage("CycleSaveSlot", ICON_FA_SEARCH,
|
||||
fmt::format(TRANSLATE_SV("Hotkeys", "Save slot {} selected (no save yet)."), s_current_save_slot),
|
||||
Host::OSD_QUICK_DURATION);
|
||||
}
|
||||
}
|
||||
@@ -113,8 +120,8 @@ static void HotkeyLoadStateSlot(s32 slot)
|
||||
Host::RunOnCPUThread([slot]() {
|
||||
if (!VMManager::HasSaveStateInSlot(VMManager::GetDiscSerial().c_str(), VMManager::GetDiscCRC(), slot))
|
||||
{
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE, fmt::format("No save state found in slot {}.", slot),
|
||||
Host::OSD_INFO_DURATION);
|
||||
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE,
|
||||
fmt::format(TRANSLATE_SV("Hotkeys", "No save state found in slot {}."), slot), Host::OSD_INFO_DURATION);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,146 +135,171 @@ static void HotkeySaveStateSlot(s32 slot)
|
||||
}
|
||||
|
||||
BEGIN_HOTKEY_LIST(g_common_hotkeys)
|
||||
DEFINE_HOTKEY("OpenPauseMenu", "System", "Open Pause Menu", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
FullscreenUI::OpenPauseMenu();
|
||||
})
|
||||
DEFINE_HOTKEY("OpenPauseMenu", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Open Pause Menu"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
FullscreenUI::OpenPauseMenu();
|
||||
})
|
||||
#ifdef ENABLE_ACHIEVEMENTS
|
||||
DEFINE_HOTKEY("OpenAchievementsList", "System", "Open Achievements List", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
FullscreenUI::OpenAchievementsWindow();
|
||||
})
|
||||
DEFINE_HOTKEY("OpenLeaderboardsList", "System", "Open Leaderboards List", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
FullscreenUI::OpenLeaderboardsWindow();
|
||||
})
|
||||
DEFINE_HOTKEY("OpenAchievementsList", TRANSLATE_NOOP("Hotkeys", "System"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Open Achievements List"), [](s32 pressed) {
|
||||
if (!pressed)
|
||||
FullscreenUI::OpenAchievementsWindow();
|
||||
})
|
||||
DEFINE_HOTKEY("OpenLeaderboardsList", TRANSLATE_NOOP("Hotkeys", "System"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Open Leaderboards List"), [](s32 pressed) {
|
||||
if (!pressed)
|
||||
FullscreenUI::OpenLeaderboardsWindow();
|
||||
})
|
||||
#endif
|
||||
DEFINE_HOTKEY("TogglePause", "System", "Toggle Pause", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
VMManager::SetPaused(VMManager::GetState() != VMState::Paused);
|
||||
})
|
||||
DEFINE_HOTKEY("ToggleFullscreen", "System", "Toggle Fullscreen", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
Host::SetFullscreen(!Host::IsFullscreen());
|
||||
})
|
||||
DEFINE_HOTKEY("ToggleFrameLimit", "System", "Toggle Frame Limit", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
{
|
||||
VMManager::SetLimiterMode(
|
||||
(EmuConfig.LimiterMode != LimiterModeType::Unlimited) ? LimiterModeType::Unlimited : LimiterModeType::Nominal);
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("ToggleTurbo", "System", "Toggle Turbo / Fast Forward", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
{
|
||||
VMManager::SetLimiterMode((EmuConfig.LimiterMode != LimiterModeType::Turbo) ? LimiterModeType::Turbo : LimiterModeType::Nominal);
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("ToggleSlowMotion", "System", "Toggle Slow Motion", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
{
|
||||
VMManager::SetLimiterMode((EmuConfig.LimiterMode != LimiterModeType::Slomo) ? LimiterModeType::Slomo : LimiterModeType::Nominal);
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("HoldTurbo", "System", "Turbo / Fast Forward (Hold)", [](s32 pressed) {
|
||||
if (!VMManager::HasValidVM())
|
||||
return;
|
||||
if (pressed > 0 && !s_limiter_mode_prior_to_hold_interaction.has_value())
|
||||
{
|
||||
s_limiter_mode_prior_to_hold_interaction = VMManager::GetLimiterMode();
|
||||
VMManager::SetLimiterMode((s_limiter_mode_prior_to_hold_interaction.value() != LimiterModeType::Turbo) ? LimiterModeType::Turbo :
|
||||
LimiterModeType::Nominal);
|
||||
}
|
||||
else if (pressed >= 0 && s_limiter_mode_prior_to_hold_interaction.has_value())
|
||||
{
|
||||
VMManager::SetLimiterMode(s_limiter_mode_prior_to_hold_interaction.value());
|
||||
s_limiter_mode_prior_to_hold_interaction.reset();
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("IncreaseSpeed", "System", "Increase Target Speed", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyAdjustTargetSpeed(0.1);
|
||||
})
|
||||
DEFINE_HOTKEY("DecreaseSpeed", "System", "Decrease Target Speed", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyAdjustTargetSpeed(-0.1);
|
||||
})
|
||||
DEFINE_HOTKEY("IncreaseVolume", "System", "Increase Volume", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyAdjustVolume(-1, 5);
|
||||
})
|
||||
DEFINE_HOTKEY("DecreaseVolume", "System", "Decrease Volume", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyAdjustVolume(-1, -5);
|
||||
})
|
||||
DEFINE_HOTKEY("Mute", "System", "Toggle Mute", [](s32 pressed) {
|
||||
DEFINE_HOTKEY(
|
||||
"TogglePause", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Pause"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
VMManager::SetPaused(VMManager::GetState() != VMState::Paused);
|
||||
})
|
||||
DEFINE_HOTKEY("ToggleFullscreen", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Fullscreen"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed)
|
||||
Host::SetFullscreen(!Host::IsFullscreen());
|
||||
})
|
||||
DEFINE_HOTKEY("ToggleFrameLimit", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Frame Limit"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
{
|
||||
VMManager::SetLimiterMode((EmuConfig.LimiterMode != LimiterModeType::Unlimited) ?
|
||||
LimiterModeType::Unlimited :
|
||||
LimiterModeType::Nominal);
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("ToggleTurbo", TRANSLATE_NOOP("Hotkeys", "System"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Toggle Turbo / Fast Forward"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
{
|
||||
VMManager::SetLimiterMode(
|
||||
(EmuConfig.LimiterMode != LimiterModeType::Turbo) ? LimiterModeType::Turbo : LimiterModeType::Nominal);
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("ToggleSlowMotion", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Slow Motion"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
{
|
||||
VMManager::SetLimiterMode(
|
||||
(EmuConfig.LimiterMode != LimiterModeType::Slomo) ? LimiterModeType::Slomo : LimiterModeType::Nominal);
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("HoldTurbo", TRANSLATE_NOOP("Hotkeys", "System"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Turbo / Fast Forward (Hold)"), [](s32 pressed) {
|
||||
if (!VMManager::HasValidVM())
|
||||
return;
|
||||
if (pressed > 0 && !s_limiter_mode_prior_to_hold_interaction.has_value())
|
||||
{
|
||||
s_limiter_mode_prior_to_hold_interaction = VMManager::GetLimiterMode();
|
||||
VMManager::SetLimiterMode((s_limiter_mode_prior_to_hold_interaction.value() != LimiterModeType::Turbo) ?
|
||||
LimiterModeType::Turbo :
|
||||
LimiterModeType::Nominal);
|
||||
}
|
||||
else if (pressed >= 0 && s_limiter_mode_prior_to_hold_interaction.has_value())
|
||||
{
|
||||
VMManager::SetLimiterMode(s_limiter_mode_prior_to_hold_interaction.value());
|
||||
s_limiter_mode_prior_to_hold_interaction.reset();
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("IncreaseSpeed", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Increase Target Speed"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyAdjustTargetSpeed(0.1);
|
||||
})
|
||||
DEFINE_HOTKEY("DecreaseSpeed", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Decrease Target Speed"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyAdjustTargetSpeed(-0.1);
|
||||
})
|
||||
DEFINE_HOTKEY("IncreaseVolume", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Increase Volume"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyAdjustVolume(-1, 5);
|
||||
})
|
||||
DEFINE_HOTKEY("DecreaseVolume", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Decrease Volume"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyAdjustVolume(-1, -5);
|
||||
})
|
||||
DEFINE_HOTKEY("Mute", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Toggle Mute"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyAdjustVolume((SPU2::GetOutputVolume() == 0) ? EmuConfig.SPU2.FinalVolume : 0, 0);
|
||||
})
|
||||
DEFINE_HOTKEY("FrameAdvance", "System", "Frame Advance", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
VMManager::FrameAdvance(1);
|
||||
})
|
||||
DEFINE_HOTKEY("ShutdownVM", "System", "Shut Down Virtual Machine", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
Host::RequestVMShutdown(true, true, EmuConfig.SaveStateOnShutdown);
|
||||
})
|
||||
DEFINE_HOTKEY("ResetVM", "System", "Reset Virtual Machine", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
VMManager::Reset();
|
||||
})
|
||||
DEFINE_HOTKEY("InputRecToggleMode", "System", "Toggle Input Recording Mode", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
g_InputRecording.getControls().toggleRecordMode();
|
||||
})
|
||||
DEFINE_HOTKEY(
|
||||
"FrameAdvance", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Frame Advance"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
VMManager::FrameAdvance(1);
|
||||
})
|
||||
DEFINE_HOTKEY("ShutdownVM", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Shut Down Virtual Machine"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
Host::RequestVMShutdown(true, true, EmuConfig.SaveStateOnShutdown);
|
||||
})
|
||||
DEFINE_HOTKEY("ResetVM", TRANSLATE_NOOP("Hotkeys", "System"), TRANSLATE_NOOP("Hotkeys", "Reset Virtual Machine"),
|
||||
[](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
VMManager::Reset();
|
||||
})
|
||||
DEFINE_HOTKEY("InputRecToggleMode", TRANSLATE_NOOP("Hotkeys", "System"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Toggle Input Recording Mode"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
g_InputRecording.getControls().toggleRecordMode();
|
||||
})
|
||||
|
||||
DEFINE_HOTKEY("PreviousSaveStateSlot", "Save States", "Select Previous Save Slot", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyCycleSaveSlot(-1);
|
||||
})
|
||||
DEFINE_HOTKEY("NextSaveStateSlot", "Save States", "Select Next Save Slot", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyCycleSaveSlot(1);
|
||||
})
|
||||
DEFINE_HOTKEY("SaveStateToSlot", "Save States", "Save State To Selected Slot", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
VMManager::SaveStateToSlot(s_current_save_slot);
|
||||
})
|
||||
DEFINE_HOTKEY("LoadStateFromSlot", "Save States", "Load State From Selected Slot", [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyLoadStateSlot(s_current_save_slot);
|
||||
})
|
||||
DEFINE_HOTKEY("PreviousSaveStateSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Select Previous Save Slot"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyCycleSaveSlot(-1);
|
||||
})
|
||||
DEFINE_HOTKEY("NextSaveStateSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Select Next Save Slot"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyCycleSaveSlot(1);
|
||||
})
|
||||
DEFINE_HOTKEY("SaveStateToSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Save State To Selected Slot"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
VMManager::SaveStateToSlot(s_current_save_slot);
|
||||
})
|
||||
DEFINE_HOTKEY("LoadStateFromSlot", TRANSLATE_NOOP("Hotkeys", "Save States"),
|
||||
TRANSLATE_NOOP("Hotkeys", "Load State From Selected Slot"), [](s32 pressed) {
|
||||
if (!pressed && VMManager::HasValidVM())
|
||||
HotkeyLoadStateSlot(s_current_save_slot);
|
||||
})
|
||||
|
||||
#define DEFINE_HOTKEY_SAVESTATE_X(slotnum) \
|
||||
DEFINE_HOTKEY("SaveStateToSlot" #slotnum, "Save States", "Save State To Slot " #slotnum, [](s32 pressed) { \
|
||||
#define DEFINE_HOTKEY_SAVESTATE_X(slotnum, title) \
|
||||
DEFINE_HOTKEY("SaveStateToSlot" #slotnum, "Save States", title, [](s32 pressed) { \
|
||||
if (!pressed) \
|
||||
HotkeySaveStateSlot(slotnum); \
|
||||
})
|
||||
#define DEFINE_HOTKEY_LOADSTATE_X(slotnum) \
|
||||
DEFINE_HOTKEY("LoadStateFromSlot" #slotnum, "Save States", "Load State From Slot " #slotnum, [](s32 pressed) { \
|
||||
#define DEFINE_HOTKEY_LOADSTATE_X(slotnum, title) \
|
||||
DEFINE_HOTKEY("LoadStateFromSlot" #slotnum, "Save States", title, [](s32 pressed) { \
|
||||
if (!pressed) \
|
||||
HotkeyLoadStateSlot(slotnum); \
|
||||
})
|
||||
DEFINE_HOTKEY_SAVESTATE_X(1)
|
||||
DEFINE_HOTKEY_LOADSTATE_X(1)
|
||||
DEFINE_HOTKEY_SAVESTATE_X(2)
|
||||
DEFINE_HOTKEY_LOADSTATE_X(2)
|
||||
DEFINE_HOTKEY_SAVESTATE_X(3)
|
||||
DEFINE_HOTKEY_LOADSTATE_X(3)
|
||||
DEFINE_HOTKEY_SAVESTATE_X(4)
|
||||
DEFINE_HOTKEY_LOADSTATE_X(4)
|
||||
DEFINE_HOTKEY_SAVESTATE_X(5)
|
||||
DEFINE_HOTKEY_LOADSTATE_X(5)
|
||||
DEFINE_HOTKEY_SAVESTATE_X(6)
|
||||
DEFINE_HOTKEY_LOADSTATE_X(6)
|
||||
DEFINE_HOTKEY_SAVESTATE_X(7)
|
||||
DEFINE_HOTKEY_LOADSTATE_X(7)
|
||||
DEFINE_HOTKEY_SAVESTATE_X(8)
|
||||
DEFINE_HOTKEY_LOADSTATE_X(8)
|
||||
DEFINE_HOTKEY_SAVESTATE_X(9)
|
||||
DEFINE_HOTKEY_LOADSTATE_X(9)
|
||||
DEFINE_HOTKEY_SAVESTATE_X(10)
|
||||
DEFINE_HOTKEY_LOADSTATE_X(10)
|
||||
DEFINE_HOTKEY_SAVESTATE_X(1, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 1"))
|
||||
DEFINE_HOTKEY_LOADSTATE_X(1, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 1"))
|
||||
DEFINE_HOTKEY_SAVESTATE_X(2, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 2"))
|
||||
DEFINE_HOTKEY_LOADSTATE_X(2, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 2"))
|
||||
DEFINE_HOTKEY_SAVESTATE_X(3, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 3"))
|
||||
DEFINE_HOTKEY_LOADSTATE_X(3, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 3"))
|
||||
DEFINE_HOTKEY_SAVESTATE_X(4, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 4"))
|
||||
DEFINE_HOTKEY_LOADSTATE_X(4, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 4"))
|
||||
DEFINE_HOTKEY_SAVESTATE_X(5, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 5"))
|
||||
DEFINE_HOTKEY_LOADSTATE_X(5, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 5"))
|
||||
DEFINE_HOTKEY_SAVESTATE_X(6, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 6"))
|
||||
DEFINE_HOTKEY_LOADSTATE_X(6, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 6"))
|
||||
DEFINE_HOTKEY_SAVESTATE_X(7, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 7"))
|
||||
DEFINE_HOTKEY_LOADSTATE_X(7, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 7"))
|
||||
DEFINE_HOTKEY_SAVESTATE_X(8, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 8"))
|
||||
DEFINE_HOTKEY_LOADSTATE_X(8, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 8"))
|
||||
DEFINE_HOTKEY_SAVESTATE_X(9, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 9"))
|
||||
DEFINE_HOTKEY_LOADSTATE_X(9, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 9"))
|
||||
DEFINE_HOTKEY_SAVESTATE_X(10, TRANSLATE_NOOP("Hotkeys", "Save State To Slot 10"))
|
||||
DEFINE_HOTKEY_LOADSTATE_X(10, TRANSLATE_NOOP("Hotkeys", "Load State From Slot 10"))
|
||||
#undef DEFINE_HOTKEY_SAVESTATE_X
|
||||
#undef DEFINE_HOTKEY_LOADSTATE_X
|
||||
END_HOTKEY_LIST()
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ void hwReset()
|
||||
{
|
||||
hwInit();
|
||||
|
||||
memzero( eeHw );
|
||||
std::memset(eeHw, 0, sizeof(eeHw));
|
||||
|
||||
psHu32(SBUS_F260) = 0x1D000060;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user