Merge remote-tracking branch 'upstream/master' into master_qt

This commit is contained in:
987123879113 2022-08-05 20:04:14 +09:00
commit 1d6c7b17fb
51 changed files with 1092 additions and 1030 deletions

View File

@ -15,13 +15,14 @@ for dir_name in os.listdir(scan_dir):
asset_name += "-linux-AppImage-64bit"
elif "windows" in dir_name.lower():
asset_name += "-windows-64bit"
if "avx" in dir_name.lower():
asset_name += "-AVX2"
else:
asset_name += "-SSE4"
else:
continue;
if "avx2" in dir_name.lower():
asset_name += "-AVX2"
elif "sse4" in dir_name.lower():
asset_name += "-SSE4"
if "wxwidgets" in dir_name.lower():
asset_name += "-wxWidgets"
else:

View File

@ -1198,6 +1198,7 @@ SCAJ-20159:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
halfPixelOffset: 1 # Fixes blurriness.
texturePreloading: 1 # Improves performance.
SCAJ-20160:
name: "Yoshitsuneki"
region: "NTSC-Unk"
@ -1328,8 +1329,8 @@ SCAJ-20183:
name: "Wild ARMs - The Vth Vanguard"
region: "NTSC-J"
gsHWFixes:
wildArmsHack: 1 # Fixes font artifacts and out-of-bound 2D textures.
roundSprite: 1 # Fixes font sizes.
cpuFramebufferConversion: 1 # Fixes sepia-tone flashback sequences.
SCAJ-20184:
name: "Seiken Densetsu 4"
region: "NTSC-Unk"
@ -1509,7 +1510,6 @@ SCAJ-30010:
region: "NTSC-E"
gsHWFixes:
alignSprite: 1 # Fixes water vertical lines.
halfPixelOffset: 2 # Fixes depth lines and vertical lines and green fog bloom effect.
roundSprite: 1 # Fixes vertical lines and minor ghosting.
wrapGSMem: 1 # Fixes FMV when in progressive mode.
autoFlush: 1 # Fixes sun going through walls.
@ -2599,6 +2599,9 @@ SCES-50000:
gsHWFixes:
cpuFramebufferConversion: 1
textureInsideRT: 1
halfPixelOffset: 2 # Fixes title screen and some intro post processing alignment.
roundSprite: 1 # Fixes ui and hud alignment.
texturePreloading: 0 # Disabling for major speedup.
SCES-50001:
name: "Tekken Tag Tournament"
region: "PAL-M5"
@ -3101,7 +3104,6 @@ SCES-51533:
region: "PAL-Unk"
gsHWFixes:
alignSprite: 1 # Fixes water vertical lines.
halfPixelOffset: 2 # Fixes depth lines and vertical lines and green fog bloom effect.
roundSprite: 1 # Fixes vertical lines and minor ghosting.
wrapGSMem: 1 # Fixes FMV when in progressive mode.
autoFlush: 1 # Fixes sun going through walls.
@ -3321,7 +3323,7 @@ SCES-52330:
SCES-52389:
name: "WRC 4"
region: "PAL-M8"
compat: 1
compat: 5
gameFixes:
- XGKickHack # Fixes SPS.
patches:
@ -3342,6 +3344,9 @@ SCES-52389:
patch=0,EE,005fffe4,double,279c000024840800
patch=0,EE,005fffec,double,24e7100024c60080
patch=0,EE,005ffff4,double,00c7e8200818000c
gsHWFixes:
autoFlush: 1 # Fixes car shadows.
roundSprite: 1 # Fixes misalgined text.
SCES-52405:
name: "DJ - Decks & FX - House Edition"
region: "PAL-M9"
@ -3507,7 +3512,7 @@ SCES-52830:
SCES-52883:
name: "EyeToy - Kinetic"
region: "PAL-M7"
compat: 2
compat: 5
SCES-52892:
name: "MotoGP 4"
region: "PAL-M5"
@ -3522,7 +3527,7 @@ SCES-52893:
SCES-52930:
name: "EyeToy - Monkey Mania"
region: "PAL-M5"
compat: 2
compat: 5
SCES-52948:
name: "Getaway, The - Black Monday"
region: "PAL-M4"
@ -3548,7 +3553,6 @@ SCES-53133:
compat: 5
gsHWFixes:
alignSprite: 1 # Fixes water vertical lines.
halfPixelOffset: 2 # Fixes depth lines and vertical lines and green fog bloom effect.
roundSprite: 1 # Fixes vertical lines and minor ghosting.
wrapGSMem: 1 # Fixes FMV when in progressive mode.
autoFlush: 1 # Fixes sun going through walls.
@ -3643,6 +3647,7 @@ SCES-53312:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
halfPixelOffset: 1 # Fixes blurriness.
texturePreloading: 1 # Improves performance.
SCES-53315:
name: "EyeToy - Play 3"
region: "PAL-M12"
@ -4802,6 +4807,7 @@ SCKA-20059:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
halfPixelOffset: 1 # Fixes blurriness.
texturePreloading: 1 # Improves performance.
SCKA-20060:
name: "Ratchet - Deadlocked"
region: "NTSC-K"
@ -5016,7 +5022,6 @@ SCKA-30002:
compat: 5
gsHWFixes:
alignSprite: 1 # Fixes water vertical lines.
halfPixelOffset: 2 # Fixes depth lines and vertical lines and green fog bloom effect.
roundSprite: 1 # Fixes vertical lines and minor ghosting.
wrapGSMem: 1 # Fixes FMV when in progressive mode.
autoFlush: 1 # Fixes sun going through walls.
@ -5768,7 +5773,7 @@ SCPS-15118:
name: "Wild ARMs - The Vth Vanguard"
region: "NTSC-J"
gsHWFixes:
wildArmsHack: 1 # Fixes font artifacts and out-of-bound 2D textures.
cpuFramebufferConversion: 1 # Fixes sepia-tone flashback sequences.
SCPS-15119:
name: "Bleach - Blade Battlers 2nd"
region: "NTSC-J"
@ -6366,6 +6371,8 @@ SCPS-55028:
SCPS-55029:
name: "dot hack - Infection Part 1"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 1 # Sharpens world in far distances.
memcardFilters:
- "SCPS-55029"
- "SCPS-55042"
@ -7288,7 +7295,7 @@ SCUS-97318:
SCUS-97319:
name: "EyeToy - Play"
region: "NTSC-U"
compat: 2
compat: 5
SCUS-97321:
name: "Kiosk Demo Disc 2.10"
region: "NTSC-U"
@ -7392,7 +7399,7 @@ SCUS-97342:
SCUS-97345:
name: "EyeToy - Groove"
region: "NTSC-U"
compat: 2
compat: 5
SCUS-97347:
name: "MLB 2006"
region: "NTSC-U"
@ -7527,7 +7534,6 @@ SCUS-97399:
compat: 5
gsHWFixes:
alignSprite: 1 # Fixes water vertical lines.
halfPixelOffset: 2 # Fixes depth lines and vertical lines and green fog bloom effect.
roundSprite: 1 # Fixes vertical lines and minor ghosting.
wrapGSMem: 1 # Fixes FMV when in progressive mode.
autoFlush: 1 # Fixes sun going through walls.
@ -7608,7 +7614,7 @@ SCUS-97413:
SCUS-97414:
name: "EyeToy - AntiGrav"
region: "NTSC-U"
compat: 2
compat: 5
SCUS-97415:
name: "Sly 2 - Band of Thieves [E3 Demo]"
region: "NTSC-U"
@ -7809,7 +7815,6 @@ SCUS-97467:
region: "NTSC-U"
gsHWFixes:
alignSprite: 1 # Fixes water vertical lines.
halfPixelOffset: 2 # Fixes depth lines and vertical lines and green fog bloom effect.
roundSprite: 1 # Fixes vertical lines and minor ghosting.
wrapGSMem: 1 # Fixes FMV when in progressive mode.
autoFlush: 1 # Fixes sun going through walls.
@ -8762,6 +8767,8 @@ SLED-53083:
SLED-53109:
name: "Juiced [Demo]"
region: "PAL-M5"
speedHacks:
InstantVU1SpeedHack: 0 # Significantly improves game speed.
SLED-53537:
name: "187 - Ride or Die [Demo]"
region: "PAL-E"
@ -11831,9 +11838,12 @@ SLES-51392:
patches:
C24C7FE3:
content: |-
author=kozarovv
// Skip PSS movies, workaround for EE Cache requirement.
patch=1,EE,001233e0,word,100000d7
author=Goatman13
// Fix issues caused by PSS video playback.
// Extend stack to avoid sending bad data to VIF1.
// Required due to lack of data cache emulation.
patch=1,EE,00122E60,word,27BDFD00
patch=1,EE,001231C4,word,27BD0300
SLES-51393:
name: "Syberia"
region: "PAL-M5"
@ -11978,7 +11988,9 @@ SLES-51473:
gameFixes:
- EETimingHack # Fixes smoke effects.
gsHWFixes:
halfPixelOffset: 1 # Fixes fog misalignment.
halfPixelOffset: 2 # Fixes fog misalignment and depth line.
autoFlush: 1 # Fixes sun going through objects.
preloadFrameData: 1 # Fixes missing sun and sky.
SLES-51474:
name: "Blood Rayne"
region: "PAL-M4"
@ -12051,6 +12063,8 @@ SLES-51523:
name: "Conflict - Desert Storm II"
region: "PAL-M5"
compat: 5
gameFixes:
- SoftwareRendererFMVHack # Fixes seizure inducing FMVs.
SLES-51525:
name: "Fallout - Brotherhood of Steel"
region: "PAL-M3"
@ -12450,6 +12464,8 @@ SLES-51758:
SLES-51759:
name: "Maximo vs. Army of Zin"
region: "PAL-M5"
gsHWFixes:
halfPixelOffset: 2 # Fixes outlines around environmental objects.
SLES-51761:
name: "Italian Job, The - L.A. Heist"
region: "PAL-M5"
@ -12599,7 +12615,7 @@ SLES-51834:
name: "Premier Manager 2003-2004"
region: "PAL-F"
SLES-51838:
name: "Asterix & Obelix XXL2"
name: "Asterix & Obelix XXL"
region: "PAL-M5"
SLES-51839:
name: "DragonBall Z - Budokai 2"
@ -13228,19 +13244,29 @@ SLES-52125:
SLES-52132:
name: "Hitman - Contracts"
region: "PAL-E"
gsHWFixes:
texturePreloading: 1 # Performs much better with partial preload.
SLES-52133:
name: "Hitman - Contracts"
region: "PAL-F"
gsHWFixes:
texturePreloading: 1 # Performs much better with partial preload.
SLES-52134:
name: "Hitman - Contracts"
region: "PAL-I"
compat: 4
gsHWFixes:
texturePreloading: 1 # Performs much better with partial preload.
SLES-52135:
name: "Hitman - Contracts"
region: "PAL-G"
gsHWFixes:
texturePreloading: 1 # Performs much better with partial preload.
SLES-52136:
name: "Hitman - Contracts"
region: "PAL-S"
gsHWFixes:
texturePreloading: 1 # Performs much better with partial preload.
SLES-52143:
name: "Carmen Sandiego - The Secret of the Stolen Drums"
region: "PAL-M4"
@ -13355,6 +13381,8 @@ SLES-52230:
SLES-52237:
name: "dot hack - Infection Part 1"
region: "PAL-M5"
gsHWFixes:
halfPixelOffset: 1 # Sharpens world in far distances.
memcardFilters:
- "SLES-52237"
- "SLES-52467"
@ -14747,7 +14775,7 @@ SLES-52832:
SLES-52834:
name: "Sega Superstars Eyetoy Bundle"
region: "PAL-M4"
compat: 1
compat: 5
SLES-52835:
name: "Mummy, The"
region: "PAL-M6"
@ -14975,6 +15003,8 @@ SLES-52942:
// for VU1 to finish, which reduces the advantage of MTVU to basically zero.
patch=1,EE,D0525A1C,extended,00000800
patch=1,EE,20525A1C,extended,00000000
gsHWFixes:
texturePreloading: 1 # Improves performance and prevents it disabling itself regardless.
SLES-52943:
name: "ESPN NFL 2K5"
region: "PAL-E"
@ -15290,6 +15320,7 @@ SLES-53038:
eeRoundMode: 0
gsHWFixes:
halfPixelOffset: 2 # Reduces ghosting but still an issue compared to native.
roundSprite: 2 # Clears up much of the blurring that HPO Special does not.
SLES-53039:
name: "Champions - Return to Arms" # aka "Champions of Norrath 2"
region: "PAL-M4"
@ -15309,6 +15340,8 @@ SLES-53044:
name: "Juiced"
region: "PAL-M4"
compat: 5
speedHacks:
InstantVU1SpeedHack: 0 # Significantly improves game speed.
SLES-53045:
name: "Street Racing Syndicate"
region: "PAL-M5"
@ -15538,6 +15571,8 @@ SLES-53150:
SLES-53151:
name: "Juiced"
region: "PAL-I"
speedHacks:
InstantVU1SpeedHack: 0 # Significantly improves game speed.
SLES-53152:
name: "Mashed Fully Loaded"
region: "PAL-M5"
@ -16099,6 +16134,8 @@ SLES-53444:
region: "PAL-M5"
gameFixes:
- VUSyncHack # Partly fixes SPS still needs EE+3.
gsHWFixes:
halfPixelOffset: 1 # Fixes misaligned bloom.
SLES-53446:
name: "Arcade USA"
region: "PAL-E"
@ -16414,6 +16451,8 @@ SLES-53541:
SLES-53542:
name: "Shadow the Hedgehog"
region: "PAL-M5"
gsHWFixes:
halfPixelOffset: 2 # Fixes misaligned lighting.
SLES-53544:
name: "Pro Evolution Soccer 5"
region: "PAL-M4"
@ -16873,6 +16912,8 @@ SLES-53717:
// for VU1 to finish, which reduces the advantage of MTVU to basically zero.
patch=1,EE,D0529074,extended,00000800
patch=1,EE,20529074,extended,00000000
gsHWFixes:
texturePreloading: 1 # Improves performance and prevents it disabling itself regardless.
SLES-53718:
name: "Sims 2, The"
region: "PAL-M10"
@ -17963,6 +18004,7 @@ SLES-54186:
eeRoundMode: 0
gsHWFixes:
halfPixelOffset: 2 # Reduces ghosting but still an issue compared to native.
roundSprite: 2 # Clears up much of the blurring that HPO Special does not.
SLES-54187:
name: "Real World Golf 2007"
region: "PAL-M3"
@ -19860,7 +19902,7 @@ SLES-54972:
name: "Wild Arms 5"
region: "PAL-M3"
gsHWFixes:
wildArmsHack: 1 # Fixes font artifacts and out-of-bound 2D textures.
cpuFramebufferConversion: 1 # Fixes sepia-tone flashback sequences.
SLES-54973:
name: "Le Avventure di Lupin III - Lupin la Morte, Zenigata l'Amore"
region: "PAL-I"
@ -19958,18 +20000,28 @@ SLES-55001:
SLES-55002:
name: "Need for Speed - ProStreet"
region: "PAL-E"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
SLES-55003:
name: "Need for Speed - ProStreet"
region: "PAL-F-G"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
SLES-55004:
name: "Need for Speed - ProStreet"
region: "PAL-I-S"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
SLES-55005:
name: "Need for Speed - ProStreet"
region: "PAL-M8"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
SLES-55006:
name: "Need for Speed - ProStreet"
region: "PAL-R"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
SLES-55007:
name: "Boogie"
region: "PAL-M7"
@ -21392,13 +21444,13 @@ SLES-82030:
name: "Shadow Hearts - Covenant [Disc1of2]"
region: "PAL-M3"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
halfPixelOffset: 2 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
disablePartialInvalidation: 1 # Fixes shadows when upscaling.
SLES-82031:
name: "Shadow Hearts - Covenant [Disc2of2]"
region: "PAL-M3"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
halfPixelOffset: 2 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
disablePartialInvalidation: 1 # Fixes shadows when upscaling.
memcardFilters:
- "SLES-82030"
@ -21802,6 +21854,11 @@ SLKA-25071:
name: "Tantei Jinguji Saburo 8 Innocent Black"
region: "NTSC-K"
compat: 5
SLKA-25072:
name: "Maximo vs. Army of Zin"
region: "NTSC-K"
gsHWFixes:
halfPixelOffset: 2 # Fixes outlines around environmental objects.
SLKA-25073:
name: "Tomb Raider - The Angel of Darkness"
region: "NTSC-K"
@ -21820,6 +21877,8 @@ SLKA-25078:
SLKA-25080:
name: "dot hack - Infection"
region: "NTSC-K"
gsHWFixes:
halfPixelOffset: 1 # Sharpens world in far distances.
SLKA-25081:
name: "SD Gundam G Generation Neo"
region: "NTSC-K"
@ -22172,6 +22231,8 @@ SLKA-25217:
SLKA-25218:
name: "Hitman - Contracts"
region: "NTSC-K"
gsHWFixes:
texturePreloading: 1 # Performs much better with partial preload.
SLKA-25219:
name: "Monster Hunter G"
region: "NTSC-K"
@ -22290,6 +22351,7 @@ SLKA-25265:
eeRoundMode: 0
gsHWFixes:
halfPixelOffset: 2 # Reduces ghosting but still an issue compared to native.
roundSprite: 2 # Clears up much of the blurring that HPO Special does not.
SLKA-25266:
name: "Sangokushi IX [PlayStation 2 - Big Hit Series]"
region: "NTSC-K"
@ -22457,6 +22519,8 @@ SLKA-25334:
SLKA-25335:
name: "Shadow the Hedgehog"
region: "NTSC-K"
gsHWFixes:
halfPixelOffset: 2 # Fixes misaligned lighting.
SLKA-25341:
name: "Driver - Parallel Lines"
region: "NTSC-K"
@ -23093,6 +23157,9 @@ SLPM-60109:
gsHWFixes:
cpuFramebufferConversion: 1
textureInsideRT: 1
halfPixelOffset: 2 # Fixes title screen and some intro post processing alignment.
roundSprite: 1 # Fixes ui and hud alignment.
texturePreloading: 0 # Disabling for major speedup.
SLPM-60123:
name: "Gekikuukan Pro Baseball - The End of the Century 1999 [Trial]"
region: "NTSC-J"
@ -23162,6 +23229,7 @@ SLPM-60251:
eeRoundMode: 0
gsHWFixes:
halfPixelOffset: 2 # Reduces ghosting but still an issue compared to native.
roundSprite: 2 # Clears up much of the blurring that HPO Special does not.
SLPM-60254:
name: "Zettai Zetsumei Toshi 2 - Itetsuita Kioku-tachi [Trial A]"
region: "NTSC-J"
@ -23304,6 +23372,7 @@ SLPM-61133:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
halfPixelOffset: 1 # Fixes blurriness.
texturePreloading: 1 # Improves performance.
SLPM-61135:
name: "Naruto - Narutimett Hero 3 [Trial Version]"
region: "NTSC-J"
@ -26238,9 +26307,12 @@ SLPM-65231:
patches:
F96A2390:
content: |-
author=kozarovv
// Skip PSS movies, workaround for EE Cache requirement.
patch=1,EE,00122d00,word,100000d9
author=Goatman13
// Fix issues caused by PSS video playback.
// Extend stack to avoid sending bad data to VIF1.
// Required due to lack of data cache emulation.
patch=1,EE,00122780,word,27BDFD00
patch=1,EE,00122AE8,word,27BD0300
SLPM-65232:
name: "Devil May Cry 2 [Dante Disc]"
region: "NTSC-J"
@ -26693,6 +26765,8 @@ SLPM-65367:
name: "Makai Eiyuuki Maximo - Machine Monster no Yabou"
region: "NTSC-J"
compat: 5
gsHWFixes:
halfPixelOffset: 2 # Fixes outlines around environmental objects.
SLPM-65368:
name: "D.N. Angel - TV Animation Series"
region: "NTSC-J"
@ -28345,6 +28419,7 @@ SLPM-65880:
eeRoundMode: 0
gsHWFixes:
halfPixelOffset: 2 # Reduces ghosting but still an issue compared to native.
roundSprite: 2 # Clears up much of the blurring that HPO Special does not.
SLPM-65881:
name: "SmackDown vs. Raw - Exciting Professional Wrestling 6"
region: "NTSC-J"
@ -28660,6 +28735,9 @@ SLPM-65974:
SLPM-65975:
name: "WRC 4"
region: "NTSC-J"
gsHWFixes:
autoFlush: 1 # Fixes car shadows.
roundSprite: 1 # Fixes misalgined text.
SLPM-65976:
name: "Grandia III [Disc1of2]"
region: "NTSC-J"
@ -28747,6 +28825,8 @@ SLPM-65999:
SLPM-66000:
name: "Conflict Delta II - Gulf War 1991"
region: "NTSC-J"
gameFixes:
- SoftwareRendererFMVHack # Fixes seizure inducing FMVs.
SLPM-66001:
name: "Chocolat - Maid Cafe Curio"
region: "NTSC-J"
@ -29295,6 +29375,7 @@ SLPM-66160:
eeRoundMode: 0
gsHWFixes:
halfPixelOffset: 2 # Reduces ghosting but still an issue compared to native.
roundSprite: 2 # Clears up much of the blurring that HPO Special does not.
SLPM-66163:
name: "Fuuraiki 2"
region: "NTSC-J"
@ -29315,12 +29396,13 @@ SLPM-66165:
SLPM-66166:
name: "Shadow the Hedgehog"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 2 # Fixes misaligned lighting.
SLPM-66167:
name: "God of War"
region: "NTSC-J"
gsHWFixes:
alignSprite: 1 # Fixes water vertical lines.
halfPixelOffset: 2 # Fixes depth lines and vertical lines and green fog bloom effect.
roundSprite: 1 # Fixes vertical lines and minor ghosting.
wrapGSMem: 1 # Fixes FMV when in progressive mode.
autoFlush: 1 # Fixes sun going through walls.
@ -29624,6 +29706,8 @@ SLPM-66248:
SLPM-66249:
name: "Growlanser V - Generations [Limited Edition]"
region: "NTSC-J"
gsHWFixes:
preloadFrameData: 1 # Fixes layers where characters should be visually behind an object.
SLPM-66250:
name: "Choro Q - HG 4 [Takara Best]"
region: "NTSC-J"
@ -29722,6 +29806,8 @@ SLPM-66276:
SLPM-66277:
name: "Juiced"
region: "NTSC-J"
speedHacks:
InstantVU1SpeedHack: 0 # Significantly improves game speed.
SLPM-66278:
name: "Shin Gouketuji Ichizoku - Bonnou Kaihou"
region: "NTSC-J"
@ -29929,6 +30015,9 @@ SLPM-66333:
SLPM-66334:
name: "WRC 4 [Spike the Best]"
region: "NTSC-J"
gsHWFixes:
autoFlush: 1 # Fixes car shadows.
roundSprite: 1 # Fixes misalgined text.
SLPM-66336:
name: "Shinseiki Evangelion - Koutetsu no Girlfriend [Special Edition]"
region: "NTSC-J"
@ -30191,6 +30280,8 @@ SLPM-66417:
SLPM-66418:
name: "Growlanser V - Generations"
region: "NTSC-J"
gsHWFixes:
preloadFrameData: 1 # Fixes layers where characters should be visually behind an object.
SLPM-66419:
name: "Valkyrie Profile 2 - Silmeria"
region: "NTSC-J"
@ -31157,6 +31248,9 @@ SLPM-66676:
name: "Kingdom Hearts Re-Chain of Memories"
region: "NTSC-J"
compat: 5
gsHWFixes:
autoFlush: 1 # Fixes double image.
halfPixelOffset: 1 # Fixes misaligned bloom.
memcardFilters:
- "SLPM-66675"
- "SLPM-66676"
@ -31312,6 +31406,8 @@ SLPM-66715:
SLPM-66716:
name: "Growlanser VI"
region: "NTSC-J"
gsHWFixes:
preloadFrameData: 1 # Fixes layers where characters should be visually behind an object.
SLPM-66717:
name: "Standard Daisenryaku - Dengekisen [Sega the Best]"
region: "NTSC-J"
@ -32019,6 +32115,8 @@ SLPM-66931:
SLPM-66932:
name: "Need for Speed - ProStreet"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
SLPM-66933:
name: "Kimi ga Aruji de Shitsuji ga Ore de - Oshie Nikki [Limited Edition]"
region: "NTSC-J"
@ -32251,7 +32349,6 @@ SLPM-67010:
region: "NTSC-J"
gsHWFixes:
alignSprite: 1 # Fixes water vertical lines.
halfPixelOffset: 2 # Fixes depth lines and vertical lines and green fog bloom effect.
roundSprite: 1 # Fixes vertical lines and minor ghosting.
wrapGSMem: 1 # Fixes FMV when in progressive mode.
autoFlush: 1 # Fixes sun going through walls.
@ -32260,7 +32357,6 @@ SLPM-67011:
region: "NTSC-J"
gsHWFixes:
alignSprite: 1 # Fixes water vertical lines.
halfPixelOffset: 2 # Fixes depth lines and vertical lines and green fog bloom effect.
roundSprite: 1 # Fixes vertical lines and minor ghosting.
wrapGSMem: 1 # Fixes FMV when in progressive mode.
autoFlush: 1 # Fixes sun going through walls.
@ -32269,7 +32365,6 @@ SLPM-67012:
region: "NTSC-J"
gsHWFixes:
alignSprite: 1 # Fixes water vertical lines.
halfPixelOffset: 2 # Fixes depth lines and vertical lines and green fog bloom effect.
roundSprite: 1 # Fixes vertical lines and minor ghosting.
wrapGSMem: 1 # Fixes FMV when in progressive mode.
autoFlush: 1 # Fixes sun going through walls.
@ -32639,6 +32734,7 @@ SLPM-74242:
eeRoundMode: 0
gsHWFixes:
halfPixelOffset: 2 # Reduces ghosting but still an issue compared to native.
roundSprite: 2 # Clears up much of the blurring that HPO Special does not.
SLPM-74243:
name: "True Crime - New York City [PlayStation 2 The Best]"
region: "NTSC-J"
@ -32804,6 +32900,9 @@ SLPS-20001:
gsHWFixes:
cpuFramebufferConversion: 1
textureInsideRT: 1
halfPixelOffset: 2 # Fixes title screen and some intro post processing alignment.
roundSprite: 1 # Fixes ui and hud alignment.
texturePreloading: 0 # Disabling for major speedup.
SLPS-20002:
name: "Doukyu Billiards"
region: "NTSC-J"
@ -34503,6 +34602,8 @@ SLPS-25120:
SLPS-25121:
name: "dot hack - Infection Part 1"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 1 # Sharpens world in far distances.
memcardFilters:
- "SCPS-55029"
- "SCPS-55042"
@ -35128,13 +35229,13 @@ SLPS-25317:
name: "Shadow Hearts 2 [Deluxe Pack] [Disc1of2]"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
halfPixelOffset: 2 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
disablePartialInvalidation: 1 # Fixes shadows when upscaling.
SLPS-25318:
name: "Shadow Hearts 2 [Deluxe Pack] [Disc2of2]"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
halfPixelOffset: 2 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
disablePartialInvalidation: 1 # Fixes shadows when upscaling.
memcardFilters:
- "SLPS-25317"
@ -35181,13 +35282,13 @@ SLPS-25334:
name: "Shadow Hearts 2 [Disc1of2]"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
halfPixelOffset: 2 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
disablePartialInvalidation: 1 # Fixes shadows when upscaling.
SLPS-25335:
name: "Shadow Hearts 2 [Disc1of2]"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
halfPixelOffset: 2 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
disablePartialInvalidation: 1 # Fixes shadows when upscaling.
memcardFilters:
- "SLPS-25334"
@ -35482,6 +35583,8 @@ SLPS-25405:
SLPS-25406:
name: "Hitman - Contracts"
region: "NTSC-J"
gsHWFixes:
texturePreloading: 1 # Performs much better with partial preload.
SLPS-25407:
name: "King of Fighters 2003, The"
region: "NTSC-J"
@ -36058,6 +36161,7 @@ SLPS-25577:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
halfPixelOffset: 1 # Fixes blurriness.
texturePreloading: 1 # Improves performance.
SLPS-25578:
name: "K-1 World Grand Prix 2005"
region: "NTSC-J"
@ -37515,13 +37619,13 @@ SLPS-73214:
name: "Shadow Hearts 2 [Director's Cut] [PlayStation 2 The Best] [Disc1of2]"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
halfPixelOffset: 2 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
disablePartialInvalidation: 1 # Fixes shadows when upscaling.
SLPS-73215:
name: "Shadow Hearts 2 [Director's Cut] [PlayStation 2 The Best] [Disc2of2]"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 1 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
halfPixelOffset: 2 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
disablePartialInvalidation: 1 # Fixes shadows when upscaling.
memcardFilters:
- "SLPS-73214"
@ -37961,6 +38065,9 @@ SLUS-20002:
gsHWFixes:
cpuFramebufferConversion: 1
textureInsideRT: 1
halfPixelOffset: 2 # Fixes title screen and some intro post processing alignment.
roundSprite: 1 # Fixes ui and hud alignment.
texturePreloading: 0 # Disabling for major speedup.
SLUS-20003:
name: "Portal Runner"
region: "NTSC-U"
@ -38920,6 +39027,8 @@ SLUS-20267:
name: "dot hack - Infection Part 1"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 1 # Sharpens world in far distances.
memcardFilters:
- "SLUS-20267"
- "SLUS-20562"
@ -39703,7 +39812,9 @@ SLUS-20440:
gameFixes:
- EETimingHack # Fixes smoke effects.
gsHWFixes:
halfPixelOffset: 1 # Fixes fog misalignment.
halfPixelOffset: 2 # Fixes fog misalignment and depth line.
autoFlush: 1 # Fixes sun going through objects.
preloadFrameData: 1 # Fixes missing sun and sky.
SLUS-20441:
name: "NASCAR - Dirt to Daytona"
region: "NTSC-U"
@ -39867,6 +39978,8 @@ SLUS-20474:
SLUS-20475:
name: "Dual Hearts"
region: "NTSC-U"
gsHWFixes:
deinterlace: 5 # Game requires blend tff deinterlacing when auto.
compat: 5
SLUS-20476:
name: "NBA 2K3 - Sega Sports"
@ -40167,9 +40280,12 @@ SLUS-20546:
patches:
D3F68D3F:
content: |-
author=kozarovv
// Skip PSS movies, workaround for EE Cache requirement.
patch=1,EE,00122d00,word,100000d9
author=Goatman13
// Fix issues caused by PSS video playback.
// Extend stack to avoid sending bad data to VIF1.
// Required due to lack of data cache emulation.
patch=1,EE,00122780,word,27BDFD00
patch=1,EE,00122AE8,word,27BD0300
SLUS-20547:
name: "Cubix Showdown"
region: "NTSC-U"
@ -40830,6 +40946,8 @@ SLUS-20688:
SLUS-20689:
name: "Conflict - Desert Storm 2 - Back to Baghdad"
region: "NTSC-U"
gameFixes:
- SoftwareRendererFMVHack # Fixes seizure inducing FMVs.
SLUS-20690:
name: "G1 Jockey 3"
region: "NTSC-U"
@ -40968,6 +41086,8 @@ SLUS-20722:
name: "Maximo vs. Army of Zin"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 2 # Fixes outlines around environmental objects.
SLUS-20723:
name: "Robin Hood - Defender of the Crown"
region: "NTSC-U"
@ -41653,6 +41773,8 @@ SLUS-20872:
name: "Juiced"
region: "NTSC-U"
compat: 5
speedHacks:
InstantVU1SpeedHack: 0 # Significantly improves game speed.
SLUS-20873:
name: "Silent Hill 4 - The Room"
region: "NTSC-U"
@ -41694,7 +41816,9 @@ SLUS-20881:
SLUS-20882:
name: "Hitman - Contracts"
region: "NTSC-U"
compat: 3
compat: 4
gsHWFixes:
texturePreloading: 1 # Performs much better with partial preload.
SLUS-20883:
name: "Tom Clancy's Rainbow Six 3"
region: "NTSC-U"
@ -42108,6 +42232,7 @@ SLUS-20964:
eeRoundMode: 0
gsHWFixes:
halfPixelOffset: 2 # Reduces ghosting but still an issue compared to native.
roundSprite: 2 # Clears up much of the blurring that HPO Special does not.
SLUS-20965:
name: "Tony Hawk's Underground 2"
region: "NTSC-U"
@ -42470,6 +42595,8 @@ SLUS-21029:
// for VU1 to finish, which reduces the advantage of MTVU to basically zero.
patch=1,EE,D05257FC,extended,00000800
patch=1,EE,205257FC,extended,00000000
gsHWFixes:
texturePreloading: 1 # Improves performance and prevents it disabling itself regardless.
SLUS-21030:
name: "Outlaw Golf 2"
region: "NTSC-U"
@ -42526,7 +42653,7 @@ SLUS-21041:
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 1 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
halfPixelOffset: 2 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
disablePartialInvalidation: 1 # Fixes shadows when upscaling.
SLUS-21042:
name: "Darkwatch"
@ -42541,7 +42668,7 @@ SLUS-21044:
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 1 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
halfPixelOffset: 2 # Fixes blurrines, preload frame for FMV breaks visuals with this setting.
disablePartialInvalidation: 1 # Fixes shadows when upscaling.
memcardFilters:
- "SLUS-21041"
@ -43350,6 +43477,7 @@ SLUS-21216:
gsHWFixes:
alignSprite: 1 # Fixes vertical lines.
halfPixelOffset: 1 # Fixes blurriness.
texturePreloading: 1 # Improves performance.
SLUS-21217:
name: "Incredibles, The - Rise of the Underminers"
region: "NTSC-U"
@ -43612,6 +43740,8 @@ SLUS-21261:
name: "Shadow the Hedgehog"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 2 # Fixes misaligned lighting.
SLUS-21262:
name: "Radiata Stories"
region: "NTSC-U"
@ -44136,6 +44266,8 @@ SLUS-21355:
// for VU1 to finish, which reduces the advantage of MTVU to basically zero.
patch=1,EE,D052907C,extended,00000800
patch=1,EE,2052907C,extended,00000000
gsHWFixes:
texturePreloading: 1 # Improves performance and prevents it disabling itself regardless.
SLUS-21356:
name: "Tom Clancy's Splinter Cell - Double Agent"
region: "NTSC-U"
@ -44173,6 +44305,7 @@ SLUS-21361:
eeRoundMode: 0
gsHWFixes:
halfPixelOffset: 2 # Reduces ghosting but still an issue compared to native.
roundSprite: 2 # Clears up much of the blurring that HPO Special does not.
SLUS-21362:
name: "Onimusha - Dawn of Dreams [Disc2of2]"
region: "NTSC-U"
@ -45326,8 +45459,7 @@ SLUS-21615:
region: "NTSC-U"
compat: 5
gsHWFixes:
wildArmsHack: 1 # Fixes font artifacts and out-of-bound 2D textures.
roundSprite: 1 # Fixes font sizes.
cpuFramebufferConversion: 1 # Fixes sepia-tone flashback sequences.
SLUS-21616:
name: "Tony Hawk's Proving Ground"
region: "NTSC-U"
@ -45520,6 +45652,8 @@ SLUS-21658:
name: "Need for Speed - ProStreet"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 2 # Fixes depth line.
SLUS-21660:
name: "Disney Princess - Enchanted Journey"
region: "NTSC-U"
@ -46153,6 +46287,9 @@ SLUS-21799:
name: "Kingdom Hearts Re-Chain of Memories"
region: "NTSC-U"
compat: 5
gsHWFixes:
autoFlush: 1 # Fixes double image.
halfPixelOffset: 1 # Fixes misaligned bloom.
SLUS-21800:
name: "Rock Band 2"
region: "NTSC-U"
@ -46825,6 +46962,8 @@ SLUS-28021:
SLUS-28023:
name: "dot hack - Infection Part 1 [Trade Demo]"
region: "NTSC-U"
gsHWFixes:
halfPixelOffset: 1 # Sharpens world in far distances.
SLUS-28025:
name: "Disaster Report [Trade Demo]"
region: "NTSC-U"
@ -46852,7 +46991,9 @@ SLUS-28037:
gameFixes:
- EETimingHack # Fixes smoke effects.
gsHWFixes:
halfPixelOffset: 1 # Fixes fog misalignment.
halfPixelOffset: 2 # Fixes fog misalignment and depth line.
autoFlush: 1 # Fixes sun going through objects.
preloadFrameData: 1 # Fixes missing sun and sky.
SLUS-28039:
name: "Rogue Ops [Trade Demo]"
region: "NTSC-U"
@ -47055,6 +47196,8 @@ SLUS-29040:
SLUS-29042:
name: "dot hack - Infection Part 1 [Regular Demo]"
region: "NTSC-U"
gsHWFixes:
halfPixelOffset: 1 # Sharpens world in far distances.
SLUS-29044:
name: "Pride FC - Fighting Championships [Demo]"
region: "NTSC-U"
@ -47177,6 +47320,8 @@ SLUS-29082:
SLUS-29083:
name: "Maximo vs. The Army of Zin [Demo]"
region: "NTSC-U"
gsHWFixes:
halfPixelOffset: 2 # Fixes outlines around environmental objects.
SLUS-29084:
name: "dot hack - Quarantine Part 4 [Demo]"
region: "NTSC-U"
@ -47558,6 +47703,9 @@ TCES-52042:
TCES-52389:
name: "World Rally Championship 4 Beta Trial Code"
region: "PAL-E"
gsHWFixes:
autoFlush: 1 # Fixes car shadows.
roundSprite: 1 # Fixes misalgined text.
TCES-52456:
name: "Ratchet and Clank 3 Beta Trial Code"
region: "PAL-E"

