mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e7ac3d66c | ||
|
|
730e6fa737 | ||
|
|
cdfcd9fddd | ||
|
|
b6930c10b9 | ||
|
|
852734580d | ||
|
|
d1dc6a9c1d | ||
|
|
4fa6d3ed3f | ||
|
|
92e190ad6c | ||
|
|
da4fcffef4 | ||
|
|
1a5731dd8e | ||
|
|
e764c5cd4e | ||
|
|
e23b247947 | ||
|
|
3d7792436f | ||
|
|
d8187fbea4 | ||
|
|
02259ad0a5 | ||
|
|
220a68df9a | ||
|
|
2ced24f69e | ||
|
|
ec91d0dc74 | ||
|
|
46874f4673 | ||
|
|
9eac47dc6c | ||
|
|
9e3fd5c2e0 | ||
|
|
ae4be6e2b1 | ||
|
|
434df49a7d | ||
|
|
c939c0fcd5 | ||
|
|
952c39f324 | ||
|
|
0fea7e2a70 | ||
|
|
c1baab68d0 | ||
|
|
ccef18f7a9 | ||
|
|
8cb056bde3 | ||
|
|
6ecaaee9e0 | ||
|
|
c5f916bda0 | ||
|
|
52a9a4649c |
@@ -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()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
@@ -1940,11 +1940,13 @@ SCAJ-20115:
|
||||
name: "Yoshitsune Eiyuuden"
|
||||
region: "NTSC-Unk"
|
||||
SCAJ-20116:
|
||||
name: "Death by Degrees - Tekken - Nina Williams"
|
||||
region: "NTSC-C-J"
|
||||
name: "戰慄殺機 鐵拳 - 妮娜 - 威廉斯"
|
||||
name-en: "Death by Degrees"
|
||||
region: "NTSC-C"
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
getSkipCount: "GSC_NamcoGames"
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post processing.
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
textureInsideRT: 1 # Fixes post shuffles.
|
||||
SCAJ-20117:
|
||||
name: "Fu-un Bakumatsu-den"
|
||||
@@ -5763,8 +5765,9 @@ SCES-52586:
|
||||
region: "PAL-E-S"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
getSkipCount: "GSC_NamcoGames"
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post processing.
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
textureInsideRT: 1 # Fixes post shuffles.
|
||||
SCES-52596:
|
||||
name: "This is Football 2005"
|
||||
@@ -5865,16 +5868,18 @@ SCES-53053:
|
||||
name: "Death by Degrees"
|
||||
region: "PAL-F-I"
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
getSkipCount: "GSC_NamcoGames"
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post processing.
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
textureInsideRT: 1 # Fixes post shuffles.
|
||||
SCES-53054:
|
||||
name: "Death by Degrees"
|
||||
region: "PAL-E-G"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
getSkipCount: "GSC_NamcoGames"
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post processing.
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
textureInsideRT: 1 # Fixes post shuffles.
|
||||
SCES-53055:
|
||||
name: "Eyetoy - Antigrav"
|
||||
@@ -7309,8 +7314,9 @@ SCKA-20039:
|
||||
name: "Tekken Nina Williams In Death By Degree"
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_NamcoGames"
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post processing.
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
halfPixelOffset: 2 # Aligns post effects.
|
||||
textureInsideRT: 1 # Fixes post shuffles.
|
||||
SCKA-20040:
|
||||
name: "Jak 3"
|
||||
@@ -12921,7 +12927,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:
|
||||
@@ -14276,8 +14282,6 @@ SLES-50078:
|
||||
SLES-50079:
|
||||
name: "Armored Core 2"
|
||||
region: "PAL-E"
|
||||
gameFixes:
|
||||
- SoftwareRendererFMVHack # Fixes random corruption.
|
||||
clampModes:
|
||||
eeClampMode: 2 # Fixes Abnormal AI behavior.
|
||||
gsHWFixes:
|
||||
@@ -16825,7 +16829,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:
|
||||
@@ -16835,7 +16839,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:
|
||||
@@ -16845,7 +16849,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:
|
||||
@@ -16855,7 +16859,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:
|
||||
@@ -16865,7 +16869,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:
|
||||
@@ -16922,7 +16926,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:
|
||||
@@ -16932,7 +16936,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:
|
||||
@@ -16942,7 +16946,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:
|
||||
@@ -16952,7 +16956,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:
|
||||
@@ -16962,7 +16966,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:
|
||||
@@ -16972,7 +16976,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:
|
||||
@@ -19892,7 +19896,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:
|
||||
@@ -20119,7 +20123,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:
|
||||
@@ -20430,7 +20434,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:
|
||||
@@ -22082,6 +22086,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"
|
||||
@@ -31104,7 +31110,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:
|
||||
@@ -34788,8 +34794,9 @@ SLPM-60257:
|
||||
name-en: "Death by Degrees - Tekken - Nina Williams [Trial]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
getSkipCount: "GSC_NamcoGames"
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post processing.
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
textureInsideRT: 1 # Fixes post shuffles.
|
||||
SLPM-60258:
|
||||
name: "THE TYPING OF THE DEAD ZOMBIE PANIC [体験版]"
|
||||
@@ -36952,7 +36959,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"
|
||||
@@ -38364,7 +38371,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]"
|
||||
@@ -39795,7 +39802,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"
|
||||
@@ -43350,7 +43357,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:
|
||||
@@ -52152,7 +52159,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: "カラオケレボリューション用マイク同梱お試しディスク"
|
||||
@@ -54303,7 +54310,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"
|
||||
@@ -55563,7 +55570,8 @@ SLPS-20489:
|
||||
name-en: "Simple 2000 Series Vol. 114 - The Onna Okappichi Torimonochou - Oharu-chan GoGoGo!"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
getSkipCount: "GSC_Simple2000Vol114"
|
||||
halfPixelOffset: 5 # Fixes DoF alignment.
|
||||
nativeScaling: 1 # Corrects DoF.
|
||||
SLPS-20490:
|
||||
name: "パチスロ倶楽部コレクション アイムジャグラーEX~ジャグラーセレクション~"
|
||||
name-sort: "ぱちすろくらぶこれくしょん あいむじゃぐらーEX じゃぐらーせれくしょん"
|
||||
@@ -55725,8 +55733,6 @@ SLPS-25007:
|
||||
name-sort: "あーまーどこあ 2"
|
||||
name-en: "Armored Core 2"
|
||||
region: "NTSC-J"
|
||||
gameFixes:
|
||||
- SoftwareRendererFMVHack # Fixes random corruption.
|
||||
clampModes:
|
||||
eeClampMode: 2 # Fixes Abnormal AI behavior.
|
||||
gsHWFixes:
|
||||
@@ -58223,8 +58229,9 @@ SLPS-25422:
|
||||
name-en: "Death by Degrees - Tekken - Nina Williams"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
getSkipCount: "GSC_NamcoGames"
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post processing.
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
textureInsideRT: 1 # Fixes post shuffles.
|
||||
SLPS-25423:
|
||||
name: "怪盗アプリコット 完全版 [限定版]"
|
||||
@@ -59131,6 +59138,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: "あすとろきゅうだん けっせん!!びくとりーきゅうだんへん"
|
||||
@@ -62370,8 +62379,6 @@ SLPS-73403:
|
||||
name-sort: "あーまーどこあ 2 [PlayStation2 the Best]"
|
||||
name-en: "Armored Core 2 [PlayStation2 the Best]"
|
||||
region: "NTSC-J"
|
||||
gameFixes:
|
||||
- SoftwareRendererFMVHack # Fixes random corruption.
|
||||
clampModes:
|
||||
eeClampMode: 2 # Fixes Abnormal AI behavior.
|
||||
gsHWFixes:
|
||||
@@ -62626,8 +62633,6 @@ SLUS-20014:
|
||||
name: "Armored Core 2"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gameFixes:
|
||||
- SoftwareRendererFMVHack # Fixes random corruption.
|
||||
clampModes:
|
||||
eeClampMode: 2 # Fixes Abnormal AI behavior.
|
||||
gsHWFixes:
|
||||
@@ -65272,7 +65277,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"
|
||||
@@ -67217,7 +67222,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:
|
||||
@@ -67262,8 +67267,9 @@ SLUS-20934:
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
getSkipCount: "GSC_NamcoGames"
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post processing.
|
||||
alignSprite: 1 # Fixes FMV lines.
|
||||
textureInsideRT: 1 # Fixes post shuffles.
|
||||
SLUS-20935:
|
||||
name: "IHRA Professional Drag Racing 2005"
|
||||
@@ -68229,6 +68235,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"
|
||||
|
||||
@@ -1283,7 +1283,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006f0e00008401000011010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000852100000201000010010000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
05000000b40400001224000001010000,Flydigi APEX 4,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b20,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
@@ -1606,6 +1606,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
0300132d9b2800006500000001010000,Raphnet GameCube 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,
|
||||
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,
|
||||
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,
|
||||
@@ -1802,6 +1803,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
060000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
050000005e040000130b000022050000,Xbox Series X Controller,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,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000200b000013050000,Xbox Wireless Controller,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,
|
||||
050000005e040000200b000017050000,Xbox Wireless Controller,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,
|
||||
050000005e040000220b000017050000,Xbox Wireless Controller,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;
|
||||
@@ -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__
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "CoverDownloadDialog.h"
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "pcsx2/GameList.h"
|
||||
|
||||
@@ -11,7 +12,7 @@ CoverDownloadDialog::CoverDownloadDialog(QWidget* parent /*= nullptr*/)
|
||||
: QDialog(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_ui.coverIcon->setPixmap(QIcon::fromTheme("artboard-2-line").pixmap(32));
|
||||
QtUtils::SetScalableIcon(m_ui.coverIcon, QIcon::fromTheme(QStringLiteral("artboard-2-line")), QSize(32, 32));
|
||||
updateEnabled();
|
||||
|
||||
connect(m_ui.start, &QPushButton::clicked, this, &CoverDownloadDialog::onStartClicked);
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -52,12 +52,12 @@ DisplayWidget::~DisplayWidget()
|
||||
|
||||
int DisplayWidget::scaledWindowWidth() const
|
||||
{
|
||||
return std::max(static_cast<int>(std::ceil(static_cast<qreal>(width()) * QtUtils::GetDevicePixelRatioForWidget(this))), 1);
|
||||
return std::max(static_cast<int>(std::ceil(static_cast<qreal>(width()) * devicePixelRatioF())), 1);
|
||||
}
|
||||
|
||||
int DisplayWidget::scaledWindowHeight() const
|
||||
{
|
||||
return std::max(static_cast<int>(std::ceil(static_cast<qreal>(height()) * QtUtils::GetDevicePixelRatioForWidget(this))), 1);
|
||||
return std::max(static_cast<int>(std::ceil(static_cast<qreal>(height()) * devicePixelRatioF())), 1);
|
||||
}
|
||||
|
||||
std::optional<WindowInfo> DisplayWidget::getWindowInfo()
|
||||
@@ -268,7 +268,7 @@ bool DisplayWidget::event(QEvent* event)
|
||||
|
||||
if (!m_relative_mouse_enabled)
|
||||
{
|
||||
const qreal dpr = QtUtils::GetDevicePixelRatioForWidget(this);
|
||||
const qreal dpr = devicePixelRatioF();
|
||||
const QPoint mouse_pos = mouse_event->pos();
|
||||
|
||||
const float scaled_x = static_cast<float>(static_cast<qreal>(mouse_pos.x()) * dpr);
|
||||
@@ -349,13 +349,12 @@ bool DisplayWidget::event(QEvent* event)
|
||||
return true;
|
||||
}
|
||||
|
||||
// According to https://bugreports.qt.io/browse/QTBUG-95925 the recommended practice for handling DPI change is responding to paint events
|
||||
case QEvent::Paint:
|
||||
case QEvent::DevicePixelRatioChange:
|
||||
case QEvent::Resize:
|
||||
{
|
||||
QWidget::event(event);
|
||||
|
||||
const float dpr = QtUtils::GetDevicePixelRatioForWidget(this);
|
||||
const float dpr = devicePixelRatioF();
|
||||
const u32 scaled_width = static_cast<u32>(std::max(static_cast<int>(std::ceil(static_cast<qreal>(width()) * dpr)), 1));
|
||||
const u32 scaled_height = static_cast<u32>(std::max(static_cast<int>(std::ceil(static_cast<qreal>(height()) * dpr)), 1));
|
||||
|
||||
|
||||
@@ -25,17 +25,17 @@ static constexpr int COVER_ART_HEIGHT = 512;
|
||||
static constexpr int COVER_ART_SPACING = 32;
|
||||
static constexpr int MIN_COVER_CACHE_SIZE = 256;
|
||||
|
||||
static int DPRScale(int size, float dpr)
|
||||
static int DPRScale(int size, qreal dpr)
|
||||
{
|
||||
return static_cast<int>(static_cast<float>(size) * dpr);
|
||||
return static_cast<int>(static_cast<qreal>(size) * dpr);
|
||||
}
|
||||
|
||||
static int DPRUnscale(int size, float dpr)
|
||||
static int DPRUnscale(int size, qreal dpr)
|
||||
{
|
||||
return static_cast<int>(static_cast<float>(size) / dpr);
|
||||
return static_cast<int>(static_cast<qreal>(size) / dpr);
|
||||
}
|
||||
|
||||
static void resizeAndPadPixmap(QPixmap* pm, int expected_width, int expected_height, float dpr)
|
||||
static void resizeAndPadPixmap(QPixmap* pm, int expected_width, int expected_height, qreal dpr)
|
||||
{
|
||||
const int dpr_expected_width = DPRScale(expected_width, dpr);
|
||||
const int dpr_expected_height = DPRScale(expected_height, dpr);
|
||||
@@ -71,9 +71,8 @@ static void resizeAndPadPixmap(QPixmap* pm, int expected_width, int expected_hei
|
||||
}
|
||||
|
||||
static QPixmap createPlaceholderImage(const QPixmap& placeholder_pixmap, int width, int height, float scale,
|
||||
const std::string& title)
|
||||
qreal dpr, const std::string& title)
|
||||
{
|
||||
const float dpr = qApp->devicePixelRatio();
|
||||
QPixmap pm(placeholder_pixmap.copy());
|
||||
pm.setDevicePixelRatio(dpr);
|
||||
if (pm.isNull())
|
||||
@@ -113,9 +112,10 @@ const char* GameListModel::getColumnName(Column col)
|
||||
return s_column_names[static_cast<int>(col)];
|
||||
}
|
||||
|
||||
GameListModel::GameListModel(float cover_scale, bool show_cover_titles, QObject* parent /* = nullptr */)
|
||||
GameListModel::GameListModel(float cover_scale, bool show_cover_titles, qreal dpr, QObject* parent /* = nullptr */)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_show_titles_for_covers(show_cover_titles)
|
||||
, m_dpr{dpr}
|
||||
{
|
||||
loadSettings();
|
||||
loadCommonImages();
|
||||
@@ -160,6 +160,13 @@ void GameListModel::updateCacheSize(int width, int height)
|
||||
m_cover_pixmap_cache.SetMaxCapacity(static_cast<int>(std::max(num_columns * num_rows, MIN_COVER_CACHE_SIZE)));
|
||||
}
|
||||
|
||||
void GameListModel::setDevicePixelRatio(qreal dpr)
|
||||
{
|
||||
m_dpr = dpr;
|
||||
loadCommonImages();
|
||||
refreshCovers();
|
||||
}
|
||||
|
||||
void GameListModel::loadOrGenerateCover(const GameList::Entry* ge)
|
||||
{
|
||||
// Why this counter: Every time we change the cover scale, we increment the counter variable. This way if the scale is changed
|
||||
@@ -173,12 +180,11 @@ void GameListModel::loadOrGenerateCover(const GameList::Entry* ge)
|
||||
const std::string cover_path(GameList::GetCoverImagePathForEntry(&entry));
|
||||
if (!cover_path.empty())
|
||||
{
|
||||
const float dpr = qApp->devicePixelRatio();
|
||||
image = QPixmap(QString::fromStdString(cover_path));
|
||||
if (!image.isNull())
|
||||
{
|
||||
image.setDevicePixelRatio(dpr);
|
||||
resizeAndPadPixmap(&image, getCoverArtWidth(), getCoverArtHeight(), dpr);
|
||||
image.setDevicePixelRatio(m_dpr);
|
||||
resizeAndPadPixmap(&image, getCoverArtWidth(), getCoverArtHeight(), m_dpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,7 +192,7 @@ void GameListModel::loadOrGenerateCover(const GameList::Entry* ge)
|
||||
const std::string& title = entry.GetTitle(m_prefer_english_titles);
|
||||
|
||||
if (image.isNull())
|
||||
image = createPlaceholderImage(m_placeholder_pixmap, getCoverArtWidth(), getCoverArtHeight(), m_cover_scale, title);
|
||||
image = createPlaceholderImage(m_placeholder_pixmap, getCoverArtWidth(), getCoverArtHeight(), m_cover_scale, m_dpr, title);
|
||||
|
||||
if (m_cover_scale_counter.load(std::memory_order_acquire) != counter)
|
||||
image = {};
|
||||
@@ -575,10 +581,10 @@ QIcon GameListModel::getIconForRegion(GameList::Region region)
|
||||
void GameListModel::loadThemeSpecificImages()
|
||||
{
|
||||
for (u32 type = 0; type < static_cast<u32>(GameList::EntryType::Count); type++)
|
||||
m_type_pixmaps[type] = getIconForType(static_cast<GameList::EntryType>(type)).pixmap(QSize(24, 24));
|
||||
m_type_pixmaps[type] = getIconForType(static_cast<GameList::EntryType>(type)).pixmap(QSize(24, 24), m_dpr);
|
||||
|
||||
for (u32 i = 0; i < static_cast<u32>(GameList::Region::Count); i++)
|
||||
m_region_pixmaps[i] = getIconForRegion(static_cast<GameList::Region>(i)).pixmap(QSize(36, 26));
|
||||
m_region_pixmaps[i] = getIconForRegion(static_cast<GameList::Region>(i)).pixmap(QSize(36, 26), m_dpr);
|
||||
}
|
||||
|
||||
void GameListModel::loadCommonImages()
|
||||
@@ -587,7 +593,7 @@ void GameListModel::loadCommonImages()
|
||||
|
||||
const QString base_path(QtHost::GetResourcesBasePath());
|
||||
for (u32 i = 1; i < GameList::CompatibilityRatingCount; i++)
|
||||
m_compatibility_pixmaps[i].load(QStringLiteral("%1/icons/star-%2.svg").arg(base_path).arg(i - 1));
|
||||
m_compatibility_pixmaps[i] = QIcon((QStringLiteral("%1/icons/star-%2.svg").arg(base_path).arg(i - 1))).pixmap(QSize(88, 16), m_dpr);
|
||||
|
||||
m_placeholder_pixmap.load(QStringLiteral("%1/cover-placeholder.png").arg(base_path));
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
static QIcon getIconForType(GameList::EntryType type);
|
||||
static QIcon getIconForRegion(GameList::Region region);
|
||||
|
||||
GameListModel(float cover_scale, bool show_cover_titles, QObject* parent = nullptr);
|
||||
GameListModel(float cover_scale, bool show_cover_titles, qreal dpr, QObject* parent = nullptr);
|
||||
~GameListModel();
|
||||
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
@@ -71,6 +71,8 @@ public:
|
||||
void refreshCovers();
|
||||
void updateCacheSize(int width, int height);
|
||||
|
||||
void setDevicePixelRatio(qreal dpr);
|
||||
|
||||
Q_SIGNALS:
|
||||
void coverScaleChanged();
|
||||
|
||||
@@ -94,6 +96,7 @@ private:
|
||||
std::array<QPixmap, static_cast<u32>(GameList::Region::Count)> m_region_pixmaps;
|
||||
QPixmap m_placeholder_pixmap;
|
||||
QPixmap m_loading_pixmap;
|
||||
qreal m_dpr;
|
||||
|
||||
std::array<QPixmap, static_cast<int>(GameList::CompatibilityRatingCount)> m_compatibility_pixmaps;
|
||||
mutable LRUCache<std::string, QPixmap> m_cover_pixmap_cache;
|
||||
|
||||
@@ -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);
|
||||
@@ -181,7 +180,7 @@ void GameListWidget::initialize()
|
||||
{
|
||||
const float cover_scale = Host::GetBaseFloatSettingValue("UI", "GameListCoverArtScale", 0.45f);
|
||||
const bool show_cover_titles = Host::GetBaseBoolSettingValue("UI", "GameListShowCoverTitles", true);
|
||||
m_model = new GameListModel(cover_scale, show_cover_titles, this);
|
||||
m_model = new GameListModel(cover_scale, show_cover_titles, devicePixelRatioF(), this);
|
||||
m_model->updateCacheSize(width(), height());
|
||||
|
||||
m_sort_model = new GameListSortModel(m_model);
|
||||
@@ -559,6 +558,18 @@ void GameListWidget::resizeEvent(QResizeEvent* event)
|
||||
m_model->updateCacheSize(width(), height());
|
||||
}
|
||||
|
||||
bool GameListWidget::event(QEvent* event)
|
||||
{
|
||||
if (event->type() == QEvent::DevicePixelRatioChange)
|
||||
{
|
||||
m_model->setDevicePixelRatio(devicePixelRatioF());
|
||||
QWidget::event(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
void GameListWidget::resizeTableViewColumnsToFit()
|
||||
{
|
||||
QtUtils::ResizeColumnsForTableView(m_table_view, {
|
||||
|
||||
@@ -93,6 +93,7 @@ public Q_SLOTS:
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
private:
|
||||
void loadTableViewColumnVisibilitySettings();
|
||||
|
||||
@@ -254,15 +254,6 @@ namespace QtUtils
|
||||
widget->resize(width, height);
|
||||
}
|
||||
|
||||
qreal GetDevicePixelRatioForWidget(const QWidget* widget)
|
||||
{
|
||||
const QScreen* screen_for_ratio = widget->screen();
|
||||
if (!screen_for_ratio)
|
||||
screen_for_ratio = QGuiApplication::primaryScreen();
|
||||
|
||||
return screen_for_ratio ? screen_for_ratio->devicePixelRatio() : static_cast<qreal>(1);
|
||||
}
|
||||
|
||||
std::optional<WindowInfo> GetWindowInfoForWidget(QWidget* widget)
|
||||
{
|
||||
WindowInfo wi;
|
||||
@@ -303,7 +294,7 @@ namespace QtUtils
|
||||
}
|
||||
#endif
|
||||
|
||||
const qreal dpr = GetDevicePixelRatioForWidget(widget);
|
||||
const qreal dpr = widget->devicePixelRatioF();
|
||||
wi.surface_width = static_cast<u32>(static_cast<qreal>(widget->width()) * dpr);
|
||||
wi.surface_height = static_cast<u32>(static_cast<qreal>(widget->height()) * dpr);
|
||||
wi.surface_scale = static_cast<float>(dpr);
|
||||
@@ -374,4 +365,37 @@ namespace QtUtils
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class IconVariableDpiFilter : QObject
|
||||
{
|
||||
public:
|
||||
explicit IconVariableDpiFilter(QLabel* lbl, const QIcon& icon, const QSize& size, QObject* parent = nullptr)
|
||||
: QObject(parent)
|
||||
, m_lbl{lbl}
|
||||
, m_icn{icon}
|
||||
, m_size{size}
|
||||
{
|
||||
lbl->installEventFilter(this);
|
||||
m_lbl->setPixmap(m_icn.pixmap(m_size, m_lbl->devicePixelRatioF()));
|
||||
}
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* object, QEvent* event) override
|
||||
{
|
||||
if (object == m_lbl && event->type() == QEvent::DevicePixelRatioChange)
|
||||
m_lbl->setPixmap(m_icn.pixmap(m_size, m_lbl->devicePixelRatioF()));
|
||||
// Don't block the event
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
QLabel* m_lbl;
|
||||
QIcon m_icn;
|
||||
QSize m_size;
|
||||
};
|
||||
|
||||
void SetScalableIcon(QLabel* lbl, const QIcon& icon, const QSize& size)
|
||||
{
|
||||
new IconVariableDpiFilter(lbl, icon, size, lbl);
|
||||
}
|
||||
} // namespace QtUtils
|
||||
|
||||
@@ -20,6 +20,7 @@ class QAction;
|
||||
class QComboBox;
|
||||
class QFileInfo;
|
||||
class QFrame;
|
||||
class QIcon;
|
||||
class QLabel;
|
||||
class QKeyEvent;
|
||||
class QSlider;
|
||||
@@ -82,9 +83,6 @@ namespace QtUtils
|
||||
/// Adjusts the fixed size for a window if it's not resizeable.
|
||||
void ResizePotentiallyFixedSizeWindow(QWidget* widget, int width, int height);
|
||||
|
||||
/// Returns the pixel ratio/scaling factor for a widget.
|
||||
qreal GetDevicePixelRatioForWidget(const QWidget* widget);
|
||||
|
||||
/// Returns the common window info structure for a Qt widget.
|
||||
std::optional<WindowInfo> GetWindowInfoForWidget(QWidget* widget);
|
||||
|
||||
@@ -102,4 +100,8 @@ namespace QtUtils
|
||||
bool IsLightTheme(const QPalette& palette);
|
||||
|
||||
bool IsCompositorManagerRunning();
|
||||
|
||||
/// Sets the scalable icon to a given label (svg icons, or icons with multiple size pixmaps)
|
||||
/// The icon will then be reloaded on DPR changes using an event filter
|
||||
void SetScalableIcon(QLabel* lbl, const QIcon& icon, const QSize& size);
|
||||
} // namespace QtUtils
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "AchievementLoginDialog.h"
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "pcsx2/Achievements.h"
|
||||
|
||||
@@ -15,7 +16,7 @@ AchievementLoginDialog::AchievementLoginDialog(QWidget* parent, Achievements::Lo
|
||||
, m_reason(reason)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_ui.loginIcon->setPixmap(QIcon::fromTheme("login-box-line").pixmap(32));
|
||||
QtUtils::SetScalableIcon(m_ui.loginIcon, QIcon::fromTheme(QStringLiteral("login-box-line")), QSize(32, 32));
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
// Adjust text if needed based on reason.
|
||||
@@ -116,7 +117,6 @@ void AchievementLoginDialog::processLoginResult(bool result, const QString& mess
|
||||
g_emu_thread->resetVM();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
done(0);
|
||||
|
||||
@@ -342,7 +342,7 @@ void AudioSettingsWidget::onExpansionSettingsClicked()
|
||||
QDialog dlg(QtUtils::GetRootWidget(this));
|
||||
Ui::AudioExpansionSettingsDialog dlgui;
|
||||
dlgui.setupUi(&dlg);
|
||||
dlgui.icon->setPixmap(QIcon::fromTheme(QStringLiteral("volume-up-line")).pixmap(32, 32));
|
||||
QtUtils::SetScalableIcon(dlgui.icon, QIcon::fromTheme(QStringLiteral("volume-up-line")), QSize(32, 32));
|
||||
|
||||
SettingsInterface* sif = m_dialog->getSettingsInterface();
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, dlgui.blockSize, "SPU2/Output", "ExpandBlockSize",
|
||||
@@ -431,7 +431,7 @@ void AudioSettingsWidget::onStretchSettingsClicked()
|
||||
QDialog dlg(QtUtils::GetRootWidget(this));
|
||||
Ui::AudioStretchSettingsDialog dlgui;
|
||||
dlgui.setupUi(&dlg);
|
||||
dlgui.icon->setPixmap(QIcon::fromTheme(QStringLiteral("volume-up-line")).pixmap(32, 32));
|
||||
QtUtils::SetScalableIcon(dlgui.icon, QIcon::fromTheme(QStringLiteral("volume-up-line")), QSize(32, 32));
|
||||
|
||||
SettingsInterface* sif = m_dialog->getSettingsInterface();
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, dlgui.sequenceLength, "SPU2/Output", "StretchSequenceLengthMS",
|
||||
|
||||
@@ -170,7 +170,7 @@ ControllerMouseSettingsDialog::ControllerMouseSettingsDialog(QWidget* parent, Co
|
||||
|
||||
SettingsInterface* sif = dialog->getProfileSettingsInterface();
|
||||
|
||||
m_ui.icon->setPixmap(QIcon::fromTheme(QStringLiteral("mouse-line")).pixmap(32, 32));
|
||||
QtUtils::SetScalableIcon(m_ui.icon, QIcon::fromTheme(QStringLiteral("mouse-line")), QSize(32, 32));
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXSpeedSlider, "Pad", "PointerXSpeed", 40.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYSpeedSlider, "Pad", "PointerYSpeed", 40.0f);
|
||||
@@ -202,11 +202,10 @@ ControllerMappingSettingsDialog::ControllerMappingSettingsDialog(ControllerSetti
|
||||
|
||||
SettingsInterface* sif = parent->getProfileSettingsInterface();
|
||||
|
||||
m_ui.icon->setPixmap(QIcon::fromTheme(QStringLiteral("settings-3-line")).pixmap(32, 32));
|
||||
QtUtils::SetScalableIcon(m_ui.icon, QIcon::fromTheme(QStringLiteral("settings-3-line")), QSize(32, 32));
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.ignoreInversion, "InputSources", "IgnoreInversion", false);
|
||||
|
||||
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
|
||||
}
|
||||
|
||||
ControllerMappingSettingsDialog::~ControllerMappingSettingsDialog() = default;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
#include "Settings/MemoryCardCreateDialog.h"
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "pcsx2/SIO/Memcard/MemoryCardFile.h"
|
||||
|
||||
@@ -16,7 +17,7 @@ MemoryCardCreateDialog::MemoryCardCreateDialog(QWidget* parent /* = nullptr */)
|
||||
: QDialog(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_ui.icon->setPixmap(QIcon::fromTheme("memcard-line").pixmap(m_ui.icon->width()));
|
||||
QtUtils::SetScalableIcon(m_ui.icon, QIcon::fromTheme(QStringLiteral("memcard-line")), QSize(m_ui.icon->width(), m_ui.icon->width()));
|
||||
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -95,27 +95,27 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="25"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="26"/>
|
||||
<source><strong>Your RetroAchievements login token is no longer valid.</strong> You must re-enter your credentials for achievements to be tracked. Your password will not be saved in PCSX2, an access token will be generated and used instead.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="30"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="31"/>
|
||||
<source>&Login</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="43"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="44"/>
|
||||
<source>Logging in...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="73"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="74"/>
|
||||
<source>Login Error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="74"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="75"/>
|
||||
<source>Login failed.
|
||||
Error: %1
|
||||
|
||||
@@ -123,29 +123,29 @@ Please check your username and password, and try again.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="75"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="76"/>
|
||||
<source>Login failed.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="83"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="84"/>
|
||||
<source>Enable Achievements</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="84"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="85"/>
|
||||
<source>Achievement tracking is not currently enabled. Your login will have no effect until after tracking is enabled.
|
||||
|
||||
Do you want to enable tracking now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="95"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="96"/>
|
||||
<source>Enable Hardcore Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="96"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="97"/>
|
||||
<source>Hardcore mode is not currently enabled. Enabling hardcore mode allows you to set times, scores, and participate in game-specific leaderboards.
|
||||
|
||||
However, hardcore mode also prevents the usage of save states, cheats and slowdown functionality.
|
||||
@@ -154,12 +154,12 @@ Do you want to enable hardcore mode?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="112"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="113"/>
|
||||
<source>Reset System</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="113"/>
|
||||
<location filename="../Settings/AchievementLoginDialog.cpp" line="114"/>
|
||||
<source>Hardcore mode will not be enabled until the system is reset. Do you want to reset the system now?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -3539,7 +3539,7 @@ You cannot undo this action.</source>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../CoverDownloadDialog.ui" line="95"/>
|
||||
<location filename="../CoverDownloadDialog.cpp" line="86"/>
|
||||
<location filename="../CoverDownloadDialog.cpp" line="87"/>
|
||||
<source>Start</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -3549,12 +3549,12 @@ You cannot undo this action.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../CoverDownloadDialog.cpp" line="64"/>
|
||||
<location filename="../CoverDownloadDialog.cpp" line="65"/>
|
||||
<source>Download complete.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../CoverDownloadDialog.cpp" line="86"/>
|
||||
<location filename="../CoverDownloadDialog.cpp" line="87"/>
|
||||
<source>Stop</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -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>
|
||||
@@ -11599,7 +11599,7 @@ graphical quality, but this will increase system requirements.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../GameList/GameListModel.cpp" line="268"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="274"/>
|
||||
<location filename="../../pcsx2/GameList.cpp" line="1200"/>
|
||||
<source>%n hours</source>
|
||||
<translation type="unfinished">
|
||||
@@ -11608,7 +11608,7 @@ graphical quality, but this will increase system requirements.</source>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../GameList/GameListModel.cpp" line="270"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="276"/>
|
||||
<location filename="../../pcsx2/GameList.cpp" line="1202"/>
|
||||
<source>%n minutes</source>
|
||||
<translation type="unfinished">
|
||||
@@ -11625,52 +11625,52 @@ graphical quality, but this will increase system requirements.</source>
|
||||
<context>
|
||||
<name>GameListModel</name>
|
||||
<message>
|
||||
<location filename="../GameList/GameListModel.cpp" line="597"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="603"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameList/GameListModel.cpp" line="598"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="604"/>
|
||||
<source>Code</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameList/GameListModel.cpp" line="599"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="605"/>
|
||||
<source>Title</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameList/GameListModel.cpp" line="600"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="606"/>
|
||||
<source>File Title</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameList/GameListModel.cpp" line="601"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="607"/>
|
||||
<source>CRC</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameList/GameListModel.cpp" line="602"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="608"/>
|
||||
<source>Time Played</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameList/GameListModel.cpp" line="603"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="609"/>
|
||||
<source>Last Played</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameList/GameListModel.cpp" line="604"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="610"/>
|
||||
<source>Size</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameList/GameListModel.cpp" line="605"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="611"/>
|
||||
<source>Region</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../GameList/GameListModel.cpp" line="606"/>
|
||||
<location filename="../GameList/GameListModel.cpp" line="612"/>
|
||||
<source>Compatibility</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -17587,10 +17587,10 @@ Savestates should not be used in place of in-game saves.</source>
|
||||
<name>MemoryCardCreateDialog</name>
|
||||
<message>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.ui" line="14"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="106"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="113"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="120"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="133"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="107"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="114"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="121"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="134"/>
|
||||
<source>Create Memory Card</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -17671,22 +17671,22 @@ Savestates should not be used in place of in-game saves.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="107"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="108"/>
|
||||
<source>Failed to create the Memory Card, because the name '%1' contains one or more invalid characters.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="114"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="115"/>
|
||||
<source>Failed to create the Memory Card, because another card with the name '%1' already exists.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="121"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="122"/>
|
||||
<source>Failed to create the Memory Card, the log may contain more information.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="133"/>
|
||||
<location filename="../Settings/MemoryCardCreateDialog.cpp" line="134"/>
|
||||
<source>Memory Card '%1' created.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@@ -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})
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -703,11 +703,17 @@ bool GSDevice12::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
if (!AcquireWindow(true) || (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain()))
|
||||
return false;
|
||||
|
||||
if (!CreateNullTexture())
|
||||
{
|
||||
Host::ReportErrorAsync("GS", "Failed to create dummy texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
std::optional<std::string> shader = ReadShaderSource("shaders/dx11/tfx.fx");
|
||||
if (!shader.has_value())
|
||||
{
|
||||
Host::ReportErrorAsync("GS", "Failed to read shaders/dx11/tfx.fxf.");
|
||||
Host::ReportErrorAsync("GS", "Failed to read shaders/dx11/tfx.fx.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -717,12 +723,6 @@ bool GSDevice12::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
if (!m_shader_cache.Open(m_feature_level, GSConfig.UseDebugDevice))
|
||||
Console.Warning("D3D12: Shader cache failed to open.");
|
||||
|
||||
if (!CreateNullTexture())
|
||||
{
|
||||
Host::ReportErrorAsync("GS", "Failed to create dummy texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateRootSignatures())
|
||||
{
|
||||
Host::ReportErrorAsync("GS", "Failed to create pipeline layouts");
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -557,26 +557,6 @@ bool GSHwHack::GSC_TalesofSymphonia(GSRendererHW& r, int& skip)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_Simple2000Vol114(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
if (!s_nativeres && RTME == 0 && (RFBP == 0x1500) && (RTBP0 == 0x2c97 || RTBP0 == 0x2ace || RTBP0 == 0x03d0 || RTBP0 == 0x2448) && (RFBMSK == 0x0000))
|
||||
{
|
||||
// Don't enable hack on native res if crc is below aggressive.
|
||||
// Upscaling issues, removes glow/blur effect which fixes ghosting.
|
||||
skip = 1;
|
||||
}
|
||||
if (RTME && (RFBP == 0x0e00) && (RTBP0 == 0x1000) && (RFBMSK == 0x0000))
|
||||
{
|
||||
// Depth shadows.
|
||||
skip = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_UrbanReign(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
@@ -1419,7 +1399,6 @@ const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_function
|
||||
CRC_F(GSC_SacredBlaze),
|
||||
CRC_F(GSC_GuitarHero),
|
||||
CRC_F(GSC_SakuraWarsSoLongMyLove),
|
||||
CRC_F(GSC_Simple2000Vol114),
|
||||
CRC_F(GSC_SFEX3),
|
||||
CRC_F(GSC_DTGames),
|
||||
CRC_F(GSC_TalesOfLegendia),
|
||||
|
||||
@@ -21,7 +21,6 @@ public:
|
||||
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_Simple2000Vol114(GSRendererHW& r, int& skip);
|
||||
static bool GSC_UrbanReign(GSRendererHW& r, int& skip);
|
||||
static bool GSC_SteambotChronicles(GSRendererHW& r, int& skip);
|
||||
static bool GSC_BlueTongueGames(GSRendererHW& r, int& skip);
|
||||
|
||||
@@ -1617,8 +1617,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 +1646,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 +1665,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)))))
|
||||
{
|
||||
@@ -2007,7 +2006,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.
|
||||
@@ -4808,8 +4806,17 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
|
||||
if (!dst)
|
||||
dst = CreateTarget(new_TEX0, target_size, target_size, src->m_scale, src->m_type);
|
||||
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));
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dst)
|
||||
return false;
|
||||
|
||||
@@ -5658,7 +5665,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
|
||||
@@ -5728,7 +5735,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;
|
||||
}
|
||||
@@ -5899,7 +5910,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);
|
||||
@@ -6686,6 +6698,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
|
||||
@@ -6711,27 +6725,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);
|
||||
|
||||
@@ -2059,6 +2059,12 @@ bool GSDeviceVK::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateNullTexture())
|
||||
{
|
||||
Host::ReportErrorAsync("GS", "Failed to create dummy texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
std::optional<std::string> shader = ReadShaderSource("shaders/vulkan/tfx.glsl");
|
||||
if (!shader.has_value())
|
||||
@@ -2070,12 +2076,6 @@ bool GSDeviceVK::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
|
||||
m_tfx_source = std::move(*shader);
|
||||
}
|
||||
|
||||
if (!CreateNullTexture())
|
||||
{
|
||||
Host::ReportErrorAsync("GS", "Failed to create dummy texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreatePipelineLayouts())
|
||||
{
|
||||
Host::ReportErrorAsync("GS", "Failed to create pipeline layouts");
|
||||
@@ -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);
|
||||
@@ -5291,8 +5292,12 @@ void GSDeviceVK::SetPipeline(VkPipeline pipeline)
|
||||
|
||||
void GSDeviceVK::SetInitialState(VkCommandBuffer cmdbuf)
|
||||
{
|
||||
const VkDeviceSize buffer_offset = 0;
|
||||
vkCmdBindVertexBuffers(cmdbuf, 0, 1, m_vertex_stream_buffer.GetBufferPtr(), &buffer_offset);
|
||||
VkBuffer buffer = *m_vertex_stream_buffer.GetBufferPtr();
|
||||
if (buffer != VK_NULL_HANDLE)
|
||||
{
|
||||
constexpr VkDeviceSize buffer_offset = 0;
|
||||
vkCmdBindVertexBuffers(cmdbuf, 0, 1, &buffer, &buffer_offset);
|
||||
}
|
||||
}
|
||||
|
||||
__ri void GSDeviceVK::ApplyBaseState(u32 flags, VkCommandBuffer cmdbuf)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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