Compare commits

...
49 Commits
Author SHA1 Message Date
lightningterror c77d8b3709 DEV9: Cleanup ATA. 2023-06-23 00:52:15 +02:00
lightningterror 7b428bb6b0 DEV9: Cleanup dev9 base tree. 2023-06-23 00:52:15 +02:00
Tyler WildingandGitHub 6986030cd9 ci: don't build the localization branch on push (#9031) 2023-06-22 17:33:10 -04:00
refractionpcsx2 cc9b9a1935 UI: Fix some typo's and casing in UI 2023-06-22 18:42:03 +01:00
JordanTheToasterandrefractionpcsx2 2b7eeba55c GameDB: Matrix Path Of Neo Fixes
Fixes broken post processing by using autoflush.
2023-06-22 10:13:50 +01:00
Stenzek c87dd99824 GS/HW: Remove targets which lie completely within the invalidate range
Fixes part of Burnout 3's car reflections.
2023-06-22 19:12:22 +10:00
Stenzek fbd837eadb GS/HW: Improve draw rect accuracy 2023-06-22 19:12:22 +10:00
Stenzek 7c9c8e197c Common: Replace MemsetFast routines with C memset
And associated cleanup.

On most compilers these days, it'll either inline the memset with vector
fills or rep stosq, or outline with a call to memset.

I trust the compiler is probably going to make a better decision here,
than manual SSE intrinsics.