View File

@ -11,7 +11,7 @@
03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,
03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000951000000000000,8BitDo Dogbone Modkit,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,
03000000c82d00000951000000000000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows,
03000000008000000210000000000000,8BitDo F30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
030000003512000011ab000000000000,8BitDo F30 Arcade Joystick,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:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000c82d00001028000000000000,8BitDo F30 Arcade Joystick,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
@ -19,14 +19,15 @@
03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000151000000000000,8BitDo M30 Modkit,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000451000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows,
03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d0000e002000000000000,8BitDo N30,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b6,platform:Windows,
03000000c82d00000451000000000000,8BitDo N30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,start:b11,platform:Windows,
03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
@ -37,7 +38,8 @@
03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000851000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
@ -45,7 +47,7 @@
03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000431000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00002867000000000000,8BitDo S30 Modkit,a:b0,b:b1,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00002867000000000000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b10,x:b3,y:b4,platform:Windows,
03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
@ -54,11 +56,11 @@
03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
030000003512000020ab000000000000,8BitDo SN30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a2,rightshoulder:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000351000000000000,8BitDo SN30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000021000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
@ -120,6 +122,7 @@
030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
03000000120c0000200e000000000000,Brook Mars PS4 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:Windows,
03000000120c0000210e000000000000,Brook Mars PS4 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,
030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
@ -234,14 +237,14 @@
030000000d0f00005100000000000000,Hori Fighting Commander PS3,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:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00008800000000000000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00001000000000000000,Hori Fightstick,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:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00003200000000000000,Hori Fightstick 3W,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:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows,
030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008800000000000000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00002100000000000000,Hori Fightstick V3,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:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows,
@ -482,7 +485,6 @@
03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f10e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@ -740,11 +742,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,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:b3,y:b0,platform:Mac OS X,
03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000c82d00001151000000020000,8BitDo Lite SE,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X,
03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,lefttrigger:a5,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
@ -753,14 +761,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000190000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,x:b4,y:b3,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Mac OS X,
03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,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:b4,y:b3,platform:Mac OS X,
03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Mac OS X,
03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
@ -958,11 +969,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
# Linux
030000005e0400008e02000020010000,8BitDo Adapter,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,
03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@ -972,12 +988,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,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:b4,y:b3,platform:Linux,
05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,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:b4,y:b3,platform:Linux,
03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Linux,
05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
@ -985,6 +1004,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
@ -1079,10 +1099,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00008500000010010000,Hori Fighting Commander PS3,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00008800000011010000,Hori Fighting Stick mini 4 (PS3),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,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00008700000011010000,Hori Fighting Stick mini 4 (PS4),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:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00004d00000011010000,Hori Gem Pad 3,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux,
@ -1209,8 +1229,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux,
03000000d620000013a7000011010000,Nintendo Switch PowerA 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus 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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,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:b4,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,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:b4,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,
05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
@ -1440,6 +1460,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000130b000013050000,Xbox Series 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,
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,
050000005e040000130b000011050000,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,
030000005e040000120b000007050000,Xbox Series X Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,misc1:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
050000005e040000130b000007050000,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,
03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,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:b2,y:b3,platform:Linux,
05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,

View File

@ -43,7 +43,7 @@ BIOSSettingsWidget::BIOSSettingsWidget(SettingsDialog* dialog, QWidget* parent)
dialog->registerWidgetHelp(m_ui.patchRegion, tr("Patch Region"), tr("Unchecked"),
tr("Patches the BIOS region byte in ROM. Not recommended unless you really know what you're doing."));
dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Unchecked"),
dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Checked"),
tr("Patches the BIOS to skip the console's boot animation."));
refreshList();

View File

