mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4a8fc5b71 | ||
|
|
8eb46b5a4c | ||
|
|
8be16d1039 | ||
|
|
76e6208d1b | ||
|
|
bc09080ba5 | ||
|
|
a6eb257a3a | ||
|
|
e62450d255 | ||
|
|
1aa922f700 | ||
|
|
4c9d2f99b1 | ||
|
|
f6e899b570 | ||
|
|
695c39fba2 | ||
|
|
e5616cff98 | ||
|
|
76d5994c1e | ||
|
|
cbb40832a1 | ||
|
|
e4bdcde1ca | ||
|
|
863e119ff4 | ||
|
|
2ccf6dc872 | ||
|
|
24ebf1b4f1 | ||
|
|
ed2832434c | ||
|
|
5e160fca8f | ||
|
|
a0ef82e221 | ||
|
|
3e7ac3d66c | ||
|
|
730e6fa737 | ||
|
|
cdfcd9fddd | ||
|
|
b6930c10b9 | ||
|
|
852734580d | ||
|
|
d1dc6a9c1d | ||
|
|
4fa6d3ed3f | ||
|
|
92e190ad6c | ||
|
|
da4fcffef4 | ||
|
|
1a5731dd8e | ||
|
|
e764c5cd4e | ||
|
|
e23b247947 | ||
|
|
3d7792436f | ||
|
|
d8187fbea4 | ||
|
|
02259ad0a5 | ||
|
|
220a68df9a | ||
|
|
2ced24f69e | ||
|
|
ec91d0dc74 | ||
|
|
46874f4673 | ||
|
|
9eac47dc6c | ||
|
|
9e3fd5c2e0 |
@@ -11,10 +11,9 @@
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"type": "git",
|
||||
"url": "https://github.com/sammycage/plutovg.git",
|
||||
"tag": "v0.0.13",
|
||||
"sha256": "5e4712cf873b0c7829a4a6157763e2ad3ac49164"
|
||||
"tag": "v0.0.13"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
|
||||
@@ -12,10 +12,9 @@
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"type": "git",
|
||||
"url": "https://github.com/sammycage/plutosvg.git",
|
||||
"tag": "v0.0.6",
|
||||
"sha256": "c5388fa96feca1f1376a3d0485d5e35159452707"
|
||||
"tag": "v0.0.6"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
||||
|
||||
@@ -62,10 +62,12 @@ endif()
|
||||
|
||||
# gsrunner
|
||||
if(ENABLE_GSRUNNER)
|
||||
if (NOT WIN32)
|
||||
message(WARNING "GSRunner is only supported on Windows and may not build on your system")
|
||||
if (NOT WIN32 AND NOT APPLE)
|
||||
message(WARNING "GSRunner is only supported on Windows and macOS and may not build on your system")
|
||||
endif()
|
||||
add_subdirectory(pcsx2-gsrunner)
|
||||
else()
|
||||
add_subdirectory(pcsx2-gsrunner EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
@@ -2557,8 +2557,6 @@ SCAJ-25012:
|
||||
SCAJ-25026:
|
||||
name: "Kunoichi Shinobi"
|
||||
region: "NTSC-Unk"
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_Kunoichi"
|
||||
SCAJ-25034:
|
||||
name: "Sakura Taisen Monogatari"
|
||||
region: "NTSC-Unk"
|
||||
@@ -12878,8 +12876,6 @@ SLAJ-25023:
|
||||
SLAJ-25026:
|
||||
name: "Kunoichi Shinobi"
|
||||
region: "NTSC-Unk"
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_Kunoichi"
|
||||
SLAJ-25027:
|
||||
name: "Sonic Heroes"
|
||||
region: "NTSC-Unk"
|
||||
@@ -12894,8 +12890,6 @@ SLAJ-25030:
|
||||
SLAJ-25031:
|
||||
name: "Kunoichi - Shinobu"
|
||||
region: "NTSC-C-J"
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_Kunoichi"
|
||||
SLAJ-25033:
|
||||
name: "Puyo Puyo Fever"
|
||||
region: "NTSC-Unk"
|
||||
@@ -12927,7 +12921,7 @@ SLAJ-25041:
|
||||
name: "Harry Potter and the Prisoner of Azkaban"
|
||||
region: "NTSC-C"
|
||||
gsHWFixes:
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Aligns mirror reflections, removes some bloom-related ghosting.
|
||||
recommendedBlendingLevel: 4 # Improves lighting effects.
|
||||
SLAJ-25042:
|
||||
@@ -16829,7 +16823,7 @@ SLES-51192:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51193:
|
||||
@@ -16839,7 +16833,7 @@ SLES-51193:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51194:
|
||||
@@ -16849,7 +16843,7 @@ SLES-51194:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51195:
|
||||
@@ -16859,7 +16853,7 @@ SLES-51195:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51196:
|
||||
@@ -16869,7 +16863,7 @@ SLES-51196:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51197:
|
||||
@@ -16926,7 +16920,7 @@ SLES-51214:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51215:
|
||||
@@ -16936,7 +16930,7 @@ SLES-51215:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51216:
|
||||
@@ -16946,7 +16940,7 @@ SLES-51216:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51217:
|
||||
@@ -16956,7 +16950,7 @@ SLES-51217:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51218:
|
||||
@@ -16966,7 +16960,7 @@ SLES-51218:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51219:
|
||||
@@ -16976,7 +16970,7 @@ SLES-51219:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
texturePreloading: 0 # Performs better on certain areas like mid-game in and around the castle as the hash goes easily to 200 MB.
|
||||
SLES-51220:
|
||||
@@ -19388,8 +19382,6 @@ SLES-52238:
|
||||
name: "Nightshade"
|
||||
region: "PAL-M5"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_Kunoichi"
|
||||
SLES-52240:
|
||||
name: "International Pool Championship"
|
||||
region: "PAL-M5"
|
||||
@@ -19896,7 +19888,7 @@ SLES-52440:
|
||||
region: "PAL-M7"
|
||||
compat: 3
|
||||
gsHWFixes:
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Aligns mirror reflections, removes some bloom-related ghosting.
|
||||
recommendedBlendingLevel: 4 # Improves lighting effects.
|
||||
SLES-52444:
|
||||
@@ -20123,7 +20115,7 @@ SLES-52527:
|
||||
name: "Harry Potter og Fangen fra Azkaban"
|
||||
region: "PAL-M4"
|
||||
gsHWFixes:
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Aligns mirror reflections, removes some bloom-related ghosting.
|
||||
recommendedBlendingLevel: 4 # Improves lighting effects.
|
||||
SLES-52531:
|
||||
@@ -20434,7 +20426,7 @@ SLES-52600:
|
||||
name: "Harry Potter and the Prisoner of Azkaban"
|
||||
region: "PAL-PL"
|
||||
gsHWFixes:
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Aligns mirror reflections, removes some bloom-related ghosting.
|
||||
recommendedBlendingLevel: 4 # Improves lighting effects.
|
||||
SLES-52601:
|
||||
@@ -22086,6 +22078,8 @@ SLES-53099:
|
||||
SLES-53100:
|
||||
name: "Scooby-Doo! Unmasked"
|
||||
region: "PAL-M4"
|
||||
gsHWFixes:
|
||||
nativeScaling: 2 # Fixes post processing position.
|
||||
SLES-53104:
|
||||
name: "Tom Clancy's Rainbow Six - Lockdown"
|
||||
region: "PAL-M5"
|
||||
@@ -30956,8 +30950,6 @@ SLKA-25135:
|
||||
name: "Kunoichi"
|
||||
region: "NTSC-K"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_Kunoichi"
|
||||
SLKA-25136:
|
||||
name: "Need for Speed - Underground"
|
||||
region: "NTSC-K"
|
||||
@@ -31108,7 +31100,7 @@ SLKA-25172:
|
||||
name: "Harry Potter and the Prisoner of Azkaban"
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Aligns mirror reflections, removes some bloom-related ghosting.
|
||||
recommendedBlendingLevel: 4 # Improves lighting effects.
|
||||
SLKA-25173:
|
||||
@@ -32522,8 +32514,6 @@ SLKA-35004:
|
||||
name: "Sakura Wars 5 So Long My Love"
|
||||
region: "NTSC-K"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_SakuraWarsSoLongMyLove"
|
||||
SLKA-35005:
|
||||
name: "Jin Samguk Mussang 5 - Special"
|
||||
region: "NTSC-K"
|
||||
@@ -35217,8 +35207,6 @@ SLPM-61059:
|
||||
name-sort: "くのいち -しのび- [たいけんばん]"
|
||||
name-en: "Kunoichi -Shinobi- [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_Kunoichi"
|
||||
SLPM-61060:
|
||||
name: "BUSIN 0 ~Wizardry Alternative NEO~ [体験版]"
|
||||
name-sort: "ぶしん ぜろ ~うぃざーどりぃ おるたなてぃぶ ねお~ [たいけんばん]"
|
||||
@@ -36957,7 +36945,7 @@ SLPM-62241:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
SLPM-62242:
|
||||
name: "撞球 ビリヤードマスター2"
|
||||
@@ -38369,7 +38357,7 @@ SLPM-62513:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
SLPM-62514:
|
||||
name: "シムピープル ~お茶の間劇場~ [EA BEST HITS]"
|
||||
@@ -39800,7 +39788,7 @@ SLPM-64528:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
SLPM-64532:
|
||||
name: "Digital Holmes"
|
||||
@@ -42473,8 +42461,6 @@ SLPM-65447:
|
||||
name-en: "Kunoichi -Shinobi-"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_Kunoichi"
|
||||
SLPM-65448:
|
||||
name: "カンブリアンQTS ~化石になっても~"
|
||||
name-sort: "かんぶりあんQTS ~かせきになっても~"
|
||||
@@ -43355,7 +43341,7 @@ SLPM-65612:
|
||||
name-en: "Harry Potter and the Prisoner of Azkaban"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Aligns mirror reflections, removes some bloom-related ghosting.
|
||||
recommendedBlendingLevel: 4 # Improves lighting effects.
|
||||
SLPM-65613:
|
||||
@@ -52157,7 +52143,7 @@ SLPM-68005:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
SLPM-68007:
|
||||
name: "カラオケレボリューション用マイク同梱お試しディスク"
|
||||
@@ -54308,7 +54294,7 @@ SLPS-20234:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
SLPS-20237:
|
||||
name: "Saikyou Toudai Shougi 3"
|
||||
@@ -59136,6 +59122,8 @@ SLPS-25581:
|
||||
name-sort: "しんぷる2000しりーず Vol. 92 THE のろいのげーむ"
|
||||
name-en: "Simple 2000 Series Vol. 92 - The Game of a Curse"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
cpuCLUTRender: 1 # Fixes corrupted and missing graphics.
|
||||
SLPS-25582:
|
||||
name: "アストロ球団 決戦!!ビクトリー球団編"
|
||||
name-sort: "あすとろきゅうだん けっせん!!びくとりーきゅうだんへん"
|
||||
@@ -65273,7 +65261,7 @@ SLUS-20576:
|
||||
- EETimingHack # Fixes flickering textures.
|
||||
gsHWFixes:
|
||||
recommendedBlendingLevel: 4 # Fixes missing lighting effects.
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Fixes misaligned lighting and other effects.
|
||||
SLUS-20577:
|
||||
name: "Drome Racers"
|
||||
@@ -66538,8 +66526,6 @@ SLUS-20810:
|
||||
name: "Nightshade"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_Kunoichi"
|
||||
SLUS-20811:
|
||||
name: "Need for Speed - Underground"
|
||||
region: "NTSC-U"
|
||||
@@ -67218,7 +67204,7 @@ SLUS-20926:
|
||||
name: "Harry Potter and the Prisoner of Azkaban"
|
||||
region: "NTSC-U"
|
||||
gsHWFixes:
|
||||
cpuFramebufferConversion: 1 # Fixes right side of the screen from garbage textures.
|
||||
textureInsideRT: 1 # Fixes right side shadow lookup.
|
||||
halfPixelOffset: 2 # Aligns mirror reflections, removes some bloom-related ghosting.
|
||||
recommendedBlendingLevel: 4 # Improves lighting effects.
|
||||
SLUS-20927:
|
||||
@@ -68231,6 +68217,8 @@ SLUS-21091:
|
||||
name: "Scooby-Doo! Unmasked"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
nativeScaling: 2 # Fixes post processing position.
|
||||
SLUS-21093:
|
||||
name: "Worms Forts - Under Siege"
|
||||
region: "NTSC-U"
|
||||
@@ -73133,8 +73121,6 @@ SLUS-21927:
|
||||
name: "Sakura Wars - So Long, My Love [English - Disc 1]"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_SakuraWarsSoLongMyLove"
|
||||
SLUS-21928:
|
||||
name: "Scooby-Doo! and the Spooky Swamp"
|
||||
region: "NTSC-U"
|
||||
@@ -73151,8 +73137,6 @@ SLUS-21930:
|
||||
name: "Sakura Wars - So Long, My Love [Japanese - Disc 2]"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_SakuraWarsSoLongMyLove"
|
||||
SLUS-21931:
|
||||
name: "Disney/Pixar Toy Story 3"
|
||||
region: "NTSC-U"
|
||||
|
||||
@@ -1000,6 +1000,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000853200008906000000010000,Nacon Revolution X Unlimited,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X,
|
||||
030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
@@ -1607,6 +1608,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
|
||||
030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
|
||||
030000009b2800006100000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux,
|
||||
030000009b2800006400000001010000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Linux,
|
||||
030000009b2800008000000020020000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux,
|
||||
030000009b2800008000000001010000,Raphnet Wii Classic Adapter V3,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux,
|
||||
03000000f8270000bf0b000011010000,Razer Kishi,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
|
||||
@@ -313,6 +313,127 @@ float ps_convert_rgb5a1_float16_biln(PS_INPUT input) : SV_Depth
|
||||
SAMPLE_RGBA_DEPTH_BILN(rgb5a1_to_depth16);
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_convert_rgb5a1_8i(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
// Convert a RGB5A1 texture into a 8 bits packed texture
|
||||
// Input column: 16x2 RGB5A1 pixels
|
||||
// 0: 16 RGBA
|
||||
// 1: 16 RGBA
|
||||
// Output column: 16x4 Index pixels
|
||||
// 0: 16 R5G2
|
||||
// 1: 16 R5G2
|
||||
// 2: 16 G2B5A1
|
||||
// 3: 16 G2B5A1
|
||||
uint2 pos = uint2(input.p.xy);
|
||||
|
||||
// Collapse separate R G B A areas into their base pixel
|
||||
uint2 column = (pos & ~uint2(0u, 3u)) / uint2(1,2);
|
||||
uint2 subcolumn = (pos & uint2(0u, 1u));
|
||||
column.x -= (column.x / 128) * 64;
|
||||
column.y += (column.y / 32) * 32;
|
||||
|
||||
uint PSM = uint(DOFFSET);
|
||||
|
||||
// Deal with swizzling differences
|
||||
if ((PSM & 0x8) != 0) // PSMCT16S
|
||||
{
|
||||
if ((pos.x & 32) != 0)
|
||||
{
|
||||
column.y += 32; // 4 columns high times 4 to get bottom 4 blocks
|
||||
column.x &= ~32;
|
||||
}
|
||||
|
||||
if ((pos.x & 64) != 0)
|
||||
{
|
||||
column.x -= 32;
|
||||
}
|
||||
|
||||
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
|
||||
{
|
||||
column.x ^= 16;
|
||||
column.y ^= 8;
|
||||
}
|
||||
|
||||
if ((PSM & 0x30) != 0) // PSMZ16S - Untested but hopefully ok if anything uses it.
|
||||
{
|
||||
column.x ^= 32;
|
||||
column.y ^= 16;
|
||||
}
|
||||
}
|
||||
else // PSMCT16
|
||||
{
|
||||
if ((pos.y & 32) != 0)
|
||||
{
|
||||
column.y -= 16;
|
||||
column.x += 32;
|
||||
}
|
||||
|
||||
if ((pos.x & 96) != 0)
|
||||
{
|
||||
uint multi = (pos.x & 96) / 32;
|
||||
column.y += 16 * multi; // 4 columns high times 4 to get bottom 4 blocks
|
||||
column.x -= (pos.x & 96);
|
||||
}
|
||||
|
||||
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
|
||||
{
|
||||
column.x ^= 16;
|
||||
column.y ^= 8;
|
||||
}
|
||||
|
||||
if ((PSM & 0x30) != 0) // PSMZ16 - Untested but hopefully ok if anything uses it.
|
||||
{
|
||||
column.x ^= 32;
|
||||
column.y ^= 32;
|
||||
}
|
||||
}
|
||||
|
||||
uint2 coord = column | subcolumn;
|
||||
|
||||
// Compensate for potentially differing page pitch.
|
||||
uint SBW = uint(EMODA);
|
||||
uint DBW = uint(EMODC);
|
||||
uint2 block_xy = coord / uint2(64,64);
|
||||
uint block_num = (block_xy.y * (DBW / 128)) + block_xy.x;
|
||||
uint2 block_offset = uint2((block_num % (SBW / 64)) * 64, (block_num / (SBW / 64)) * 64);
|
||||
coord = (coord % uint2(64, 64)) + block_offset;
|
||||
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
|
||||
float ScaleFactor = BGColor.x;
|
||||
if (floor(ScaleFactor) != ScaleFactor)
|
||||
coord = uint2(float2(coord) * ScaleFactor);
|
||||
else
|
||||
coord *= uint(ScaleFactor);
|
||||
|
||||
float4 pixel = Texture.Load(int3(int2(coord), 0));
|
||||
uint4 denorm_c = (uint4)(pixel * 255.5f);
|
||||
if ((pos.y & 2u) == 0u)
|
||||
{
|
||||
uint red = (denorm_c.r >> 3) & 0x1Fu;
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
float sel0 = (float)(((green << 5) | red) & 0xFF) / 255.0f;
|
||||
|
||||
output.c = (float4)(sel0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
uint blue = (denorm_c.b >> 3) & 0x1Fu;
|
||||
uint alpha = denorm_c.a & 0x80u;
|
||||
float sel0 = (float)((alpha | (blue << 2) | (green >> 3)) & 0xFF) / 255.0f;
|
||||
|
||||
output.c = (float4)(sel0);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
@@ -237,9 +237,131 @@ void ps_convert_rgb5a1_float16_biln()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgb5a1_8i
|
||||
uniform uint SBW;
|
||||
uniform uint DBW;
|
||||
uniform uint PSM;
|
||||
uniform float ScaleFactor;
|
||||
|
||||
void ps_convert_rgb5a1_8i()
|
||||
{
|
||||
// Convert a RGB5A1 texture into a 8 bits packed texture
|
||||
// Input column: 16x2 RGB5A1 pixels
|
||||
// 0: 16 RGBA
|
||||
// 1: 16 RGBA
|
||||
// Output column: 16x4 Index pixels
|
||||
// 0: 16 R5G2
|
||||
// 1: 16 R5G2
|
||||
// 2: 16 G2B5A1
|
||||
// 3: 16 G2B5A1
|
||||
|
||||
uvec2 pos = uvec2(gl_FragCoord.xy);
|
||||
|
||||
// Collapse separate R G B A areas into their base pixel
|
||||
uvec2 column = (pos & ~uvec2(0u, 3u)) / uvec2(1,2);
|
||||
uvec2 subcolumn = (pos & uvec2(0u, 1u));
|
||||
column.x -= (column.x / 128) * 64;
|
||||
column.y += (column.y / 32) * 32;
|
||||
|
||||
// Deal with swizzling differences
|
||||
if ((PSM & 0x8) != 0) // PSMCT16S
|
||||
{
|
||||
if ((pos.x & 32) != 0)
|
||||
{
|
||||
column.y += 32; // 4 columns high times 4 to get bottom 4 blocks
|
||||
column.x &= ~32;
|
||||
}
|
||||
|
||||
if ((pos.x & 64) != 0)
|
||||
{
|
||||
column.x -= 32;
|
||||
}
|
||||
|
||||
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
|
||||
{
|
||||
column.x ^= 16;
|
||||
column.y ^= 8;
|
||||
}
|
||||
|
||||
if ((PSM & 0x30) != 0) // PSMZ16S - Untested but hopefully ok if anything uses it.
|
||||
{
|
||||
column.x ^= 32;
|
||||
column.y ^= 16;
|
||||
}
|
||||
}
|
||||
else // PSMCT16
|
||||
{
|
||||
if ((pos.y & 32) != 0)
|
||||
{
|
||||
column.y -= 16;
|
||||
column.x += 32;
|
||||
}
|
||||
|
||||
if ((pos.x & 96) != 0)
|
||||
{
|
||||
uint multi = (pos.x & 96) / 32;
|
||||
column.y += 16 * multi; // 4 columns high times 4 to get bottom 4 blocks
|
||||
column.x -= (pos.x & 96);
|
||||
}
|
||||
|
||||
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
|
||||
{
|
||||
column.x ^= 16;
|
||||
column.y ^= 8;
|
||||
}
|
||||
|
||||
if ((PSM & 0x30) != 0) // PSMZ16 - Untested but hopefully ok if anything uses it.
|
||||
{
|
||||
column.x ^= 32;
|
||||
column.y ^= 32;
|
||||
}
|
||||
}
|
||||
uvec2 coord = column | subcolumn;
|
||||
|
||||
// Compensate for potentially differing page pitch.
|
||||
uvec2 block_xy = coord / uvec2(64u, 64u);
|
||||
uint block_num = (block_xy.y * (DBW / 128u)) + block_xy.x;
|
||||
uvec2 block_offset = uvec2((block_num % (SBW / 64u)) * 64u, (block_num / (SBW / 64u)) * 64u);
|
||||
coord = (coord % uvec2(64u, 64u)) + block_offset;
|
||||
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
|
||||
if (floor(ScaleFactor) != ScaleFactor)
|
||||
coord = uvec2(vec2(coord) * ScaleFactor);
|
||||
else
|
||||
coord *= uvec2(ScaleFactor);
|
||||
|
||||
vec4 pixel = texelFetch(TextureSampler, ivec2(coord), 0);
|
||||
|
||||
uvec4 denorm_c = uvec4(pixel * 255.5f);
|
||||
if ((pos.y & 2u) == 0u)
|
||||
{
|
||||
uint red = (denorm_c.r >> 3) & 0x1Fu;
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
float sel0 = float(((green << 5) | red) & 0xFF) / 255.0f;
|
||||
|
||||
SV_Target0 = vec4(sel0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
uint blue = (denorm_c.b >> 3) & 0x1Fu;
|
||||
uint alpha = denorm_c.a & 0x80u;
|
||||
float sel0 = float((alpha | (blue << 2) | (green >> 3)) & 0xFF) / 255.0f;
|
||||
|
||||
SV_Target0 = vec4(sel0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba_8i
|
||||
uniform uint SBW;
|
||||
uniform uint DBW;
|
||||
uniform uint PSM;
|
||||
uniform float ScaleFactor;
|
||||
|
||||
void ps_convert_rgba_8i()
|
||||
|
||||
@@ -307,12 +307,138 @@ void ps_convert_rgb5a1_float16_biln()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgb5a1_8i
|
||||
layout(push_constant) uniform cb10
|
||||
{
|
||||
uint SBW;
|
||||
uint DBW;
|
||||
uint PSM;
|
||||
float cb_pad1;
|
||||
float ScaleFactor;
|
||||
vec3 cb_pad2;
|
||||
};
|
||||
|
||||
void ps_convert_rgb5a1_8i()
|
||||
{
|
||||
// Convert a RGB5A1 texture into a 8 bits packed texture
|
||||
// Input column: 16x2 RGB5A1 pixels
|
||||
// 0: 16 RGBA
|
||||
// 1: 16 RGBA
|
||||
// Output column: 16x4 Index pixels
|
||||
// 0: 16 R5G2
|
||||
// 1: 16 R5G2
|
||||
// 2: 16 G2B5A1
|
||||
// 3: 16 G2B5A1
|
||||
|
||||
uvec2 pos = uvec2(gl_FragCoord.xy);
|
||||
|
||||
// Collapse separate R G B A areas into their base pixel
|
||||
uvec2 column = (pos & ~uvec2(0u, 3u)) / uvec2(1,2);
|
||||
uvec2 subcolumn = (pos & uvec2(0u, 1u));
|
||||
column.x -= (column.x / 128) * 64;
|
||||
column.y += (column.y / 32) * 32;
|
||||
|
||||
// Deal with swizzling differences
|
||||
if ((PSM & 0x8) != 0) // PSMCT16S
|
||||
{
|
||||
if ((pos.x & 32) != 0)
|
||||
{
|
||||
column.y += 32; // 4 columns high times 4 to get bottom 4 blocks
|
||||
column.x &= ~32;
|
||||
}
|
||||
|
||||
if ((pos.x & 64) != 0)
|
||||
{
|
||||
column.x -= 32;
|
||||
}
|
||||
|
||||
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
|
||||
{
|
||||
column.x ^= 16;
|
||||
column.y ^= 8;
|
||||
}
|
||||
|
||||
if ((PSM & 0x30) != 0) // PSMZ16S - Untested but hopefully ok if anything uses it.
|
||||
{
|
||||
column.x ^= 32;
|
||||
column.y ^= 16;
|
||||
}
|
||||
}
|
||||
else // PSMCT16
|
||||
{
|
||||
if ((pos.y & 32) != 0)
|
||||
{
|
||||
column.y -= 16;
|
||||
column.x += 32;
|
||||
}
|
||||
|
||||
if ((pos.x & 96) != 0)
|
||||
{
|
||||
uint multi = (pos.x & 96) / 32;
|
||||
column.y += 16 * multi; // 4 columns high times 4 to get bottom 4 blocks
|
||||
column.x -= (pos.x & 96);
|
||||
}
|
||||
|
||||
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
|
||||
{
|
||||
column.x ^= 16;
|
||||
column.y ^= 8;
|
||||
}
|
||||
|
||||
if ((PSM & 0x30) != 0) // PSMZ16 - Untested but hopefully ok if anything uses it.
|
||||
{
|
||||
column.x ^= 32;
|
||||
column.y ^= 32;
|
||||
}
|
||||
}
|
||||
uvec2 coord = column | subcolumn;
|
||||
|
||||
// Compensate for potentially differing page pitch.
|
||||
uvec2 block_xy = coord / uvec2(64u, 64u);
|
||||
uint block_num = (block_xy.y * (DBW / 128u)) + block_xy.x;
|
||||
uvec2 block_offset = uvec2((block_num % (SBW / 64u)) * 64u, (block_num / (SBW / 64u)) * 64u);
|
||||
coord = (coord % uvec2(64u, 64u)) + block_offset;
|
||||
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
|
||||
if (floor(ScaleFactor) != ScaleFactor)
|
||||
coord = uvec2(vec2(coord) * ScaleFactor);
|
||||
else
|
||||
coord *= uvec2(ScaleFactor);
|
||||
|
||||
vec4 pixel = texelFetch(samp0, ivec2(coord), 0);
|
||||
uvec4 denorm_c = uvec4(pixel * 255.5f);
|
||||
if ((pos.y & 2u) == 0u)
|
||||
{
|
||||
uint red = (denorm_c.r >> 3) & 0x1Fu;
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
float sel0 = float(((green << 5) | red) & 0xFF) / 255.0f;
|
||||
|
||||
o_col0 = vec4(sel0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
uint blue = (denorm_c.b >> 3) & 0x1Fu;
|
||||
uint alpha = denorm_c.a & 0x80u;
|
||||
float sel0 = float((alpha | (blue << 2) | (green >> 3)) & 0xFF) / 255.0f;
|
||||
|
||||
o_col0 = vec4(sel0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba_8i
|
||||
layout(push_constant) uniform cb10
|
||||
{
|
||||
uint SBW;
|
||||
uint DBW;
|
||||
uvec2 cb_pad1;
|
||||
uint PSM;
|
||||
float cb_pad1;
|
||||
float ScaleFactor;
|
||||
vec3 cb_pad2;
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ include(GNUInstallDirs)
|
||||
# Misc option
|
||||
#-------------------------------------------------------------------------------
|
||||
option(ENABLE_TESTS "Enables building the unit tests" ON)
|
||||
option(ENABLE_GSRUNNER "Enables building the GSRunner" OFF)
|
||||
option(ENABLE_GSRUNNER "Enables building the GSRunner by default. It can still be built with `make pcsx2-gsrunner` otherwise." OFF)
|
||||
option(LTO_PCSX2_CORE "Enable LTO/IPO/LTCG on the subset of pcsx2 that benefits most from it but not anything else")
|
||||
option(USE_VTUNE "Plug VTUNE to profile GS JIT.")
|
||||
option(PACKAGE_MODE "Use this option to ease packaging of PCSX2 (developer/distribution option)")
|
||||
|
||||
@@ -120,7 +120,7 @@ add_subdirectory(3rdparty/demangler EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/ccc EXCLUDE_FROM_ALL)
|
||||
|
||||
# The docking system for the debugger.
|
||||
find_package(KDDockWidgets-qt6 REQUIRED)
|
||||
find_package(KDDockWidgets-qt6 2.0.0 REQUIRED)
|
||||
# Add an extra include path to work around a broken include directive.
|
||||
# TODO: Remove this the next time we update KDDockWidgets.
|
||||
get_target_property(KDDOCKWIDGETS_INCLUDE_DIRECTORY KDAB::kddockwidgets INTERFACE_INCLUDE_DIRECTORIES)
|
||||
|
||||
@@ -31,6 +31,19 @@ namespace CocoaTools
|
||||
bool DelayedLaunch(std::string_view file);
|
||||
/// Open a Finder window to the given URL
|
||||
bool ShowInFinder(std::string_view file);
|
||||
/// Get the path to the resources directory of the current application
|
||||
std::optional<std::string> GetResourcePath();
|
||||
|
||||
/// Create a window
|
||||
void* CreateWindow(std::string_view title, uint32_t width, uint32_t height);
|
||||
/// Destroy a window
|
||||
void DestroyWindow(void* window);
|
||||
/// Make a WindowInfo from the given window
|
||||
void GetWindowInfoFromWindow(WindowInfo* wi, void* window);
|
||||
/// Run cocoa event loop
|
||||
void RunCocoaEventLoop(bool wait_forever = false);
|
||||
/// Posts an event to the main telling `RunCocoaEventLoop(true)` to exit
|
||||
void StopMainThreadEventLoop();
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
@@ -224,5 +224,103 @@ bool CocoaTools::DelayedLaunch(std::string_view file)
|
||||
bool CocoaTools::ShowInFinder(std::string_view file)
|
||||
{
|
||||
return [[NSWorkspace sharedWorkspace] selectFile:NSStringFromStringView(file)
|
||||
inFileViewerRootedAtPath:nil];
|
||||
inFileViewerRootedAtPath:@""];
|
||||
}
|
||||
|
||||
std::optional<std::string> CocoaTools::GetResourcePath()
|
||||
{ @autoreleasepool {
|
||||
if (NSBundle* bundle = [NSBundle mainBundle])
|
||||
{
|
||||
NSString* rsrc = [bundle resourcePath];
|
||||
NSString* root = [bundle bundlePath];
|
||||
if ([rsrc isEqualToString:root])
|
||||
rsrc = [rsrc stringByAppendingString:@"/resources"];
|
||||
return [rsrc UTF8String];
|
||||
}
|
||||
return std::nullopt;
|
||||
}}
|
||||
|
||||
// MARK: - GSRunner
|
||||
|
||||
void* CocoaTools::CreateWindow(std::string_view title, u32 width, u32 height)
|
||||
{
|
||||
if (!NSApp)
|
||||
{
|
||||
[NSApplication sharedApplication];
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
[NSApp finishLaunching];
|
||||
}
|
||||
constexpr NSWindowStyleMask style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
|
||||
NSScreen* mainScreen = [NSScreen mainScreen];
|
||||
// Center the window on the screen, because why not
|
||||
NSRect screenFrame = [mainScreen frame];
|
||||
NSRect viewFrame = screenFrame;
|
||||
viewFrame.size = NSMakeSize(width, height);
|
||||
viewFrame.origin.x += (screenFrame.size.width - viewFrame.size.width) / 2;
|
||||
viewFrame.origin.y += (screenFrame.size.height - viewFrame.size.height) / 2;
|
||||
NSWindow* window = [[NSWindow alloc]
|
||||
initWithContentRect:viewFrame
|
||||
styleMask:style
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
[window setTitle:NSStringFromStringView(title)];
|
||||
[window makeKeyAndOrderFront:window];
|
||||
return (__bridge_retained void*)window;
|
||||
}
|
||||
|
||||
void CocoaTools::DestroyWindow(void* window)
|
||||
{
|
||||
(void)(__bridge_transfer NSWindow*)window;
|
||||
}
|
||||
|
||||
void CocoaTools::GetWindowInfoFromWindow(WindowInfo* wi, void* cf_window)
|
||||
{
|
||||
if (cf_window)
|
||||
{
|
||||
NSWindow* window = (__bridge NSWindow*)cf_window;
|
||||
float scale = [window backingScaleFactor];
|
||||
NSView* view = [window contentView];
|
||||
NSRect dims = [view frame];
|
||||
wi->type = WindowInfo::Type::MacOS;
|
||||
wi->window_handle = (__bridge void*)view;
|
||||
wi->surface_width = dims.size.width * scale;
|
||||
wi->surface_height = dims.size.height * scale;
|
||||
wi->surface_scale = scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
wi->type = WindowInfo::Type::Surfaceless;
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr short STOP_EVENT_LOOP = 0x100;
|
||||
|
||||
void CocoaTools::RunCocoaEventLoop(bool forever)
|
||||
{
|
||||
NSDate* end = forever ? [NSDate distantFuture] : [NSDate distantPast];
|
||||
[NSApplication sharedApplication]; // Ensure NSApp is initialized
|
||||
while (true)
|
||||
{ @autoreleasepool {
|
||||
NSEvent* ev = [NSApp nextEventMatchingMask:NSEventMaskAny
|
||||
untilDate:end
|
||||
inMode:NSDefaultRunLoopMode
|
||||
dequeue:YES];
|
||||
if (!ev || ([ev type] == NSEventTypeApplicationDefined && [ev subtype] == STOP_EVENT_LOOP))
|
||||
break;
|
||||
[NSApp sendEvent:ev];
|
||||
}}
|
||||
}
|
||||
|
||||
void CocoaTools::StopMainThreadEventLoop()
|
||||
{ @autoreleasepool {
|
||||
NSEvent* ev = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
|
||||
location:{}
|
||||
modifierFlags:0
|
||||
timestamp:0
|
||||
windowNumber:0
|
||||
context:nil
|
||||
subtype:STOP_EVENT_LOOP
|
||||
data1:0
|
||||
data2:0];
|
||||
[NSApp postEvent:ev atStart:NO];
|
||||
}}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "fmt/format.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/CocoaTools.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/CrashHandler.h"
|
||||
#include "common/FileSystem.h"
|
||||
@@ -56,7 +57,8 @@ namespace GSRunner
|
||||
static bool CreatePlatformWindow();
|
||||
static void DestroyPlatformWindow();
|
||||
static std::optional<WindowInfo> GetPlatformWindowInfo();
|
||||
static void PumpPlatformMessages();
|
||||
static void PumpPlatformMessages(bool forever = false);
|
||||
static void StopPlatformMessagePump();
|
||||
} // namespace GSRunner
|
||||
|
||||
static constexpr u32 WINDOW_WIDTH = 640;
|
||||
@@ -532,7 +534,7 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
|
||||
{
|
||||
std::string str(argv[++i]);
|
||||
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "dump", true);
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "DumpGSData", true);
|
||||
|
||||
if (str.find("rt") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "SaveRT", true);
|
||||
@@ -764,7 +766,7 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_settings_interface.GetBoolValue("EmuCore/GS", "dump") && !dumpdir.empty())
|
||||
if (s_settings_interface.GetBoolValue("EmuCore/GS", "DumpGSData") && !dumpdir.empty())
|
||||
{
|
||||
if (s_settings_interface.GetStringValue("EmuCore/GS", "HWDumpDirectory").empty())
|
||||
s_settings_interface.SetStringValue("EmuCore/GS", "HWDumpDirectory", dumpdir.c_str());
|
||||
@@ -809,6 +811,22 @@ void GSRunner::DumpStats()
|
||||
#define main real_main
|
||||
#endif
|
||||
|
||||
static void CPUThreadMain(VMBootParameters* params) {
|
||||
if (VMManager::Initialize(*params))
|
||||
{
|
||||
// run until end
|
||||
GSDumpReplayer::SetLoopCount(s_loop_count);
|
||||
VMManager::SetState(VMState::Running);
|
||||
while (VMManager::GetState() == VMState::Running)
|
||||
VMManager::Execute();
|
||||
VMManager::Shutdown(false);
|
||||
GSRunner::DumpStats();
|
||||
}
|
||||
|
||||
VMManager::Internal::CPUThreadShutdown();
|
||||
GSRunner::StopPlatformMessagePump();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CrashHandler::Install();
|
||||
@@ -837,16 +855,9 @@ int main(int argc, char* argv[])
|
||||
VMManager::ApplySettings();
|
||||
GSDumpReplayer::SetIsDumpRunner(true);
|
||||
|
||||
if (VMManager::Initialize(params))
|
||||
{
|
||||
// run until end
|
||||
GSDumpReplayer::SetLoopCount(s_loop_count);
|
||||
VMManager::SetState(VMState::Running);
|
||||
while (VMManager::GetState() == VMState::Running)
|
||||
VMManager::Execute();
|
||||
VMManager::Shutdown(false);
|
||||
GSRunner::DumpStats();
|
||||
}
|
||||
std::thread cputhread(CPUThreadMain, ¶ms);
|
||||
GSRunner::PumpPlatformMessages(/*forever=*/true);
|
||||
cputhread.join();
|
||||
|
||||
VMManager::Internal::CPUThreadShutdown();
|
||||
GSRunner::DestroyPlatformWindow();
|
||||
@@ -859,9 +870,6 @@ void Host::PumpMessagesOnCPUThread()
|
||||
// update GS thread copy of frame number
|
||||
MTGS::RunOnGSThread([frame_number = GSDumpReplayer::GetFrameNumber()]() { s_dump_frame_number = frame_number; });
|
||||
MTGS::RunOnGSThread([loop_number = GSDumpReplayer::GetLoopCount()]() { s_loop_number = loop_number; });
|
||||
|
||||
// process any window messages (but we shouldn't really have any)
|
||||
GSRunner::PumpPlatformMessages();
|
||||
}
|
||||
|
||||
s32 Host::Internal::GetTranslatedStringImpl(
|
||||
@@ -975,16 +983,32 @@ std::optional<WindowInfo> GSRunner::GetPlatformWindowInfo()
|
||||
return wi;
|
||||
}
|
||||
|
||||
void GSRunner::PumpPlatformMessages()
|
||||
static constexpr int SHUTDOWN_MSG = WM_APP + 0x100;
|
||||
static DWORD MainThreadID;
|
||||
|
||||
void GSRunner::PumpPlatformMessages(bool forever)
|
||||
{
|
||||
MSG msg;
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
while (true)
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if (msg.message == SHUTDOWN_MSG)
|
||||
return;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
if (!forever)
|
||||
return;
|
||||
WaitMessage();
|
||||
}
|
||||
}
|
||||
|
||||
void GSRunner::StopPlatformMessagePump()
|
||||
{
|
||||
PostThreadMessageW(MainThreadID, SHUTDOWN_MSG, 0, 0);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
return DefWindowProcW(hwnd, msg, wParam, lParam);
|
||||
@@ -1003,7 +1027,51 @@ int wmain(int argc, wchar_t** argv)
|
||||
u8_argptrs.push_back(u8_args[i].data());
|
||||
u8_argptrs.push_back(nullptr);
|
||||
|
||||
MainThreadID = GetCurrentThreadId();
|
||||
|
||||
return real_main(argc, u8_argptrs.data());
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
static void* s_window;
|
||||
static WindowInfo s_wi;
|
||||
|
||||
bool GSRunner::CreatePlatformWindow()
|
||||
{
|
||||
pxAssertRel(!s_window, "Tried to create window when there already was one!");
|
||||
s_window = CocoaTools::CreateWindow("PCSX2 GS Runner", WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
CocoaTools::GetWindowInfoFromWindow(&s_wi, s_window);
|
||||
PumpPlatformMessages();
|
||||
return s_window;
|
||||
}
|
||||
|
||||
void GSRunner::DestroyPlatformWindow()
|
||||
{
|
||||
if (s_window) {
|
||||
CocoaTools::DestroyWindow(s_window);
|
||||
s_window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<WindowInfo> GSRunner::GetPlatformWindowInfo()
|
||||
{
|
||||
WindowInfo wi;
|
||||
if (s_window)
|
||||
wi = s_wi;
|
||||
else
|
||||
wi.type = WindowInfo::Type::Surfaceless;
|
||||
return wi;
|
||||
}
|
||||
|
||||
void GSRunner::PumpPlatformMessages(bool forever)
|
||||
{
|
||||
CocoaTools::RunCocoaEventLoop(forever);
|
||||
}
|
||||
|
||||
void GSRunner::StopPlatformMessagePump()
|
||||
{
|
||||
CocoaTools::StopMainThreadEventLoop();
|
||||
}
|
||||
|
||||
#endif // _WIN32 / __APPLE__
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <kddockwidgets/Config.h>
|
||||
#include <kddockwidgets/core/Group.h>
|
||||
#include <kddockwidgets/core/Platform.h>
|
||||
#include <kddockwidgets/core/indicators/SegmentedDropIndicatorOverlay.h>
|
||||
#include <kddockwidgets/qtwidgets/ViewFactory.h>
|
||||
|
||||
|
||||
@@ -311,7 +311,7 @@ void searchWorker(DebugInterface* cpu, std::vector<SearchResult>& searchResults,
|
||||
const auto readValue = readValueAtAddress<T>(cpu, addr);
|
||||
|
||||
const bool doesMatch = handleSearchComparison(searchComparison, addr, &searchResult, searchValue, readValue);
|
||||
if (!doesMatch)
|
||||
if (doesMatch)
|
||||
searchResult = MemorySearchView::SearchResult(addr, QVariant::fromValue(readValue), searchType);
|
||||
|
||||
return !doesMatch;
|
||||
|
||||
@@ -138,16 +138,15 @@ namespace
|
||||
if (option.state & QStyle::State_Selected)
|
||||
{
|
||||
// See QItemDelegate::selectedPixmap()
|
||||
QString key = QString::fromStdString(fmt::format("{:016X}-{:d}", pix.cacheKey(), enabled));
|
||||
QColor color = option.palette.color(enabled ? QPalette::Normal : QPalette::Disabled, QPalette::Highlight);
|
||||
color.setAlphaF(0.3f);
|
||||
|
||||
QString key = QString::fromStdString(fmt::format("{:016X}-{:d}-{:08X}", pix.cacheKey(), enabled, color.rgba()));
|
||||
QPixmap pm;
|
||||
if (!QPixmapCache::find(key, &pm))
|
||||
{
|
||||
QImage img = pix.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
|
||||
QColor color = option.palette.color(enabled ? QPalette::Normal : QPalette::Disabled,
|
||||
QPalette::Highlight);
|
||||
color.setAlphaF(0.3f);
|
||||
|
||||
QPainter tinted_painter(&img);
|
||||
tinted_painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
|
||||
tinted_painter.fillRect(0, 0, img.width(), img.height(), color);
|
||||
|
||||
@@ -92,7 +92,7 @@ public Q_SLOTS:
|
||||
void refreshGridCovers();
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtGui/QPalette>
|
||||
#include <QtGui/QPixmapCache>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QStyle>
|
||||
#include <QtWidgets/QStyleFactory>
|
||||
@@ -43,6 +44,12 @@ void QtHost::UpdateApplicationTheme()
|
||||
|
||||
SetStyleFromSettings();
|
||||
SetIconThemeFromStyle();
|
||||
|
||||
// Qt generates tinted versions of icons and stores them in QPixmapCache
|
||||
// The key used does not seem to include the theme (or tint colour).
|
||||
// This can cause icons tinted for wrong theme to be used for selected/disabled.
|
||||
// As a workaround, reset the pixmap cache to clear icons tinted for the old theme.
|
||||
QPixmapCache::clear();
|
||||
}
|
||||
|
||||
bool QtHost::IsDarkApplicationTheme()
|
||||
|
||||
@@ -10856,7 +10856,7 @@ Do you want to load this save and continue?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp" line="699"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp" line="740"/>
|
||||
<source>Disabling autogenerated mipmaps on one or more compressed replacement textures. Please generate mipmaps when compressing your textures.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -10866,7 +10866,7 @@ Do you want to load this save and continue?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="5060"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp" line="5061"/>
|
||||
<source>Spin GPU During Readbacks is enabled, but calibrated timestamps are unavailable. This might be really slow.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -10959,7 +10959,7 @@ Please see our official documentation for more information.</source>
|
||||
<context>
|
||||
<name>GSDeviceOGL</name>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp" line="641"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp" line="642"/>
|
||||
<source>OpenGL renderer is not supported. Only OpenGL {}.{}
|
||||
was found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -20316,6 +20316,15 @@ Scanning recursively takes more time, but will identify files in subdirectories.
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TextureReplacement</name>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/HW/GSTextureReplacements.cpp" line="409"/>
|
||||
<source>Texture replacement directory {} will not work on case sensitive filesystems.
|
||||
Rename it to {} to remove this warning.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ThreadModel</name>
|
||||
<message>
|
||||
|
||||
@@ -1237,9 +1237,16 @@ fixup_file_properties(PCSX2)
|
||||
force_include_last(PCSX2_FLAGS "/(usr|local)/include/?$")
|
||||
|
||||
if (APPLE)
|
||||
find_library(APPKIT_LIBRARY AppKit)
|
||||
find_library(IOKIT_LIBRARY IOKit)
|
||||
find_library(METAL_LIBRARY Metal)
|
||||
find_library(QUARTZCORE_LIBRARY QuartzCore)
|
||||
target_link_libraries(PCSX2_FLAGS INTERFACE ${METAL_LIBRARY} ${QUARTZCORE_LIBRARY})
|
||||
target_link_libraries(PCSX2_FLAGS INTERFACE
|
||||
${APPKIT_LIBRARY}
|
||||
${IOKIT_LIBRARY}
|
||||
${METAL_LIBRARY}
|
||||
${QUARTZCORE_LIBRARY}
|
||||
)
|
||||
endif()
|
||||
|
||||
set_property(GLOBAL PROPERTY PCSX2_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
@@ -446,6 +446,13 @@ std::vector<GSVector2i>* GSLocalMemory::GetPage2TileMap(const GIFRegTEX0& TEX0)
|
||||
return p2t;
|
||||
}
|
||||
|
||||
u32 GSLocalMemory::IsPageAlignedMasked(u32 psm, const GSVector4i& rc)
|
||||
{
|
||||
const psm_t& psm_s = m_psm[psm];
|
||||
const GSVector4i pgmsk = GSVector4i(psm_s.pgs).xyxy() - GSVector4i(1);
|
||||
return ((rc & pgmsk) == GSVector4i::zero()).mask();
|
||||
}
|
||||
|
||||
bool GSLocalMemory::IsPageAligned(u32 psm, const GSVector4i& rc)
|
||||
{
|
||||
const psm_t& psm_s = m_psm[psm];
|
||||
|
||||
@@ -524,6 +524,7 @@ public:
|
||||
GSPixelOffset4* GetPixelOffset4(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF);
|
||||
std::vector<GSVector2i>* GetPage2TileMap(const GIFRegTEX0& TEX0);
|
||||
static bool HasOverlap(u32 src_bp, u32 src_bw, u32 src_psm, GSVector4i src_rect, u32 dst_bp, u32 dst_bw, u32 dst_psm, GSVector4i dst_rect);
|
||||
static u32 IsPageAlignedMasked(u32 psm, const GSVector4i& rc);
|
||||
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);
|
||||
|
||||
@@ -68,6 +68,7 @@ const char* shaderName(ShaderConvert value)
|
||||
case ShaderConvert::DEPTH_COPY: return "ps_depth_copy";
|
||||
case ShaderConvert::DOWNSAMPLE_COPY: return "ps_downsample_copy";
|
||||
case ShaderConvert::RGBA_TO_8I: return "ps_convert_rgba_8i";
|
||||
case ShaderConvert::RGB5A1_TO_8I: return "ps_convert_rgb5a1_8i";
|
||||
case ShaderConvert::CLUT_4: return "ps_convert_clut_4";
|
||||
case ShaderConvert::CLUT_8: return "ps_convert_clut_8";
|
||||
case ShaderConvert::YUV: return "ps_yuv";
|
||||
|
||||
@@ -44,6 +44,7 @@ enum class ShaderConvert
|
||||
DEPTH_COPY,
|
||||
DOWNSAMPLE_COPY,
|
||||
RGBA_TO_8I,
|
||||
RGB5A1_TO_8I,
|
||||
CLUT_4,
|
||||
CLUT_8,
|
||||
YUV,
|
||||
|
||||
@@ -1417,14 +1417,14 @@ void GSDevice11::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offs
|
||||
{
|
||||
float scale;
|
||||
float pad1[3];
|
||||
u32 SBW, DBW, pad3;
|
||||
u32 SBW, DBW, SPSM;
|
||||
};
|
||||
|
||||
const Uniforms cb = {sScale, {}, SBW, DBW};
|
||||
const Uniforms cb = {sScale, {}, SBW, DBW, SPSM};
|
||||
m_ctx->UpdateSubresource(m_merge.cb.get(), 0, nullptr, &cb, 0, 0);
|
||||
|
||||
const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight());
|
||||
const ShaderConvert shader = ShaderConvert::RGBA_TO_8I;
|
||||
const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I;
|
||||
StretchRect(sTex, GSVector4::zero(), dTex, dRect, m_convert.ps[static_cast<int>(shader)].get(), m_merge.cb.get(), nullptr, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1486,15 +1486,15 @@ void GSDevice12::ConvertToIndexedTexture(
|
||||
{
|
||||
float scale;
|
||||
float pad1[3];
|
||||
u32 SBW, DBW, pad2;
|
||||
u32 SBW, DBW, SPSM;
|
||||
};
|
||||
|
||||
const Uniforms cb = {sScale, {}, SBW, DBW};
|
||||
const Uniforms cb = {sScale, {}, SBW, DBW, SPSM};
|
||||
SetUtilityRootSignature();
|
||||
SetUtilityPushConstants(&cb, sizeof(cb));
|
||||
|
||||
const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight());
|
||||
const ShaderConvert shader = ShaderConvert::RGBA_TO_8I;
|
||||
const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I;
|
||||
DoStretchRect(static_cast<GSTexture12*>(sTex), GSVector4::zero(), static_cast<GSTexture12*>(dTex), dRect,
|
||||
m_convert[static_cast<int>(shader)].get(), false, true);
|
||||
}
|
||||
|
||||
@@ -184,40 +184,6 @@ bool GSHwHack::GSC_NamcoGames(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
if (r.IsPossibleChannelShuffle() && !(RTBP0 & 31))
|
||||
{
|
||||
GSVertex* v = &r.m_vertex.buff[0];
|
||||
|
||||
// Make sure we're detecting the right effect.
|
||||
if (((v[1].XYZ.X - v[0].XYZ.X) >> 4) != 8 || ((v[1].XYZ.Y - v[0].XYZ.Y) >> 4) != 14)
|
||||
return false;
|
||||
|
||||
GSTextureCache::Target* rt = g_texture_cache->LookupTarget(GIFRegTEX0::Create(RTBP0, RFBW, RFPSM),
|
||||
GSVector2i(1, 1), r.GetTextureScaleFactor(), GSTextureCache::RenderTarget);
|
||||
if (!rt)
|
||||
return false;
|
||||
|
||||
GL_INS("GSC_NamcoGames(): HLE channel shuffle");
|
||||
|
||||
// have to set up the palette ourselves too, since GSC executes before it does
|
||||
r.m_mem.m_clut.Read32(RTEX0, r.m_draw_env->TEXA);
|
||||
std::shared_ptr<GSTextureCache::Palette> palette =
|
||||
g_texture_cache->LookupPaletteObject(r.m_mem.m_clut, GSLocalMemory::m_psm[RTEX0.PSM].pal, true);
|
||||
if (!palette)
|
||||
return false;
|
||||
|
||||
GSHWDrawConfig& conf = r.BeginHLEHardwareDraw(
|
||||
rt->GetTexture(), nullptr, rt->GetScale(), rt->GetTexture(), rt->GetScale(), rt->GetUnscaledRect());
|
||||
conf.pal = palette->GetPaletteGSTexture();
|
||||
conf.ps.channel = ChannelFetch_RGB;
|
||||
conf.colormask.wa = false;
|
||||
r.EndHLEHardwareDraw(false);
|
||||
|
||||
// 12 pages: 2 calls by channel, 3 channels, 1 blit
|
||||
skip = 12 * (3 + 3 + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!s_nativeres && r.PRIM->PRIM == GS_SPRITE && RTME && RTEX0.TFX == 1 && RFPSM == RTPSM && RTPSM == PSMCT32 && RFBMSK == 0xFF000000 && r.m_index.tail > 2)
|
||||
{
|
||||
GSVertex* v = &r.m_vertex.buff[0];
|
||||
@@ -431,31 +397,6 @@ bool GSHwHack::GSC_TalesOfLegendia(GSRendererHW& r, int& skip)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_Kunoichi(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
if (!RTME && (RFBP == 0x0 || RFBP == 0x00700 || RFBP == 0x00800) && RFPSM == PSMCT32 && RFBMSK == 0x00FFFFFF)
|
||||
{
|
||||
// Removes depth effects(shadows) not rendered correctly on all renders.
|
||||
skip = 3;
|
||||
}
|
||||
if (RTME && (RFBP == 0x0700 || RFBP == 0) && RTBP0 == 0x0e00 && RTPSM == 0 && RFBMSK == 0)
|
||||
{
|
||||
skip = 1; // Removes black screen (not needed anymore maybe)?
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RTME && (RFBP == 0x0e00) && RFPSM == PSMCT32 && RFBMSK == 0xFF000000)
|
||||
{
|
||||
skip = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_ZettaiZetsumeiToshi2(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
@@ -505,27 +446,6 @@ bool GSHwHack::GSC_ZettaiZetsumeiToshi2(GSRendererHW& r, int& skip)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_SakuraWarsSoLongMyLove(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
if (RTME == 0 && RFBP != RTBP0 && RTBP0 && RFBMSK == 0x00FFFFFF)
|
||||
{
|
||||
skip = 3; // Remove darkness
|
||||
}
|
||||
else if (RTME == 0 && RFBP == RTBP0 && (RTBP0 == 0x1200 || RTBP0 == 0x1180 || RTBP0 == 0) && RFBMSK == 0x00FFFFFF)
|
||||
{
|
||||
skip = 3; // Remove darkness
|
||||
}
|
||||
else if (RTME && (RFBP == 0 || RFBP == 0x1180) && RFPSM == PSMCT32 && RTBP0 == 0x3F3F && RTPSM == PSMT8)
|
||||
{
|
||||
skip = 1; // Floodlight
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_UltramanFightingEvolution(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
@@ -1393,12 +1313,10 @@ bool GSHwHack::MV_Ico(GSRendererHW& r)
|
||||
#define CRC_F(name) { #name, &GSHwHack::name }
|
||||
|
||||
const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_functions[] = {
|
||||
CRC_F(GSC_Kunoichi),
|
||||
CRC_F(GSC_Manhunt2),
|
||||
CRC_F(GSC_MidnightClub3),
|
||||
CRC_F(GSC_SacredBlaze),
|
||||
CRC_F(GSC_GuitarHero),
|
||||
CRC_F(GSC_SakuraWarsSoLongMyLove),
|
||||
CRC_F(GSC_SFEX3),
|
||||
CRC_F(GSC_DTGames),
|
||||
CRC_F(GSC_TalesOfLegendia),
|
||||
|
||||
@@ -16,9 +16,7 @@ public:
|
||||
static bool GSC_BlackAndBurnoutSky(GSRendererHW& r, int& skip);
|
||||
static bool GSC_MidnightClub3(GSRendererHW& r, int& skip);
|
||||
static bool GSC_TalesOfLegendia(GSRendererHW& r, int& skip);
|
||||
static bool GSC_Kunoichi(GSRendererHW& r, int& skip);
|
||||
static bool GSC_ZettaiZetsumeiToshi2(GSRendererHW& r, int& skip);
|
||||
static bool GSC_SakuraWarsSoLongMyLove(GSRendererHW& r, int& skip);
|
||||
static bool GSC_UltramanFightingEvolution(GSRendererHW& r, int& skip);
|
||||
static bool GSC_TalesofSymphonia(GSRendererHW& r, int& skip);
|
||||
static bool GSC_UrbanReign(GSRendererHW& r, int& skip);
|
||||
|
||||
@@ -2862,7 +2862,9 @@ void GSRendererHW::Draw()
|
||||
|
||||
GIFRegTEX0 FRAME_TEX0;
|
||||
bool shuffle_target = false;
|
||||
if (!no_rt && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp >= 16 &&
|
||||
const u32 page_alignment = GSLocalMemory::IsPageAlignedMasked(m_cached_ctx.TEX0.PSM, m_r);
|
||||
const bool page_aligned = (page_alignment & 0xF0F0) != 0; // Make sure Y is page aligned.
|
||||
if (!no_rt && page_aligned && m_cached_ctx.ZBUF.ZMSK && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp >= 16 &&
|
||||
(m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index.tail % 6) == 0 && TrianglesAreQuads(true) && m_index.tail > 6)))
|
||||
{
|
||||
// Tail check is to make sure we have enough strips to go all the way across the page, or if it's using a region clamp could be used to draw strips.
|
||||
@@ -3164,6 +3166,144 @@ void GSRendererHW::Draw()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (no_rt && ds->m_TEX0.TBP0 != m_cached_ctx.ZBUF.Block())
|
||||
{
|
||||
const GSLocalMemory::psm_t& zbuf_psm = GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM];
|
||||
int vertical_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * zbuf_psm.pgs.y; // I know I could just not shift it..
|
||||
int texture_offset = 0;
|
||||
int horizontal_offset = ((static_cast<int>((m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0)) / 32) % static_cast<int>(std::max(ds->m_TEX0.TBW, 1U))) * zbuf_psm.pgs.x;
|
||||
// Used to reduce the offset made later in channel shuffles
|
||||
m_target_offset = std::abs(static_cast<int>((m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0)) >> 5);
|
||||
|
||||
if (vertical_offset < 0)
|
||||
{
|
||||
ds->m_TEX0.TBP0 = m_cached_ctx.ZBUF.Block();
|
||||
GSVector2i new_size = ds->m_unscaled_size;
|
||||
// Make sure to use the original format for the offset.
|
||||
const int new_offset = std::abs((vertical_offset / zbuf_psm.pgs.y) * GSLocalMemory::m_psm[ds->m_TEX0.PSM].pgs.y);
|
||||
texture_offset = new_offset;
|
||||
|
||||
new_size.y += new_offset;
|
||||
|
||||
const GSVector4i new_drect = GSVector4i(0, new_offset * ds->m_scale, new_size.x * ds->m_scale, new_size.y * ds->m_scale);
|
||||
ds->ResizeTexture(new_size.x, new_size.y, true, true, new_drect);
|
||||
|
||||
if (src && src->m_from_target && src->m_from_target == ds && src->m_target_direct)
|
||||
{
|
||||
src->m_texture = ds->m_texture;
|
||||
|
||||
// If we've moved it and the source is expecting to be inside this target, we need to update the region to point to it.
|
||||
int max_region_y = src->m_region.GetMaxY() + new_offset;
|
||||
if (max_region_y == new_offset)
|
||||
max_region_y = new_size.y;
|
||||
|
||||
src->m_region.SetY(src->m_region.GetMinY() + new_offset, max_region_y);
|
||||
}
|
||||
|
||||
ds->m_valid.y += new_offset;
|
||||
ds->m_valid.w += new_offset;
|
||||
ds->m_drawn_since_read.y += new_offset;
|
||||
ds->m_drawn_since_read.w += new_offset;
|
||||
|
||||
g_texture_cache->CombineAlignedInsideTargets(ds, src);
|
||||
|
||||
if (ds->m_dirty.size())
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(ds->m_dirty.size()); i++)
|
||||
{
|
||||
ds->m_dirty[i].r.y += new_offset;
|
||||
ds->m_dirty[i].r.w += new_offset;
|
||||
}
|
||||
}
|
||||
|
||||
t_size.y += std::abs(vertical_offset);
|
||||
vertical_offset = 0;
|
||||
}
|
||||
|
||||
if (horizontal_offset < 0)
|
||||
{
|
||||
// Thankfully this doesn't really happen, but catwoman moves the framebuffer backwards 1 page with a channel shuffle, which is really messy and not easy to deal with.
|
||||
// Hopefully the quick channel shuffle will just guess this and run with it.
|
||||
ds->m_TEX0.TBP0 += horizontal_offset;
|
||||
horizontal_offset = 0;
|
||||
}
|
||||
|
||||
if (vertical_offset || horizontal_offset)
|
||||
{
|
||||
GSVertex* v = &m_vertex.buff[0];
|
||||
|
||||
for (u32 i = 0; i < m_vertex.tail; i++)
|
||||
{
|
||||
v[i].XYZ.X += horizontal_offset << 4;
|
||||
v[i].XYZ.Y += vertical_offset << 4;
|
||||
}
|
||||
|
||||
if (texture_offset && src && src->m_from_target && src->m_target_direct && src->m_from_target == ds)
|
||||
{
|
||||
GSVector4i src_region = src->GetRegionRect();
|
||||
|
||||
if (src_region.rempty())
|
||||
{
|
||||
src_region = GSVector4i::loadh(ds->m_unscaled_size);
|
||||
src_region.y += texture_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
src_region.y += texture_offset;
|
||||
src_region.w += texture_offset;
|
||||
}
|
||||
src->m_region.SetX(src_region.x, src_region.z);
|
||||
src->m_region.SetY(src_region.y, src_region.w);
|
||||
}
|
||||
|
||||
m_context->scissor.in.x += horizontal_offset;
|
||||
m_context->scissor.in.z += horizontal_offset;
|
||||
m_context->scissor.in.y += vertical_offset;
|
||||
m_context->scissor.in.w += vertical_offset;
|
||||
m_r.y += vertical_offset;
|
||||
m_r.w += vertical_offset;
|
||||
m_r.x += horizontal_offset;
|
||||
m_r.z += horizontal_offset;
|
||||
m_in_target_draw = ds->m_TEX0.TBP0 != m_cached_ctx.ZBUF.Block();
|
||||
m_vt.m_min.p.x += horizontal_offset;
|
||||
m_vt.m_max.p.x += horizontal_offset;
|
||||
m_vt.m_min.p.y += vertical_offset;
|
||||
m_vt.m_max.p.y += vertical_offset;
|
||||
|
||||
t_size.y = ds->m_unscaled_size.y - vertical_offset;
|
||||
t_size.x = ds->m_unscaled_size.x - horizontal_offset;
|
||||
}
|
||||
|
||||
// Don't resize if the BPP don't match.
|
||||
GSVector2i new_size = GetValidSize(src, possible_shuffle);
|
||||
if (new_size.x > ds->m_unscaled_size.x || new_size.y > ds->m_unscaled_size.y)
|
||||
{
|
||||
const u32 new_width = std::max(new_size.x, ds->m_unscaled_size.x);
|
||||
const u32 new_height = std::max(new_size.y, ds->m_unscaled_size.y);
|
||||
|
||||
//DevCon.Warning("HW: Resizing texture %d x %d draw %d", ds->m_unscaled_size.x, new_height, s_n);
|
||||
ds->ResizeTexture(new_width, new_height);
|
||||
}
|
||||
else if ((IsPageCopy() || is_possible_mem_clear) && m_r.width() <= zbuf_psm.pgs.x && m_r.height() <= zbuf_psm.pgs.y)
|
||||
{
|
||||
const int get_next_ctx = m_env.PRIM.CTXT;
|
||||
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
|
||||
GSVector4i update_valid = GSVector4i::loadh(GSVector2i(horizontal_offset + GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x, GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y + vertical_offset));
|
||||
ds->UpdateValidity(update_valid, true);
|
||||
if (is_possible_mem_clear)
|
||||
{
|
||||
if ((horizontal_offset + GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x) >= static_cast<int>(ds->m_TEX0.TBW * 64) && next_ctx.ZBUF.Block() == (m_cached_ctx.ZBUF.Block() + 0x20))
|
||||
{
|
||||
update_valid.x = 0;
|
||||
update_valid.z = GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
||||
update_valid.y += GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
||||
update_valid.w += GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
||||
ds->UpdateValidity(update_valid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!no_rt)
|
||||
|
||||
@@ -228,8 +228,8 @@ bool GSTextureCache::CanTranslate(u32 bp, u32 bw, u32 spsm, GSVector4i r, u32 db
|
||||
{
|
||||
const GSVector2i src_page_size = GSLocalMemory::m_psm[spsm].pgs;
|
||||
const GSVector2i dst_page_size = GSLocalMemory::m_psm[dpsm].pgs;
|
||||
const bool bp_page_aligned_bp = ((bp & ~((1 << 5) - 1)) == bp) || bp == dbp;
|
||||
const bool block_layout_match = GSLocalMemory::m_psm[spsm].bpp == GSLocalMemory::m_psm[dpsm].bpp;
|
||||
const bool bp_page_aligned_bp = ((bp & ~((1 << 5) - 1)) == bp) || bp == dbp || (block_layout_match && bw == dbw);
|
||||
const GSVector4i page_mask(GSVector4i((src_page_size.x - 1), (src_page_size.y - 1)).xyxy());
|
||||
const GSVector4i masked_rect(r & ~page_mask);
|
||||
const int src_pixel_width = static_cast<int>(bw * 64);
|
||||
@@ -276,7 +276,7 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
|
||||
int page_offset = (static_cast<int>(sbp) - static_cast<int>(tbp)) >> 5;
|
||||
int block_offset = (static_cast<int>(sbp) - static_cast<int>(tbp)) & 0x1F;
|
||||
|
||||
if (!(s_psm.bpp == t_psm.bpp))
|
||||
if (!(s_psm.bpp == t_psm.bpp) || block_offset)
|
||||
{
|
||||
if (block_offset)
|
||||
in_rect = in_rect.ralign<Align_Outside>(s_psm.bs);
|
||||
@@ -299,6 +299,33 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
|
||||
DevCon.Warning("Error translating rect");
|
||||
return GSVector4i::zero();
|
||||
}
|
||||
|
||||
const bool block_matched_format = s_psm.bpp == t_psm.bpp && (sbw == tbw || sbw == 1);
|
||||
// If there is block offset left over, try to adjust to that.
|
||||
if (block_matched_format)
|
||||
{
|
||||
GSVector4i b2a_offset = GSVector4i::zero();
|
||||
const GSVector4i target_rect = GSVector4i(0, 0, src_bw, 2048);
|
||||
bool offset_found = false;
|
||||
|
||||
for (b2a_offset.x = target_rect.x; b2a_offset.x < target_rect.z; b2a_offset.x += s_psm.bs.x)
|
||||
{
|
||||
for (b2a_offset.y = target_rect.y; b2a_offset.y < target_rect.w; b2a_offset.y += s_psm.bs.y)
|
||||
{
|
||||
const u32 a_candidate_bp = s_psm.info.bn(b2a_offset.x, b2a_offset.y, tbp, sbw);
|
||||
if (sbp == a_candidate_bp)
|
||||
{
|
||||
offset_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (offset_found)
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset_found)
|
||||
in_rect = (in_rect + b2a_offset.xyxy()).max_i32(GSVector4i(0));
|
||||
}
|
||||
}
|
||||
|
||||
GSVector4i new_rect = GSVector4i::zero();
|
||||
@@ -618,7 +645,7 @@ void GSTextureCache::DirtyRectByPage(u32 sbp, u32 spsm, u32 sbw, Target* t, GSVe
|
||||
int block_offset = static_cast<int>(sbp) - static_cast<int>(target_bp);
|
||||
// Different format needs to be page aligned, unless the block layout matches, then we can block align
|
||||
// Might be able to translate the original rect.
|
||||
if (!(src_info->bpp == dst_info->bpp))
|
||||
if (!(src_info->bpp == dst_info->bpp) || block_offset)
|
||||
{
|
||||
const int src_bpp = src_info->bpp;
|
||||
const bool column_align = !block_offset && src_r.z <= src_info->cs.x && src_r.w <= src_info->cs.y && src_info->depth == dst_info->depth;
|
||||
@@ -741,7 +768,7 @@ void GSTextureCache::DirtyRectByPage(u32 sbp, u32 spsm, u32 sbw, Target* t, GSVe
|
||||
const int yblocks = in_rect.height() / src_info->bs.y;
|
||||
// if !(block_offset & 0x7) is false, this is technically incorrect, but FFX hates it and starts making a mess, so it's better this way without adding complexity.
|
||||
// TODO maybe: Add per block invalidation? ugh, would have to keep that to small blocks. 2 blocks in the case of FFX.
|
||||
if ((xblocks <= 4 && yblocks <= 2) || req_depth_offset)
|
||||
if ((xblocks <= (src_info->pgs.x / src_info->bs.x) && yblocks <= (src_info->pgs.y / src_info->bs.y)) || req_depth_offset)
|
||||
{
|
||||
GSVector4i b2a_offset = GSVector4i::zero();
|
||||
const GSVector4i target_rect = GSVector4i(0, 0, src_width, 2048);
|
||||
@@ -1165,8 +1192,8 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const bool is_depth, c
|
||||
if (inside_target)
|
||||
{
|
||||
// Need to set it up as a region target.
|
||||
src->m_region.SetX(block_boundary_rect.x, src->m_from_target->m_valid.z);
|
||||
src->m_region.SetY(block_boundary_rect.y, src->m_from_target->m_valid.w);
|
||||
src->m_region.SetX(block_boundary_rect.x, std::max(src->m_from_target->m_valid.z, block_boundary_rect.z));
|
||||
src->m_region.SetY(block_boundary_rect.y, std::max(src->m_from_target->m_valid.w, block_boundary_rect.w));
|
||||
}
|
||||
|
||||
if (GSRendererHW::GetInstance()->IsTBPFrameOrZ(dst->m_TEX0.TBP0))
|
||||
@@ -1279,11 +1306,6 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
// Make sure it is page aligned, otherwise things get messy with the pixel order (Tomb Raider Legend).
|
||||
if (t->m_used)
|
||||
{
|
||||
// If the BP is block offset it's unlikely to be a target, but a target can be made by a HW move, so we need to check for a match.
|
||||
// Good for Baldurs Gate Dark Alliance (HW Move), bad for Tomb Raider Legends (just offset).
|
||||
if (((bp & (BLOCKS_PER_PAGE - 1)) != (t->m_TEX0.TBP0 & (BLOCKS_PER_PAGE - 1))) && (bp & (BLOCKS_PER_PAGE - 1)))
|
||||
continue;
|
||||
|
||||
//const bool overlaps = t->Inside(bp, bw, psm, block_boundary_rect);
|
||||
const bool overlaps = t->Overlaps(bp, bw, psm, block_boundary_rect);
|
||||
// Try to make sure the target has available what we need, be careful of self referencing frames with font in the alpha.
|
||||
@@ -1293,6 +1315,12 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
if (!overlaps || (found_t && (GSState::s_n - dst->m_last_draw) < (GSState::s_n - t->m_last_draw)))
|
||||
continue;
|
||||
|
||||
// If the BP is offset in to a page and the format does not match, trying to match up the correct position is very difficult since we don't swizzle.
|
||||
// Tomb Raider Legends does a block level BP in PSMT8 over a C16 target, which is just a nightmare to get right.
|
||||
// Baldurs Gate used to have this too, but now we can translate HW moves inside targets when the format matches.
|
||||
if (((bp & (BLOCKS_PER_PAGE - 1)) != (t->m_TEX0.TBP0 & (BLOCKS_PER_PAGE - 1))) && (bp & (BLOCKS_PER_PAGE - 1)) && !CanTranslate(bp, bw, psm, block_boundary_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW))
|
||||
continue;
|
||||
|
||||
const bool width_match = (std::max(64U, bw * 64U) >> GSLocalMemory::m_psm[psm].info.pageShiftX()) ==
|
||||
(std::max(64U, t->m_TEX0.TBW * 64U) >> GSLocalMemory::m_psm[t->m_TEX0.PSM].info.pageShiftX());
|
||||
|
||||
@@ -1617,8 +1645,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
{
|
||||
const bool outside_target = !t->Overlaps(bp, bw, psm, r);
|
||||
|
||||
// We don't have a shader for this.
|
||||
if (!possible_shuffle && TEX0.PSM == PSMT8 && ((GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp != 32) || outside_target))
|
||||
if (!possible_shuffle && TEX0.PSM == PSMT8 && outside_target)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1647,7 +1674,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
// Make sure the texture actually is INSIDE the RT, it's possibly not valid if it isn't.
|
||||
// Also check BP >= TBP, create source isn't equpped to expand it backwards and all data comes from the target. (GH3)
|
||||
else if (GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets &&
|
||||
(GSLocalMemory::m_psm[color_psm].bpp >= 16 || (/*possible_shuffle &&*/ GSLocalMemory::m_psm[color_psm].bpp == 8 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32)) && // Channel shuffles or non indexed lookups.
|
||||
(GSLocalMemory::m_psm[color_psm].bpp >= 16 || (/*possible_shuffle &&*/ GSLocalMemory::m_psm[color_psm].bpp == 8 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp >= 16)) && // Channel shuffles or non indexed lookups.
|
||||
t->m_age <= 1 && (!found_t || t->m_last_draw > dst->m_last_draw) /*&& CanTranslate(bp, bw, psm, block_boundary_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW)*/)
|
||||
{
|
||||
u32 rt_tbw = std::max(1U, t->m_TEX0.TBW);
|
||||
@@ -1666,7 +1693,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
// Keep note that 2 bw is basically 1 normal page, as bw is in 64 pixels, and 8bit pages are 128 pixels wide, aka 2 bw.
|
||||
// Also check for 4HH/HL and 8H which use the alpha channel, if the page order is wrong this can cause problems as well (Jak X font).
|
||||
else if (!possible_shuffle && GSLocalMemory::m_psm[psm].trbpp <= 8 && (GSUtil::GetChannelMask(t->m_TEX0.PSM) != 0xF ||
|
||||
(GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32 && (!(block_boundary_rect.w <= GSLocalMemory::m_psm[psm].pgs.y &&
|
||||
((GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp != 16 || GSLocalMemory::m_psm[psm].bpp < 16) && (!(block_boundary_rect.w <= GSLocalMemory::m_psm[psm].pgs.y &&
|
||||
((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) <= t->m_TEX0.TBW) &&
|
||||
!(((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) == rt_tbw)))))
|
||||
{
|
||||
@@ -1773,10 +1800,6 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
if (!t->HasValidBitsForFormat(psm, req_color, req_alpha, rt_tbw == TEX0.TBW) && !(possible_shuffle && GSLocalMemory::m_psm[psm].bpp == 16 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 32))
|
||||
continue;
|
||||
|
||||
// Be careful of shuffles where it can shuffle the width of the target, even though it may not have all been drawn to.
|
||||
if (!possible_shuffle && frame.Block() != TEX0.TBP0 && !t->Inside(bp, bw, psm, block_boundary_rect))
|
||||
continue;
|
||||
|
||||
x_offset = rect.x;
|
||||
y_offset = rect.y;
|
||||
dst = t;
|
||||
@@ -2007,7 +2030,6 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
GL_CACHE("TC: src miss (0x%x, 0x%x, %s)", TEX0.TBP0, psm_s.pal > 0 ? TEX0.CBP : 0, psm_str(TEX0.PSM));
|
||||
}
|
||||
#endif
|
||||
|
||||
// This is for the condition where the target doesn't exist on a shuffle and it needs to load from memory.
|
||||
// The Godfather clears the depth buffer with a normal clear, so our depth target gets deleted, then because it finds no target
|
||||
// it assumes it really is 16bits, causing the texture to be full of garbage, and our shuffle handling becomes a mess.
|
||||
@@ -3545,11 +3567,11 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
continue;
|
||||
}
|
||||
|
||||
const int height_adjust = (((dst_end_block - t->m_TEX0.TBP0) >> 5) / std::max(t->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.y;
|
||||
const int height_adjust = ((((dst_end_block + 31) - t->m_TEX0.TBP0) >> 5) / std::max(t->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.y;
|
||||
|
||||
if (height_adjust < t->m_unscaled_size.y)
|
||||
{
|
||||
t->m_TEX0.TBP0 = dst_end_block;
|
||||
t->m_TEX0.TBP0 = GSLocalMemory::GetStartBlockAddress(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, GSVector4i(0, height_adjust, t->m_valid.z, t->m_valid.w));
|
||||
t->m_valid.w -= height_adjust;
|
||||
t->ResizeValidity(t->m_valid);
|
||||
|
||||
@@ -4735,7 +4757,7 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
// Not even going to go down the rabbit hole of palette formats on the GPU.. We shouldn't have any targets with P4/P8 anyway.
|
||||
const GSLocalMemory::psm_t& spsm_s = GSLocalMemory::m_psm[SPSM];
|
||||
const GSLocalMemory::psm_t& dpsm_s = GSLocalMemory::m_psm[DPSM];
|
||||
if (SPSM != DPSM || ((spsm_s.pal + dpsm_s.pal) != 0 && !alpha_only))
|
||||
if (GSLocalMemory::m_psm[SPSM].bpp != GSLocalMemory::m_psm[DPSM].bpp || ((spsm_s.pal + dpsm_s.pal) != 0 && !alpha_only))
|
||||
{
|
||||
GL_CACHE("TC: Skipping HW move from 0x%X to 0x%X with SPSM=%s DPSM=%s", SBP, DBP, psm_str(SPSM), psm_str(DPSM));
|
||||
return false;
|
||||
@@ -4751,6 +4773,7 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
return false;
|
||||
}
|
||||
|
||||
bool req_resize = false;
|
||||
if (m_expected_src_bp == static_cast<int>(SBP) && m_expected_dst_bp == static_cast<int>(DBP))
|
||||
{
|
||||
// Get the new position so we can work out the offset.
|
||||
@@ -4761,7 +4784,7 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
sy += rect_offset.y;
|
||||
dx += rect_offset.x;
|
||||
dy += rect_offset.y;
|
||||
|
||||
req_resize = true;
|
||||
GL_INS("TC: Detected striped move, realigning from SBP %x->%x DBP %x->%x", SBP, m_remembered_src_bp, DBP, m_remembered_dst_bp);
|
||||
|
||||
SBP = m_remembered_src_bp;
|
||||
@@ -4806,15 +4829,18 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
const GSVector2i target_size = GetTargetSize(DBP, DBW, DPSM, Common::AlignUpPow2(w, 64), h);
|
||||
dst = LookupTarget(new_TEX0, target_size, src->m_scale, src->m_type);
|
||||
if (!dst)
|
||||
dst = CreateTarget(new_TEX0, target_size, target_size, src->m_scale, src->m_type);
|
||||
{
|
||||
dst = Target::Create(new_TEX0, target_size.x, target_size.y, src->m_scale, GSLocalMemory::m_psm[DPSM].depth, true);
|
||||
if (!dst) [[unlikely]]
|
||||
return false;
|
||||
}
|
||||
else // Expand if necessary (Silent hill 4 takes an old target which is smaller).
|
||||
{
|
||||
dst->ResizeTexture(std::max(dst->m_unscaled_size.x, target_size.x), std::max(dst->m_unscaled_size.y, target_size.y));
|
||||
req_resize = true;
|
||||
|
||||
// If it was matched to an old target, make sure to clear the other type and update its information.
|
||||
if (dst->m_was_dst_matched)
|
||||
{
|
||||
g_texture_cache->InvalidateVideoMemType(GSTextureCache::DepthStencil - dst->m_type, dst->m_TEX0.TBP0);
|
||||
dst->m_TEX0 = new_TEX0;
|
||||
}
|
||||
}
|
||||
@@ -4829,6 +4855,24 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
if (!src || !dst || src->m_scale != dst->m_scale)
|
||||
return false;
|
||||
|
||||
// If we have an offset, adjust the base positions
|
||||
if (src->m_TEX0.TBP0 != SBP)
|
||||
{
|
||||
GSVector4i offset = TranslateAlignedRectByPage(dst, SBP, SPSM, SBW, GSVector4i(0, 1).xxyy(), false);
|
||||
|
||||
sx += offset.x;
|
||||
sy += offset.y;
|
||||
}
|
||||
|
||||
if (dst->m_TEX0.TBP0 != DBP)
|
||||
{
|
||||
GSVector4i offset = TranslateAlignedRectByPage(dst, DBP, DPSM, DBW, GSVector4i(0, 1).xxyy(), false);
|
||||
|
||||
dx += offset.x;
|
||||
dy += offset.y;
|
||||
req_resize = true;
|
||||
}
|
||||
|
||||
// Scale coordinates.
|
||||
const float scale = src->m_scale;
|
||||
const int scaled_sx = static_cast<int>(sx * scale);
|
||||
@@ -4842,6 +4886,11 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
if ((scaled_sx + scaled_w) > src->m_texture->GetWidth() || (scaled_sy + scaled_h) > src->m_texture->GetHeight())
|
||||
return false;
|
||||
|
||||
if (req_resize)
|
||||
{
|
||||
const GSVector2i target_size = GetTargetSize(DBP, DBW, DPSM, Common::AlignUpPow2(dx + w, 64), dx + h);
|
||||
dst->ResizeTexture(std::max(dst->m_unscaled_size.x, target_size.x), std::max(dst->m_unscaled_size.y, target_size.y));
|
||||
}
|
||||
// We don't want to copy "old" data that the game has overwritten with writes,
|
||||
// so flush any overlapping dirty area.
|
||||
src->UpdateIfDirtyIntersects(GSVector4i(sx, sy, sx + w, sy + h));
|
||||
@@ -4850,6 +4899,9 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
// we're not going to be able to use it as a source.
|
||||
dst->Update();
|
||||
|
||||
// Invalidate any opposite targets.
|
||||
g_texture_cache->InvalidateVideoMemType(GSTextureCache::DepthStencil - dst->m_type, dst->m_TEX0.TBP0);
|
||||
|
||||
// Expand the target when we used a more conservative size.
|
||||
const int required_dh = scaled_dy + scaled_h;
|
||||
if ((scaled_dx + scaled_w) <= dst->m_texture->GetWidth() && required_dh > dst->m_texture->GetHeight())
|
||||
@@ -4938,9 +4990,30 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
{
|
||||
if (SPSM == PSMT8H && SPSM == DPSM)
|
||||
{
|
||||
ShaderConvert shader = ShaderConvert::COPY;
|
||||
|
||||
const GSVector4 src_rect = GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h) / (GSVector4(src->m_texture->GetSize()).xyxy());
|
||||
const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h));
|
||||
g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, dst_rect, false, false, false, true);
|
||||
g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, dst_rect, false, false, false, true, shader);
|
||||
}
|
||||
else if (src->m_type != dst->m_type)
|
||||
{
|
||||
ShaderConvert shader = dst->m_type ? ShaderConvert::RGBA8_TO_FLOAT32 : ShaderConvert::FLOAT32_TO_RGBA8;
|
||||
|
||||
switch (dpsm_s.trbpp)
|
||||
{
|
||||
case 24:
|
||||
shader = dst->m_type ? ShaderConvert::RGBA8_TO_FLOAT24 : ShaderConvert::FLOAT32_TO_RGB8;
|
||||
break;
|
||||
case 16:
|
||||
shader = dst->m_type ? ShaderConvert::RGB5A1_TO_FLOAT16 : ShaderConvert::FLOAT16_TO_RGB5A1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const GSVector4 src_rect = GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h) / (GSVector4(src->m_texture->GetSize()).xyxy());
|
||||
g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h), shader, false);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4968,7 +5041,8 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
dst->m_alpha_range |= src->m_alpha_range;
|
||||
}
|
||||
|
||||
if (GSLocalMemory::IsPageAligned(src->m_TEX0.PSM, GSVector4i(sx, sy, sx + w, sy + h)) && (w == GSLocalMemory::m_psm[src->m_TEX0.PSM].pgs.x || h == GSLocalMemory::m_psm[src->m_TEX0.PSM].pgs.y))
|
||||
u32 page_mask = GSLocalMemory::IsPageAlignedMasked(src->m_TEX0.PSM, GSVector4i(sx, sy, sx + w, sy + h));
|
||||
if (((page_mask & 0x0f0f) == 0x0f0f || (page_mask & 0xf0f0) == 0xf0f0) && (w == GSLocalMemory::m_psm[src->m_TEX0.PSM].pgs.x || h == GSLocalMemory::m_psm[src->m_TEX0.PSM].pgs.y))
|
||||
{
|
||||
// Vertical Strips
|
||||
if (w == GSLocalMemory::m_psm[src->m_TEX0.PSM].pgs.x)
|
||||
@@ -5003,7 +5077,7 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
|
||||
// Invalidate any sources that overlap with the target (since they're now stale).
|
||||
InvalidateVideoMem(g_gs_renderer->m_mem.GetOffset(DBP, DBW, DPSM), GSVector4i(dx, dy, dx + w, dy + h), false);
|
||||
|
||||
CombineAlignedInsideTargets(dst);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5190,7 +5264,7 @@ GSTextureCache::Target* GSTextureCache::GetExactTarget(u32 BP, u32 BW, int type,
|
||||
{
|
||||
Target* t = *it;
|
||||
const u32 tgt_bw = std::max(t->m_TEX0.TBW, 1U);
|
||||
if ((t->m_TEX0.TBP0 == BP || (GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets && t->m_TEX0.TBP0 < BP && (((BP - t->m_TEX0.TBP0) >> 5) % tgt_bw) == 0)) && tgt_bw == BW && t->UnwrappedEndBlock() >= end_bp)
|
||||
if ((t->m_TEX0.TBP0 == BP || (GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets && t->m_TEX0.TBP0 < BP && !(BP & 0x1f) && (((BP - t->m_TEX0.TBP0) >> 5) % tgt_bw) == 0)) && tgt_bw == BW && t->UnwrappedEndBlock() >= end_bp)
|
||||
{
|
||||
rts.MoveFront(it.Index());
|
||||
return t;
|
||||
@@ -5667,7 +5741,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
if (is_8bits)
|
||||
{
|
||||
GL_INS("TC: Reading RT as a packed-indexed 8 bits format");
|
||||
shader = ShaderConvert::RGBA_TO_8I;
|
||||
shader = GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 16 ? ShaderConvert::RGB5A1_TO_8I : ShaderConvert::RGBA_TO_8I;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_OGL_DEBUG
|
||||
@@ -5737,7 +5811,11 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
{
|
||||
// We're inside the target, so conversion needs to happen on the entire target so we can offset properly.
|
||||
src->m_unscaled_size.x = dst->m_unscaled_size.x * 2;
|
||||
src->m_unscaled_size.y = dst->m_unscaled_size.y * 2;
|
||||
if (GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 32)
|
||||
src->m_unscaled_size.y = dst->m_unscaled_size.y * 2;
|
||||
else
|
||||
src->m_unscaled_size.y = dst->m_unscaled_size.y;
|
||||
|
||||
new_size.x = src->m_unscaled_size.x;
|
||||
new_size.y = src->m_unscaled_size.y;
|
||||
}
|
||||
@@ -5908,7 +5986,8 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
|
||||
// Adjust to match a PSMT8 texture (coordinates are double C32, we shouldn't be converting from anything else).
|
||||
x_offset *= 2;
|
||||
y_offset *= 2;
|
||||
if (GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 32)
|
||||
y_offset *= 2;
|
||||
|
||||
src->m_region.SetX(x_offset, x_offset + tw);
|
||||
src->m_region.SetY(y_offset, y_offset + th);
|
||||
@@ -6695,6 +6774,8 @@ void GSTextureCache::Read(Target* t, const GSVector4i& r)
|
||||
{
|
||||
case PSMCT32:
|
||||
case PSMCT24:
|
||||
case PSMZ32:
|
||||
case PSMZ24:
|
||||
{
|
||||
// If we're downloading a depth buffer that's been reinterpreted as a color
|
||||
// format, convert it to integer. The format/swizzle is likely wrong, but it's
|
||||
@@ -6720,27 +6801,11 @@ void GSTextureCache::Read(Target* t, const GSVector4i& r)
|
||||
|
||||
case PSMCT16:
|
||||
case PSMCT16S:
|
||||
{
|
||||
fmt = GSTexture::Format::UInt16;
|
||||
ps_shader = is_depth ? ShaderConvert::FLOAT32_TO_16_BITS : ShaderConvert::RGBA8_TO_16_BITS;
|
||||
dltex = &m_uint16_download_texture;
|
||||
}
|
||||
break;
|
||||
|
||||
case PSMZ32:
|
||||
case PSMZ24:
|
||||
{
|
||||
fmt = GSTexture::Format::UInt32;
|
||||
ps_shader = ShaderConvert::FLOAT32_TO_32_BITS;
|
||||
dltex = &m_uint32_download_texture;
|
||||
}
|
||||
break;
|
||||
|
||||
case PSMZ16:
|
||||
case PSMZ16S:
|
||||
{
|
||||
fmt = GSTexture::Format::UInt16;
|
||||
ps_shader = ShaderConvert::FLOAT32_TO_16_BITS;
|
||||
ps_shader = is_depth ? ShaderConvert::FLOAT32_TO_16_BITS : ShaderConvert::RGBA8_TO_16_BITS;
|
||||
dltex = &m_uint16_download_texture;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -270,56 +270,57 @@ std::string GSTextureReplacements::GetDumpFilename(const TextureName& name, u32
|
||||
return ret;
|
||||
|
||||
const std::string game_dir(GetGameTextureDirectory());
|
||||
if (!FileSystem::DirectoryExists(game_dir.c_str()))
|
||||
const std::string game_subdir(Path::Combine(game_dir, TEXTURE_DUMP_SUBDIRECTORY_NAME));
|
||||
|
||||
if (!FileSystem::DirectoryExists(game_subdir.c_str()))
|
||||
{
|
||||
// create both dumps and replacements
|
||||
if (!FileSystem::CreateDirectoryPath(game_dir.c_str(), false) ||
|
||||
!FileSystem::EnsureDirectoryExists(Path::Combine(game_dir, "dumps").c_str(), false) ||
|
||||
!FileSystem::EnsureDirectoryExists(Path::Combine(game_dir, "replacements").c_str(), false))
|
||||
!FileSystem::EnsureDirectoryExists(game_subdir.c_str(), false) ||
|
||||
!FileSystem::EnsureDirectoryExists(Path::Combine(game_dir, TEXTURE_REPLACEMENT_SUBDIRECTORY_NAME).c_str(), false))
|
||||
{
|
||||
// if it fails to create, we're not going to be able to use it anyway
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string game_subdir(Path::Combine(game_dir, TEXTURE_DUMP_SUBDIRECTORY_NAME));
|
||||
|
||||
std::string filename;
|
||||
if (name.HasRegion())
|
||||
{
|
||||
if (name.HasPalette())
|
||||
{
|
||||
filename = (level > 0) ?
|
||||
StringUtil::StdStringFromFormat(TEXTURE_FILENAME_REGION_CLUT_FORMAT_STRING "-mip%u.png",
|
||||
name.TEX0Hash, name.CLUTHash, name.region_width, name.region_height, name.bits, level) :
|
||||
StringUtil::StdStringFromFormat(TEXTURE_FILENAME_REGION_CLUT_FORMAT_STRING ".png",
|
||||
name.TEX0Hash, name.CLUTHash, name.region_width, name.region_height, name.bits);
|
||||
filename = (level > 0)
|
||||
? StringUtil::StdStringFromFormat(TEXTURE_FILENAME_REGION_CLUT_FORMAT_STRING "-mip%u.png",
|
||||
name.TEX0Hash, name.CLUTHash, name.region_width, name.region_height, name.bits, level)
|
||||
: StringUtil::StdStringFromFormat(TEXTURE_FILENAME_REGION_CLUT_FORMAT_STRING ".png",
|
||||
name.TEX0Hash, name.CLUTHash, name.region_width, name.region_height, name.bits);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = (level > 0) ? StringUtil::StdStringFromFormat(
|
||||
TEXTURE_FILENAME_REGION_FORMAT_STRING "-mip%u.png", name.TEX0Hash,
|
||||
name.region_width, name.region_height, name.bits, level) :
|
||||
StringUtil::StdStringFromFormat(
|
||||
TEXTURE_FILENAME_REGION_FORMAT_STRING ".png", name.TEX0Hash,
|
||||
name.region_width, name.region_height, name.bits);
|
||||
filename = (level > 0)
|
||||
? StringUtil::StdStringFromFormat(TEXTURE_FILENAME_REGION_FORMAT_STRING "-mip%u.png",
|
||||
name.TEX0Hash, name.region_width, name.region_height, name.bits, level)
|
||||
: StringUtil::StdStringFromFormat(TEXTURE_FILENAME_REGION_FORMAT_STRING ".png",
|
||||
name.TEX0Hash, name.region_width, name.region_height, name.bits);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (name.HasPalette())
|
||||
{
|
||||
filename = (level > 0) ? StringUtil::StdStringFromFormat(TEXTURE_FILENAME_CLUT_FORMAT_STRING "-mip%u.png",
|
||||
name.TEX0Hash, name.CLUTHash, name.bits, level) :
|
||||
StringUtil::StdStringFromFormat(TEXTURE_FILENAME_CLUT_FORMAT_STRING ".png",
|
||||
name.TEX0Hash, name.CLUTHash, name.bits);
|
||||
filename = (level > 0)
|
||||
? StringUtil::StdStringFromFormat(TEXTURE_FILENAME_CLUT_FORMAT_STRING "-mip%u.png",
|
||||
name.TEX0Hash, name.CLUTHash, name.bits, level)
|
||||
: StringUtil::StdStringFromFormat(TEXTURE_FILENAME_CLUT_FORMAT_STRING ".png",
|
||||
name.TEX0Hash, name.CLUTHash, name.bits);
|
||||
}
|
||||
else
|
||||
{
|
||||
filename = (level > 0) ? StringUtil::StdStringFromFormat(
|
||||
TEXTURE_FILENAME_FORMAT_STRING "-mip%u.png", name.TEX0Hash, name.bits, level) :
|
||||
StringUtil::StdStringFromFormat(
|
||||
TEXTURE_FILENAME_FORMAT_STRING ".png", name.TEX0Hash, name.bits);
|
||||
filename = (level > 0)
|
||||
? StringUtil::StdStringFromFormat(TEXTURE_FILENAME_FORMAT_STRING "-mip%u.png",
|
||||
name.TEX0Hash, name.bits, level)
|
||||
: StringUtil::StdStringFromFormat(TEXTURE_FILENAME_FORMAT_STRING ".png",
|
||||
name.TEX0Hash, name.bits);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -349,6 +350,28 @@ void GSTextureReplacements::GameChanged()
|
||||
ClearDumpedTextureList();
|
||||
}
|
||||
|
||||
/// If the given file exists in the given directory, but with a different case than the original file, write its path to `*output` and return true.
|
||||
static bool GetWrongCasePath(std::string* output, const char* dir, std::string_view file, FileSystem::FindResultsArray* reuseme)
|
||||
{
|
||||
if (FileSystem::FindFiles(dir, "*", FILESYSTEM_FIND_FOLDERS | FILESYSTEM_FIND_HIDDEN_FILES, reuseme))
|
||||
{
|
||||
for (const FILESYSTEM_FIND_DATA& fd : *reuseme)
|
||||
{
|
||||
std::string_view name = Path::GetFileName(fd.FileName);
|
||||
if (name.size() != file.size())
|
||||
continue;
|
||||
if (0 == strncmp(name.data(), file.data(), name.size()))
|
||||
continue;
|
||||
if (0 == StringUtil::Strncasecmp(name.data(), file.data(), name.size()))
|
||||
{
|
||||
*output = fd.FileName;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GSTextureReplacements::ReloadReplacementMap()
|
||||
{
|
||||
SyncWorkerThread();
|
||||
@@ -368,9 +391,27 @@ void GSTextureReplacements::ReloadReplacementMap()
|
||||
if (s_current_serial.empty() || !GSConfig.LoadTextureReplacements)
|
||||
return;
|
||||
|
||||
const std::string replacement_dir(Path::Combine(GetGameTextureDirectory(), TEXTURE_REPLACEMENT_SUBDIRECTORY_NAME));
|
||||
const std::string texture_dir = GetGameTextureDirectory();
|
||||
const std::string replacement_dir(Path::Combine(texture_dir, TEXTURE_REPLACEMENT_SUBDIRECTORY_NAME));
|
||||
|
||||
FileSystem::FindResultsArray files;
|
||||
|
||||
// For some reason texture pack authors think it's a good idea to rename the replacements directory to something with the wrong case...
|
||||
std::string wrong_case_path;
|
||||
const std::string* right_case_path = nullptr;
|
||||
if (GetWrongCasePath(&wrong_case_path, EmuFolders::Textures.c_str(), s_current_serial, &files))
|
||||
right_case_path = &texture_dir;
|
||||
else if (GetWrongCasePath(&wrong_case_path, texture_dir.c_str(), TEXTURE_REPLACEMENT_SUBDIRECTORY_NAME, &files))
|
||||
right_case_path = &replacement_dir;
|
||||
if (right_case_path)
|
||||
{
|
||||
Host::AddKeyedOSDMessage("TextureReplacementDirCaseMismatch",
|
||||
fmt::format(TRANSLATE_FS("TextureReplacement", "Texture replacement directory {} will not work on case sensitive filesystems.\n"
|
||||
"Rename it to {} to remove this warning."),
|
||||
wrong_case_path, *right_case_path),
|
||||
Host::OSD_WARNING_DURATION);
|
||||
}
|
||||
|
||||
if (!FileSystem::FindFiles(replacement_dir.c_str(), "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES | FILESYSTEM_FIND_RECURSIVE, &files))
|
||||
return;
|
||||
|
||||
|
||||
@@ -1713,12 +1713,12 @@ void GSDeviceMTL::UpdateCLUTTexture(GSTexture* sTex, float sScale, u32 offsetX,
|
||||
|
||||
void GSDeviceMTL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 offsetX, u32 offsetY, u32 SBW, u32 SPSM, GSTexture* dTex, u32 DBW, u32 DPSM)
|
||||
{ @autoreleasepool {
|
||||
const ShaderConvert shader = ShaderConvert::RGBA_TO_8I;
|
||||
const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I;
|
||||
id<MTLRenderPipelineState> pipeline = m_convert_pipeline[static_cast<int>(shader)];
|
||||
if (!pipeline)
|
||||
[NSException raise:@"StretchRect Missing Pipeline" format:@"No pipeline for %d", static_cast<int>(shader)];
|
||||
|
||||
GSMTLIndexedConvertPSUniform uniform = { sScale, SBW, DBW };
|
||||
GSMTLIndexedConvertPSUniform uniform = { sScale, SBW, DBW, SPSM };
|
||||
|
||||
const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight());
|
||||
DoStretchRect(sTex, GSVector4::zero(), dTex, dRect, pipeline, false, LoadAction::DontCareIfFull, &uniform, sizeof(uniform));
|
||||
|
||||
@@ -4,12 +4,19 @@
|
||||
#include "GSMTLDeviceInfo.h"
|
||||
#include "GS/GS.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/Path.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
static id<MTLLibrary> loadMainLibrary(id<MTLDevice> dev, NSString* name)
|
||||
{
|
||||
NSString* path = [[NSBundle mainBundle] pathForResource:name ofType:@"metallib"];
|
||||
if (!path)
|
||||
{
|
||||
std::string ssname = std::string([name UTF8String]) + ".metallib";
|
||||
std::string sspath = Path::Combine(EmuFolders::Resources, ssname);
|
||||
path = [[NSString alloc] initWithBytes:sspath.data() length:sspath.length() encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
return path ? [dev newLibraryWithFile:path error:nullptr] : nullptr;
|
||||
}
|
||||
|
||||
@@ -24,6 +31,8 @@ static MRCOwned<id<MTLLibrary>> loadMainLibrary(id<MTLDevice> dev)
|
||||
if (@available(macOS 10.14, iOS 12.0, *))
|
||||
if (id<MTLLibrary> lib = loadMainLibrary(dev, @"Metal21"))
|
||||
return MRCTransfer(lib);
|
||||
if (id<MTLLibrary> lib = loadMainLibrary(dev, @"default"))
|
||||
return MRCTransfer(lib);
|
||||
return MRCTransfer([dev newDefaultLibrary]);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ struct GSMTLIndexedConvertPSUniform
|
||||
float scale;
|
||||
uint sbw;
|
||||
uint dbw;
|
||||
uint psm;
|
||||
};
|
||||
|
||||
struct GSMTLDownsamplePSUniform
|
||||
|
||||
@@ -296,6 +296,121 @@ fragment DepthOut ps_convert_rgb5a1_float16_biln(ConvertShaderData data [[stage_
|
||||
return res.sample_biln<rgb5a1_to_depth16>(data.t);
|
||||
}
|
||||
|
||||
fragment float4 ps_convert_rgb5a1_8i(ConvertShaderData data [[stage_in]], DirectReadTextureIn<float> res,
|
||||
constant GSMTLIndexedConvertPSUniform& uniform [[buffer(GSMTLBufferIndexUniforms)]])
|
||||
{
|
||||
// Convert a RGB5A1 texture into a 8 bits packed texture
|
||||
// Input column: 16x2 RGB5A1 pixels
|
||||
// 0: 16 RGBA
|
||||
// 1: 16 RGBA
|
||||
// Output column: 16x4 Index pixels
|
||||
// 0: 16 R5G2
|
||||
// 1: 16 R5G2
|
||||
// 2: 16 G2B5A1
|
||||
// 3: 16 G2B5A1
|
||||
uint2 pos = uint2(data.p.xy);
|
||||
|
||||
// Collapse separate R G B A areas into their base pixel
|
||||
uint2 column = (pos & ~uint2(0u, 3u)) / uint2(1,2);
|
||||
uint2 subcolumn = (pos & uint2(0u, 1u));
|
||||
column.x -= (column.x / 128) * 64;
|
||||
column.y += (column.y / 32) * 32;
|
||||
|
||||
// Deal with swizzling differences
|
||||
if ((uniform.psm & 0x8) != 0) // PSMCT16S
|
||||
{
|
||||
if ((pos.x & 32) != 0)
|
||||
{
|
||||
column.y += 32; // 4 columns high times 4 to get bottom 4 blocks
|
||||
column.x &= ~32;
|
||||
}
|
||||
|
||||
if ((pos.x & 64) != 0)
|
||||
{
|
||||
column.x -= 32;
|
||||
}
|
||||
|
||||
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
|
||||
{
|
||||
column.x ^= 16;
|
||||
column.y ^= 8;
|
||||
}
|
||||
|
||||
if ((uniform.psm & 0x30) != 0) // PSMZ16S - Untested but hopefully ok if anything uses it.
|
||||
{
|
||||
column.x ^= 32;
|
||||
column.y ^= 16;
|
||||
}
|
||||
}
|
||||
else // PSMCT16
|
||||
{
|
||||
if ((pos.y & 32) != 0)
|
||||
{
|
||||
column.y -= 16;
|
||||
column.x += 32;
|
||||
}
|
||||
|
||||
if ((pos.x & 96) != 0)
|
||||
{
|
||||
uint multi = (pos.x & 96) / 32;
|
||||
column.y += 16 * multi; // 4 columns high times 4 to get bottom 4 blocks
|
||||
column.x -= (pos.x & 96);
|
||||
}
|
||||
|
||||
if (((pos.x & 16) != 0) != ((pos.y & 16) != 0))
|
||||
{
|
||||
column.x ^= 16;
|
||||
column.y ^= 8;
|
||||
}
|
||||
|
||||
if ((uniform.psm & 0x30) != 0) // PSMZ16 - Untested but hopefully ok if anything uses it.
|
||||
{
|
||||
column.x ^= 32;
|
||||
column.y ^= 32;
|
||||
}
|
||||
}
|
||||
|
||||
uint2 coord = column | subcolumn;
|
||||
|
||||
// Compensate for potentially differing page pitch.
|
||||
uint2 block_xy = coord / uint2(64, 64);
|
||||
uint block_num = (block_xy.y * (uniform.dbw / 128)) + block_xy.x;
|
||||
uint2 block_offset = uint2((block_num % (uniform.sbw / 64)) * 64, (block_num / (uniform.sbw / 64)) * 64);
|
||||
coord = (coord % uint2(64, 64)) + block_offset;
|
||||
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4;
|
||||
uint is_col13 = pos.y & 2;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
|
||||
if (any(floor(uniform.scale) != uniform.scale))
|
||||
coord = uint2(float2(coord) * uniform.scale);
|
||||
else
|
||||
coord = mul24(coord, uint2(uniform.scale));
|
||||
|
||||
float4 pixel = res.tex.read(coord);
|
||||
|
||||
uint4 denorm_c = (uint4)(pixel * 255.5f);
|
||||
if ((pos.y & 2u) == 0u)
|
||||
{
|
||||
uint red = (denorm_c.r >> 3) & 0x1Fu;
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
float sel0 = (float)(((green << 5) | red) & 0xFF) / 255.0f;
|
||||
|
||||
return float4(sel0);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint green = (denorm_c.g >> 3) & 0x1Fu;
|
||||
uint blue = (denorm_c.b >> 3) & 0x1Fu;
|
||||
uint alpha = denorm_c.a & 0x80u;
|
||||
float sel0 = (float)((alpha | (blue << 2) | (green >> 3)) & 0xFF) / 255.0f;
|
||||
|
||||
return float4(sel0);
|
||||
}
|
||||
}
|
||||
|
||||
fragment float4 ps_convert_rgba_8i(ConvertShaderData data [[stage_in]], DirectReadTextureIn<float> res,
|
||||
constant GSMTLIndexedConvertPSUniform& uniform [[buffer(GSMTLBufferIndexUniforms)]])
|
||||
{
|
||||
|
||||
@@ -350,10 +350,11 @@ bool GSDeviceOGL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
return false;
|
||||
m_convert.ps[i].SetFormattedName("Convert pipe %s", name);
|
||||
|
||||
if (static_cast<ShaderConvert>(i) == ShaderConvert::RGBA_TO_8I)
|
||||
if (static_cast<ShaderConvert>(i) == ShaderConvert::RGBA_TO_8I || static_cast<ShaderConvert>(i) == ShaderConvert::RGB5A1_TO_8I)
|
||||
{
|
||||
m_convert.ps[i].RegisterUniform("SBW");
|
||||
m_convert.ps[i].RegisterUniform("DBW");
|
||||
m_convert.ps[i].RegisterUniform("PSM");
|
||||
m_convert.ps[i].RegisterUniform("ScaleFactor");
|
||||
}
|
||||
else if (static_cast<ShaderConvert>(i) == ShaderConvert::YUV)
|
||||
@@ -1594,12 +1595,13 @@ void GSDeviceOGL::ConvertToIndexedTexture(GSTexture* sTex, float sScale, u32 off
|
||||
{
|
||||
CommitClear(sTex, false);
|
||||
|
||||
const ShaderConvert shader = ShaderConvert::RGBA_TO_8I;
|
||||
const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I;
|
||||
GLProgram& prog = m_convert.ps[static_cast<int>(shader)];
|
||||
prog.Bind();
|
||||
prog.Uniform1ui(0, SBW);
|
||||
prog.Uniform1ui(1, DBW);
|
||||
prog.Uniform1f(2, sScale);
|
||||
prog.Uniform1ui(2, SPSM);
|
||||
prog.Uniform1f(3, sScale);
|
||||
|
||||
OMSetDepthStencilState(m_convert.dss);
|
||||
OMSetBlendState(false);
|
||||
|
||||
@@ -3158,15 +3158,16 @@ void GSDeviceVK::ConvertToIndexedTexture(
|
||||
{
|
||||
u32 SBW;
|
||||
u32 DBW;
|
||||
u32 pad1[2];
|
||||
u32 PSM;
|
||||
u32 pad1[1];
|
||||
float ScaleFactor;
|
||||
float pad2[3];
|
||||
};
|
||||
|
||||
const Uniforms uniforms = {SBW, DBW, {}, sScale, {}};
|
||||
const Uniforms uniforms = {SBW, DBW, SPSM, {}, sScale, {}};
|
||||
SetUtilityPushConstants(&uniforms, sizeof(uniforms));
|
||||
|
||||
const ShaderConvert shader = ShaderConvert::RGBA_TO_8I;
|
||||
const ShaderConvert shader = ((SPSM & 0xE) == 0) ? ShaderConvert::RGBA_TO_8I : ShaderConvert::RGB5A1_TO_8I;
|
||||
const GSVector4 dRect(0, 0, dTex->GetWidth(), dTex->GetHeight());
|
||||
DoStretchRect(static_cast<GSTextureVK*>(sTex), GSVector4::zero(), static_cast<GSTextureVK*>(dTex), dRect,
|
||||
m_convert[static_cast<int>(shader)], false, true);
|
||||
|
||||
@@ -857,7 +857,7 @@ void AudioStreamParameters::LoadSave(SettingsWrapper& wrap, const char* section)
|
||||
wrap.EnumEntry(section, "ExpansionMode", expansion_mode, &AudioStream::ParseExpansionMode, &AudioStream::GetExpansionModeName, DEFAULT_EXPANSION_MODE);
|
||||
minimal_output_latency = wrap.EntryBitBool(section, "OutputLatencyMinimal", DEFAULT_OUTPUT_LATENCY_MINIMAL);
|
||||
buffer_ms = static_cast<u16>(std::clamp<int>(wrap.EntryBitfield(section, "BufferMS", buffer_ms, DEFAULT_BUFFER_MS), 0, std::numeric_limits<u16>::max()));
|
||||
output_latency_ms = static_cast<u16>(std::clamp<int>(wrap.EntryBitfield(section, "OutputLatencyMS", buffer_ms, DEFAULT_OUTPUT_LATENCY_MS), 0, std::numeric_limits<u16>::max()));
|
||||
output_latency_ms = static_cast<u16>(std::clamp<int>(wrap.EntryBitfield(section, "OutputLatencyMS", output_latency_ms, DEFAULT_OUTPUT_LATENCY_MS), 0, std::numeric_limits<u16>::max()));
|
||||
|
||||
stretch_sequence_length_ms = static_cast<u16>(std::clamp<int>(wrap.EntryBitfield(section, "StretchSequenceLengthMS", DEFAULT_STRETCH_SEQUENCE_LENGTH), 0, std::numeric_limits<u16>::max()));
|
||||
stretch_seekwindow_ms = static_cast<u16>(std::clamp<int>(wrap.EntryBitfield(section, "StretchSeekWindowMS", DEFAULT_STRETCH_SEEKWINDOW), 0, std::numeric_limits<u16>::max()));
|
||||
|
||||
@@ -1615,7 +1615,7 @@ void InputManager::CloseSources()
|
||||
{
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i]->IsInitialized())
|
||||
if (s_input_sources[i] && s_input_sources[i]->IsInitialized())
|
||||
{
|
||||
s_input_sources[i]->Shutdown();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <cstring>
|
||||
#include <fmt/format.h>
|
||||
#include <sys/stat.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
@@ -641,7 +642,7 @@ namespace R3000A
|
||||
|
||||
for (size_t i = 0; i < handles.size(); i++)
|
||||
{
|
||||
if (handles[i].fd_index == (u32) fd - firstfd)
|
||||
if (handles[i].fd_index == (u32)fd - firstfd)
|
||||
{
|
||||
handles.erase(handles.begin() + i);
|
||||
break;
|
||||
@@ -928,12 +929,6 @@ namespace R3000A
|
||||
{
|
||||
int Kprintf_HLE()
|
||||
{
|
||||
// Using sprintf here is a bit nasty, but it has a large buffer..
|
||||
// Don't feel like rewriting it.
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
// Emulate the expected Kprintf functionality:
|
||||
iopMemWrite32(sp, a0);
|
||||
@@ -951,8 +946,12 @@ namespace R3000A
|
||||
if (!ConsoleLogging.iopConsole.IsActive())
|
||||
return 1;
|
||||
|
||||
char tmp[1024], tmp2[1024];
|
||||
// maximum allowed size for our buffer before we truncate
|
||||
const unsigned int max_len = 4096;
|
||||
char tmp[max_len], tmp2[max_len];
|
||||
char* ptmp = tmp;
|
||||
unsigned int printed_bytes = 0;
|
||||
int remaining_buf = max_len - 1;
|
||||
int n = 1, i = 0, j = 0;
|
||||
|
||||
while (fmt[i])
|
||||
@@ -963,21 +962,32 @@ namespace R3000A
|
||||
j = 0;
|
||||
tmp2[j++] = '%';
|
||||
_start:
|
||||
switch (fmt[++i])
|
||||
// let's check whether this is our null terminator
|
||||
// before allowing the parser to proceed
|
||||
if (fmt[i + 1])
|
||||
{
|
||||
case '.':
|
||||
case 'l':
|
||||
tmp2[j++] = fmt[i];
|
||||
goto _start;
|
||||
default:
|
||||
if (fmt[i] >= '0' && fmt[i] <= '9')
|
||||
{
|
||||
switch (fmt[++i])
|
||||
{
|
||||
case '.':
|
||||
case 'l':
|
||||
if (j >= max_len)
|
||||
break;
|
||||
tmp2[j++] = fmt[i];
|
||||
goto _start;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (fmt[i] >= '0' && fmt[i] <= '9')
|
||||
{
|
||||
if (j >= max_len)
|
||||
break;
|
||||
tmp2[j++] = fmt[i];
|
||||
goto _start;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j >= max_len)
|
||||
break;
|
||||
tmp2[j++] = fmt[i];
|
||||
tmp2[j] = 0;
|
||||
|
||||
@@ -985,7 +995,9 @@ namespace R3000A
|
||||
{
|
||||
case 'f':
|
||||
case 'F':
|
||||
ptmp += sprintf(ptmp, tmp2, (float)iopMemRead32(sp + n * 4));
|
||||
printed_bytes = std::min(remaining_buf, snprintf(ptmp, remaining_buf, tmp2, (float)iopMemRead32(sp + n * 4)));
|
||||
remaining_buf -= printed_bytes;
|
||||
ptmp += printed_bytes;
|
||||
n++;
|
||||
break;
|
||||
|
||||
@@ -995,7 +1007,9 @@ namespace R3000A
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
ptmp += sprintf(ptmp, tmp2, (double)iopMemRead32(sp + n * 4));
|
||||
printed_bytes = std::min(remaining_buf, snprintf(ptmp, remaining_buf, tmp2, (double)iopMemRead32(sp + n * 4)));
|
||||
remaining_buf -= printed_bytes;
|
||||
ptmp += printed_bytes;
|
||||
n++;
|
||||
break;
|
||||
|
||||
@@ -1007,19 +1021,27 @@ namespace R3000A
|
||||
case 'O':
|
||||
case 'x':
|
||||
case 'X':
|
||||
ptmp += sprintf(ptmp, tmp2, (u32)iopMemRead32(sp + n * 4));
|
||||
case 'u':
|
||||
case 'U':
|
||||
printed_bytes = std::min(remaining_buf, snprintf(ptmp, remaining_buf, tmp2, (u32)iopMemRead32(sp + n * 4)));
|
||||
remaining_buf -= printed_bytes;
|
||||
ptmp += printed_bytes;
|
||||
n++;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
ptmp += sprintf(ptmp, tmp2, (u8)iopMemRead32(sp + n * 4));
|
||||
printed_bytes = std::min(remaining_buf, snprintf(ptmp, remaining_buf, tmp2, (u8)iopMemRead32(sp + n * 4)));
|
||||
remaining_buf -= printed_bytes;
|
||||
ptmp += printed_bytes;
|
||||
n++;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
{
|
||||
std::string s = iopMemReadString(iopMemRead32(sp + n * 4));
|
||||
ptmp += sprintf(ptmp, tmp2, s.data());
|
||||
printed_bytes = std::min(remaining_buf, snprintf(ptmp, remaining_buf, tmp2, s.data()));
|
||||
remaining_buf -= printed_bytes;
|
||||
ptmp += printed_bytes;
|
||||
n++;
|
||||
}
|
||||
break;
|
||||
@@ -1043,10 +1065,6 @@ namespace R3000A
|
||||
iopConLog(ShiftJIS_ConvertString(tmp, 1023));
|
||||
|
||||
return 1;
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
}
|
||||
} // namespace sysmem
|
||||
|
||||
|
||||
@@ -2084,17 +2084,16 @@ void Pcsx2Config::ClearInvalidPerGameConfiguration(SettingsInterface* si)
|
||||
void EmuFolders::SetAppRoot()
|
||||
{
|
||||
std::string program_path = FileSystem::GetProgramPath();
|
||||
Console.WriteLnFmt("Program Path: {}", program_path);
|
||||
AppRoot = Path::Canonicalize(Path::GetDirectory(program_path));
|
||||
#ifdef __APPLE__
|
||||
const auto bundle_path = CocoaTools::GetNonTranslocatedBundlePath();
|
||||
if (bundle_path.has_value())
|
||||
{
|
||||
// On macOS, override with the bundle path if launched from a bundle.
|
||||
program_path = bundle_path.value();
|
||||
AppRoot = StringUtil::EndsWithNoCase(*bundle_path, ".app") ? Path::GetDirectory(*bundle_path) : *bundle_path;
|
||||
}
|
||||
#endif
|
||||
Console.WriteLnFmt("Program Path: {}", program_path);
|
||||
|
||||
AppRoot = Path::Canonicalize(Path::GetDirectory(program_path));
|
||||
|
||||
// logging of directories in case something goes wrong super early
|
||||
Console.WriteLnFmt("AppRoot Directory: {}", AppRoot);
|
||||
@@ -2111,8 +2110,10 @@ bool EmuFolders::SetResourcesDirectory()
|
||||
#endif
|
||||
#else
|
||||
// On macOS, this is in the bundle resources directory.
|
||||
const std::string program_path = FileSystem::GetProgramPath();
|
||||
Resources = Path::Canonicalize(Path::Combine(Path::GetDirectory(program_path), "../Resources"));
|
||||
if (auto resources = CocoaTools::GetResourcePath())
|
||||
Resources = *resources;
|
||||
else
|
||||
Resources = Path::Combine(AppRoot, "resources");
|
||||
#endif
|
||||
|
||||
Console.WriteLnFmt("Resources Directory: {}", Resources);
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
/// Version number for GS and other shaders. Increment whenever any of the contents of the
|
||||
/// shaders change, to invalidate the cache.
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 65;
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 66;
|
||||
|
||||
Reference in New Issue
Block a user