Ends up a couple of percent faster in FMV decoding.
2023-06-22 19:11:57 +10:00
Stenzek 0366929231 Flatpak: Add screenshots 2023-06-22 18:32:51 +10:00
KamFretoZandrefractionpcsx2 10d5261153 Updater: Clarify the error message when the program being runs directly 2023-06-21 17:32:24 +01:00
refractionpcsx2 3278856764 GS/HW: Adjust BurnoutGames CRC to allow preloading of undercarriage 2023-06-21 15:11:09 +01:00
refractionpcsx2 ff5a9e0ea1 GS/HW: Add target check safety to FFX and Sonic Unleashed CRC hacks 2023-06-21 15:11:09 +01:00
lightningterror 59b0c09443 GS-hw: Fix Wunused-variable warning. 2023-06-21 00:19:26 +02:00
lightningterror ae772e6a74 Elfheader: Fix Wsign-compare warnings. 2023-06-21 00:19:26 +02:00
RedPanda4552andrefractionpcsx2 0a58783a86 Translations: Fix missing context marker on Manual Hardware Fixes string
Fixes CTD when OSD messages print
2023-06-20 21:19:07 +01:00
refractionpcsx2 6f6de13fd4 GameDB: Add VU Clamping to Motorstorm 2023-06-20 20:30:23 +01:00
refractionpcsx2 89dcb78efa GS/CRC: Fix Ar Tonelico 2 CRC hack to check DS exists 2023-06-20 20:14:13 +01:00
Stenzek 703c02c32c Qt: Update base (en) translation 2023-06-20 22:46:00 +10:00
Stenzek adcfca4db3 Qt: Localization support 2023-06-20 22:46:00 +10:00
Stenzek c359223fd4 ImGuiManager: Localization support 2023-06-20 22:46:00 +10:00
Stenzek c4c7d26bb3 Host: Remove now-unused Add[Keyed]FormattedOSDMessage 2023-06-20 22:46:00 +10:00
Stenzek c06bc16b22 Misc: Mark core strings for translation 2023-06-20 22:46:00 +10:00
Stenzek f7bc05c735 Host: Add message translation functions 2023-06-20 22:46:00 +10:00
Stenzek ff02d41992 USB: Make GetDeviceTypes() return C strings 2023-06-20 22:46:00 +10:00
Stenzek ec180e2771 Hotkeys: Fix adjust target speed 2023-06-20 20:36:47 +10:00
Stenzek dffa9e0b8c VMManager: Fix WS patch not applying auto aspect ratio 2023-06-20 20:36:47 +10:00
Stenzek 497e06bcd9 VMManager: Close memcards on boot failure
And get rid of some double shutdowns.
2023-06-20 20:36:47 +10:00
Stenzek 4c67c165fa GS/HW: Preload uploads even when CPU CLUT is on 2023-06-20 12:52:06 +10:00
Stenzek 2c175c0c7e GS/Skip draw when ZTE=1 and ZTST is NEVER 2023-06-20 12:52:06 +10:00
Stenzek 6babbc1ff9 GS/HW: Cache PrimitiveCoversWithoutGaps() value 2023-06-20 12:52:06 +10:00
Stenzek 8af9aace3c GS/Vulkan: Fix incorrect push/pop with cleared colclip target 2023-06-20 12:52:06 +10:00
Stenzek 601b75b611 GS/HW: Fix some incorrect clear behavior 2023-06-20 12:52:06 +10:00
Stenzek 350037fc75 GS: Store clear colour as RGBA32
And defer clears until draw time for DX11 and OpenGL.
2023-06-20 12:52:06 +10:00
Stenzek f6bcfc3abd GS: Make ClearDepth() take a value 2023-06-20 12:52:06 +10:00
Stenzek a480c972f7 GS/HW: Add ReplaceVerticesWithSprite() helper 2023-06-20 12:52:06 +10:00
Stenzek 581ded2c93 GS/HW: Fix mem clear for Z formats 2023-06-20 12:52:06 +10:00
Stenzek 06176e291a GS/Vulkan: Prevent upload heap being used w/ debug and non Re-BAR GPUs 2023-06-20 12:52:06 +10:00
Stenzek 14ee1b40d0 MTGS: Sync privileged registers before loading state
Fixes display registers not being present for the first frame when
loading GS dumps.
2023-06-20 12:52:06 +10:00
refractionpcsx2 9acb98a2c8 Host/Mcd: Fix boot order so memcard type is set before loading memcards 2023-06-19 22:21:16 +01:00
PCSX2 Botandlightningterror daf50df337 PAD: Update to latest controller database. 2023-06-19 18:23:42 +02:00
Stenzek c4d136383c Qt: Fix size of input profile dropdown 2023-06-19 23:16:37 +10:00
Stenzek 5b5016bfd4 USB: Copy configuration when creating input profile
Also reset configuration when requested.
2023-06-19 23:16:37 +10:00
Stenzek 02352ab231 VMManager: Only reload core settings on ELF load
Game/HW fixes are really the only thing which is going to change, so we
can save ourselves some time by only applying those.
2023-06-19 23:16:37 +10:00
Stenzek a4909d3575 Qt: Fix crash booting with mouse mapping 2023-06-19 23:16:37 +10:00
Stenzek fbb50e2895 VMManager: Fix fast forward boot with GS dumps 2023-06-19 23:16:37 +10:00
Stenzek 0e4bf501f1 VMManager: Fix title updates when switching GS dumps 2023-06-19 23:16:37 +10:00
Stenzek 89b97456b7 VMManager: Fix dump playback adding to play time 2023-06-19 23:16:37 +10:00
Stenzek fc4112c459 GS/HW: Implement FBW-based moves
Used by Metal Gear Solid 2, and Zone of the Enders 2.
2023-06-19 13:42:02 +10:00
Stenzekandrefractionpcsx2 b6923f49b1 GS/HW: Add render fix for MGS3 DoF effect 2023-06-17 20:26:19 +01:00
153 changed files with 7421 additions and 3773 deletions
+2 -2
View File
@@ -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 -2
View File
@@ -2,8 +2,8 @@ name: 🐧 Linux Builds
on:
push:
branches:
- '*'
branches-ignore:
- "l10n_master"
pull_request:
branches:
- master
+2 -2
View File
@@ -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 -2
View File
@@ -2,8 +2,8 @@ name: 🖥️ Windows Builds
on:
push:
branches:
- '*'
branches-ignore:
- "l10n_master"
pull_request:
branches:
- master
+52 -2
View File
@@ -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:
+3 -1
View File
@@ -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,
-1
View File
@@ -81,7 +81,6 @@ target_sources(common PRIVATE
HeapArray.h
HTTPDownloader.h
MemorySettingsInterface.h
MemsetFast.inl
MD5Digest.h
MRCHelpers.h
Path.h
-18
View File
@@ -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();
-95
View File
@@ -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));
}
+1 -1
View File
@@ -180,4 +180,4 @@
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
</Project>
-4
View File
@@ -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);
+6 -6
View File
@@ -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();
+12 -7
View File
@@ -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
View File
@@ -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'
+12
View File
@@ -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
//////////////////////////////////////////////////////////////////////////
+23
View File
@@ -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
View File
@@ -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);
+1
View File
@@ -159,6 +159,7 @@ private Q_SLOTS:
void onToolsOpenDataDirectoryTriggered();
void onToolsCoverDownloaderTriggered();
void updateTheme();
void updateLanguage();
void onScreenshotActionTriggered();
void onSaveGSDumpActionTriggered();
void onBlockDumpActionToggled(bool checked);
+1
View File
@@ -1220,6 +1220,7 @@ bool QtHost::InitializeConfig()
LogSink::SetBlockSystemConsole(QtHost::InNoGUIMode());
VMManager::Internal::LoadStartupSettings();
InstallTranslator();
return true;
}
+9
View File
@@ -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)) :
+14 -1
View File
@@ -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">
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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."));
+1 -1
View File
@@ -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>
+10 -3
View File
@@ -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;
};
+218
View File
@@ -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)
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
+5
View File
@@ -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>
+9
View File
@@ -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>
+6 -5
View File
@@ -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
View File
@@ -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)
{
+6 -2
View File
@@ -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))
{
+2 -2
View File
@@ -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
View File
@@ -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)
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
//Vendors 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++)
+29 -37
View File
@@ -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;
}
+8 -17
View File
@@ -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();
+3 -3
View File
@@ -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)
+2 -2
View File
@@ -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
View File
@@ -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;
}
+5 -6
View File
@@ -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
+2 -3
View File
@@ -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;
+6 -7
View File
@@ -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);
+3 -7
View File
@@ -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
View File
@@ -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);
+6 -8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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()
+16
View File
@@ -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
+2
View File
@@ -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
+5 -1
View File
@@ -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&)
{
+5
View File
@@ -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());
+2 -2
View File
@@ -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);
+3 -4
View File
@@ -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();
+29 -20
View File
@@ -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)
+5 -4
View File
@@ -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)
{
+49 -31
View File
@@ -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));
+3 -4
View File
@@ -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;
+8 -26
View File
@@ -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())
+19 -36
View File
@@ -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);
+3 -4
View File
@@ -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);
+1 -1
View File
@@ -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);
+57 -14
View File
@@ -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),
+1
View File
@@ -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);
+107 -29
View File
@@ -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)
{
+8 -2
View File
@@ -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);
+16 -3
View File
@@ -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;
}
+135 -9
View File
@@ -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
{
+3
View File
@@ -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;
}
+2 -3
View File
@@ -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;
+8 -16
View File
@@ -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);
}
+136 -138
View File
@@ -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)
+5 -6
View File
@@ -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;
+11 -18
View File
@@ -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());
+1 -9
View File
@@ -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
+20 -28
View File
@@ -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};
+3 -4
View File
@@ -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();
+1 -1
View File
@@ -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);
}
+35
View File
@@ -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)
{
+6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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