@ -186,7 +186,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), -1);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.accurateDATE, "EmuCore/GS", "accurate_date", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.conservativeBufferAllocation, "EmuCore/GS", "conservative_framebuffer", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading",
static_cast<int>(TexturePreloadingLevel::Off));
@ -251,6 +250,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
//////////////////////////////////////////////////////////////////////////
// SW Settings
//////////////////////////////////////////////////////////////////////////
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.swTextureFiltering, "EmuCore/GS", "filter", static_cast<int>(BiFiltering::PS2));
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.extraSWThreads, "EmuCore/GS", "extrathreads", 2);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.swAutoFlush, "EmuCore/GS", "autoflush_sw", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.swMipmap, "EmuCore/GS", "mipmap", true);
@ -286,6 +286,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
connect(m_ui.renderer, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onRendererChanged);
connect(m_ui.enableHWFixes, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onEnableHardwareFixesChanged);
connect(m_ui.textureFiltering, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onTextureFilteringChange);
connect(m_ui.swTextureFiltering, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onSWTextureFilteringChange);
updateRendererDependentOptions();
// only allow disabling readbacks for per-game settings, it's too dangerous
@ -347,7 +349,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
"The higher the setting, the more blending is emulated in the shader accurately, and the higher the speed penalty will be. "
"Do note that Direct3D's blending is reduced in capability compared to OpenGL/Vulkan"));
dialog->registerWidgetHelp(m_ui.texturePreloading, tr("Texture Preloading"), tr(""),
dialog->registerWidgetHelp(m_ui.texturePreloading, tr("Texture Preloading"), tr("Full (Hash Cache)"),
tr("Uploads entire textures at once instead of small pieces, avoiding redundant uploads when possible. "
"Improves performance in most games, but can make a small selection slower."));
@ -355,10 +357,6 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
tr("Implement a more accurate algorithm to compute GS destination alpha testing. "
"It improves shadow and transparency rendering."));
dialog->registerWidgetHelp(m_ui.conservativeBufferAllocation, tr("Conservative Buffer Allocation"), tr("Checked"),
tr("Disabled: Reserves a larger framebuffer to prevent FMV flickers. Increases GPU/memory requirements. "
"Disabling this can amplify stuttering due to low RAM/VRAM."));
dialog->registerWidgetHelp(m_ui.gpuPaletteConversion, tr("GPU Palette Conversion"), tr("Unchecked"),
tr("When enabled GPU converts colormap-textures, otherwise the CPU will. "
"It is a trade-off between GPU and CPU."));
@ -478,6 +476,20 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
GraphicsSettingsWidget::~GraphicsSettingsWidget() = default;
void GraphicsSettingsWidget::onTextureFilteringChange()
{
const QSignalBlocker block(m_ui.swTextureFiltering);
m_ui.swTextureFiltering->setCurrentIndex(m_ui.textureFiltering->currentIndex());
}
void GraphicsSettingsWidget::onSWTextureFilteringChange()
{
const QSignalBlocker block(m_ui.textureFiltering);
m_ui.textureFiltering->setCurrentIndex(m_ui.swTextureFiltering->currentIndex());
}
void GraphicsSettingsWidget::onRendererChanged(int index)
{
if (m_dialog->isPerGameSettings())

View File

@ -35,6 +35,8 @@ Q_SIGNALS:
void fullscreenModesChanged(const QStringList& modes);
private Q_SLOTS:
void onTextureFilteringChange();
void onSWTextureFilteringChange();
void onRendererChanged(int index);
void onAdapterChanged(int index);
void onEnableHardwareFixesChanged();

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>657</width>
<width>658</width>
<height>890</height>
</rect>
</property>
@ -58,7 +58,7 @@
<item>
<widget class="QTabWidget" name="hardwareRendererGroup">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<property name="documentMode">
<bool>true</bool>
@ -642,38 +642,6 @@
</item>
</widget>
</item>
<item row="9" column="0" colspan="2">
<layout class="QGridLayout" name="basicCheckboxGridLayout">
<item row="1" column="0">
<widget class="QCheckBox" name="gpuPaletteConversion">
<property name="text">
<string>GPU Palette Conversion</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="conservativeBufferAllocation">
<property name="text">
<string>Conservative Buffer Allocation</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="accurateDATE">
<property name="text">
<string>Accurate Destination Alpha Test</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="enableHWFixes">
<property name="text">
<string>Manual Hardware Renderer Fixes</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
@ -700,6 +668,31 @@
</item>
</widget>
</item>
<item row="9" column="0" colspan="2">
<layout class="QGridLayout" name="basicCheckboxGridLayout">
<item row="0" column="0">
<widget class="QCheckBox" name="accurateDATE">
<property name="text">
<string>Accurate Destination Alpha Test</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="gpuPaletteConversion">
<property name="text">
<string>GPU Palette Conversion</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="enableHWFixes">
<property name="text">
<string>Manual Hardware Renderer Fixes</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="hardwareFixesTab">
@ -1523,6 +1516,15 @@
</item>
<item>
<widget class="QTabWidget" name="softwareRendererGroup">
<property name="enabled">
<bool>true</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>203</height>
</size>
</property>
<property name="documentMode">
<bool>true</bool>
</property>
@ -1531,29 +1533,65 @@
<string>Rendering</string>
</attribute>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="1">
<widget class="QComboBox" name="swTextureFiltering">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<item>
<property name="text">
<string>Nearest</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear (Forced)</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear (PS2)</string>
</property>
</item>
<item>
<property name="text">
<string>Bilinear (Forced excluding sprite)</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<widget class="QLabel" name="label_37">
<property name="text">
<string>Extra Rendering Threads:</string>
<string>Texture Filtering:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<widget class="QSpinBox" name="extraSWThreads">
<property name="suffix">
<string> threads</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<item row="1" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Extra Rendering Threads:</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QCheckBox" name="swAutoFlush">
<property name="text">
<string>Auto Flush</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="swMipmap">
<property name="text">
@ -1561,6 +1599,13 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="swAutoFlush">
<property name="text">
<string>Auto Flush</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@ -80,7 +80,7 @@ SystemSettingsWidget::SystemSettingsWidget(SettingsDialog* dialog, QWidget* pare
tr("Higher values may increase internal framerate in games, but will increase CPU requirements substantially. "
"Lower values will reduce the CPU load allowing lightweight games to run full speed on weaker CPUs."));
dialog->registerWidgetHelp(m_ui.eeCycleSkipping, tr("Cycle Skip"), tr("Normal Speed"),
dialog->registerWidgetHelp(m_ui.eeCycleSkipping, tr("Cycle Skip"), tr("None"),
tr("Makes the emulated Emotion Engine skip cycles. "
"Helps a small subset of games like SOTC. Most of the time it's harmful to performance."));
@ -89,23 +89,15 @@ SystemSettingsWidget::SystemSettingsWidget(SettingsDialog* dialog, QWidget* pare
"Safe for most games, but a few are incompatible and may hang."));
dialog->registerWidgetHelp(m_ui.instantVU1, tr("Instant VU1"), tr("Checked"),
tr("Runs VU1 instantly (when MTVU is disabled). Provides a modest speed improvement. "
tr("Runs VU1 instantly. Provides a modest speed improvement in most games. "
"Safe for most games, but a few games may exhibit graphical errors."));
dialog->registerWidgetHelp(m_ui.fastCDVD, tr("Enable Fast CDVD"), tr("Unchecked"),
tr("Fast disc access, less loading times. Check HDLoader compatibility lists for known games that have issues with this."));
updateVU1InstantState();
connect(m_ui.MTVU, &QCheckBox::stateChanged, this, &SystemSettingsWidget::updateVU1InstantState);
}
SystemSettingsWidget::~SystemSettingsWidget() = default;
void SystemSettingsWidget::updateVU1InstantState()
{
m_ui.instantVU1->setEnabled(!m_dialog->getEffectiveBoolValue("EmuCore/Speedhacks", "vuThread", false));
}
int SystemSettingsWidget::getGlobalClampingModeIndex(bool vu) const
{
if (Host::GetBaseBoolSettingValue("EmuCore/CPU/Recompiler", vu ? "vuSignOverflow" : "fpuFullMode", false))

View File

@ -29,9 +29,6 @@ public:
SystemSettingsWidget(SettingsDialog* dialog, QWidget* parent);
~SystemSettingsWidget();
private Q_SLOTS:
void updateVU1InstantState();
private:
int getGlobalClampingModeIndex(bool vu) const;
int getClampingModeIndex(bool vu) const;

View File

@ -89,7 +89,7 @@
<widget class="QComboBox" name="eeCycleSkipping">
<item>
<property name="text">
<string>Normal</string>
<string>None</string>
</property>
</item>
<item>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 62 KiB

View File

@ -461,7 +461,6 @@ struct Pcsx2Config
HWDisableReadbacks : 1,
AccurateDATE : 1,
GPUPaletteConversion : 1,
ConservativeFramebuffer : 1,
AutoFlushSW : 1,
PreloadFrameWithGSData : 1,
WrapGSMem : 1,

View File

@ -390,6 +390,7 @@ bool SocketAdapter::send(NetPacket* pkt)
memcpy(arpRet->senderProtocolAddress.get(), arpPkt.targetProtocolAddress.get(), 4);
arpRet->op = 2,
arpRet->protocol = arpPkt.protocol;
arpRet->hardwareType = arpPkt.hardwareType;
EthernetFrame* retARP = new EthernetFrame(arpRet);
memcpy(retARP->destinationMAC, ps2MAC, 6);

View File

@ -829,7 +829,6 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
// reload texture cache when trilinear filtering or TC options change
if (
(GSConfig.UseHardwareRenderer() && GSConfig.HWMipmap != old_config.HWMipmap) ||
GSConfig.ConservativeFramebuffer != old_config.ConservativeFramebuffer ||
GSConfig.TexturePreloading != old_config.TexturePreloading ||
GSConfig.UserHacks_TriFilter != old_config.UserHacks_TriFilter ||
GSConfig.GPUPaletteConversion != old_config.GPUPaletteConversion ||
@ -1456,7 +1455,6 @@ void GSApp::Init()
m_default_configuration["pcrtc_overscan"] = "0";
m_default_configuration["IntegerScaling"] = "0";
m_default_configuration["deinterlace"] = "7";
m_default_configuration["conservative_framebuffer"] = "1";
m_default_configuration["linear_present"] = "1";
m_default_configuration["LoadTextureReplacements"] = "0";
m_default_configuration["LoadTextureReplacementsAsync"] = "1";
@ -1479,8 +1477,6 @@ void GSApp::Init()
m_default_configuration["override_GL_ARB_draw_buffers_blend"] = "-1";
m_default_configuration["override_GL_ARB_gpu_shader5"] = "-1";
m_default_configuration["override_GL_ARB_shader_image_load_store"] = "-1";
m_default_configuration["override_GL_ARB_sparse_texture"] = "-1";
m_default_configuration["override_GL_ARB_sparse_texture2"] = "-1";
m_default_configuration["override_GL_ARB_texture_barrier"] = "-1";
m_default_configuration["OverrideTextureBarriers"] = "-1";
m_default_configuration["OverrideGeometryShaders"] = "-1";

View File

@ -76,12 +76,6 @@ __forceinline bool BitEqual(const T& a, const T& b)
return eqb;
}
#ifdef ENABLE_ACCURATE_BUFFER_EMULATION
static const GSVector2i default_rt_size(2048, 2048);
#else
static const GSVector2i default_rt_size(0, 0);
#endif
extern Pcsx2Config::GSOptions GSConfig;
// Maximum texture size to skip preload/hash path.

View File

@ -482,7 +482,7 @@ GSVector2i GSState::GetResolution()
// The resolution of the framebuffer is double when in FRAME mode and interlaced.
// Also we need a special check because no-interlace patches like to render in the original height, but in non-interlaced mode
// which means it would normally go off the bottom of the screen. Advantages of emulation, i guess... Limited to Ignore Offsets + Deinterlacing = Off.
if ((isinterlaced() && !m_regs->SMODE2.FFMD) || (GSConfig.InterlaceMode == GSInterlaceMode::Off && !GSConfig.PCRTCOffsets))
if ((isinterlaced() && !m_regs->SMODE2.FFMD) || (GSConfig.InterlaceMode == GSInterlaceMode::Off && !GSConfig.PCRTCOffsets && !isinterlaced()))
resolution.y *= 2;
if (ignore_offset)

View File

@ -161,12 +161,10 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
}
t->SetScale(GSVector2(1, 1)); // Things seem to assume that all textures come out of here with scale 1...
t->Commit(); // Clear won't be done if the texture isn't committed.
switch (type)
{
case GSTexture::Type::RenderTarget:
case GSTexture::Type::SparseRenderTarget:
{
if (clear)
ClearRenderTarget(t, 0);
@ -175,7 +173,6 @@ GSTexture* GSDevice::FetchSurface(GSTexture::Type type, int width, int height, i
}
break;
case GSTexture::Type::DepthStencil:
case GSTexture::Type::SparseDepthStencil:
{
if (clear)
ClearDepth(t);
@ -215,12 +212,6 @@ void GSDevice::Recycle(GSTexture* t)
{
if (t)
{
#ifdef _DEBUG
// Uncommit saves memory but it means a futur allocation when we want to reuse the texture.
// Which is slow and defeat the purpose of the m_pool cache.
// However, it can help to spot part of texture that we forgot to commit
t->Uncommit();
#endif
t->last_frame_used = m_frame;
m_pool.push_front(t);
@ -259,16 +250,6 @@ void GSDevice::ClearSamplerCache()
{
}
GSTexture* GSDevice::CreateSparseRenderTarget(int w, int h, GSTexture::Format format, bool clear)
{
return FetchSurface(HasColorSparse() ? GSTexture::Type::SparseRenderTarget : GSTexture::Type::RenderTarget, w, h, 1, format, clear, true);
}
GSTexture* GSDevice::CreateSparseDepthStencil(int w, int h, GSTexture::Format format, bool clear)
{
return FetchSurface(HasDepthSparse() ? GSTexture::Type::SparseDepthStencil : GSTexture::Type::DepthStencil, w, h, 1, format, clear, true);
}
GSTexture* GSDevice::CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear)
{
return FetchSurface(GSTexture::Type::RenderTarget, w, h, 1, format, clear, true);
@ -292,7 +273,7 @@ GSTexture* GSDevice::CreateOffscreen(int w, int h, GSTexture::Format format)
GSTexture::Format GSDevice::GetDefaultTextureFormat(GSTexture::Type type)
{
if (type == GSTexture::Type::DepthStencil || type == GSTexture::Type::SparseDepthStencil)
if (type == GSTexture::Type::DepthStencil)
return GSTexture::Format::DepthStencil;
else
return GSTexture::Format::Color;

View File

@ -729,9 +729,6 @@ public:
virtual void BeginScene() {}
virtual void EndScene();
virtual bool HasDepthSparse() { return false; }
virtual bool HasColorSparse() { return false; }
virtual void ClearRenderTarget(GSTexture* t, const GSVector4& c) {}
virtual void ClearRenderTarget(GSTexture* t, u32 c) {}
virtual void InvalidateRenderTarget(GSTexture* t) {}
@ -742,8 +739,6 @@ public:
virtual void PopDebugGroup() {}
virtual void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) {}
GSTexture* CreateSparseRenderTarget(int w, int h, GSTexture::Format format, bool clear = true);
GSTexture* CreateSparseDepthStencil(int w, int h, GSTexture::Format format, bool clear = true);
GSTexture* CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear = true);
GSTexture* CreateDepthStencil(int w, int h, GSTexture::Format format, bool clear = true);
GSTexture* CreateTexture(int w, int h, bool mipmap, GSTexture::Format format, bool prefer_reuse = false);

View File

@ -762,6 +762,23 @@ void GSRenderer::QueueSnapshot(const std::string& path, u32 gsdump_frames)
}
else
{
m_snapshot = "";
// append the game serial and title
if (std::string name(GetDumpName()); !name.empty())
{
Path::SanitizeFileName(name);
if (name.length() > 219)
name.resize(219);
m_snapshot += name;
}
if (std::string serial(GetDumpSerial()); !serial.empty())
{
Path::SanitizeFileName(serial);
m_snapshot += '_';
m_snapshot += serial;
}
time_t cur_time = time(nullptr);
char local_time[16];
@ -774,30 +791,18 @@ void GSRenderer::QueueSnapshot(const std::string& path, u32 gsdump_frames)
// the captured image is the 2nd image captured at this specific time.
static int n = 2;
m_snapshot += '_';
if (cur_time == prev_snap)
m_snapshot = fmt::format("gs_{0}_({1})", local_time, n++);
m_snapshot += fmt::format("{0}_({1})", local_time, n++);
else
{
n = 2;
m_snapshot = fmt::format("gs_{}", local_time);
m_snapshot += fmt::format("{}", local_time);
}
prev_snap = cur_time;
}
// append the game serial and title
if (std::string name(GetDumpName()); !name.empty())
{
Path::SanitizeFileName(name);
m_snapshot += '_';
m_snapshot += name;
}
if (std::string serial(GetDumpSerial()); !serial.empty())
{
Path::SanitizeFileName(serial);
m_snapshot += '_';
m_snapshot += serial;
}
// prepend snapshots directory
m_snapshot = Path::Combine(EmuFolders::Snapshots, m_snapshot);
}

View File

@ -22,13 +22,10 @@
GSTexture::GSTexture()
: m_scale(1, 1)
, m_size(0, 0)
, m_committed_size(0, 0)
, m_gpu_page_size(0, 0)
, m_mipmap_levels(0)
, m_type(Type::Invalid)
, m_format(Format::Invalid)
, m_state(State::Dirty)
, m_sparse(false)
, m_needs_mipmaps_generated(true)
, last_frame_used(0)
, OffsetHack_modxy(0.0f)
@ -73,12 +70,10 @@ void GSTexture::Swap(GSTexture* tex)
{
std::swap(m_scale, tex->m_scale);
std::swap(m_size, tex->m_size);
std::swap(m_committed_size, tex->m_committed_size);
std::swap(m_mipmap_levels, tex->m_mipmap_levels);
std::swap(m_type, tex->m_type);
std::swap(m_format, tex->m_format);
std::swap(m_state, tex->m_state);
std::swap(m_sparse, tex->m_sparse);
std::swap(m_needs_mipmaps_generated, tex->m_needs_mipmaps_generated);
std::swap(last_frame_used, tex->last_frame_used);
std::swap(OffsetHack_modxy, tex->OffsetHack_modxy);
@ -133,55 +128,3 @@ void GSTexture::GenerateMipmapsIfNeeded()
m_needs_mipmaps_generated = false;
GenerateMipmap();
}
void GSTexture::CommitRegion(const GSVector2i& region)
{
if (!m_sparse)
return;
GSVector2i aligned_region = RoundUpPage(region);
aligned_region.x = std::max(m_committed_size.x, aligned_region.x);
aligned_region.y = std::max(m_committed_size.y, aligned_region.y);
if (aligned_region != m_committed_size)
CommitPages(aligned_region, true);
}
void GSTexture::Commit()
{
if (!m_sparse)
return;
if (m_committed_size != m_size)
CommitPages(m_size, true);
}
void GSTexture::Uncommit()
{
if (!m_sparse)
return;
GSVector2i zero = GSVector2i(0, 0);
if (m_committed_size != zero)
CommitPages(m_committed_size, false);
}
void GSTexture::SetGpuPageSize(const GSVector2i& page_size)
{
pxAssert(std::bitset<32>(page_size.x + 1).count() == 1);
pxAssert(std::bitset<32>(page_size.y + 1).count() == 1);
m_gpu_page_size = page_size;
}
GSVector2i GSTexture::RoundUpPage(GSVector2i v)
{
v.x = std::min(m_size.x, v.x);
v.y = std::min(m_size.y, v.y);
v.x += m_gpu_page_size.x;
v.y += m_gpu_page_size.y;
v.x &= ~m_gpu_page_size.x;
v.y &= ~m_gpu_page_size.y;
return v;
}

View File

@ -33,8 +33,6 @@ public:
DepthStencil,
Texture,
Offscreen,
SparseRenderTarget,
SparseDepthStencil,
};
enum class Format : u8
@ -63,25 +61,16 @@ public:
protected:
GSVector2 m_scale;
GSVector2i m_size;
GSVector2i m_committed_size;
GSVector2i m_gpu_page_size;
int m_mipmap_levels;
Type m_type;
Format m_format;
State m_state;
bool m_sparse;
bool m_needs_mipmaps_generated;
public:
GSTexture();
virtual ~GSTexture() {}
virtual operator bool()
{
pxAssert(0);
return false;
}
// Returns the native handle of a texture.
virtual void* GetNativeHandle() const = 0;
@ -113,16 +102,15 @@ public:
bool IsRenderTargetOrDepthStencil() const
{
return (m_type >= Type::RenderTarget && m_type <= Type::DepthStencil) ||
(m_type >= Type::SparseRenderTarget && m_type <= Type::SparseDepthStencil);
return (m_type >= Type::RenderTarget && m_type <= Type::DepthStencil);
}
bool IsRenderTarget() const
{
return (m_type == Type::RenderTarget || m_type == Type::SparseRenderTarget);
return (m_type == Type::RenderTarget);
}
bool IsDepthStencil() const
{
return (m_type == Type::DepthStencil || m_type == Type::SparseDepthStencil);
return (m_type == Type::DepthStencil);
}
State GetState() const { return m_state; }
@ -131,14 +119,6 @@ public:
void GenerateMipmapsIfNeeded();
void ClearMipmapGenerationFlag() { m_needs_mipmaps_generated = false; }
virtual void CommitPages(const GSVector2i& region, bool commit) {}
void CommitRegion(const GSVector2i& region);
void Commit();
void Uncommit();
GSVector2i GetCommittedSize() const { return m_committed_size; }
void SetGpuPageSize(const GSVector2i& page_size);
GSVector2i RoundUpPage(GSVector2i v);
// frame number (arbitrary base) the texture was recycled on
// different purpose than texture cache ages, do not attempt to merge
unsigned last_frame_used;
@ -146,7 +126,7 @@ public:
float OffsetHack_modxy;
// Typical size of a RGBA texture
virtual u32 GetMemUsage() { return m_size.x * m_size.y * (m_format == Format::UNorm8 ? 1 : 4); }
u32 GetMemUsage() const { return m_size.x * m_size.y * (m_format == Format::UNorm8 ? 1 : 4); }
// Helper routines for formats/types
static bool IsCompressedFormat(Format format) { return (format >= Format::BC1 && format <= Format::BC7); }

View File

@ -1370,7 +1370,6 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const GSVector4 dRect(config.drawarea);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
hdr_rt = CreateRenderTarget(size.x, size.y, GSTexture::Format::FloatColor);
hdr_rt->CommitRegion(GSVector2i(config.drawarea.z, config.drawarea.w));
// Warning: StretchRect must be called before BeginScene otherwise
// vertices will be overwritten. Trust me you don't want to do that.
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::COPY, false);

View File

@ -319,8 +319,7 @@ void GSDevice12::LookupNativeFormat(GSTexture::Format format, DXGI_FORMAT* d3d_f
GSTexture* GSDevice12::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
{
pxAssert(type != GSTexture::Type::Offscreen && type != GSTexture::Type::SparseRenderTarget &&
type != GSTexture::Type::SparseDepthStencil);
pxAssert(type != GSTexture::Type::Offscreen);
const u32 clamped_width = static_cast<u32>(std::clamp<int>(1, width, D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION));
const u32 clamped_height = static_cast<u32>(std::clamp<int>(1, height, D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION));

View File

@ -20,15 +20,15 @@
#include "GS/Renderers/SW/GSTextureCacheSW.h"
#include "GS/Renderers/SW/GSDrawScanline.h"
#include "Host.h"
#include "common/Align.h"
#include "common/StringUtil.h"
GSRendererHW::GSRendererHW()
: GSRenderer()
, m_width(default_rt_size.x)
, m_height(default_rt_size.y)
, m_tc(new GSTextureCache())
, m_src(nullptr)
, m_reset(false)
, m_tex_is_fb(false)
, m_channel_shuffle(false)
, m_userhacks_tcoffset(false)
, m_userhacks_tcoffset_x(0)
@ -50,7 +50,7 @@ GSRendererHW::GSRendererHW()
ResetStates();
}
void GSRendererHW::SetScaling()
GSVector2i GSRendererHW::GetOutputSize(int real_h)
{
GSVector2i crtc_size(GetResolution());
@ -90,63 +90,10 @@ void GSRendererHW::SetScaling()
}
}
// Details of (potential) perf impact of a big framebuffer
// 1/ extra memory
// 2/ texture cache framebuffer rescaling/copy
// 3/ upload of framebuffer (preload hack)
// 4/ framebuffer clear (color/depth/stencil)
// 5/ read back of the frambuffer
//
// With the solution
// 1/ Nothing to do.Except the texture cache bug (channel shuffle effect)
// most of the market is 1GB of VRAM (and soon 2GB)
// 2/ limit rescaling/copy to the valid data of the framebuffer
// 3/ ??? no solution so far
// 4a/ stencil can be limited to valid data.
// 4b/ is it useful to clear color? depth? (in any case, it ought to be few operation)
// 5/ limit the read to the valid data
// Include negative display offsets in the height here.
crtc_size.y = std::max(crtc_size.y, real_h);
// Framebuffer width is always a multiple of 64 so at certain cases it can't cover some weird width values.
// 480P , 576P use width as 720 which is not referencable by FBW * 64. so it produces 704 ( the closest value multiple by 64).
// In such cases, let's just use the CRTC width.
const int fb_width = std::max({(int)m_context->FRAME.FBW * 64, crtc_size.x, 512});
// GS doesn't have a specific register for the FrameBuffer height. so we get the height
// from physical units of the display rectangle in case the game uses a heigher value of height.
//
// Gregory: the framebuffer must have enough room to draw
// * at least 2 frames such as FMV (see OI_BlitFMV)
// * high resolution game such as snowblind engine game
//
// Autodetection isn't a good idea because it will create flickering
// If memory consumption is an issue, there are 2 possibilities
// * 1/ Avoid to create hundreds of RT
// * 2/ Use sparse texture (requires recent HW)
//
// Avoid to alternate between 640x1280 and 1280x1024 on snow blind engine game
// int fb_height = (fb_width < 1024) ? 1280 : 1024;
//
// Until performance issue is properly fixed, let's keep an option to reduce the framebuffer size.
//
// m_large_framebuffer has been inverted to m_conservative_framebuffer, it isn't an option that benefits being enabled all the time for everyone.
int fb_height = MAX_FRAMEBUFFER_HEIGHT;
if (GSConfig.ConservativeFramebuffer)
{
fb_height = fb_width < 1024 ? std::max(512, crtc_size.y) : 1024;
}
const int upscaled_fb_w = fb_width * GSConfig.UpscaleMultiplier;
const int upscaled_fb_h = fb_height * GSConfig.UpscaleMultiplier;
const bool good_rt_size = m_width >= upscaled_fb_w && m_height >= upscaled_fb_h;
// No need to resize for native/custom resolutions as default size will be enough for native and we manually get RT Buffer size for custom.
// don't resize until the display rectangle and register states are stabilized.
if (good_rt_size)
return;
m_tc->RemovePartial();
m_width = upscaled_fb_w;
m_height = upscaled_fb_h;
printf("Frame buffer size set to %dx%d (%dx%d)\n", fb_width, fb_height, m_width, m_height);
return crtc_size * GSVector2i(static_cast<int>(GSConfig.UpscaleMultiplier), static_cast<int>(GSConfig.UpscaleMultiplier));
}
void GSRendererHW::SetTCOffset()
@ -174,10 +121,42 @@ void GSRendererHW::PurgeTextureCache()
m_tc->RemoveAll();
}
bool GSRendererHW::IsPossibleTextureShuffle(GSTextureCache::Source* src) const
bool GSRendererHW::UpdateTexIsFB(GSTextureCache::Target* dst, const GIFRegTEX0& TEX0)
{
if (GSConfig.AccurateBlendingUnit == AccBlendLevel::Minimum || !g_gs_device->Features().texture_barrier)
return false;
// Texture is actually the frame buffer. Stencil emulation to compute shadow (Jak series/tri-ace game)
// Will hit the "m_ps_sel.tex_is_fb = 1" path in the draw
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
{
if (m_context->FRAME.FBMSK == 0x00FFFFFF && TEX0.TBP0 == m_context->FRAME.Block())
m_tex_is_fb = true;
}
else if (m_vt.m_primclass == GS_SPRITE_CLASS)
{
if (TEX0.TBP0 == m_context->FRAME.Block())
{
m_tex_is_fb = IsPossibleTextureShuffle(dst, TEX0);
if (!m_tex_is_fb && !m_vt.IsLinear())
{
// Make sure that we're not sampling away from the area we're rendering.
// We need to take the absolute here, because Beyond Good and Evil undithers itself using a -1,-1 offset.
const GSVector4 diff(m_vt.m_min.p.xyxy(m_vt.m_max.p) - m_vt.m_min.t.xyxy(m_vt.m_max.t));
if ((diff.abs() < GSVector4(1.0f)).alltrue())
m_tex_is_fb = true;
}
}
}
return m_tex_is_fb;
}
bool GSRendererHW::IsPossibleTextureShuffle(GSTextureCache::Target* dst, const GIFRegTEX0& TEX0) const
{
return (PRIM->TME && m_vt.m_primclass == GS_SPRITE_CLASS &&
src->m_32_bits_fmt && GSLocalMemory::m_psm[src->m_TEX0.PSM].bpp == 16 &&
dst->m_32_bits_fmt && GSLocalMemory::m_psm[TEX0.PSM].bpp == 16 &&
GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp == 16);
}
@ -192,11 +171,6 @@ void GSRendererHW::SetGameCRC(u32 crc, int options)
bool GSRendererHW::CanUpscale()
{
if (m_hacks.m_cu && !(this->*m_hacks.m_cu)())
{
return false;
}
return GSConfig.UpscaleMultiplier != 1;
}
@ -227,20 +201,12 @@ void GSRendererHW::VSync(u32 field, bool registers_written)
if (m_reset)
{
m_tc->RemoveAll();
// Reset RT size.
m_width = default_rt_size.x;
m_height = default_rt_size.y;
m_reset = false;
}
if (GSConfig.LoadTextureReplacements)
GSTextureReplacements::ProcessAsyncLoadedTextures();
//Check if the frame buffer width or display width has changed
SetScaling();
GSRenderer::VSync(field, registers_written);
m_tc->IncAge();
@ -286,7 +252,7 @@ GSTexture* GSRendererHW::GetOutput(int i, int& y_offset)
GSTexture* t = NULL;
if (GSTextureCache::Target* rt = m_tc->LookupTarget(TEX0, GetTargetSize(), fb_height))
if (GSTextureCache::Target* rt = m_tc->LookupDisplayTarget(TEX0, GetOutputSize(fb_height), fb_height))
{
t = rt->m_texture;
@ -321,7 +287,8 @@ GSTexture* GSRendererHW::GetFeedbackOutput()
TEX0.TBW = m_regs->EXTBUF.EXBW;
TEX0.PSM = m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPFB.PSM;
GSTextureCache::Target* rt = m_tc->LookupTarget(TEX0, GetTargetSize(), /*GetFrameRect(i).bottom*/ m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPLAY.DH);
const int fb_height = /*GetFrameRect(i).bottom*/ m_regs->DISP[m_regs->EXTBUF.FBIN & 1].DISPLAY.DH;
GSTextureCache::Target* rt = m_tc->LookupDisplayTarget(TEX0, GetOutputSize(fb_height), fb_height);
GSTexture* t = rt->m_texture;
@ -763,35 +730,41 @@ void GSRendererHW::MergeSprite(GSTextureCache::Source* tex)
}
}
GSVector2 GSRendererHW::GetTextureScaleFactor(const bool force_upscaling)
{
GSVector2 scale_factor{ 1.0f, 1.0f };
if (force_upscaling || CanUpscale())
{
const int multiplier = GetUpscaleMultiplier();
scale_factor.x = multiplier;
scale_factor.y = multiplier;
}
return scale_factor;
}
GSVector2 GSRendererHW::GetTextureScaleFactor()
{
return GetTextureScaleFactor(false);
const float f_upscale = static_cast<float>(GetUpscaleMultiplier());
return GSVector2(f_upscale, f_upscale);
}
GSVector2i GSRendererHW::GetTargetSize()
{
const GSVector2i t_size = { m_width, m_height };
if (GetUpscaleMultiplier() == 1 || CanUpscale())
return t_size;
// Undo the upscaling for native resolution draws.
const GSVector2 up_s = GetTextureScaleFactor(true);
return {
static_cast<int>(std::ceil(static_cast<float>(t_size.x) / up_s.x)),
static_cast<int>(std::ceil(static_cast<float>(t_size.y) / up_s.y)),
};
// Don't blindly expand out to the scissor size if we're not drawing to it.
// e.g. Burnout 3, God of War II, etc.
u32 min_height = std::min<u32>(m_context->scissor.in.w, m_r.w);
// Another thing these games like to do, is draw a 512x896 shuffle, which would result in us
// expanding the target out to 896 height, but the extra area would all be black, with the
// draw effectively changing nothing for the new area. So, instead, lets try to detect these
// draws by double-checking we're not stretching the texture (gradient of <1).
if (PRIM->TME && m_vt.m_primclass == GS_SPRITE_CLASS && m_src && (m_src->m_target || m_src->m_from_target))
{
const float diff = std::abs((m_vt.m_max.p.y - m_vt.m_min.p.y) - (m_vt.m_max.t.y - m_vt.m_min.t.y));
if (diff <= 1.0f)
{
// Clamp to the texture size. We're working in unscaled coordinates here, so undo the upscaling.
min_height = std::min(min_height, static_cast<u32>(static_cast<float>(m_src->m_texture->GetHeight()) / m_src->m_texture->GetScale().y));
}
}
// Align to even lines, reduces the chance of tiny resizes.
min_height = Common::AlignUpPow2(min_height, 2);
const u32 width = m_context->FRAME.FBW * 64u;
const u32 height = m_tc->GetTargetHeight(m_context->FRAME.FBP, m_context->FRAME.FBW, m_context->FRAME.PSM, min_height);
GL_INS("Target size for %x %u %u: %ux%u", m_context->FRAME.FBP, m_context->FRAME.FBW, m_context->FRAME.PSM, width, height);
return GSVector2i(static_cast<int>(width * GSConfig.UpscaleMultiplier), static_cast<int>(height * GSConfig.UpscaleMultiplier));
}
void GSRendererHW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r)
@ -1380,6 +1353,7 @@ void GSRendererHW::Draw()
m_src = nullptr;
m_texture_shuffle = false;
m_tex_is_fb = false;
if (PRIM->TME)
{
@ -1605,6 +1579,8 @@ void GSRendererHW::Draw()
}
}
// The rectangle of the draw
m_r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(context->scissor.in));
const GSVector2i t_size = GetTargetSize();
TEX0.TBP0 = context->FRAME.Block();
@ -1612,24 +1588,16 @@ void GSRendererHW::Draw()
TEX0.PSM = context->FRAME.PSM;
GSTextureCache::Target* rt = nullptr;
GSTexture* rt_tex = nullptr;
if (!no_rt)
{
rt = m_tc->LookupTarget(TEX0, t_size, GSTextureCache::RenderTarget, true, fm);
rt_tex = rt->m_texture;
}
TEX0.TBP0 = context->ZBUF.Block();
TEX0.TBW = context->FRAME.FBW;
TEX0.PSM = context->ZBUF.PSM;
GSTextureCache::Target* ds = nullptr;
GSTexture* ds_tex = nullptr;
if (!no_ds)
{
ds = m_tc->LookupTarget(TEX0, t_size, GSTextureCache::DepthStencil, context->DepthWrite());
ds_tex = ds->m_texture;
}
if (rt)
{
@ -1639,38 +1607,24 @@ void GSRendererHW::Draw()
rt->m_32_bits_fmt = m_texture_shuffle || (GSLocalMemory::m_psm[context->FRAME.PSM].bpp != 16);
}
// The rectangle of the draw
m_r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(context->scissor.in));
{
const GSVector2 up_s = GetTextureScaleFactor();
const int up_w = static_cast<int>(std::ceil(static_cast<float>(m_r.z) * up_s.x));
const int up_h = static_cast<int>(std::ceil(static_cast<float>(m_r.w) * up_s.y));
const int new_w = std::max(up_w, std::max(rt_tex ? rt_tex->GetWidth() : 0, ds_tex ? ds_tex->GetWidth() : 0));
const int new_h = std::max(up_h, std::max(rt_tex ? rt_tex->GetHeight() : 0, ds_tex ? ds_tex->GetHeight() : 0));
std::array<GSTextureCache::Target*, 2> ts{ rt, ds };
for (GSTextureCache::Target* t : ts)
// We still need to make sure the dimensions of the targets match.
const GSVector2 up_s(GetTextureScaleFactor());
const int new_w = std::max(t_size.x, std::max(rt ? rt->m_texture->GetWidth() : 0, ds ? ds->m_texture->GetWidth() : 0));
const int new_h = std::max(t_size.y, std::max(rt ? rt->m_texture->GetHeight() : 0, ds ? ds->m_texture->GetHeight() : 0));
// Ensure draw rect is clamped to framebuffer size. Necessary for updating valid area.
m_r = m_r.rintersect(GSVector4i(0, 0, new_w, new_h));
if (rt)
{
if (t)
{
// Adjust texture size to fit current draw if necessary.
GSTexture* tex = t->m_texture;
assert(up_s == tex->GetScale());
const int w = tex->GetWidth();
const int h = tex->GetHeight();
if (w != new_w || h != new_h)
{
const bool is_rt = t == rt;
t->m_texture = is_rt ?
g_gs_device->CreateSparseRenderTarget(new_w, new_h, tex->GetFormat()) :
g_gs_device->CreateSparseDepthStencil(new_w, new_h, tex->GetFormat());
const GSVector4i r{ 0, 0, w, h };
g_gs_device->CopyRect(tex, t->m_texture, r, 0, 0);
g_gs_device->Recycle(tex);
t->m_texture->SetScale(up_s);
(is_rt ? rt_tex : ds_tex) = t->m_texture;
}
}
pxAssert(rt->m_texture->GetScale() == up_s);
rt->ResizeTexture(new_w, new_h, up_s);
}
if (ds)
{
pxAssert(ds->m_texture->GetScale() == up_s);
ds->ResizeTexture(new_w, new_h, up_s);
}
}
@ -1704,24 +1658,24 @@ void GSRendererHW::Draw()
}
}
if (s_save && s_n >= s_saven)
if (rt && s_save && s_n >= s_saven)
{
s = StringUtil::StdStringFromFormat("%05d_f%lld_rt0_%05x_%s.bmp", s_n, frame, context->FRAME.Block(), psm_str(context->FRAME.PSM));
if (rt_tex)
rt_tex->Save(m_dump_root + s);
if (rt->m_texture)
rt->m_texture->Save(m_dump_root + s);
}
if (s_savez && s_n >= s_saven)
if (ds && s_savez && s_n >= s_saven)
{
s = StringUtil::StdStringFromFormat("%05d_f%lld_rz0_%05x_%s.bmp", s_n, frame, context->ZBUF.Block(), psm_str(context->ZBUF.PSM));
if (ds_tex)
ds_tex->Save(m_dump_root + s);
if (ds->m_texture)
ds->m_texture->Save(m_dump_root + s);
}
}
if (m_hacks.m_oi && !(this->*m_hacks.m_oi)(rt_tex, ds_tex, m_src))
if (m_hacks.m_oi && !(this->*m_hacks.m_oi)(rt ? rt->m_texture : nullptr, ds ? ds->m_texture : nullptr, m_src))
{
GL_INS("Warning skipping a draw call (%d)", s_n);
return;
@ -1746,7 +1700,7 @@ void GSRendererHW::Draw()
OI_GsMemClear();
OI_DoubleHalfClear(rt_tex, ds_tex);
OI_DoubleHalfClear(rt, ds);
}
}
@ -1801,7 +1755,7 @@ void GSRendererHW::Draw()
//
DrawPrims(rt_tex, ds_tex, m_src);
DrawPrims(rt ? rt->m_texture : nullptr, ds ? ds->m_texture : nullptr, m_src);
//
@ -1853,16 +1807,16 @@ void GSRendererHW::Draw()
{
s = StringUtil::StdStringFromFormat("%05d_f%lld_rt1_%05x_%s.bmp", s_n, frame, context->FRAME.Block(), psm_str(context->FRAME.PSM));
if (rt_tex)
rt_tex->Save(m_dump_root + s);
if (rt)
rt->m_texture->Save(m_dump_root + s);
}
if (s_savez && s_n >= s_saven)
{
s = StringUtil::StdStringFromFormat("%05d_f%lld_rz1_%05x_%s.bmp", s_n, frame, context->ZBUF.Block(), psm_str(context->ZBUF.PSM));
if (ds_tex)
ds_tex->Save(m_dump_root + s);
if (ds)
rt->m_texture->Save(m_dump_root + s);
}
if (s_savel > 0 && (s_n - s_saven) > s_savel)
@ -2336,21 +2290,8 @@ void GSRendererHW::EmulateChannelShuffle(const GSTextureCache::Source* tex)
m_conf.tex = *tex->m_from_target;
if (m_conf.tex)
{
if (m_conf.tex == m_conf.rt)
{
// sample from fb instead
m_conf.tex = nullptr;
m_conf.ps.tex_is_fb = true;
m_conf.require_one_barrier = true;
}
else if (m_conf.tex == m_conf.ds)
{
// if depth testing is disabled, we don't need to copy, and can just unbind the depth buffer
// no need for a barrier for GL either, since it's not bound to depth and texture concurrently
// otherwise, the backend should recognise the hazard, and copy the buffer (D3D/Vulkan).
if (m_conf.depth.ztst == ZTST_ALWAYS)
m_conf.ds = nullptr;
}
// Identify when we're sampling the current buffer, defer fixup for later.
m_tex_is_fb |= (m_conf.tex == m_conf.rt || m_conf.tex == m_conf.ds);
}
// Replace current draw with a fullscreen sprite
@ -3150,6 +3091,41 @@ void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Source* tex)
if (!m_channel_shuffle)
m_conf.tex = tex->m_texture;
m_conf.pal = tex->m_palette;
// Detect framebuffer read that will need special handling
if (m_tex_is_fb)
{
if (m_conf.tex == m_conf.rt)
{
// This pattern is used by several games to emulate a stencil (shadow)
// Ratchet & Clank, Jak do alpha integer multiplication (tfx) which is mostly equivalent to +1/-1
// Tri-Ace (Star Ocean 3/RadiataStories/VP2) uses a palette to handle the +1/-1
GL_DBG("Source and Target are the same! Let's sample the framebuffer");
m_conf.tex = nullptr;
m_conf.ps.tex_is_fb = true;
if (m_prim_overlap == PRIM_OVERLAP_NO || !g_gs_device->Features().texture_barrier)
m_conf.require_one_barrier = true;
else
m_conf.require_full_barrier = true;
}
else if (m_conf.tex == m_conf.ds)
{
// if depth testing is disabled, we don't need to copy, and can just unbind the depth buffer
// no need for a barrier for GL either, since it's not bound to depth and texture concurrently
// otherwise, the backend should recognise the hazard, and copy the buffer (D3D/Vulkan).
if (m_conf.depth.ztst == ZTST_ALWAYS)
{
m_conf.ds = nullptr;
m_tex_is_fb = false;
}
}
else
{
// weird... we detected a fb read, but didn't end up using it?
DevCon.WriteLn("Tex-is-FB set but not used?");
m_tex_is_fb = false;
}
}
}
void GSRendererHW::EmulateATST(float& AREF, GSHWDrawConfig::PSSelector& ps, bool pass_2)
@ -3217,10 +3193,6 @@ void GSRendererHW::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
area_out.x, area_out.y, area_out.z, area_out.w);
#endif
const GSVector2i& rtsize = ds ? ds->GetSize() : rt->GetSize();
const GSVector2& rtscale = ds ? ds->GetScale() : rt->GetScale();
const GSDevice::FeatureSupport features(g_gs_device->Features());
const bool DATE = m_context->TEST.DATE && m_context->FRAME.PSM != PSM_PSMCT24;
bool DATE_PRIMID = false;
bool DATE_BARRIER = false;
@ -3250,32 +3222,12 @@ void GSRendererHW::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
// Upscaling hack to avoid various line/grid issues
MergeSprite(tex);
const GSDevice::FeatureSupport features(g_gs_device->Features());
if (!features.framebuffer_fetch)
m_prim_overlap = PrimitiveOverlap();
else
m_prim_overlap = PRIM_OVERLAP_UNKNOW;
// Detect framebuffer read that will need special handling
if (features.texture_barrier && (m_context->FRAME.Block() == m_context->TEX0.TBP0) && PRIM->TME && GSConfig.AccurateBlendingUnit != AccBlendLevel::Minimum)
{
const u32 fb_mask = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk;
if (((m_context->FRAME.FBMSK & fb_mask) == (fb_mask & 0x00FFFFFF)) && (m_vt.m_primclass == GS_TRIANGLE_CLASS))
{
// This pattern is used by several games to emulate a stencil (shadow)
// Ratchet & Clank, Jak do alpha integer multiplication (tfx) which is mostly equivalent to +1/-1
// Tri-Ace (Star Ocean 3/RadiataStories/VP2) uses a palette to handle the +1/-1
GL_DBG("Source and Target are the same! Let's sample the framebuffer");
m_conf.ps.tex_is_fb = 1;
m_conf.require_full_barrier = !features.framebuffer_fetch;
}
else if (m_prim_overlap != PRIM_OVERLAP_NO)
{
// Note: It is fine if the texture fits in a single GS page. First access will cache
// the page in the GS texture buffer.
GL_INS("ERROR: Source and Target are the same!");
}
}
EmulateTextureShuffleAndFbmask();
// DATE: selection of the algorithm. Must be done before blending because GL42 is not compatible with blending
@ -3418,6 +3370,8 @@ void GSRendererHW::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
m_conf.vs.fst = PRIM->FST;
// FIXME D3D11 and GL support half pixel center. Code could be easier!!!
const GSVector2i rtsize(m_conf.ds ? m_conf.ds->GetSize() : m_conf.rt->GetSize());
const GSVector2 rtscale(m_conf.ds ? m_conf.ds->GetScale() : m_conf.rt->GetScale());
const float sx = 2.0f * rtscale.x / (rtsize.x << 4);
const float sy = 2.0f * rtscale.y / (rtsize.y << 4);
const float ox = (float)(int)m_context->XYOFFSET.OFX;
@ -3471,7 +3425,7 @@ void GSRendererHW::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
if (m_conf.ps.dither)
{
GL_DBG("DITHERING mode ENABLED (%d)", m_dithering);
GL_DBG("DITHERING mode ENABLED (%d)", GSConfig.Dithering);
m_conf.ps.dither = GSConfig.Dithering;
m_conf.cb_ps.DitherMatrix[0] = GSVector4(m_env.DIMX.DM00, m_env.DIMX.DM01, m_env.DIMX.DM02, m_env.DIMX.DM03);
@ -3601,12 +3555,6 @@ void GSRendererHW::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
SetupIA(sx, sy);
if (rt)
rt->CommitRegion(GSVector2i(m_conf.drawarea.z, m_conf.drawarea.w));
if (ds)
ds->CommitRegion(GSVector2i(m_conf.drawarea.z, m_conf.drawarea.w));
m_conf.alpha_second_pass.enable = ate_second_pass;
if (ate_second_pass)
@ -3722,13 +3670,6 @@ void GSRendererHW::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc
g_gs_device->RenderHW(m_conf);
}
bool GSRendererHW::IsDummyTexture() const
{
// Texture is actually the frame buffer. Stencil emulation to compute shadow (Jak series/tri-ace game)
// Will hit the "m_ps_sel.tex_is_fb = 1" path in the draw
return g_gs_device->Features().texture_barrier && (m_context->FRAME.Block() == m_context->TEX0.TBP0) && PRIM->TME && GSConfig.AccurateBlendingUnit != AccBlendLevel::Minimum && m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_context->FRAME.FBMSK == 0x00FFFFFF);
}
bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_tex)
{
// Master enable.
@ -4177,10 +4118,8 @@ bool GSRendererHW::SwPrimRender()
GSRendererHW::Hacks::Hacks()
: m_oi_map(m_oi_list)
, m_oo_map(m_oo_list)
, m_cu_map(m_cu_list)
, m_oi(NULL)
, m_oo(NULL)
, m_cu(NULL)
{
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::BigMuthaTruckers, CRC::RegionCount, &GSRendererHW::OI_BigMuthaTruckers));
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::DBZBT2, CRC::RegionCount, &GSRendererHW::OI_DBZBTGames));
@ -4206,7 +4145,6 @@ void GSRendererHW::Hacks::SetGameCRC(const CRC::Game& game)
m_oi = m_oi_map[hash];
m_oo = m_oo_map[hash];
m_cu = m_cu_map[hash];
if (GSConfig.PointListPalette)
{
@ -4220,7 +4158,7 @@ void GSRendererHW::Hacks::SetGameCRC(const CRC::Game& game)
// Trick to do a fast clear on the GS
// Set frame buffer pointer on the start of the buffer. Set depth buffer pointer on the half buffer
// FB + depth write will fill the full buffer.
void GSRendererHW::OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds)
void GSRendererHW::OI_DoubleHalfClear(GSTextureCache::Target*& rt, GSTextureCache::Target*& ds)
{
// Note gs mem clear must be tested before calling this function
@ -4266,20 +4204,35 @@ void GSRendererHW::OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds)
GL_INS("OI_DoubleHalfClear:%s: base %x half %x. w_pages %d h_pages %d fbw %d. Color %x",
clear_depth ? "depth" : "target", base << 5, half << 5, w_pages, h_pages, m_context->FRAME.FBW, color);
// Commit texture with a factor 2 on the height
GSTexture* t = clear_depth ? ds : rt;
const GSVector4i commitRect = ComputeBoundingBox(t->GetScale(), t->GetSize());
t->CommitRegion(GSVector2i(commitRect.z, 2 * commitRect.w));
// Handle the case where the game stacks FBP and ZBP immediately after one another.
// We incorrectly compute the height here, because both the scissor and draw rectangle will only be half
// the height of what's effectively being cleared. Spider-Man 2's shadows are a good test case here: it
// draws the shadow map to a 128x128 texture, but relies on a 1 pixel border around the edge to "cut off"
// the shadows. We cap it to a 256 height, because having a >=512 height framebuffer is very rare, and it
// stops us doubling actual framebuffers unintentionally (very common).
GSTextureCache::Target* t = clear_depth ? ds : rt;
const u32 unscaled_height = static_cast<u32>(static_cast<float>(t->m_texture->GetHeight()) / t->m_texture->GetScale().y);
if (unscaled_height == m_context->scissor.in.w && unscaled_height <= 256)
{
t->ResizeTexture(t->m_texture->GetWidth(), t->m_texture->GetHeight() * 2, t->m_texture->GetScale());
if (clear_depth)
rt = nullptr;
else
ds = nullptr;
// Feed it back into the height cache.
m_tc->GetTargetHeight(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, unscaled_height * 2);
}
if (clear_depth)
{
// Only pure clear are supported for depth
ASSERT(color == 0);
g_gs_device->ClearDepth(t);
g_gs_device->ClearDepth(ds->m_texture);
}
else
{
g_gs_device->ClearRenderTarget(t, color);
g_gs_device->ClearRenderTarget(rt->m_texture, color);
}
}
}
@ -4295,10 +4248,7 @@ void GSRendererHW::OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds)
// If both buffers are side by side we can expect a fast clear in on-going
const u32 color = v[1].RGBAQ.U32[0];
const GSVector4i commitRect = ComputeBoundingBox(rt->GetScale(), rt->GetSize());
rt->CommitRegion(GSVector2i(commitRect.z, commitRect.w));
g_gs_device->ClearRenderTarget(rt, color);
g_gs_device->ClearRenderTarget(rt->m_texture, color);
}
}
@ -4582,8 +4532,6 @@ bool GSRendererHW::OI_FFX(GSTexture* rt, GSTexture* ds, GSTextureCache::Source*
{
// random battle transition (z buffer written directly, clear it now)
GL_INS("OI_FFX ZB clear");
if (ds)
ds->Commit(); // Don't bother to save few MB for a single game
g_gs_device->ClearDepth(ds);
}
@ -4635,7 +4583,6 @@ bool GSRendererHW::OI_RozenMaidenGebetGarden(GSTexture* rt, GSTexture* ds, GSTex
if (GSTextureCache::Target* tmp_rt = m_tc->LookupTarget(TEX0, GetTargetSize(), GSTextureCache::RenderTarget, true))
{
GL_INS("OI_RozenMaidenGebetGarden FB clear");
tmp_rt->m_texture->Commit(); // Don't bother to save few MB for a single game
g_gs_device->ClearRenderTarget(tmp_rt->m_texture, 0);
}
@ -4654,7 +4601,6 @@ bool GSRendererHW::OI_RozenMaidenGebetGarden(GSTexture* rt, GSTexture* ds, GSTex
if (GSTextureCache::Target* tmp_ds = m_tc->LookupTarget(TEX0, GetTargetSize(), GSTextureCache::DepthStencil, true))
{
GL_INS("OI_RozenMaidenGebetGarden ZB clear");
tmp_ds->m_texture->Commit(); // Don't bother to save few MB for a single game
g_gs_device->ClearDepth(tmp_ds->m_texture);
}
@ -4689,12 +4635,14 @@ bool GSRendererHW::OI_SonicUnleashed(GSTexture* rt, GSTexture* ds, GSTextureCach
GL_INS("OI_SonicUnleashed replace draw by a copy");
GSTextureCache::Target* src = m_tc->LookupTarget(Texture, GetTargetSize(), GSTextureCache::RenderTarget, true);
GSTextureCache::Target* src = m_tc->LookupTarget(Texture, GSVector2i(1, 1), GSTextureCache::RenderTarget, true);
const GSVector2i size = rt->GetSize();
const GSVector2i rt_size(rt->GetSize());
const GSVector2i src_size(src->m_texture->GetSize());
const GSVector2i copy_size(std::min(rt_size.x, src_size.x), std::min(rt_size.y, src_size.y));
const GSVector4 sRect(0, 0, 1, 1);
const GSVector4 dRect(0, 0, size.x, size.y);
const GSVector4 sRect(0.0f, 0.0f, static_cast<float>(copy_size.x) / static_cast<float>(src_size.x), static_cast<float>(copy_size.y) / static_cast<float>(src_size.y));
const GSVector4 dRect(0, 0, copy_size.x, copy_size.y);
g_gs_device->StretchRect(src->m_texture, sRect, rt, dRect, true, true, true, false);
@ -4772,8 +4720,6 @@ bool GSRendererHW::OI_SuperManReturns(GSTexture* rt, GSTexture* ds, GSTextureCac
ASSERT((v->RGBAQ.A << 24 | v->RGBAQ.B << 16 | v->RGBAQ.G << 8 | v->RGBAQ.R) == (int)v->XYZ.Z);
// Do a direct write
if (rt)
rt->Commit(); // Don't bother to save few MB for a single game
g_gs_device->ClearRenderTarget(rt, GSVector4(m_vt.m_min.c));
m_tc->InvalidateVideoMemType(GSTextureCache::DepthStencil, ctx->FRAME.Block());
@ -4810,8 +4756,6 @@ bool GSRendererHW::OI_ArTonelico2(GSTexture* rt, GSTexture* ds, GSTextureCache::
if (m_vertex.next == 2 && !PRIM->TME && m_context->FRAME.FBW == 10 && v->XYZ.Z == 0 && m_context->TEST.ZTST == ZTST_ALWAYS)
{
GL_INS("OI_ArTonelico2");
if (ds)
ds->Commit(); // Don't bother to save few MB for a single game
g_gs_device->ClearDepth(ds);
}

View File

@ -29,9 +29,6 @@ public:
static constexpr int MAX_FRAMEBUFFER_HEIGHT = 1280;
private:
int m_width;
int m_height;
static constexpr float SSR_UV_TOLERANCE = 1.0f;
#pragma region hacks
@ -43,7 +40,7 @@ private:
// Require special argument
bool OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Source* t, const GSVector4i& r_draw);
void OI_GsMemClear(); // always on
void OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds); // always on
void OI_DoubleHalfClear(GSTextureCache::Target*& rt, GSTextureCache::Target*& ds); // always on
bool OI_BigMuthaTruckers(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
bool OI_DBZBTGames(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
@ -108,16 +105,13 @@ private:
std::list<HackEntry<OI_Ptr>> m_oi_list;
std::list<HackEntry<OO_Ptr>> m_oo_list;
std::list<HackEntry<CU_Ptr>> m_cu_list;
FunctionMap<OI_Ptr> m_oi_map;
FunctionMap<OO_Ptr> m_oo_map;
FunctionMap<CU_Ptr> m_cu_map;
public:
OI_Ptr m_oi;
OO_Ptr m_oo;
CU_Ptr m_cu;
Hacks();
@ -157,6 +151,7 @@ private:
GSTextureCache::Source* m_src;
bool m_reset;
bool m_tex_is_fb;
bool m_channel_shuffle;
bool m_userhacks_tcoffset;
float m_userhacks_tcoffset_x;
@ -183,15 +178,14 @@ public:
void SetGameCRC(u32 crc, int options) override;
bool CanUpscale() override;
int GetUpscaleMultiplier() override;
void SetScaling();
void Lines2Sprites();
void EmulateAtst(GSVector4& FogColor_AREF, u8& atst, const bool pass_2);
void ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba);
GSVector4 RealignTargetTextureCoordinate(const GSTextureCache::Source* tex);
GSVector4i ComputeBoundingBox(const GSVector2& rtscale, const GSVector2i& rtsize);
void MergeSprite(GSTextureCache::Source* tex);
GSVector2 GetTextureScaleFactor(const bool force_upscaling);
GSVector2 GetTextureScaleFactor() override;
GSVector2i GetOutputSize(int real_h);
GSVector2i GetTargetSize();
void Reset(bool hardware_reset) override;
@ -208,8 +202,8 @@ public:
void PurgeTextureCache() override;
// Called by the texture cache to know if current texture is useful
bool IsDummyTexture() const;
bool UpdateTexIsFB(GSTextureCache::Target* src, const GIFRegTEX0& TEX0);
// Called by the texture cache when optimizing the copy range for sources
bool IsPossibleTextureShuffle(GSTextureCache::Source* src) const;
bool IsPossibleTextureShuffle(GSTextureCache::Target* dst, const GIFRegTEX0& TEX0) const;
};

View File

@ -83,6 +83,7 @@ void GSTextureCache::RemoveAll()
m_hash_cache_memory_usage = 0;
m_palette_map.Clear();
m_target_heights.clear();
}
GSTextureCache::Source* GSTextureCache::LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, bool palette)
@ -416,7 +417,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask, const bool is_frame, const int real_h)
{
const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM];
const GSVector2& new_s = g_gs_renderer->GetTextureScaleFactor();
const GSVector2& new_s = static_cast<GSRendererHW*>(g_gs_renderer.get())->GetTextureScaleFactor();
const u32 bp = TEX0.TBP0;
GSVector2 res_size{ 0, 0 };
GSVector2i new_size{ 0, 0 };
@ -468,6 +469,9 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
{
dst = t;
GL_CACHE("TC: Lookup Frame %dx%d, perfect hit: %d (0x%x -> 0x%x %s)", size.x, size.y, dst->m_texture->GetID(), bp, t->m_end_block, psm_str(TEX0.PSM));
if (real_h > 0)
ScaleTargetForDisplay(dst, TEX0, real_h);
break;
}
}
@ -517,8 +521,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
if (new_s != old_s)
{
calcRescale(dst->m_texture);
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateSparseRenderTarget(new_size.x, new_size.y, GSTexture::Format::Color, clear) :
g_gs_device->CreateSparseDepthStencil(new_size.x, new_size.y, GSTexture::Format::DepthStencil, clear);
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_size.x, new_size.y, GSTexture::Format::Color, clear) :
g_gs_device->CreateDepthStencil(new_size.x, new_size.y, GSTexture::Format::DepthStencil, clear);
g_gs_device->StretchRect(dst->m_texture, sRect, tex, dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false);
g_gs_device->Recycle(dst->m_texture);
tex->SetScale(new_s);
@ -619,7 +623,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
return dst;
}
GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h)
GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h)
{
return LookupTarget(TEX0, size, RenderTarget, true, 0, true, real_h);
}
@ -675,6 +679,9 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb,
// We unconditionally preload the frame here, because otherwise we'll end up with blackness for one frame (when the expand happens).
t->m_dirty.push_back(GSDirtyRect(GSVector4i(0, 0, t->m_TEX0.TBW * 64, needed_height), t->m_TEX0.PSM, t->m_TEX0.TBW));
// Inject the new height back into the cache.
GetTargetHeight(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, static_cast<u32>(needed_height));
}
// Goal: Depth And Target at the same address is not possible. On GS it is
@ -1187,6 +1194,20 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
const int scaled_w = static_cast<int>(w * scale.x);
const int scaled_h = static_cast<int>(h * scale.y);
// Expand the target when we used a more conservative size.
const int required_dh = scaled_dy + scaled_h;
if ((scaled_dx + scaled_w) <= dst->m_texture->GetWidth() && required_dh > dst->m_texture->GetHeight())
{
const int new_height = dy + h;
if (new_height > GSRendererHW::MAX_FRAMEBUFFER_HEIGHT)
return false;
const int scaled_new_height = static_cast<int>(static_cast<float>(new_height) * scale.y);
GL_INS("Resize %dx%d target to %dx%d for move", dst->m_texture->GetWidth(), dst->m_texture->GetHeight(), dst->m_texture->GetHeight(), scaled_new_height);
dst->ResizeTexture(dst->m_texture->GetWidth(), scaled_new_height);
GetTargetHeight(DBP, DBW, DPSM, new_height);
}
// Make sure the copy doesn't go out of bounds (it shouldn't).
if ((scaled_sx + scaled_w) > src->m_texture->GetWidth() || (scaled_sy + scaled_h) > src->m_texture->GetHeight() ||
(scaled_dx + scaled_w) > dst->m_texture->GetWidth() || (scaled_dy + scaled_h) > dst->m_texture->GetHeight())
@ -1230,6 +1251,36 @@ GSTextureCache::Target* GSTextureCache::GetTargetWithSharedBits(u32 BP, u32 PSM)
return nullptr;
}
u32 GSTextureCache::GetTargetHeight(u32 fbp, u32 fbw, u32 psm, u32 min_height)
{
TargetHeightElem search = {};
search.fbp = fbp;
search.fbw = fbw;
search.psm = psm;
search.height = min_height;
for (auto it = m_target_heights.begin(); it != m_target_heights.end(); ++it)
{
TargetHeightElem& elem = const_cast<TargetHeightElem&>(*it);
if (elem.bits == search.bits)
{
if (elem.height < min_height)
{
DbgCon.WriteLn("Expand height at %x %u %u from %u to %u", fbp, fbw, psm, elem.height, min_height);
elem.height = min_height;
}
m_target_heights.MoveFront(it.Index());
elem.age = 0;
return elem.height;
}
}
DbgCon.WriteLn("New height at %x %u %u: %u", fbp, fbw, psm, min_height);
m_target_heights.push_front(search);
return min_height;
}
// Hack: remove Target that are strictly included in current rt. Typically uses for FMV
// For example, game is rendered at 0x800->0x1000, fmv will be uploaded to 0x0->0x2800
// FIXME In theory, we ought to report the data from the sub rt to the main rt. But let's
@ -1345,6 +1396,20 @@ void GSTextureCache::IncAge()
}
}
}
for (auto it = m_target_heights.begin(); it != m_target_heights.end();)
{
TargetHeightElem& elem = const_cast<TargetHeightElem&>(*it);
if (elem.age >= max_rt_age)
{
it = m_target_heights.erase(it);
}
else
{
elem.age++;
++it;
}
}
}
//Fixme: Several issues in here. Not handling depth stencil, pitch conversion doesnt work.
@ -1393,7 +1458,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
AttachPaletteToSource(src, psm.pal, true);
}
}
else if (dst && GSRendererHW::GetInstance()->IsDummyTexture())
else if (dst && GSRendererHW::GetInstance()->UpdateTexIsFB(dst, TEX0))
{
// This shortcut is a temporary solution. It isn't a good solution
// as it won't work with Channel Shuffle/Texture Shuffle pattern
@ -1405,21 +1470,23 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
// Be aware that you can't use StrechRect between BeginScene/EndScene.
// So it could be tricky to put in the middle of the DrawPrims
// Texture is created to keep code compatibility
GSTexture* dTex = g_gs_device->CreateTexture(tw, th, false, GSTexture::Format::Color, true);
// Keep a trace of origin of the texture
src->m_texture = dTex;
src->m_texture = dst->m_texture;
src->m_target = true;
src->m_shared_texture = true;
src->m_from_target = &dst->m_texture;
src->m_from_target_TEX0 = dst->m_TEX0;
src->m_end_block = dst->m_end_block;
src->m_texture->SetScale(dst->m_texture->GetScale());
src->m_32_bits_fmt = dst->m_32_bits_fmt;
// Even if we sample the framebuffer directly we might need the palette
// to handle the format conversion on GPU
if (psm.pal > 0)
AttachPaletteToSource(src, psm.pal, true);
// This will get immediately invalidated.
m_temporary_source = src;
}
else if (dst)
{
@ -1561,7 +1628,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
{
// if it looks like a texture shuffle, we might read up to +/- 8 pixels on either side.
GSVector4 adjusted_src_range(*src_range);
if (GSRendererHW::GetInstance()->IsPossibleTextureShuffle(src))
if (GSRendererHW::GetInstance()->IsPossibleTextureShuffle(dst, TEX0))
adjusted_src_range += GSVector4(-8.0f, 0.0f, 8.0f, 0.0f);
// don't forget to scale the copy range
@ -1575,13 +1642,55 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
}
}
// Don't be fooled by the name. 'dst' is the old target (hence the input)
// 'src' is the new texture cache entry (hence the output)
GSTexture* sTex = dst->m_texture;
GSTexture* dTex = use_texture ?
g_gs_device->CreateTexture(w, h, false, GSTexture::Format::Color, true) :
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, false);
src->m_texture = dTex;
// Assuming everything matches up, instead of copying the target, we can just sample it directly.
// It's the same as doing the copy first, except we save GPU time.
if (!half_right && // not the size change from above
use_texture && // not reinterpreting the RT
w == dst->m_texture->GetWidth() && h == dst->m_texture->GetHeight() && // same dimensions
!m_temporary_source // not the shuffle case above
)
{
// sample the target directly
src->m_texture = dst->m_texture;
src->m_shared_texture = true;
src->m_target = true; // So renderer can check if a conversion is required
src->m_from_target = &dst->m_texture; // avoid complex condition on the renderer
src->m_from_target_TEX0 = dst->m_TEX0;
src->m_32_bits_fmt = dst->m_32_bits_fmt;
src->m_valid_rect = dst->m_valid;
src->m_end_block = dst->m_end_block;
// kill the source afterwards, since we don't want to have to track changes to the target
m_temporary_source = src;
}
else
{
// Don't be fooled by the name. 'dst' is the old target (hence the input)
// 'src' is the new texture cache entry (hence the output)
GSTexture* sTex = dst->m_texture;
GSTexture* dTex = use_texture ?
g_gs_device->CreateTexture(w, h, false, GSTexture::Format::Color, true) :
g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, false);
src->m_texture = dTex;
if (use_texture)
{
g_gs_device->CopyRect(sTex, dTex, sRect, destX, destY);
}
else
{
GSVector4 sRectF(sRect);
sRectF.z /= sTex->GetWidth();
sRectF.w /= sTex->GetHeight();
g_gs_device->StretchRect(sTex, sRectF, dTex, GSVector4(destX, destY, w, h), shader, false);
}
if (src->m_texture)
src->m_texture->SetScale(scale);
else
ASSERT(0);
}
// GH: by default (m_paltex == 0) GS converts texture to the 32 bit format
// However it is different here. We want to reuse a Render Target as a texture.
@ -1591,24 +1700,6 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
AttachPaletteToSource(src, psm.pal, true);
}
if (use_texture)
{
g_gs_device->CopyRect(sTex, dTex, sRect, destX, destY);
}
else
{
GSVector4 sRectF(sRect);
sRectF.z /= sTex->GetWidth();
sRectF.w /= sTex->GetHeight();
g_gs_device->StretchRect(sTex, sRectF, dTex, GSVector4(destX, destY, w, h), shader, false);
}
if (src->m_texture)
src->m_texture->SetScale(scale);
else
ASSERT(0);
// Offset hack. Can be enabled via GS options.
// The offset will be used in Draw().
float modxy = 0.0f;
@ -1813,16 +1904,16 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(const GIFRegTEX0& TEX0, int
if (type == RenderTarget)
{
t->m_texture = g_gs_device->CreateSparseRenderTarget(w, h, GSTexture::Format::Color, clear);
t->m_texture = g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, clear);
t->m_used = true; // FIXME
}
else if (type == DepthStencil)
{
t->m_texture = g_gs_device->CreateSparseDepthStencil(w, h, GSTexture::Format::DepthStencil, clear);
t->m_texture = g_gs_device->CreateDepthStencil(w, h, GSTexture::Format::DepthStencil, clear);
}
t->m_texture->SetScale(g_gs_renderer->GetTextureScaleFactor());
t->m_texture->SetScale(static_cast<GSRendererHW*>(g_gs_renderer.get())->GetTextureScaleFactor());
m_dst[type].push_front(t);
@ -1999,6 +2090,47 @@ bool GSTextureCache::Surface::Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i
return overlap;
}
void GSTextureCache::Surface::ResizeTexture(int new_width, int new_height)
{
ResizeTexture(new_width, new_height, m_texture->GetScale());
}
void GSTextureCache::Surface::ResizeTexture(int new_width, int new_height, GSVector2 new_scale)
{
const int width = m_texture->GetWidth();
const int height = m_texture->GetHeight();
if (width == new_width && height == new_height)
return;
const bool clear = (new_width > width || new_height > height);
GSTexture* tex = m_texture->IsDepthStencil() ?
g_gs_device->CreateDepthStencil(new_width, new_height, m_texture->GetFormat(), clear) :
g_gs_device->CreateRenderTarget(new_width, new_height, m_texture->GetFormat(), clear);
if (!tex)
{
Console.Error("(GSTextureCache::Surface::ResizeTexture) Failed to allocate %dx%d texture", new_width, new_height);
return;
}
tex->SetScale(new_scale);
const GSVector4i rc(0, 0, std::min(width, new_width), std::min(height, new_height));
if (tex->IsDepthStencil())
{
// Can't do partial copies in DirectX for depth textures, and it's probably not ideal in other
// APIs either. So use a fullscreen quad setting depth instead.
g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::DEPTH_COPY, false);
}
else
{
// Fast memcpy()-like path for color targets.
g_gs_device->CopyRect(m_texture, tex, rc, 0, 0);
}
g_gs_device->Recycle(m_texture);
m_texture = tex;
}
// GSTextureCache::Source
GSTextureCache::Source::Source(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, bool dummy_container)
@ -2410,7 +2542,10 @@ void GSTextureCache::Target::UpdateIfDirtyIntersects(const GSVector4i& rc)
void GSTextureCache::Target::UpdateValidity(const GSVector4i& rect)
{
m_valid = m_valid.runion(rect);
if (m_valid.eq(GSVector4i::zero()))
m_valid = rect;
else
m_valid = m_valid.runion(rect);
// Block of the bottom right texel of the validity rectangle, last valid block of the texture
m_end_block = GSLocalMemory::m_psm[m_TEX0.PSM].info.bn(m_valid.z - 1, m_valid.w - 1, m_TEX0.TBP0, m_TEX0.TBW); // Valid only for color formats

View File

@ -92,6 +92,9 @@ public:
void UpdateAge();
bool Inside(u32 bp, u32 bw, u32 psm, const GSVector4i& rect);
bool Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i& rect);
void ResizeTexture(int new_width, int new_height);
void ResizeTexture(int new_width, int new_height, GSVector2 new_scale);
};
struct PaletteKey
@ -243,6 +246,25 @@ public:
void RemoveAt(Source* s);
};
struct TargetHeightElem
{
union
{
u32 bits;
struct
{
u32 fbp : 9;
u32 fbw : 6;
u32 psm : 6;
u32 pad : 11;
};
};
u32 height;
u32 age;
};
struct SurfaceOffsetKeyElem
{
u32 psm;
@ -278,6 +300,7 @@ protected:
std::unordered_map<HashCacheKey, HashCacheEntry, HashCacheKeyHash> m_hash_cache;
u64 m_hash_cache_memory_usage = 0;
FastList<Target*> m_dst[2];
FastList<TargetHeightElem> m_target_heights;
static u8* m_temp;
constexpr static size_t S_SURFACE_OFFSET_CACHE_MAX_SIZE = std::numeric_limits<u16>::max();
std::unordered_map<SurfaceOffsetKey, SurfaceOffset, SurfaceOffsetKeyHash, SurfaceOffsetKeyEqual> m_surface_offset_cache;
@ -286,6 +309,10 @@ protected:
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t = NULL, bool half_right = false, int x_offset = 0, int y_offset = 0, const GSVector2i* lod = nullptr, const GSVector4i* src_range = nullptr);
Target* CreateTarget(const GIFRegTEX0& TEX0, int w, int h, int type, const bool clear);
/// Expands a target when the block pointer for a display framebuffer is within another target, but the read offset
/// plus the height is larger than the current size of the target.
void ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_h);
HashCacheEntry* LookupHashCache(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, bool& paltex, const u32* clut, const GSVector2i* lod);
static void PreloadTexture(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, GSLocalMemory& mem, bool paltex, GSTexture* tex, u32 level);
@ -309,12 +336,14 @@ public:
Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, bool palette = false);
Target* LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask = 0, const bool is_frame = false, const int real_h = 0);
Target* LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h);
Target* LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h);
/// Looks up a target in the cache, and only returns it if the BP/BW/PSM match exactly.
Target* GetExactTarget(u32 BP, u32 BW, u32 PSM) const;
Target* GetTargetWithSharedBits(u32 BP, u32 PSM) const;
u32 GetTargetHeight(u32 fbp, u32 fbw, u32 psm, u32 min_height);
void InvalidateVideoMemType(int type, u32 bp);
void InvalidateVideoMemSubTarget(GSTextureCache::Target* rt);
void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool target = true);
@ -335,10 +364,6 @@ public:
SurfaceOffset ComputeSurfaceOffset(const uint32_t bp, const uint32_t bw, const uint32_t psm, const GSVector4i& r, const Target* t);
SurfaceOffset ComputeSurfaceOffset(const SurfaceOffsetKey& sok);
/// Expands a target when the block pointer for a display framebuffer is within another target, but the read offset
/// plus the height is larger than the current size of the target.
static void ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_h);
/// Invalidates a temporary source, a partial copy only created from the current RT/DS for the current draw.
void InvalidateTemporarySource();

View File

@ -402,7 +402,6 @@ GSTexture* GSDeviceMTL::CreateSurface(GSTexture::Type type, int width, int heigh
[desc setUsage:MTLTextureUsageRenderTarget];
break;
case GSTexture::Type::RenderTarget:
case GSTexture::Type::SparseRenderTarget:
if (m_dev.features.slow_color_compression)
[desc setUsage:MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget | MTLTextureUsagePixelFormatView]; // Force color compression off by including PixelFormatView
else

View File

@ -122,7 +122,7 @@ namespace Emulate_DSA
// Replace function pointer to emulate DSA behavior
void Init()
{
fprintf(stderr, "DSA is not supported. Expect slower performance\n");
Console.Warning("DSA is not supported. Expect slower performance");
glBindTextureUnit = BindTextureUnit;
glCreateTextures = CreateTexture;
glTextureStorage2D = TextureStorage;
@ -139,15 +139,6 @@ namespace Emulate_DSA
namespace GLLoader
{
#define fprintf_once(out, ...) \
do \
if (s_first_load) \
fprintf(out, __VA_ARGS__); \
while (0);
bool s_first_load = true;
bool vendor_id_amd = false;
bool vendor_id_nvidia = false;
bool vendor_id_intel = false;
@ -162,10 +153,6 @@ namespace GLLoader
bool found_GL_ARB_gpu_shader5 = false; // Require IvyBridge
bool found_GL_ARB_shader_image_load_store = false; // Intel IB. Nvidia/AMD miss Mesa implementation.
// In case sparse2 isn't supported
bool found_compatible_GL_ARB_sparse_texture2 = false;
bool found_compatible_sparse_depth = false;
static bool mandatory(const std::string& ext)
{
if (!GLExtension::Has(ext))
@ -183,11 +170,11 @@ namespace GLLoader
if (!found)
{
fprintf_once(stdout, "INFO: %s is NOT SUPPORTED\n", name.c_str());
DevCon.Warning("INFO: %s is NOT SUPPORTED", name.c_str());
}
else
{
fprintf_once(stdout, "INFO: %s is available\n", name.c_str());
DevCon.WriteLn("INFO: %s is available", name.c_str());
}
std::string opt("override_");
@ -276,9 +263,6 @@ namespace GLLoader
// Extra
{
// Bonus
optional("GL_ARB_sparse_texture");
optional("GL_ARB_sparse_texture2");
// GL4.0
found_GL_ARB_gpu_shader5 = optional("GL_ARB_gpu_shader5");
// GL4.2
@ -300,32 +284,17 @@ namespace GLLoader
}
}
if (vendor_id_amd)
{
fprintf_once(stderr, "The OpenGL hardware renderer is slow on AMD GPUs due to an inefficient driver.\n"
"Check out the link below for further information.\n"
"https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-AMD-GPUs---All-you-need-to-know\n");
}
if (vendor_id_intel && (!GLExtension::Has("GL_ARB_texture_barrier") || !GLExtension::Has("GL_ARB_direct_state_access")))
{
// Assume that driver support is good when texture barrier and DSA is supported, disable the log then.
fprintf_once(stderr, "The OpenGL renderer is inefficient on Intel GPUs due to an inefficient driver.\n"
"Check out the link below for further information.\n"
"https://github.com/PCSX2/pcsx2/wiki/OpenGL-and-Intel-GPUs-All-you-need-to-know\n");
}
if (!GLExtension::Has("GL_ARB_viewport_array"))
{
glScissorIndexed = ReplaceGL::ScissorIndexed;
glViewportIndexedf = ReplaceGL::ViewportIndexedf;
fprintf_once(stderr, "GL_ARB_viewport_array is not supported! Function pointer will be replaced\n");
Console.Warning("GL_ARB_viewport_array is not supported! Function pointer will be replaced");
}
if (!GLExtension::Has("GL_ARB_texture_barrier"))
{
glTextureBarrier = ReplaceGL::TextureBarrier;
fprintf_once(stderr, "GL_ARB_texture_barrier is not supported! Blending emulation will not be supported\n");
Console.Warning("GL_ARB_texture_barrier is not supported! Blending emulation will not be supported");
}
#ifdef _WIN32
@ -339,70 +308,6 @@ namespace GLLoader
return true;
}
bool is_sparse2_compatible(const char* name, GLenum internal_fmt, int x_max, int y_max)
{
GLint index_count = 0;
glGetInternalformativ(GL_TEXTURE_2D, internal_fmt, GL_NUM_VIRTUAL_PAGE_SIZES_ARB, 1, &index_count);
if (!index_count)
{
fprintf_once(stdout, "%s isn't sparse compatible. No index found\n", name);
return false;
}
GLint x, y;
glGetInternalformativ(GL_TEXTURE_2D, internal_fmt, GL_VIRTUAL_PAGE_SIZE_X_ARB, 1, &x);
glGetInternalformativ(GL_TEXTURE_2D, internal_fmt, GL_VIRTUAL_PAGE_SIZE_Y_ARB, 1, &y);
if (x > x_max && y > y_max)
{
fprintf_once(stdout, "%s isn't sparse compatible. Page size (%d,%d) is too big (%d, %d)\n",
name, x, y, x_max, y_max);
return false;
}
return true;
}
static void check_sparse_compatibility()
{
if (!GLExtension::Has("GL_ARB_sparse_texture") ||
!GLExtension::Has("GL_EXT_direct_state_access") ||
theApp.GetConfigI("override_GL_ARB_sparse_texture") != 1)
{
found_compatible_GL_ARB_sparse_texture2 = false;
found_compatible_sparse_depth = false;
return;
}
found_compatible_GL_ARB_sparse_texture2 = true;
if (!GLExtension::Has("GL_ARB_sparse_texture2"))
{
// Only check format from GSTextureOGL
found_compatible_GL_ARB_sparse_texture2 &= is_sparse2_compatible("GL_R8", GL_R8, 256, 256);
found_compatible_GL_ARB_sparse_texture2 &= is_sparse2_compatible("GL_R16UI", GL_R16UI, 256, 128);
found_compatible_GL_ARB_sparse_texture2 &= is_sparse2_compatible("GL_R32UI", GL_R32UI, 128, 128);
found_compatible_GL_ARB_sparse_texture2 &= is_sparse2_compatible("GL_R32I", GL_R32I, 128, 128);
found_compatible_GL_ARB_sparse_texture2 &= is_sparse2_compatible("GL_RGBA8", GL_RGBA8, 128, 128);
found_compatible_GL_ARB_sparse_texture2 &= is_sparse2_compatible("GL_RGBA16", GL_RGBA16, 128, 64);
found_compatible_GL_ARB_sparse_texture2 &= is_sparse2_compatible("GL_RGBA16I", GL_RGBA16I, 128, 64);
found_compatible_GL_ARB_sparse_texture2 &= is_sparse2_compatible("GL_RGBA16UI", GL_RGBA16UI, 128, 64);
found_compatible_GL_ARB_sparse_texture2 &= is_sparse2_compatible("GL_RGBA16F", GL_RGBA16F, 128, 64);
found_compatible_GL_ARB_sparse_texture2 &= is_sparse2_compatible("GL_RGBA32F", GL_RGBA32F, 64, 64);
}
// Can fit in 128x64 but 128x128 is enough
// Disable sparse depth for AMD. Bad driver strikes again.
// driver reports a compatible sparse format for depth texture but it isn't attachable to a frame buffer.
found_compatible_sparse_depth = !vendor_id_amd && is_sparse2_compatible("GL_DEPTH32F_STENCIL8", GL_DEPTH32F_STENCIL8, 128, 128);
fprintf_once(stdout, "INFO: sparse color texture is %s\n", found_compatible_GL_ARB_sparse_texture2 ? "available" : "NOT SUPPORTED");
fprintf_once(stdout, "INFO: sparse depth texture is %s\n", found_compatible_sparse_depth ? "available" : "NOT SUPPORTED");
}
bool check_gl_requirements()
{
if (!check_gl_version(3, 3))
@ -411,12 +316,6 @@ namespace GLLoader
if (!check_gl_supported_extension())
return false;
// Bonus for sparse texture
check_sparse_compatibility();
fprintf_once(stdout, "\n");
s_first_load = false;
return true;
}
} // namespace GLLoader

View File

@ -45,7 +45,4 @@ namespace GLLoader
extern bool found_GL_ARB_gpu_shader5;
extern bool found_GL_ARB_shader_image_load_store;
extern bool found_GL_ARB_clear_texture;
extern bool found_compatible_GL_ARB_sparse_texture2;
extern bool found_compatible_sparse_depth;
} // namespace GLLoader

View File

@ -774,7 +774,7 @@ void GSDeviceOGL::InvalidateRenderTarget(GSTexture* t)
{
OMSetFBO(m_fbo);
if (T->GetType() == GSTexture::Type::DepthStencil || T->GetType() == GSTexture::Type::SparseDepthStencil)
if (T->GetType() == GSTexture::Type::DepthStencil)
{
OMAttachDs(T);
const GLenum attachments[] = {GL_DEPTH_STENCIL_ATTACHMENT};
@ -1192,7 +1192,6 @@ void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r
PSSetShaderResource(6, sTex);
#endif
dTex->CommitRegion(GSVector2i(r.z, r.w));
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
ASSERT(GLExtension::Has("GL_ARB_copy_image") && glCopyImageSubData);
@ -1242,7 +1241,6 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
BeginScene();
GL_PUSH("StretchRect from %d to %d", sTex->GetID(), dTex->GetID());
dTex->CommitRegion(GSVector2i((int)dRect.z + 1, (int)dRect.w + 1));
if (draw_in_depth)
OMSetRenderTargets(NULL, dTex);
else
@ -1885,7 +1883,6 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
{
GSVector2i size = config.rt->GetSize();
hdr_rt = CreateRenderTarget(size.x, size.y, GSTexture::Format::FloatColor, false);
hdr_rt->CommitRegion(GSVector2i(config.drawarea.z, config.drawarea.w));
OMSetRenderTargets(hdr_rt, config.ds, &config.scissor);
// save blend state, since BlitRect destroys it

View File

@ -377,9 +377,6 @@ public:
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL);
void OMSetColorMaskState(OMColorMaskSelector sel = OMColorMaskSelector());
bool HasColorSparse() final { return GLLoader::found_compatible_GL_ARB_sparse_texture2; }
bool HasDepthSparse() final { return GLLoader::found_compatible_sparse_depth; }
bool CreateTextureFX();
std::string GetShaderSource(const std::string_view& entry, GLenum type, const std::string_view& common_header, const std::string_view& glsl_h_code, const std::string_view& macro_sel);
std::string GenGlslHeader(const std::string_view& entry, GLenum type, const std::string_view& macro);

View File

@ -181,7 +181,6 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
m_type = type;
m_fbo_read = fbo_read;
m_texture_id = 0;
m_sparse = false;
m_mipmap_levels = 1;
int gl_fmt = 0;
@ -287,56 +286,9 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
ASSERT(0);
}
switch (m_type)
{
case Type::Texture:
// Only 32 bits input texture will be supported for mipmap
m_mipmap_levels = levels;
break;
case Type::SparseRenderTarget:
case Type::SparseDepthStencil:
m_sparse = true;
break;
default:
break;
}
switch (m_format)
{
case Format::UInt16:
case Format::UNorm8:
m_sparse &= GLLoader::found_compatible_GL_ARB_sparse_texture2;
SetGpuPageSize(GSVector2i(255, 255));
break;
case Format::Color:
case Format::UInt32:
case Format::PrimID:
m_sparse &= GLLoader::found_compatible_GL_ARB_sparse_texture2;
SetGpuPageSize(GSVector2i(127, 127));
break;
case Format::FloatColor:
m_sparse &= GLLoader::found_compatible_GL_ARB_sparse_texture2;
SetGpuPageSize(GSVector2i(63, 63));
break;
case Format::DepthStencil:
m_sparse &= GLLoader::found_compatible_sparse_depth;
SetGpuPageSize(GSVector2i(127, 127));
break;
case GSTexture::Format::BC1:
case GSTexture::Format::BC2:
case GSTexture::Format::BC3:
case GSTexture::Format::BC7:
m_sparse = false;
SetGpuPageSize(GSVector2i(127, 127));
break;
case Format::Invalid:
ASSERT(0);
}
// Only 32 bits input texture will be supported for mipmap
if (m_type == Type::Texture)
m_mipmap_levels = levels;
// Create a gl object (texture isn't allocated here)
glCreateTextures(GL_TEXTURE_2D, 1, &m_texture_id);
@ -347,26 +299,8 @@ GSTextureOGL::GSTextureOGL(Type type, int width, int height, int levels, Format
glTextureParameteri(m_texture_id, GL_TEXTURE_SWIZZLE_A, GL_RED);
}
if (m_sparse)
{
GSVector2i old_size = m_size;
m_size = RoundUpPage(m_size);
if (m_size != old_size)
{
fprintf(stderr, "Sparse texture size (%dx%d) isn't a multiple of gpu page size (%dx%d)\n",
old_size.x, old_size.y, m_gpu_page_size.x, m_gpu_page_size.y);
}
glTextureParameteri(m_texture_id, GL_TEXTURE_SPARSE_ARB, true);
}
else
{
m_committed_size = m_size;
}
m_mem_usage = (m_committed_size.x * m_committed_size.y) << m_int_shift;
static int every_512 = 0;
GLState::available_vram -= m_mem_usage;
GLState::available_vram -= GetMemUsage();
if ((GLState::available_vram < 0) && (every_512 % 512 == 0))
{
fprintf(stderr, "Available VRAM is very low (%lld), a crash is expected! Enable conservative buffer allocation or reduce upscaling!\n", GLState::available_vram);
@ -394,7 +328,7 @@ GSTextureOGL::~GSTextureOGL()
glDeleteTextures(1, &m_texture_id);
GLState::available_vram += m_mem_usage;
GLState::available_vram += GetMemUsage();
}
void* GSTextureOGL::GetNativeHandle() const
@ -560,44 +494,6 @@ void GSTextureOGL::GenerateMipmap()
glGenerateTextureMipmap(m_texture_id);
}
void GSTextureOGL::CommitPages(const GSVector2i& region, bool commit)
{
GLState::available_vram += m_mem_usage;
if (commit)
{
if (m_committed_size.x == 0)
{
// Nothing allocated so far
GL_INS("CommitPages initial %dx%d of %u", region.x, region.y, m_texture_id);
glTexturePageCommitmentEXT(m_texture_id, GL_TEX_LEVEL_0, 0, 0, 0, region.x, region.y, 1, commit);
}
else
{
GL_INS("CommitPages extend %dx%d to %dx%d of %u", m_committed_size.x, m_committed_size.y, region.x, region.y, m_texture_id);
int w = region.x - m_committed_size.x;
int h = region.y - m_committed_size.y;
// Extend width
glTexturePageCommitmentEXT(m_texture_id, GL_TEX_LEVEL_0, m_committed_size.x, 0, 0, w, m_committed_size.y, 1, commit);
// Extend height
glTexturePageCommitmentEXT(m_texture_id, GL_TEX_LEVEL_0, 0, m_committed_size.y, 0, region.x, h, 1, commit);
}
m_committed_size = region;
}
else
{
// Release everything
GL_INS("CommitPages release of %u", m_texture_id);
glTexturePageCommitmentEXT(m_texture_id, GL_TEX_LEVEL_0, 0, 0, 0, m_committed_size.x, m_committed_size.y, 1, commit);
m_committed_size = GSVector2i(0, 0);
}
m_mem_usage = (m_committed_size.x * m_committed_size.y) << m_int_shift;
GLState::available_vram -= m_mem_usage;
}
GSTexture::GSMap GSTextureOGL::Read(const GSVector4i& r, AlignedBuffer<u8, 32>& buffer)
{
GSMap m;
@ -625,8 +521,8 @@ GSTexture::GSMap GSTextureOGL::Read(const GSVector4i& r, AlignedBuffer<u8, 32>&
bool GSTextureOGL::Save(const std::string& fn)
{
// Collect the texture data
u32 pitch = 4 * m_committed_size.x;
u32 buf_size = pitch * m_committed_size.y * 2; // Note *2 for security (depth/stencil)
u32 pitch = 4 * m_size.x;
u32 buf_size = pitch * m_size.y * 2; // Note *2 for security (depth/stencil)
std::unique_ptr<u8[]> image(new u8[buf_size]);
#ifdef PCSX2_DEVBUILD
GSPng::Format fmt = GSPng::RGB_A_PNG;
@ -634,12 +530,12 @@ bool GSTextureOGL::Save(const std::string& fn)
GSPng::Format fmt = GSPng::RGB_PNG;
#endif
if (IsDepth())
if (IsDepthStencil())
{
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_texture_id, 0);
glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image.get());
glReadPixels(0, 0, m_size.x, m_size.y, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, image.get());
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
@ -648,7 +544,6 @@ bool GSTextureOGL::Save(const std::string& fn)
else if (m_format == Format::PrimID)
{
// Note: 4.5 function used for accurate DATE
// barely used outside of dev and not sparse anyway
glGetTextureImage(m_texture_id, 0, GL_RED_INTEGER, GL_INT, buf_size, image.get());
fmt = GSPng::R32I_PNG;
@ -661,24 +556,24 @@ bool GSTextureOGL::Save(const std::string& fn)
if (m_format == Format::Color)
{
glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image.get());
glReadPixels(0, 0, m_size.x, m_size.y, GL_RGBA, GL_UNSIGNED_BYTE, image.get());
}
else if (m_format == Format::UInt16)
{
glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_RED_INTEGER, GL_UNSIGNED_SHORT, image.get());
glReadPixels(0, 0, m_size.x, m_size.y, GL_RED_INTEGER, GL_UNSIGNED_SHORT, image.get());
fmt = GSPng::R16I_PNG;
}
else if (m_format == Format::UNorm8)
{
fmt = GSPng::R8I_PNG;
glReadPixels(0, 0, m_committed_size.x, m_committed_size.y, GL_RED, GL_UNSIGNED_BYTE, image.get());
glReadPixels(0, 0, m_size.x, m_size.y, GL_RED, GL_UNSIGNED_BYTE, image.get());
}
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
}
int compression = theApp.GetConfigI("png_compression_level");
return GSPng::Save(fmt, fn, image.get(), m_committed_size.x, m_committed_size.y, pitch, compression);
return GSPng::Save(fmt, fn, image.get(), m_size.x, m_size.y, pitch, compression);
}
void GSTextureOGL::Swap(GSTexture* tex)
@ -696,10 +591,4 @@ void GSTextureOGL::Swap(GSTexture* tex)
std::swap(m_int_format, static_cast<GSTextureOGL*>(tex)->m_int_format);
std::swap(m_int_type, static_cast<GSTextureOGL*>(tex)->m_int_type);
std::swap(m_int_shift, static_cast<GSTextureOGL*>(tex)->m_int_shift);
std::swap(m_mem_usage, static_cast<GSTextureOGL*>(tex)->m_mem_usage);
}
u32 GSTextureOGL::GetMemUsage()
{
return m_mem_usage;
}

View File

@ -54,9 +54,6 @@ private:
GLenum m_int_type;
u32 m_int_shift;
// Allow to track size of allocated memory
u32 m_mem_usage;
public:
explicit GSTextureOGL(Type type, int width, int height, int levels, Format format, GLuint fbo_read);
virtual ~GSTextureOGL();
@ -71,7 +68,6 @@ public:
void Swap(GSTexture* tex) final;
GSMap Read(const GSVector4i& r, AlignedBuffer<u8, 32>& buffer);
bool IsDepth() { return (m_type == Type::DepthStencil || m_type == Type::SparseDepthStencil); }
bool IsIntegerFormat() const
{
return (m_int_format == GL_RED_INTEGER || m_int_format == GL_RGBA_INTEGER);
@ -88,8 +84,4 @@ public:
void Clear(const void* data);
void Clear(const void* data, const GSVector4i& area);
void CommitPages(const GSVector2i& region, bool commit) final;
u32 GetMemUsage() final;
};

View File

@ -405,8 +405,7 @@ VkFormat GSDeviceVK::LookupNativeFormat(GSTexture::Format format) const
GSTexture* GSDeviceVK::CreateSurface(GSTexture::Type type, int width, int height, int levels, GSTexture::Format format)
{
pxAssert(type != GSTexture::Type::Offscreen && type != GSTexture::Type::SparseRenderTarget &&
type != GSTexture::Type::SparseDepthStencil);
pxAssert(type != GSTexture::Type::Offscreen);
const u32 clamped_width = static_cast<u32>(std::clamp<int>(1, width, g_vulkan_context->GetMaxImageDimension2D()));
const u32 clamped_height = static_cast<u32>(std::clamp<int>(1, height, g_vulkan_context->GetMaxImageDimension2D()));
@ -508,25 +507,38 @@ void GSDeviceVK::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r,
return;
}
else
if (dTexVK->GetState() == GSTexture::State::Cleared)
{
// otherwise we need to do an attachment clear
const bool depth = (dTexVK->GetType() == GSTexture::Type::DepthStencil);
OMSetRenderTargets(depth ? nullptr : dTexVK, depth ? dTexVK : nullptr, dtex_rc, false);
BeginRenderPassForStretchRect(dTexVK, dtex_rc, GSVector4i(destX, destY, destX + r.width(), destY + r.height()));
// so use an attachment clear
VkClearAttachment ca;
ca.aspectMask = depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
GSVector4::store<false>(ca.clearValue.color.float32, sTexVK->GetClearColor());
ca.clearValue.depthStencil.depth = sTexVK->GetClearDepth();
ca.clearValue.depthStencil.stencil = 0;
ca.colorAttachment = 0;
const VkClearRect cr = { {{0, 0}, {static_cast<u32>(r.width()), static_cast<u32>(r.height())}}, 0u, 1u };
vkCmdClearAttachments(g_vulkan_context->GetCurrentCommandBuffer(), 1, &ca, 1, &cr);
return;
// destination is cleared, if it's the same colour and rect, we can just avoid this entirely
if (dTexVK->IsDepthStencil())
{
if (dTexVK->GetClearDepth() == sTexVK->GetClearDepth())
return;
}
else
{
if ((dTexVK->GetClearColor() == (sTexVK->GetClearColor())).alltrue())
return;
}
}
// otherwise we need to do an attachment clear
const bool depth = (dTexVK->GetType() == GSTexture::Type::DepthStencil);
OMSetRenderTargets(depth ? nullptr : dTexVK, depth ? dTexVK : nullptr, dtex_rc, false);
BeginRenderPassForStretchRect(dTexVK, dtex_rc, GSVector4i(destX, destY, destX + r.width(), destY + r.height()));
// so use an attachment clear
VkClearAttachment ca;
ca.aspectMask = depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
GSVector4::store<false>(ca.clearValue.color.float32, sTexVK->GetClearColor());
ca.clearValue.depthStencil.depth = sTexVK->GetClearDepth();
ca.clearValue.depthStencil.stencil = 0;
ca.colorAttachment = 0;
const VkClearRect cr = { {{0, 0}, {static_cast<u32>(r.width()), static_cast<u32>(r.height())}}, 0u, 1u };
vkCmdClearAttachments(g_vulkan_context->GetCurrentCommandBuffer(), 1, &ca, 1, &cr);
return;
}
// commit the clear to the source first, then do normal copy
@ -1957,7 +1969,6 @@ VkShaderModule GSDeviceVK::GetTFXFragmentShader(const GSHWDrawConfig::PSSelector
AddMacro(ss, "PS_CHANNEL_FETCH", sel.channel);
AddMacro(ss, "PS_URBAN_CHAOS_HLE", sel.urban_chaos_hle);
AddMacro(ss, "PS_TALES_OF_ABYSS_HLE", sel.tales_of_abyss_hle);
AddMacro(ss, "PS_TEX_IS_FB", sel.tex_is_fb);
AddMacro(ss, "PS_INVALID_TEX0", sel.invalid_tex0);
AddMacro(ss, "PS_AEM", sel.aem);
AddMacro(ss, "PS_TFX", sel.tfx);
@ -2980,22 +2991,32 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
}
}
if (config.tex && config.tex == config.ds)
if (config.tex)
{
// requires a copy of the depth buffer. this is mainly for ico.
copy_ds = static_cast<GSTextureVK*>(CreateDepthStencil(rtsize.x, rtsize.y, GSTexture::Format::DepthStencil, false));
if (copy_ds)
if (config.tex == config.ds)
{
EndRenderPass();
// requires a copy of the depth buffer. this is mainly for ico.
copy_ds = static_cast<GSTextureVK*>(CreateDepthStencil(rtsize.x, rtsize.y, GSTexture::Format::DepthStencil, false));
if (copy_ds)
{
EndRenderPass();
GL_PUSH("Copy depth to temp texture for shuffle {%d,%d %dx%d}",
config.drawarea.left, config.drawarea.top,
config.drawarea.width(), config.drawarea.height());
GL_PUSH("Copy depth to temp texture for shuffle {%d,%d %dx%d}",
config.drawarea.left, config.drawarea.top,
config.drawarea.width(), config.drawarea.height());
CopyRect(config.ds, copy_ds, config.drawarea, config.drawarea.left, config.drawarea.top);
PSSetShaderResource(0, copy_ds, true);
CopyRect(config.ds, copy_ds, config.drawarea, config.drawarea.left, config.drawarea.top);
PSSetShaderResource(0, copy_ds, true);
}
}
}
// clear texture binding when it's bound to RT or DS
if (!config.tex && m_tfx_textures[0] &&
((!pipe.feedback_loop && config.rt && static_cast<GSTextureVK*>(config.rt)->GetView() == m_tfx_textures[0]) ||
(config.ds && static_cast<GSTextureVK*>(config.ds)->GetView() == m_tfx_textures[0])))
{
PSSetShaderResource(0, nullptr, false);
}
const bool render_area_okay =
(!hdr_rt && DATE_rp != DATE_RENDER_PASS_STENCIL_ONE && CheckRenderPassArea(render_area));

View File

@ -172,9 +172,6 @@ const char* dialog_message(int ID, bool* updateText)
return cvtString("Allows advanced atomic operations to speed up Accurate DATE.\n"
"Only disable this if using Accurate DATE causes (GPU driver) issues.\n\n"
"Note: This option is only supported by GPUs which support at least Direct3D 11.");
case IDC_SPARSE_TEXTURE:
return cvtString("Allows to reduce VRAM usage on the GPU.\n\n"
"Note: Feature is currently experimental and works only on Nvidia GPUs.");
case IDC_LINEAR_PRESENT:
return cvtString("Use bilinear filtering when Upscaling/Downscaling the image to the screen. Disable it if you want a sharper/pixelated output.");
// Exclusive for Hardware Renderer
@ -191,12 +188,6 @@ const char* dialog_message(int ID, bool* updateText)
case IDC_DISABLE_PARTIAL_TC_INV:
return cvtString("By default, the texture cache handles partial invalidations. Unfortunately it is very costly to compute CPU wise."
"\n\nThis hack replaces the partial invalidation with a complete deletion of the texture to reduce the CPU load.\n\nIt helps snowblind engine games.");
case IDC_CONSERVATIVE_FB:
return cvtString("Disabled: Reserves a larger framebuffer to prevent FMV flickers.\n"
"Increases GPU/memory requirements.\n"
"Disabling this can amplify stuttering due to low RAM/VRAM.\n\n"
"Note: It should be enabled for Armored Core, Destroy All Humans, Gran Turismo and possibly others.\n"
"This option does not improve the graphics or the FPS.");
case IDC_DITHERING:
return cvtString("In the PS2's case, it reduces banding between colors and improves the perceived color depth.\n"
"In the PS1's case, it was used more aggressively due to 16-bit colour.\n"

View File

@ -50,7 +50,6 @@ enum
IDC_PRELOAD_TEXTURES,
IDC_ACCURATE_DATE,
IDC_PALTEX,
IDC_CONSERVATIVE_FB,
IDC_AFCOMBO,
IDC_DITHERING,
IDC_MIPMAP_HW,
@ -90,7 +89,6 @@ enum
// OpenGL Advanced Settings
IDC_GEOMETRY_SHADER_OVERRIDE,
IDC_IMAGE_LOAD_STORE,
IDC_SPARSE_TEXTURE,
// On-screen Display
IDC_OSD_LOG,
IDC_OSD_MONITOR,

View File

@ -275,7 +275,6 @@ RendererTab::RendererTab(wxWindow* parent)
const int space = wxSizerFlags().Border().GetBorderInPixels();
auto hw_prereq = [this]{ return m_is_hardware; };
auto sw_prereq = [this]{ return !m_is_hardware; };
auto upscale_prereq = [this]{ return !m_is_native_res; };
PaddedBoxSizer<wxBoxSizer> tab_box(wxVERTICAL);
PaddedBoxSizer<wxStaticBoxSizer> general_box(wxVERTICAL, this, "General GS Settings");
@ -285,7 +284,6 @@ RendererTab::RendererTab(wxWindow* parent)
auto* hw_checks_box = new wxWrapSizer(wxHORIZONTAL);
m_ui.addCheckBox(hw_checks_box, "Accurate Destination Alpha Test", "accurate_date", IDC_ACCURATE_DATE, hw_prereq);
m_ui.addCheckBox(hw_checks_box, "Conservative Buffer Allocation", "conservative_framebuffer", IDC_CONSERVATIVE_FB, upscale_prereq);
auto* paltex_prereq = m_ui.addCheckBox(hw_checks_box, "GPU Palette Conversion", "paltex", IDC_PALTEX, hw_prereq);
auto aniso_prereq = [this, paltex_prereq]{ return m_is_hardware && paltex_prereq->GetValue() == false; };
@ -589,7 +587,6 @@ DebugTab::DebugTab(wxWindow* parent)
m_ui.addComboBoxAndLabel(ogl_grid, "Texture Barriers:", "OverrideTextureBarriers", &theApp.m_gs_generic_list, -1, vk_ogl_hw_prereq);
m_ui.addComboBoxAndLabel(ogl_grid, "Geometry Shader:", "OverrideGeometryShaders", &theApp.m_gs_generic_list, IDC_GEOMETRY_SHADER_OVERRIDE, vk_ogl_hw_prereq);
m_ui.addComboBoxAndLabel(ogl_grid, "Image Load Store:", "override_GL_ARB_shader_image_load_store", &theApp.m_gs_generic_list, IDC_IMAGE_LOAD_STORE, ogl_hw_prereq);
m_ui.addComboBoxAndLabel(ogl_grid, "Sparse Texture:", "override_GL_ARB_sparse_texture", &theApp.m_gs_generic_list, IDC_SPARSE_TEXTURE, ogl_hw_prereq);
m_ui.addComboBoxAndLabel(ogl_grid, "Dump Compression:", "GSDumpCompression", &theApp.m_gs_dump_compression, -1);
ogl_box->Add(ogl_grid);
@ -804,7 +801,6 @@ void Dialog::Update()
m_hacks_panel->m_is_native_res = !is_hw || !is_upscale;
m_hacks_panel->m_is_hardware = is_hw;
m_renderer_panel->m_is_hardware = is_hw;
m_renderer_panel->m_is_native_res = !is_hw || !is_upscale;
m_post_panel->m_is_vk_hw = renderer == GSRendererType::VK;
m_debug_panel->m_is_ogl_hw = renderer == GSRendererType::OGL;
m_debug_panel->m_is_vk_hw = renderer == GSRendererType::VK;

View File

@ -106,7 +106,6 @@ namespace GSSettingsDialog
GSUIElementHolder m_ui;
wxChoice* m_internal_resolution;
bool m_is_hardware = false;
bool m_is_native_res = false;
RendererTab(wxWindow* parent);
void Load() { m_ui.Load(); }

View File

@ -270,7 +270,6 @@ void GameDatabase::parseAndInsert(const std::string_view& serial, const c4::yml:
static const char* s_gs_hw_fix_names[] = {
"autoFlush",
"conservativeFramebuffer",
"cpuFramebufferConversion",
"disableDepthSupport",
"wrapGSMem",
@ -317,7 +316,6 @@ bool GameDatabaseSchema::isUserHackHWFix(GSHWFixId id)
case GSHWFixId::Deinterlace:
case GSHWFixId::Mipmap:
case GSHWFixId::TexturePreloading:
case GSHWFixId::ConservativeFramebuffer:
case GSHWFixId::PointListPalette:
return false;
@ -446,9 +444,6 @@ bool GameDatabaseSchema::GameEntry::configMatchesHWFix(const Pcsx2Config::GSOpti
case GSHWFixId::AutoFlush:
return (static_cast<int>(config.UserHacks_AutoFlush) == value);
case GSHWFixId::ConservativeFramebuffer:
return (static_cast<int>(config.ConservativeFramebuffer) == value);
case GSHWFixId::CPUFramebufferConversion:
return (static_cast<int>(config.UserHacks_CPUFBConversion) == value);
@ -542,10 +537,6 @@ u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions&
config.UserHacks_AutoFlush = (value > 0);
break;
case GSHWFixId::ConservativeFramebuffer:
config.ConservativeFramebuffer = (value > 0);
break;
case GSHWFixId::CPUFramebufferConversion:
config.UserHacks_CPUFBConversion = (value > 0);
break;

View File

@ -60,7 +60,6 @@ namespace GameDatabaseSchema
{
// boolean settings
AutoFlush,
ConservativeFramebuffer,
CPUFramebufferConversion,
DisableDepthSupport,
WrapGSMem,

View File

@ -416,7 +416,8 @@ void VU_Thread::Get_MTVUChanges()
{
mtvuInterrupts.fetch_and(~InterruptFlagVUEBit, std::memory_order_relaxed);
VU0.VI[REG_VPU_STAT].UL &= ~0xFF00;
if(INSTANT_VU1)
VU0.VI[REG_VPU_STAT].UL &= ~0xFF00;
//DevCon.Warning("E-Bit registered %x", VU0.VI[REG_VPU_STAT].UL);
}
if (interrupts & InterruptFlagVUTBit)
@ -458,10 +459,17 @@ void VU_Thread::ExecuteVU(u32 vu_addr, u32 vif_top, u32 vif_itop, u32 fbrst)
CommitWritePos();
gifUnit.TransferGSPacketData(GIF_TRANS_MTVU, NULL, 0);
KickStart();
u32 cycles = std::min(Get_vuCycles(), 3000u);
cpuRegs.cycle += cycles * EmuConfig.Speedhacks.EECycleSkip;
VU0.cycle += cycles * EmuConfig.Speedhacks.EECycleSkip;
u32 cycles = std::max(Get_vuCycles(), 4u);
u32 skip_cycles = std::min(cycles, 3000u);
cpuRegs.cycle += skip_cycles * EmuConfig.Speedhacks.EECycleSkip;
VU0.cycle += skip_cycles * EmuConfig.Speedhacks.EECycleSkip;
Get_MTVUChanges();
if (!INSTANT_VU1)
{
VU0.VI[REG_VPU_STAT].UL |= 0x100;
CPU_INT(VU_MTVU_BUSY, cycles);
}
}
void VU_Thread::VifUnpack(vifStruct& _vif, VIFregisters& _vifRegs, u8* data, u32 size)

View File

@ -325,7 +325,6 @@ Pcsx2Config::GSOptions::GSOptions()
HWDisableReadbacks = false;
AccurateDATE = true;
GPUPaletteConversion = false;
ConservativeFramebuffer = true;
AutoFlushSW = true;
PreloadFrameWithGSData = false;
WrapGSMem = false;
@ -546,7 +545,6 @@ void Pcsx2Config::GSOptions::ReloadIniSettings()
GSSettingBool(HWDisableReadbacks);
GSSettingBoolEx(AccurateDATE, "accurate_date");
GSSettingBoolEx(GPUPaletteConversion, "paltex");
GSSettingBoolEx(ConservativeFramebuffer, "conservative_framebuffer");
GSSettingBoolEx(AutoFlushSW, "autoflush_sw");
GSSettingBoolEx(PreloadFrameWithGSData, "preload_frame_with_gs_data");
GSSettingBoolEx(WrapGSMem, "wrap_gs_mem");

View File

@ -246,6 +246,18 @@ __fi void cpuSetNextEventDelta( s32 delta )
cpuSetNextEvent( cpuRegs.cycle, delta );
}
__fi int cpuGetCycles(int interrupt)
{
if(interrupt == VU_MTVU_BUSY && (!THREAD_VU1 || INSTANT_VU1))
return 1;
else
{
const int cycles = (cpuRegs.sCycle[interrupt] + cpuRegs.eCycle[interrupt]) - cpuRegs.cycle;
return std::max(1, cycles);
}
}
// tests the cpu cycle against the given start and delta values.
// Returns true if the delta time has passed.
__fi int cpuTestCycle( u32 startCycle, s32 delta )
@ -292,7 +304,7 @@ static __fi void _cpuTestInterrupts()
}
/* These are 'pcsx2 interrupts', they handle asynchronous stuff
that depends on the cycle timings */
TESTINT(VU_MTVU_BUSY, MTVUInterrupt);
TESTINT(DMAC_VIF1, vif1Interrupt);
TESTINT(DMAC_GIF, gifInterrupt);
TESTINT(DMAC_SIF0, EEsif0Interrupt);
@ -521,7 +533,7 @@ __fi void CPU_INT( EE_EventType n, s32 ecycle)
// EE events happen 8 cycles in the future instead of whatever was requested.
// This can be used on games with PATH3 masking issues for example, or when
// some FMV look bad.
if(CHECK_EETIMINGHACK) ecycle = 8;
if(CHECK_EETIMINGHACK && n < VIF_VU0_FINISH) ecycle = 8;
cpuRegs.interrupt|= 1 << n;
cpuRegs.sCycle[n] = cpuRegs.cycle;

View File

@ -415,7 +415,8 @@ enum EE_EventType
DMAC_GIF_UNIT,
VIF_VU0_FINISH,
VIF_VU1_FINISH,
IPU_PROCESS
IPU_PROCESS,
VU_MTVU_BUSY
};
extern void CPU_INT( EE_EventType n, s32 ecycle );
@ -435,6 +436,7 @@ extern void cpuSetNextEvent( u32 startCycle, s32 delta );
extern void cpuSetNextEventDelta( s32 delta );
extern int cpuTestCycle( u32 startCycle, s32 delta );
extern void cpuSetEvent();
extern int cpuGetCycles(int interrupt);
extern void _cpuEventTest_Shared(); // for internal use by the Dynarecs and Ints inside R5900:

View File

@ -38,7 +38,10 @@ void vu1ResetRegs()
void vu1Finish(bool add_cycles) {
if (THREAD_VU1) {
//if (VU0.VI[REG_VPU_STAT].UL & 0x100) DevCon.Error("MTVU: VU0.VI[REG_VPU_STAT].UL & 0x100");
vu1Thread.WaitVU();
if (INSTANT_VU1 || add_cycles)
{
vu1Thread.WaitVU();
}
vu1Thread.Get_MTVUChanges();
return;
}
@ -70,7 +73,6 @@ void vu1ExecMicro(u32 addr)
// VU0.VI[REG_VPU_STAT].UL |= 0x0100;
// }
// Update 25/06/2022: Disabled this for now, let games YOLO it, if it breaks MTVU, disable MTVU (it doesn't work properly anyway) - Refraction
vu1Thread.ExecuteVU(addr, vif1Regs.top, vif1Regs.itop, VU0.VI[REG_FBRST].UL);
return;
}
@ -90,3 +92,8 @@ void vu1ExecMicro(u32 addr)
else
CpuVU1->Execute(vu1RunCycles);
}
void MTVUInterrupt()
{
VU0.VI[REG_VPU_STAT].UL &= ~0xFF00;
}

View File

@ -256,6 +256,7 @@ extern void vu1ResetRegs();
extern void vu1ExecMicro(u32 addr);
extern void vu1Exec(VURegs* VU);
extern void iDumpVU1Registers();
extern void MTVUInterrupt();
#ifdef VUM_LOG

View File

@ -40,7 +40,8 @@ void vif1TransferToMemory()
u128* pMem = (u128*)dmaGetAddr(vif1ch.madr, false);
// VIF from gsMemory
if (pMem == NULL) { // Is vif0ptag empty?
if (pMem == NULL)
{ // Is vif0ptag empty?
Console.WriteLn("Vif1 Tag BUSERR");
dmacRegs.stat.BEIS = true; // Bus Error
vif1Regs.stat.FQC = 0;
@ -55,10 +56,11 @@ void vif1TransferToMemory()
// stuff from the GS. The *only* way to handle this case safely is to flush the GS
// completely and execute the transfer there-after.
//Console.Warning("Real QWC %x", vif1ch.qwc);
const u32 size = std::min(vif1.GSLastDownloadSize, (u32)vif1ch.qwc);
const u32 size = std::min(vif1.GSLastDownloadSize, (u32)vif1ch.qwc);
//const u128* pMemEnd = vif1.GSLastDownloadSize + pMem;
if (size) {
if (size)
{
// Checking if any crazy game does a partial
// gs primitive and then does a gs download...
Gif_Path& p1 = gifUnit.gifPath[GIF_PATH_1];
@ -70,7 +72,7 @@ void vif1TransferToMemory()
}
GetMTGS().InitAndReadFIFO(reinterpret_cast<u8*>(pMem), size);
// pMem += size;
// pMem += size;
//Some games such as Alex Ferguson's Player Manager 2001 reads less than GSLastDownloadSize by VIF then reads the remainder by FIFO
//Clearing the memory is clearing memory it shouldn't be and kills it.
@ -89,25 +91,25 @@ void vif1TransferToMemory()
g_vif1Cycles += size * 2;
vif1ch.madr += size * 16; // mgs3 scene changes
if (vif1.GSLastDownloadSize >= vif1ch.qwc) {
if (vif1.GSLastDownloadSize >= vif1ch.qwc)
{
vif1.GSLastDownloadSize -= vif1ch.qwc;
vif1Regs.stat.FQC = std::min((u32)16, vif1.GSLastDownloadSize);
vif1ch.qwc = 0;
}
else {
else
{
vif1Regs.stat.FQC = 0;
vif1ch.qwc -= vif1.GSLastDownloadSize;
vif1.GSLastDownloadSize = 0;
//This could be potentially bad and cause hangs. I guess we will find out.
DevCon.Warning("QWC left on VIF FIFO Reverse");
}
}
bool _VIF1chain()
{
u32 *pMem;
u32* pMem;
if (vif1ch.qwc == 0)
{
@ -135,7 +137,7 @@ bool _VIF1chain()
}
VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx",
vif1ch.qwc, vif1ch.madr, vif1ch.tadr);
vif1ch.qwc, vif1ch.madr, vif1ch.tadr);
if (vif1.irqoffset.enabled)
return VIF1transfer(pMem + vif1.irqoffset.value, vif1ch.qwc * 4 - vif1.irqoffset.value, false);
@ -145,20 +147,21 @@ bool _VIF1chain()
__fi void vif1SetupTransfer()
{
tDMA_TAG *ptag;
tDMA_TAG* ptag;
ptag = dmaGetAddr(vif1ch.tadr, false); //Set memory pointer to TADR
if (!(vif1ch.transfer("Vif1 Tag", ptag))) return;
if (!(vif1ch.transfer("Vif1 Tag", ptag)))
return;
vif1ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR
vif1ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR
g_vif1Cycles += 1; // Add 1 g_vifCycles from the QW read for the tag
vif1.inprogress &= ~1;
VIF_LOG("VIF1 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx",
ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr);
ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr);
if (!vif1.done && ((dmacRegs.ctrl.STD == STD_VIF1) && (ptag->ID == TAG_REFS))) // STD == VIF1
if (!vif1.done && ((dmacRegs.ctrl.STD == STD_VIF1) && (ptag->ID == TAG_REFS))) // STD == VIF1
{
// there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall
if ((vif1ch.madr + vif1ch.qwc * 16) > dmacRegs.stadr.ADDR)
@ -177,7 +180,7 @@ __fi void vif1SetupTransfer()
bool ret;
alignas(16) static u128 masked_tag;
masked_tag._u64[0] = 0;
masked_tag._u64[1] = *((u64*)ptag + 1);
@ -185,7 +188,7 @@ __fi void vif1SetupTransfer()
if (vif1.irqoffset.enabled)
{
ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset.value, 4 - vif1.irqoffset.value, true); //Transfer Tag on stall
ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset.value, 4 - vif1.irqoffset.value, true); //Transfer Tag on stall
//ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on stall
}
else
@ -194,7 +197,7 @@ __fi void vif1SetupTransfer()
// to the VU's, which breaks stuff, this is where the 128bit packet will fail, so we ignore the first 2 words
vif1.irqoffset.value = 2;
vif1.irqoffset.enabled = true;
ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag
ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag
//ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag
}
@ -202,7 +205,7 @@ __fi void vif1SetupTransfer()
{
vif1.inprogress &= ~1; // Better clear this so it has to do it again (Jak 1)
vif1ch.qwc = 0; // Gumball 3000 pauses the DMA when the tag stalls so we need to reset the QWC, it'll be gotten again later
return; // IRQ set by VIFTransfer
return; // IRQ set by VIFTransfer
}
}
vif1.irqoffset.value = 0;
@ -210,14 +213,15 @@ __fi void vif1SetupTransfer()
vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID);
if(vif1ch.qwc > 0) vif1.inprogress |= 1;
if (vif1ch.qwc > 0)
vif1.inprogress |= 1;
//Check TIE bit of CHCR and IRQ bit of tag
if (vif1ch.chcr.TIE && ptag->IRQ)
{
VIF_LOG("dmaIrq Set");
//End Transfer
//End Transfer
vif1.done = true;
return;
}
@ -229,23 +233,29 @@ __fi void vif1VUFinish()
{
vu1Thread.Get_MTVUChanges();
CPU_INT(VIF_VU1_FINISH, 128);
if (THREAD_VU1 && !INSTANT_VU1 && (VU0.VI[REG_VPU_STAT].UL & 0x100))
CPU_INT(VIF_VU1_FINISH, cpuGetCycles(VU_MTVU_BUSY));
else
CPU_INT(VIF_VU1_FINISH, 128);
return;
}
if (VU0.VI[REG_VPU_STAT].UL & 0x100)
{
u32 _cycles = VU1.cycle;
//DevCon.Warning("Finishing VU1");
vu1Finish(false);
CPU_INT(VIF_VU1_FINISH, VU1.cycle - _cycles);
if (THREAD_VU1 && !INSTANT_VU1 && (VU0.VI[REG_VPU_STAT].UL & 0x100))
CPU_INT(VIF_VU1_FINISH, cpuGetCycles(VU_MTVU_BUSY));
else
CPU_INT(VIF_VU1_FINISH, VU1.cycle - _cycles);
return;
}
vif1Regs.stat.VEW = false;
VIF_LOG("VU1 finished");
if(vif1.waitforvu)
if (vif1.waitforvu)
{
vif1.waitforvu = false;
//Check if VIF is already scheduled to interrupt, if it's waiting, kick it :P
@ -257,7 +267,7 @@ __fi void vif1VUFinish()
vif1Interrupt();
}
}
//DevCon.Warning("VU1 state cleared");
}
@ -267,19 +277,22 @@ __fi void vif1Interrupt()
g_vif1Cycles = 0;
if( gifRegs.stat.APATH == 2 && gifUnit.gifPath[GIF_PATH_2].isDone())
if (gifRegs.stat.APATH == 2 && gifUnit.gifPath[GIF_PATH_2].isDone())
{
gifRegs.stat.APATH = 0;
gifRegs.stat.OPH = 0;
vif1Regs.stat.VGW = false; //Let vif continue if it's stuck on a flush
if(gifUnit.checkPaths(1,0,1)) gifUnit.Execute(false, true);
if (gifUnit.checkPaths(1, 0, 1))
gifUnit.Execute(false, true);
}
//Some games (Fahrenheit being one) start vif first, let it loop through blankness while it sets MFIFO mode, so we need to check it here.
if (dmacRegs.ctrl.MFD == MFD_VIF1) {
if (dmacRegs.ctrl.MFD == MFD_VIF1)
{
//Console.WriteLn("VIFMFIFO\n");
// Test changed because the Final Fantasy 12 opening somehow has the tag in *Undefined* mode, which is not in the documentation that I saw.
if (vif1ch.chcr.MOD == NORMAL_MODE) Console.WriteLn("MFIFO mode is normal (which isn't normal here)! %x", vif1ch.chcr._u32);
if (vif1ch.chcr.MOD == NORMAL_MODE)
Console.WriteLn("MFIFO mode is normal (which isn't normal here)! %x", vif1ch.chcr._u32);
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
vifMFIFOInterrupt();
return;
@ -287,42 +300,46 @@ __fi void vif1Interrupt()
// We need to check the direction, if it is downloading
// from the GS then we handle that separately (KH2 for testing)
if (vif1ch.chcr.DIR) {
bool isDirect = (vif1.cmd & 0x7f) == 0x50;
if (vif1ch.chcr.DIR)
{
bool isDirect = (vif1.cmd & 0x7f) == 0x50;
bool isDirectHL = (vif1.cmd & 0x7f) == 0x51;
if((isDirect && !gifUnit.CanDoPath2())
|| (isDirectHL && !gifUnit.CanDoPath2HL())) {
if ((isDirect && !gifUnit.CanDoPath2()) || (isDirectHL && !gifUnit.CanDoPath2HL()))
{
GUNIT_WARN("vif1Interrupt() - Waiting for Path 2 to be ready");
CPU_INT(DMAC_VIF1, 128);
if(gifRegs.stat.APATH == 3) vif1Regs.stat.VGW = 1; //We're waiting for path 3. Gunslinger II
if (gifRegs.stat.APATH == 3)
vif1Regs.stat.VGW = 1; //We're waiting for path 3. Gunslinger II
return;
}
vif1Regs.stat.VGW = 0; //Path 3 isn't busy so we don't need to wait for it.
vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
//Simulated GS transfer time done, clear the flags
}
if(vif1.waitforvu)
if (vif1.waitforvu)
{
//DevCon.Warning("Waiting on VU1");
//CPU_INT(DMAC_VIF1, 16);
CPU_INT(VIF_VU1_FINISH, 16);
CPU_INT(VIF_VU1_FINISH, std::max(16, cpuGetCycles(VU_MTVU_BUSY)));
return;
}
if (vif1Regs.stat.VGW)
return;
if (!vif1ch.chcr.STR) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch.chcr._u32);
if (!vif1ch.chcr.STR)
Console.WriteLn("Vif1 running when CHCR == %x", vif1ch.chcr._u32);
if (vif1.irq && vif1.vifstalled.enabled && vif1.vifstalled.value == VIF_IRQ_STALL)
{
VIF_LOG("VIF IRQ Firing");
if (!vif1Regs.stat.ER1)
vif1Regs.stat.INT = true;
//Yakuza watches VIF_STAT so lets do this here.
if (((vif1Regs.code >> 24) & 0x7f) != 0x7) {
if (((vif1Regs.code >> 24) & 0x7f) != 0x7)
{
vif1Regs.stat.VIS = true;
}
@ -336,7 +353,7 @@ __fi void vif1Interrupt()
//NFSHPS stalls when the whole packet has gone across (it stalls in the last 32bit cmd)
//In this case VIF will end
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
if((vif1ch.qwc > 0 || !vif1.done) && !CHECK_VIF1STALLHACK)
if ((vif1ch.qwc > 0 || !vif1.done) && !CHECK_VIF1STALLHACK)
{
vif1Regs.stat.VPS = VPS_DECODING; //If there's more data you need to say it's decoding the next VIF CMD (Onimusha - Blade Warriors)
VIF_LOG("VIF1 Stalled");
@ -350,40 +367,62 @@ __fi void vif1Interrupt()
//Mirroring change to VIF0
if (vif1.cmd)
{
if (vif1.done && (vif1ch.qwc == 0)) vif1Regs.stat.VPS = VPS_WAITING;
if (vif1.done && (vif1ch.qwc == 0))
vif1Regs.stat.VPS = VPS_WAITING;
}
else
{
vif1Regs.stat.VPS = VPS_IDLE;
}
if (vif1.inprogress & 0x1)
{
_VIF1chain();
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation.
// Timesplitters 2 depends on this beeing a bit higher than 128.
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
if(!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
{
_VIF1chain();
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation.
// Timesplitters 2 depends on this beeing a bit higher than 128.
if (vif1ch.chcr.DIR)
vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
if (!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
{
if (vif1.waitforvu)
{
//if (cpuGetCycles(VU_MTVU_BUSY) > static_cast<int>(g_vif1Cycles))
// DevCon.Warning("Waiting %d instead of %d", cpuGetCycles(VU_MTVU_BUSY), static_cast<int>(g_vif1Cycles));
CPU_INT(DMAC_VIF1, std::max(static_cast<int>(g_vif1Cycles), cpuGetCycles(VU_MTVU_BUSY)));
}
else
CPU_INT(DMAC_VIF1, g_vif1Cycles);
return;
}
}
return;
}
if (!vif1.done)
{
if (!vif1.done)
{
if (!(dmacRegs.ctrl.DMAE) || vif1Regs.stat.VSS) //Stopped or DMA Disabled
{
//Console.WriteLn("vif1 dma masked");
return;
}
if (!(dmacRegs.ctrl.DMAE) || vif1Regs.stat.VSS) //Stopped or DMA Disabled
{
//Console.WriteLn("vif1 dma masked");
return;
}
if ((vif1.inprogress & 0x1) == 0) vif1SetupTransfer();
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
if ((vif1.inprogress & 0x1) == 0)
vif1SetupTransfer();
if (vif1ch.chcr.DIR)
vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
if(!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
CPU_INT(DMAC_VIF1, g_vif1Cycles);
return;
if (!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
{
if (vif1.waitforvu)
{
//if (cpuGetCycles(VU_MTVU_BUSY) > static_cast<int>(g_vif1Cycles))
// DevCon.Warning("Waiting %d instead of %d", cpuGetCycles(VU_MTVU_BUSY), static_cast<int>(g_vif1Cycles));
CPU_INT(DMAC_VIF1, std::max(static_cast<int>(g_vif1Cycles), cpuGetCycles(VU_MTVU_BUSY)));
}
else
CPU_INT(DMAC_VIF1, g_vif1Cycles);
}
return;
}
if (vif1.vifstalled.enabled && vif1.done)
@ -393,52 +432,55 @@ __fi void vif1Interrupt()
return; //Dont want to end if vif is stalled.
}
#ifdef PCSX2_DEVBUILD
if (vif1ch.qwc > 0) DevCon.WriteLn("VIF1 Ending with %x QWC left", vif1ch.qwc);
if (vif1.cmd != 0) DevCon.WriteLn("vif1.cmd still set %x tag size %x", vif1.cmd, vif1.tag.size);
if (vif1ch.qwc > 0)
DevCon.WriteLn("VIF1 Ending with %x QWC left", vif1ch.qwc);
if (vif1.cmd != 0)
DevCon.WriteLn("vif1.cmd still set %x tag size %x", vif1.cmd, vif1.tag.size);
#endif
if((vif1ch.chcr.DIR == VIF_NORMAL_TO_MEM_MODE) && vif1.GSLastDownloadSize <= 16)
if ((vif1ch.chcr.DIR == VIF_NORMAL_TO_MEM_MODE) && vif1.GSLastDownloadSize <= 16)
{
//Reverse fifo has finished and nothing is left, so lets clear the outputting flag
gifRegs.stat.OPH = false;
}
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
if (vif1ch.chcr.DIR)
vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
vif1ch.chcr.STR = false;
vif1.vifstalled.enabled = false;
vif1.irqoffset.enabled = false;
if(vif1.queued_program) vifExecQueue(1);
if (vif1.queued_program)
vifExecQueue(1);
g_vif1Cycles = 0;
VIF_LOG("VIF1 DMA End");
hwDmacIrq(DMAC_VIF1);
}
void dmaVIF1()
{
VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n"
" tadr = %lx, asr0 = %lx, asr1 = %lx",
vif1ch.chcr._u32, vif1ch.madr, vif1ch.qwc,
vif1ch.tadr, vif1ch.asr0, vif1ch.asr1);
" tadr = %lx, asr0 = %lx, asr1 = %lx",
vif1ch.chcr._u32, vif1ch.madr, vif1ch.qwc,
vif1ch.tadr, vif1ch.asr0, vif1ch.asr1);
g_vif1Cycles = 0;
vif1.inprogress = 0;
if (vif1ch.qwc > 0) // Normal Mode
if (vif1ch.qwc > 0) // Normal Mode
{
// ignore tag if it's a GS download (Def Jam Fight for NY)
if(vif1ch.chcr.MOD == CHAIN_MODE && vif1ch.chcr.DIR)
if (vif1ch.chcr.MOD == CHAIN_MODE && vif1ch.chcr.DIR)
{
vif1.dmamode = VIF_CHAIN_MODE;
//DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch.chcr.desc());
if ((vif1ch.chcr.tag().ID == TAG_REFE) || (vif1ch.chcr.tag().ID == TAG_END) || (vif1ch.chcr.tag().IRQ && vif1ch.chcr.TIE))
{
vif1.done = true;
}
else
else
{
vif1.done = false;
}
@ -448,12 +490,13 @@ void dmaVIF1()
if (dmacRegs.ctrl.STD == STD_VIF1)
Console.WriteLn("DMA Stall Control on VIF1 normal not implemented - Report which game to PCSX2 Team");
if (vif1ch.chcr.DIR) // from Memory
if (vif1ch.chcr.DIR) // from Memory
vif1.dmamode = VIF_NORMAL_FROM_MEM_MODE;
else
vif1.dmamode = VIF_NORMAL_TO_MEM_MODE;
if(vif1.irqoffset.enabled && !vif1.done) DevCon.Warning("Warning! VIF1 starting a Normal transfer with vif offset set (Possible force stop?)");
if (vif1.irqoffset.enabled && !vif1.done)
DevCon.Warning("Warning! VIF1 starting a Normal transfer with vif offset set (Possible force stop?)");
vif1.done = true;
}
@ -464,10 +507,10 @@ void dmaVIF1()
vif1.inprogress &= ~0x1;
vif1.dmamode = VIF_CHAIN_MODE;
vif1.done = false;
}
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
if (vif1ch.chcr.DIR)
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
// Check VIF isn't stalled before starting the loop.
// Batman Vengence does something stupid and instead of cancelling a stall it tries to restart VIF, THEN check the stall

View File

@ -27,9 +27,9 @@ static u32 qwctag(u32 mask)
static u32 QWCinVIFMFIFO(u32 DrainADDR, u32 qwc)
{
u32 ret;
//Calculate what we have in the fifo.
if(DrainADDR <= spr0ch.madr)
if (DrainADDR <= spr0ch.madr)
{
//Drain is below the tadr, calculate the difference between them
ret = (spr0ch.madr - DrainADDR) >> 4;
@ -37,7 +37,7 @@ static u32 QWCinVIFMFIFO(u32 DrainADDR, u32 qwc)
else
{
u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
//Drain is higher than SPR so it has looped round,
//Drain is higher than SPR so it has looped round,
//calculate from base to the SPR tag addr and what is left in the top of the ring
ret = ((spr0ch.madr - dmacRegs.rbor.ADDR) + (limit - DrainADDR)) >> 4;
}
@ -50,18 +50,19 @@ static __fi bool mfifoVIF1rbTransfer()
{
u32 msize = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
u32 mfifoqwc = std::min(QWCinVIFMFIFO(vif1ch.madr, vif1ch.qwc), vif1ch.qwc);
u32 *src;
u32* src;
bool ret;
if (mfifoqwc == 0) {
if (mfifoqwc == 0)
{
DevCon.Warning("VIF MFIFO no QWC before transfer (in transfer function, bit late really)");
return true; //Cant do anything, lets forget it
return true; //Cant do anything, lets forget it
}
/* Check if the transfer should wrap around the ring buffer */
if ((vif1ch.madr + (mfifoqwc << 4)) > (msize))
{
int s1 = ((msize) - vif1ch.madr) >> 2;
int s1 = ((msize)-vif1ch.madr) >> 2;
VIF_LOG("Split MFIFO");
@ -69,7 +70,8 @@ static __fi bool mfifoVIF1rbTransfer()
vif1ch.madr = qwctag(vif1ch.madr);
src = (u32*)PSM(vif1ch.madr);
if (src == NULL) return false;
if (src == NULL)
return false;
if (vif1.irqoffset.enabled)
ret = VIF1transfer(src + vif1.irqoffset.value, s1 - vif1.irqoffset.value);
@ -78,15 +80,17 @@ static __fi bool mfifoVIF1rbTransfer()
if (ret)
{
if(vif1.irqoffset.value != 0) DevCon.Warning("VIF1 MFIFO Offest != 0! vifoffset=%x", vif1.irqoffset.value);
/* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
if (vif1.irqoffset.value != 0)
DevCon.Warning("VIF1 MFIFO Offest != 0! vifoffset=%x", vif1.irqoffset.value);
/* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
//DevCon.Warning("Loopyloop");
vif1ch.tadr = qwctag(vif1ch.tadr);
vif1ch.madr = qwctag(vif1ch.madr);
src = (u32*)PSM(vif1ch.madr);
if (src == NULL) return false;
VIF1transfer(src, ((mfifoqwc << 2) - s1));
src = (u32*)PSM(vif1ch.madr);
if (src == NULL)
return false;
VIF1transfer(src, ((mfifoqwc << 2) - s1));
}
}
else
@ -95,7 +99,8 @@ static __fi bool mfifoVIF1rbTransfer()
/* it doesn't, so just transfer 'qwc*4' words */
src = (u32*)PSM(vif1ch.madr);
if (src == NULL) return false;
if (src == NULL)
return false;
if (vif1.irqoffset.enabled)
ret = VIF1transfer(src + vif1.irqoffset.value, mfifoqwc * 4 - vif1.irqoffset.value);
@ -115,10 +120,11 @@ static __fi void mfifo_VIF1chain()
}
if (vif1ch.madr >= dmacRegs.rbor.ADDR &&
vif1ch.madr < (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16u))
vif1ch.madr < (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16u))
{
//if(vif1ch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge VIF1");
if (QWCinVIFMFIFO(vif1ch.madr, vif1ch.qwc) == 0) {
if (QWCinVIFMFIFO(vif1ch.madr, vif1ch.qwc) == 0)
{
VIF_LOG("VIF MFIFO Empty before transfer");
vif1.inprogress |= 0x10;
g_vif1Cycles += 4;
@ -132,16 +138,16 @@ static __fi void mfifo_VIF1chain()
//It does an END tag (which normally doesn't increment TADR because it breaks Soul Calibur 2)
//with a QWC of 1 (rare) so we need to increment the TADR in the case of MFIFO.
vif1ch.tadr = vif1ch.madr;
}
else
{
tDMA_TAG *pMem = dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR);
tDMA_TAG* pMem = dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR);
VIF_LOG("Non-MFIFO Location");
//No need to exit on non-mfifo as it is indirect anyway, so it can be transferring this while spr refills the mfifo
if (pMem == NULL) return;
if (pMem == NULL)
return;
if (vif1.irqoffset.enabled)
VIF1transfer((u32*)pMem + vif1.irqoffset.value, vif1ch.qwc * 4 - vif1.irqoffset.value);
@ -152,19 +158,20 @@ static __fi void mfifo_VIF1chain()
void mfifoVifMaskMem(int id)
{
switch (id) {
switch (id)
{
//These five transfer data following the tag, need to check its within the buffer (Front Mission 4)
case TAG_CNT:
case TAG_NEXT:
case TAG_CALL:
case TAG_CALL:
case TAG_RET:
case TAG_END:
if(vif1ch.madr < dmacRegs.rbor.ADDR) //probably not needed but we will check anyway.
if (vif1ch.madr < dmacRegs.rbor.ADDR) //probably not needed but we will check anyway.
{
//DevCon.Warning("VIF MFIFO MADR below bottom of ring buffer, wrapping VIF MADR = %x Ring Bottom %x", vif1ch.madr, dmacRegs.rbor.ADDR);
vif1ch.madr = qwctag(vif1ch.madr);
}
if(vif1ch.madr > (dmacRegs.rbor.ADDR + (u32)dmacRegs.rbsr.RMSK)) //Usual scenario is the tag is near the end (Front Mission 4)
if (vif1ch.madr > (dmacRegs.rbor.ADDR + (u32)dmacRegs.rbsr.RMSK)) //Usual scenario is the tag is near the end (Front Mission 4)
{
//DevCon.Warning("VIF MFIFO MADR outside top of ring buffer, wrapping VIF MADR = %x Ring Top %x", vif1ch.madr, (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK)+16);
vif1ch.madr = qwctag(vif1ch.madr);
@ -178,13 +185,14 @@ void mfifoVifMaskMem(int id)
void mfifoVIF1transfer()
{
tDMA_TAG *ptag;
tDMA_TAG* ptag;
g_vif1Cycles = 0;
if (vif1ch.qwc == 0)
{
if (QWCinVIFMFIFO(vif1ch.tadr, 1) == 0) {
if (QWCinVIFMFIFO(vif1ch.tadr, 1) == 0)
{
VIF_LOG("VIF MFIFO Empty before tag");
vif1.inprogress |= 0x10;
g_vif1Cycles += 4;
@ -212,21 +220,20 @@ void mfifoVIF1transfer()
if (vif1.irqoffset.enabled)
{
ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset.value, 4 - vif1.irqoffset.value, true); //Transfer Tag on stall
ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset.value, 4 - vif1.irqoffset.value, true); //Transfer Tag on stall
//ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on stall
}
else
{
vif1.irqoffset.value = 2;
vif1.irqoffset.enabled = true;
ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag
ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag
}
if (!ret && vif1.irqoffset.enabled)
{
vif1.inprogress &= ~1;
return; //IRQ set by VIFTransfer
return; //IRQ set by VIFTransfer
}
g_vif1Cycles += 2;
}
@ -234,12 +241,12 @@ void mfifoVIF1transfer()
vif1.irqoffset.value = 0;
vif1.irqoffset.enabled = false;
vif1ch.unsafeTransfer(ptag);
vif1ch.unsafeTransfer(ptag);
vif1ch.madr = ptag[1]._u32;
VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx spr0 madr = %x",
ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, spr0ch.madr);
ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, spr0ch.madr);
vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID);
@ -253,13 +260,14 @@ void mfifoVIF1transfer()
vif1ch.tadr = qwctag(vif1ch.tadr);
if(vif1ch.qwc > 0) vif1.inprogress |= 1;
if (vif1ch.qwc > 0)
vif1.inprogress |= 1;
}
else
{
DevCon.Warning("Vif MFIFO QWC not 0 on tag");
}
VIF_LOG("mfifoVIF1transfer end %x madr %x, tadr %x", vif1ch.chcr._u32, vif1ch.madr, vif1ch.tadr);
}
@ -269,33 +277,36 @@ void vifMFIFOInterrupt()
g_vif1Cycles = 0;
VIF_LOG("vif mfifo interrupt");
if (dmacRegs.ctrl.MFD != MFD_VIF1) {
if (dmacRegs.ctrl.MFD != MFD_VIF1)
{
vif1Interrupt();
return;
}
if( gifRegs.stat.APATH == 2 && gifUnit.gifPath[1].isDone())
if (gifRegs.stat.APATH == 2 && gifUnit.gifPath[1].isDone())
{
gifRegs.stat.APATH = 0;
gifRegs.stat.OPH = 0;
if(gifUnit.checkPaths(1,0,1)) gifUnit.Execute(false, true);
if (gifUnit.checkPaths(1, 0, 1))
gifUnit.Execute(false, true);
}
if (vif1ch.chcr.DIR) {
bool isDirect = (vif1.cmd & 0x7f) == 0x50;
if (vif1ch.chcr.DIR)
{
bool isDirect = (vif1.cmd & 0x7f) == 0x50;
bool isDirectHL = (vif1.cmd & 0x7f) == 0x51;
if((isDirect && !gifUnit.CanDoPath2())
|| (isDirectHL && !gifUnit.CanDoPath2HL())) {
if ((isDirect && !gifUnit.CanDoPath2()) || (isDirectHL && !gifUnit.CanDoPath2HL()))
{
GUNIT_WARN("vifMFIFOInterrupt() - Waiting for Path 2 to be ready");
CPU_INT(DMAC_MFIFO_VIF, 128);
return;
}
}
if(vif1.waitforvu)
if (vif1.waitforvu)
{
// DevCon.Warning("Waiting on VU1 MFIFO");
CPU_INT(VIF_VU1_FINISH, 16);
//DevCon.Warning("Waiting on VU1 MFIFO");
CPU_INT(VIF_VU1_FINISH, std::max(16, cpuGetCycles(VU_MTVU_BUSY)));
return;
}
@ -303,25 +314,29 @@ void vifMFIFOInterrupt()
// we handle that separately (KH2 for testing)
// Simulated GS transfer time done, clear the flags
if (vif1.irq && vif1.vifstalled.enabled && vif1.vifstalled.value == VIF_IRQ_STALL) {
if (vif1.irq && vif1.vifstalled.enabled && vif1.vifstalled.value == VIF_IRQ_STALL)
{
VIF_LOG("VIF MFIFO Code Interrupt detected");
vif1Regs.stat.INT = true;
if (((vif1Regs.code >> 24) & 0x7f) != 0x7) {
if (((vif1Regs.code >> 24) & 0x7f) != 0x7)
{
vif1Regs.stat.VIS = true;
}
hwIntcIrq(INTC_VIF1);
--vif1.irq;
if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) {
if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
{
//vif1Regs.stat.FQC = 0; // FQC=0
//vif1ch.chcr.STR = false;
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
VIF_LOG("VIF1 MFIFO Stalled qwc = %x done = %x inprogress = %x", vif1ch.qwc, vif1.done, vif1.inprogress & 0x10);
//Used to check if the MFIFO was empty, there's really no need if it's finished what it needed.
if((vif1ch.qwc > 0 || !vif1.done)) {
if ((vif1ch.qwc > 0 || !vif1.done))
{
vif1Regs.stat.VPS = VPS_DECODING; //If there's more data you need to say it's decoding the next VIF CMD (Onimusha - Blade Warriors)
VIF_LOG("VIF1 MFIFO Stalled");
return;
@ -330,33 +345,48 @@ void vifMFIFOInterrupt()
}
//Mirroring change to VIF0
if (vif1.cmd) {
if (vif1.done && vif1ch.qwc == 0) vif1Regs.stat.VPS = VPS_WAITING;
if (vif1.cmd)
{
if (vif1.done && vif1ch.qwc == 0)
vif1Regs.stat.VPS = VPS_WAITING;
}
else {
else
{
vif1Regs.stat.VPS = VPS_IDLE;
}
if(vif1.inprogress & 0x10) {
if (vif1.inprogress & 0x10)
{
FireMFIFOEmpty();
return;
}
vif1.vifstalled.enabled = false;
if (!vif1.done || vif1ch.qwc) {
switch(vif1.inprogress & 1) {
if (!vif1.done || vif1ch.qwc)
{
switch (vif1.inprogress & 1)
{
case 0: //Set up transfer
mfifoVIF1transfer();
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
[[fallthrough]];
case 1: //Transfer data
if(vif1.inprogress & 0x1) //Just in case the tag breaks early (or something wierd happens)!
if (vif1.inprogress & 0x1) //Just in case the tag breaks early (or something wierd happens)!
mfifo_VIF1chain();
//Sanity check! making sure we always have non-zero values
if(!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
CPU_INT(DMAC_MFIFO_VIF, (g_vif1Cycles == 0 ? 4 : g_vif1Cycles) );
if (!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
{
if (vif1.waitforvu)
{
//if (cpuGetCycles(VU_MTVU_BUSY) > static_cast<int>(g_vif1Cycles))
// DevCon.Warning("Waiting %d instead of %d", cpuGetCycles(VU_MTVU_BUSY), static_cast<int>(g_vif1Cycles));
CPU_INT(DMAC_MFIFO_VIF, std::max(static_cast<int>((g_vif1Cycles == 0 ? 4 : g_vif1Cycles)), cpuGetCycles(VU_MTVU_BUSY)));
}
else
CPU_INT(DMAC_MFIFO_VIF, (g_vif1Cycles == 0 ? 4 : g_vif1Cycles));
}
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
return;
@ -368,7 +398,8 @@ void vifMFIFOInterrupt()
vif1.irqoffset.enabled = false;
vif1.done = 1;
if (spr0ch.madr == vif1ch.tadr) {
if (spr0ch.madr == vif1ch.tadr)
{
FireMFIFOEmpty();
}

View File

@ -341,7 +341,6 @@ namespace Panels
void Defaults_Click(wxCommandEvent& evt);
void EECycleRate_Scroll(wxScrollEvent& event);
void VUCycleRate_Scroll(wxScrollEvent& event);
void VUThread_Enable(wxCommandEvent& evt);
};
// --------------------------------------------------------------------------------------

View File

@ -167,16 +167,16 @@ Panels::SpeedHacksPanel::SpeedHacksPanel( wxWindow* parent )
m_check_vuThread = new pxCheckBox( vuHacksPanel, _("MTVU (Multi-Threaded microVU1)"),
_("Good Speedup and High Compatibility; may cause hanging... [Recommended on 3+ cores]") );
m_check_vu1Instant = new pxCheckBox(vuHacksPanel, _("Instant VU1 (without MTVU only)"),
m_check_vu1Instant = new pxCheckBox(vuHacksPanel, _("Instant VU1"),
_("Good Speedup and High Compatibility; may cause some graphical errors"));
m_check_vuFlagHack->SetToolTip( pxEt( L"Updates Status Flags only on blocks which will read them, instead of all the time. This is safe most of the time."
) );
m_check_vuThread->SetToolTip( pxEt( L"Runs VU1 on its own thread (microVU1-only). Generally a speedup on CPUs with 3 or more cores. This is safe for most games, but a few games are incompatible and may hang. In the case of GS limited games, it may be a slowdown (especially on dual core CPUs)."
m_check_vuThread->SetToolTip( pxEt( L"Runs VU1 on its own thread. Generally a speedup on CPUs with 3 or more cores. This is safe for most games, but a few games are incompatible and may hang. In the case of GS limited games, it may be a slowdown (especially on dual core CPUs)."
) );
m_check_vu1Instant->SetToolTip(pxEt(L"Runs VU1 instantly (when MTVU is disabled). Provides a modest speed improvement. This is safe for most games, but a few games may exhibit graphical errors."
m_check_vu1Instant->SetToolTip(pxEt(L"Runs VU1 instantly. Provides a modest speed improvement in most games. This is safe for most games, but a few games may exhibit graphical errors."
));
// ------------------------------------------------------------------------
@ -237,7 +237,6 @@ Panels::SpeedHacksPanel::SpeedHacksPanel( wxWindow* parent )
Bind(wxEVT_SCROLL_CHANGED, &SpeedHacksPanel::VUCycleRate_Scroll, this, m_slider_eeSkip->GetId());
Bind(wxEVT_CHECKBOX, &SpeedHacksPanel::OnEnable_Toggled, this, m_check_Enable->GetId());
Bind(wxEVT_BUTTON, &SpeedHacksPanel::Defaults_Click, this, wxID_DEFAULT);
Bind(wxEVT_CHECKBOX, &SpeedHacksPanel::VUThread_Enable, this, m_check_vuThread->GetId());
}
// Doesn't modify values - only locks(gray out)/unlocks as necessary.
@ -267,11 +266,6 @@ void Panels::SpeedHacksPanel::EnableStuff( AppConfig* configToUse )
// Grayout MTVU on safest preset
m_check_vuThread->Enable(hacksEnabled && (!hasPreset || configToUse->PresetIndex != 0));
// Disables the Instant VU1 checkbox when MTVU is checked in the GUI as reflected in the code.
// Makes Instant VU1 toggleable when MTVU is unchecked in the GUI.
// Some may think that having MTVU + Instant VU1 checked, can have bad side-effects when it doesn't.
m_check_vu1Instant->Enable(hacksEnabled && !m_check_vuThread->GetValue());
// Layout necessary to ensure changed slider text gets re-aligned properly
// and to properly gray/ungray pxStaticText stuff (I suspect it causes a
// paint event to be sent on Windows)
@ -370,9 +364,3 @@ void Panels::SpeedHacksPanel::VUCycleRate_Scroll(wxScrollEvent &event)
event.Skip();
}
void Panels::SpeedHacksPanel::VUThread_Enable(wxCommandEvent& evt)
{
m_check_vu1Instant->Enable(!m_check_vuThread->GetValue());
Layout();
}