diff --git a/.github/workflows/scripts/lint/gamedb/lint.py b/.github/workflows/scripts/lint/gamedb/lint.py index 6f04617380585..8550011ccd0ca 100644 --- a/.github/workflows/scripts/lint/gamedb/lint.py +++ b/.github/workflows/scripts/lint/gamedb/lint.py @@ -62,6 +62,7 @@ "texturePreloading", "deinterlace", "cpuSpriteRenderBW", + "cpuCLUTRender", "gpuPaletteConversion", ] gs_hw_fix_ranges = { @@ -73,6 +74,7 @@ "roundSprite": (0, 2), "deinterlace": (0, 7), "cpuSpriteRenderBW": (1, 10), + "cpuCLUTRender": (1, 2), "gpuPaletteConversion": (0, 2), } allowed_speed_hacks = ["mvuFlagSpeedHack", "InstantVU1SpeedHack", "MTVUSpeedHack"] diff --git a/bin/resources/GameIndex.yaml b/bin/resources/GameIndex.yaml index 5e3982ab47794..df1b8065d145d 100644 --- a/bin/resources/GameIndex.yaml +++ b/bin/resources/GameIndex.yaml @@ -920,6 +920,7 @@ SCAJ-20104: alignSprite: 1 # Fixes vertical lines. mergeSprite: 1 # Fixes vertical lines. texturePreloading: 1 # Performs better than full. + cpuCLUTRender: 1 # Fixes sun occlusion. SCAJ-20105: name: "Armored Core - Nine breaker" region: "NTSC-Unk" @@ -1095,6 +1096,7 @@ SCAJ-20136: alignSprite: 1 # Fixes vertical lines. mergeSprite: 1 # Fixes vertical lines. texturePreloading: 1 # Performs better than full. + cpuCLUTRender: 1 # Fixes sun occlusion. SCAJ-20137: name: "Musashiden II - Blademaster" region: "NTSC-Unk" @@ -1282,6 +1284,8 @@ SCAJ-20170: SCAJ-20171: name: "Zettai Zetsumei Toshi 2 - Itetsuita Kioku Tachi" region: "NTSC-J" + gsHWFixes: + cpuCLUTRender: 1 # Fixes some shading/shadows. SCAJ-20172: name: "Final Fantasy XII" region: "NTSC-Unk" @@ -2031,6 +2035,7 @@ SCED-52049: gsHWFixes: preloadFrameData: 1 # Fixes bad textures on Jake. halfPixelOffset: 1 # Fixes double image. + cpuCLUTRender: 1 # Fixes Jake going black in Smellovision. SCED-52051: name: "Official PlayStation 2 Magazine Demo 43" region: "PAL-M5" @@ -2756,6 +2761,8 @@ SCES-50354: vuClampMode: 2 # Fixes water reflection. gameFixes: - EETimingHack # Fixes flickering graphics. + gsHWFixes: + cpuCLUTRender: 1 # Fixes shadows, object and enemy colours, platform transitions. SCES-50360: name: "Twisted Metal - Black" region: "PAL-M5" @@ -3139,6 +3146,7 @@ SCES-51248: roundSprite: 1 # Fix line in the sky. preloadFrameData: 1 # Fixes bad textures on Jake. halfPixelOffset: 1 # Fixes double image. + cpuCLUTRender: 1 # Fixes Jake going black in Smellovision. SCES-51426: name: "Getaway, The" region: "PAL-M5" @@ -6696,6 +6704,7 @@ SCPS-56012: name: "Raw Danger" region: "NTSC-K" gsHWFixes: + cpuCLUTRender: 1 # Fixes some shading/shadows. autoFlush: 1 # Fixes incorrect blur effect. SCPS-56013: name: "This is Football 2003" @@ -8663,9 +8672,11 @@ SLAJ-25053: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLAJ-25055: name: "Def Jam - Fight for N.Y." region: "NTSC-Unk" @@ -8697,9 +8708,11 @@ SLAJ-25066: vuClampMode: 0 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLAJ-25066" - "SLPM-66108" @@ -8729,6 +8742,7 @@ SLAJ-25075: region: "NTSC-Unk" gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLAJ-25075" - "SLPM-66232" @@ -8773,6 +8787,8 @@ SLAJ-25079: SLAJ-25080: name: "Godfather, The" region: "NTSC-Unk" + gsHWFixes: + cpuCLUTRender: 1 # Fixes light occlusion. SLAJ-25081: name: "FIFA World Cup - Germany 2006" region: "NTSC-Unk" @@ -8806,9 +8822,11 @@ SLAJ-25094: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLAJ-25095: name: "Medal of Honor - Vanguard" region: "NTSC-Unk" @@ -8942,6 +8960,8 @@ SLED-52476: SLED-52485: name: "Alias [Demo]" region: "PAL-E" + gsHWFixes: + cpuCLUTRender: 1 # Fixes lights penetrating objects. SLED-52488: name: "Suffering, The [Demo]" region: "PAL-E" @@ -8954,9 +8974,11 @@ SLED-52597: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLED-52875: name: "Sega Superstars [Demo]" region: "PAL-E" @@ -9004,9 +9026,11 @@ SLED-53512: vuClampMode: 0 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLED-53537: name: "187 - Ride or Die [Demo]" region: "PAL-E" @@ -10588,6 +10612,7 @@ SLES-50731: vuClampMode: 2 # White textures. gsHWFixes: halfPixelOffset: 1 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes "Busted" scenes. SLES-50735: name: "Jade Cocoon 2" region: "PAL-E" @@ -11749,6 +11774,8 @@ SLES-51229: SLES-51230: name: "Minority Report" region: "PAL-E" + gsHWFixes: + cpuCLUTRender: 1 # Fixes light bleed through objects. SLES-51232: name: "Virtua Tennis 2" region: "PAL-M4" @@ -11966,9 +11993,13 @@ SLES-51316: SLES-51317: name: "Minority Report" region: "PAL-F" + gsHWFixes: + cpuCLUTRender: 1 # Fixes light bleed through objects. SLES-51318: name: "Minority Report" region: "PAL-G" + gsHWFixes: + cpuCLUTRender: 1 # Fixes light bleed through objects. SLES-51322: name: "Robotech Battlecry" region: "PAL-M5" @@ -12879,9 +12910,13 @@ SLES-51820: SLES-51821: name: "Alias" region: "PAL-M5" + gsHWFixes: + cpuCLUTRender: 1 # Fixes lights penetrating objects. SLES-51822: name: "Alias" region: "PAL-I" + gsHWFixes: + cpuCLUTRender: 1 # Fixes lights penetrating objects. SLES-51823: name: "Hunter - The Reckoning Wayward" region: "PAL-M3" @@ -14514,9 +14549,11 @@ SLES-52584: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLES-52585: name: "Burnout 3 - Takedown" region: "PAL-F-G-I" @@ -14524,9 +14561,11 @@ SLES-52585: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLES-52587: name: "Army Men - Sarge's War" region: "PAL-M5" @@ -16209,6 +16248,8 @@ SLES-53350: compat: 5 roundModes: vuRoundMode: 0 # Prevents only backgrounds from appearing in Sonic R's multiplayer modes. + gsHWFixes: + cpuCLUTRender: 2 # Fixes CLUT colour in Sonic Fighters. memcardFilters: # Vectorman unlocks by having a Mega Collection or Heroes save. - "SLES-53350" - "SLES-52998" @@ -16620,9 +16661,11 @@ SLES-53506: vuClampMode: 0 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLES-53506" - "SLES-53507" @@ -16637,9 +16680,11 @@ SLES-53507: vuClampMode: 0 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLES-53506" - "SLES-53507" @@ -16837,12 +16882,16 @@ SLES-53556: region: "PAL-M3" gameFixes: - BlitInternalFPSHack # Fixes internal FPS detection. + gsHWFixes: + cpuSpriteRenderBW: 2 # Fixes some bad textures. + cpuCLUTRender: 1 # Fixes the rest of the bad textures. SLES-53557: name: "Need for Speed - Most Wanted" region: "PAL-E" compat: 5 gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: # Reads Underground 2 save for extra money. - "SLES-53557" - "SLES-53558" @@ -16854,6 +16903,7 @@ SLES-53558: region: "PAL-M8" gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLES-53557" - "SLES-53558" @@ -16865,6 +16915,7 @@ SLES-53559: region: "PAL-M3" gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLES-53557" - "SLES-53558" @@ -16990,6 +17041,7 @@ SLES-53616: cpuSpriteRenderBW: 1 # Fixes textures. preloadFrameData: 1 # Fixes static text screens. roundSprite: 1 # Fixes lines in some post-effects. + cpuCLUTRender: 1 # Fixes light occlusion. SLES-53617: name: "True Crime - New York City" region: "PAL-G" @@ -17001,6 +17053,7 @@ SLES-53617: cpuSpriteRenderBW: 1 # Fixes textures. preloadFrameData: 1 # Fixes static text screens. roundSprite: 1 # Fixes lines in some post-effects. + cpuCLUTRender: 1 # Fixes light occlusion. SLES-53618: name: "True Crime - New York City" region: "PAL-S" @@ -17012,6 +17065,7 @@ SLES-53618: cpuSpriteRenderBW: 1 # Fixes textures. preloadFrameData: 1 # Fixes static text screens. roundSprite: 1 # Fixes lines in some post-effects. + cpuCLUTRender: 1 # Fixes light occlusion. SLES-53621: name: "Wallace & Gromit - The Curse of the Were-Rabbit" region: "PAL-M5" @@ -17631,6 +17685,7 @@ SLES-53857: region: "PAL-M3" gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLES-53557" - "SLES-53558" @@ -17859,6 +17914,8 @@ SLES-53966: SLES-53967: name: "Godfather, The" region: "PAL-M6" + gsHWFixes: + cpuCLUTRender: 1 # Fixes light occlusion. SLES-53968: name: "Parrain, Le" region: "PAL-F" @@ -18021,6 +18078,9 @@ SLES-54027: region: "PAL-M3" gameFixes: - BlitInternalFPSHack # Fixes internal FPS detection. + gsHWFixes: + cpuSpriteRenderBW: 2 # Fixes some bad textures. + cpuCLUTRender: 1 # Fixes the rest of the bad textures. SLES-54030: name: "Black" region: "PAL-E" @@ -19324,6 +19384,8 @@ SLES-54586: SLES-54587: name: "Raw Danger" region: "PAL-E" + gsHWFixes: + cpuCLUTRender: 1 # Fixes some shading/shadows. SLES-54588: name: "Brunswick Pro Bowling" region: "PAL-E" @@ -19408,9 +19470,11 @@ SLES-54627: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLES-54628: name: "Skate Attack [Promo]" region: "PAL-E" @@ -19577,9 +19641,11 @@ SLES-54681: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLES-54683: name: "Medal of Honor - Vanguard" region: "PAL-M9" @@ -20373,6 +20439,9 @@ SLES-54991: SLES-54992: name: "PDC World Championship Darts 2008" region: "PAL-M6" + gsHWFixes: + autoFlush: 1 # Fixes lights not appearing. + cpuCLUTRender: 1 # Fixes lights going through darts players. SLES-54994: name: "Pippa Funnell - Ranch Rescue" region: "PAL-M11" @@ -22673,9 +22742,11 @@ SLKA-25206: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLKA-25207: name: "Sakura Taisen V - Episode 0 - Samurai Girl of Wild" region: "NTSC-K" @@ -22937,9 +23008,11 @@ SLKA-25304: vuClampMode: 0 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLKA-25307: name: "Dragon Ball Z Sparking" region: "NTSC-K" @@ -23027,6 +23100,7 @@ SLKA-25334: region: "NTSC-K" gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLKA-25335: name: "Shadow the Hedgehog" region: "NTSC-K" @@ -23037,6 +23111,9 @@ SLKA-25341: region: "NTSC-K" gameFixes: - BlitInternalFPSHack # Fixes internal FPS detection. + gsHWFixes: + cpuSpriteRenderBW: 2 # Fixes some bad textures. + cpuCLUTRender: 1 # Fixes the rest of the bad textures. SLKA-25342: name: "Ryu ga Gotoku" region: "NTSC-K" @@ -23218,9 +23295,11 @@ SLPM-55004: vuClampMode: 0 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLPM-55005: name: "Mana Khemia 2 - Ochita Gakuen to Renkinjutsushi Tachi" region: "NTSC-J" @@ -23255,9 +23334,11 @@ SLPM-55036: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLPM-55039: name: "Soukoku no Kusabi - Hiiro no Kakera 3 [Limited Edition]" region: "NTSC-J" @@ -23748,6 +23829,8 @@ SLPM-60138: vuClampMode: 2 # Fixes water reflection. gameFixes: - EETimingHack # Fixes flickering graphics. + gsHWFixes: + cpuCLUTRender: 1 # Fixes shadows, object and enemy colours, platform transitions. SLPM-60167: name: "Zero [Trial]" region: "NTSC-J" @@ -23797,9 +23880,11 @@ SLPM-60246: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLPM-60251: name: "Devil May Cry 3 [Trial Version]" region: "NTSC-J" @@ -23811,6 +23896,8 @@ SLPM-60251: SLPM-60254: name: "Zettai Zetsumei Toshi 2 - Itetsuita Kioku-tachi [Trial A]" region: "NTSC-J" + gsHWFixes: + cpuCLUTRender: 1 # Fixes some shading/shadows. SLPM-60256: name: "Dengeki D73 demo" region: "NTSC-J" @@ -23857,6 +23944,8 @@ SLPM-60272: SLPM-60273: name: "Zettai Zetsumei Toshi 2 - Itetsuita Kioku-tachi [Trial B]" region: "NTSC-J" + gsHWFixes: + cpuCLUTRender: 1 # Fixes some shading/shadows. SLPM-60274: name: "Full House Kiss 2 [Trial]" region: "NTSC-J" @@ -23907,6 +23996,8 @@ SLPM-61039: SLPM-61046: name: "Dennou Senki - Virtual-On Marz [Trial]" region: "NTSC-J" + gsHWFixes: + cpuCLUTRender: 2 # Fixes CLUT colours. SLPM-61051: name: "Dengeki PS2 D61" region: "NTSC-J" @@ -25415,6 +25506,8 @@ SLPM-62547: name: "Sega Ages 2500 Series Vol.16 - Virtua Fighter 2" region: "NTSC-J" compat: 5 + gsHWFixes: + cpuCLUTRender: 2 # Fixes CLUT colours. SLPM-62548: name: "Heisei Bakutoden [SuperLite 2000 Series]" region: "NTSC-J" @@ -25595,6 +25688,8 @@ SLPM-62606: name: "Sega Ages 2500 Series Vol.19 - Fighting Vipers" region: "NTSC-J" compat: 5 + gsHWFixes: + cpuCLUTRender: 2 # Fixes CLUT colours. SLPM-62607: name: "Shikigami no Shiro III [Taito The Best]" region: "NTSC-J" @@ -25828,6 +25923,8 @@ SLPM-62686: SLPM-62687: name: "Sega Ages 2500 Series Vol.24 - Last Bronx" region: "NTSC-J" + gsHWFixes: + cpuCLUTRender: 2 # Fixes CLUT colours. SLPM-62689: name: "Langrisser III" region: "NTSC-J" @@ -25875,6 +25972,8 @@ SLPM-62703: name: "Sega Rally Championship '95" region: "NTSC-J" compat: 5 + gsHWFixes: + cpuCLUTRender: 2 # Fixes CLUT colours. SLPM-62704: name: "Oretachi Geasen Zoku Sono Vol.10 - Quarth" region: "NTSC-J" @@ -27182,6 +27281,8 @@ SLPM-65302: SLPM-65303: name: "Dennou Senki - Virtual-On Marz" region: "NTSC-J" + gsHWFixes: + cpuCLUTRender: 2 # Fixes CLUT colours. SLPM-65305: name: "Genso Suikoden 3" region: "NTSC-J" @@ -28496,9 +28597,11 @@ SLPM-65719: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLPM-65720: name: "Shin Sangoku Musou 2 Mushoden [Koei the Best]" region: "NTSC-J" @@ -28928,7 +29031,7 @@ SLPM-65843: name: "120 Yen no Haru - 120 Yen Stories" region: "NTSC-J" gsHWFixes: - pointListPalette: 1 + cpuCLUTRender: 1 # Fixes CLUT generation. SLPM-65844: name: "Air [Best]" region: "NTSC-J" @@ -29306,9 +29409,11 @@ SLPM-65958: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLPM-65959: name: "Standard Daisenryaku - Ushinawareta Shouri" region: "NTSC-J" @@ -29431,6 +29536,7 @@ SLPM-65995: gsHWFixes: preloadFrameData: 1 # Fixes bad textures on Jake. halfPixelOffset: 1 # Fixes double image. + cpuCLUTRender: 1 # Fixes Jake going black in Smellovision. SLPM-65996: name: "Hametsu no Mars [Limited Edition]" region: "NTSC-J" @@ -29696,6 +29802,8 @@ SLPM-66074: compat: 5 roundModes: vuRoundMode: 0 # Prevents only backgrounds from appearing in Sonic R's multiplayer modes. + gsHWFixes: + cpuCLUTRender: 2 # Fixes CLUT colour in Sonic Fighters. memcardFilters: - "SLPM-66074" - "SLPM-65758" @@ -29821,9 +29929,11 @@ SLPM-66108: vuClampMode: 0 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLAJ-25066" - "SLPM-66108" @@ -30284,6 +30394,7 @@ SLPM-66232: region: "NTSC-J" gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLAJ-25075" - "SLPM-66232" @@ -31155,6 +31266,7 @@ SLPM-66473: cpuSpriteRenderBW: 1 # Fixes textures. preloadFrameData: 1 # Fixes static text screens. roundSprite: 1 # Fixes lines in some post-effects. + cpuCLUTRender: 1 # Fixes light occlusion. SLPM-66474: name: "Odin Sphere" region: "NTSC-J" @@ -31464,6 +31576,7 @@ SLPM-66562: region: "NTSC-J" gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLAJ-25075" - "SLPM-66232" @@ -31495,6 +31608,9 @@ SLPM-66567: region: "NTSC-J" gameFixes: - BlitInternalFPSHack # Fixes internal FPS detection. + gsHWFixes: + cpuSpriteRenderBW: 2 # Fixes some bad textures. + cpuCLUTRender: 1 # Fixes the rest of the bad textures. SLPM-66568: name: "Brothers In Arms - Road to Hill 30 [Ubisoft Best]" region: "NTSC-J" @@ -31794,9 +31910,11 @@ SLPM-66652: vuClampMode: 0 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLAJ-25066" - "SLPM-66108" @@ -32045,6 +32163,8 @@ SLPM-66709: SLPM-66710: name: "Godfather, The" region: "NTSC-J" + gsHWFixes: + cpuCLUTRender: 1 # Fixes light occlusion. SLPM-66712: name: "Rozen Maiden - Geppetto Garden [Limited Edition]" region: "NTSC-J" @@ -32161,9 +32281,11 @@ SLPM-66739: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLPM-66740: name: "Sentou Kokka Kai - Legend [DX Pack]" region: "NTSC-J" @@ -32876,9 +32998,11 @@ SLPM-66962: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLPM-66963: name: "Medal of Honor - Frontline [EA-SY! 1980]" region: "NTSC-J" @@ -32892,6 +33016,8 @@ SLPM-66965: SLPM-66966: name: "Godfather, The [EA-SY! 1980]" region: "NTSC-J" + gsHWFixes: + cpuCLUTRender: 1 # Fixes light occlusion. SLPM-66967: name: "Aria - The Natural - Tooi Yume no Mirage [Alchemist Best Collection]" region: "NTSC-J" @@ -33140,6 +33266,7 @@ SLPM-67527: vuClampMode: 2 # White textures. gsHWFixes: halfPixelOffset: 1 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes "Busted" scenes. SLPM-67528: name: "Hajime no Ippo - Victorious Boxers [Championship Edition]" region: "NTSC-K" @@ -33430,6 +33557,7 @@ SLPM-74243: cpuSpriteRenderBW: 1 # Fixes textures. preloadFrameData: 1 # Fixes static text screens. roundSprite: 1 # Fixes lines in some post-effects. + cpuCLUTRender: 1 # Fixes light occlusion. SLPM-74244: name: "Phantasy Star Universe [PlayStation 2 The Best]" region: "NTSC-J" @@ -33579,6 +33707,8 @@ SLPM-74420: SLPM-74421: name: "Dennou Senki - Virtual-On Marz [PlayStation 2 The Best]" region: "NTSC-J" + gsHWFixes: + cpuCLUTRender: 2 # Fixes CLUT colours. SLPS-20001: name: "Ridge Racer V" region: "NTSC-J" @@ -35019,6 +35149,8 @@ SLPS-25033: vuClampMode: 2 # Fixes water reflection. gameFixes: - EETimingHack # Fixes flickering graphics. + gsHWFixes: + cpuCLUTRender: 1 # Fixes shadows, object and enemy colours, platform transitions. SLPS-25034: name: "Flower, Sun and Rain" region: "NTSC-J" @@ -36348,6 +36480,7 @@ SLPS-25418: alignSprite: 1 # Fixes vertical lines. mergeSprite: 1 # Fixes vertical lines. texturePreloading: 1 # Performs better than full. + cpuCLUTRender: 1 # Fixes sun occlusion. patches: 86089F31: content: |- @@ -36995,6 +37128,8 @@ SLPS-25606: name: "Zettai Zetsumei Toshi 2 - Itetsuita Kioutachi" region: "NTSC-J" compat: 5 + gsHWFixes: + cpuCLUTRender: 1 # Fixes some shading/shadows. SLPS-25607: name: "Makai Senki Disgaea 2 [Limited Edition]" region: "NTSC-J" @@ -37905,6 +38040,8 @@ SLPS-25850: SLPS-25851: name: "Zettai Zetsumei Toshi 2 - Itetsuita Kioku Tachi [Irem Collection]" region: "NTSC-J" + gsHWFixes: + cpuCLUTRender: 1 # Fixes some shading/shadows. SLPS-25852: name: "Sanyo Pachinko Paradise 13 [Irem Collection]" region: "NTSC-J" @@ -38399,6 +38536,7 @@ SLPS-73218: alignSprite: 1 # Fixes vertical lines. mergeSprite: 1 # Fixes vertical lines. texturePreloading: 1 # Performs better than full. + cpuCLUTRender: 1 # Fixes sun occlusion. SLPS-73219: name: "Tales of Destiny 2 [PlayStation 2 The Best]" region: "NTSC-J" @@ -38699,6 +38837,8 @@ SLPS-73404: vuClampMode: 2 # Fixes water reflection. gameFixes: - EETimingHack # Fixes flickering graphics. + gsHWFixes: + cpuCLUTRender: 1 # Fixes shadows, object and enemy colours, platform transitions. SLPS-73405: name: "Zero [PlayStation 2 The Best]" region: "NTSC-J" @@ -39316,6 +39456,8 @@ SLUS-20151: vuClampMode: 2 # Fixes water reflection. gameFixes: - EETimingHack # Fixes flickering graphics. + gsHWFixes: + cpuCLUTRender: 1 # Fixes shadows, object and enemy colours, platform transitions. SLUS-20152: name: "Ace Combat 04 - Shattered Skies" region: "NTSC-U" @@ -40089,6 +40231,8 @@ SLUS-20331: name: "Minority Report - Everybody Runs" region: "NTSC-U" compat: 5 + gsHWFixes: + cpuCLUTRender: 1 # Fixes light bleed through objects. SLUS-20332: name: "NCAA March Madness 2002" region: "NTSC-U" @@ -40212,6 +40356,7 @@ SLUS-20362: vuClampMode: 2 # White textures. gsHWFixes: halfPixelOffset: 1 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes "Busted" scenes. SLUS-20363: name: "Sled Storm" region: "NTSC-U" @@ -41669,6 +41814,8 @@ SLUS-20673: name: "Alias" region: "NTSC-U" compat: 5 + gsHWFixes: + cpuCLUTRender: 1 # Fixes lights penetrating objects. SLUS-20674: name: "Cyber Troopers - Virtual-On Marz" region: "NTSC-U" @@ -42464,6 +42611,7 @@ SLUS-20851: alignSprite: 1 # Fixes vertical lines. mergeSprite: 1 # Fixes vertical lines. texturePreloading: 1 # Performs better than full. + cpuCLUTRender: 1 # Fixes sun occlusion. patches: 39B574F0: content: |- @@ -43350,7 +43498,8 @@ SLUS-21018: vuClampMode: 3 # Fixes minor SPS on characters. gsHWFixes: preloadFrameData: 1 # Fixes bad textures on Jake. - halfPixelOffset: 1 # Fixes double image. + halfPixelOffset: 1 # Fixes double image.gsHWFixes: + cpuCLUTRender: 1 # Fixes Jake going black in Smellovision. SLUS-21019: name: "Technic Beat" region: "NTSC-U" @@ -43520,9 +43669,11 @@ SLUS-21050: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLUS-21051: name: "FIFA 2005" region: "NTSC-U" @@ -43775,6 +43926,7 @@ SLUS-21106: cpuSpriteRenderBW: 1 # Fixes textures. preloadFrameData: 1 # Fixes static text screens. roundSprite: 1 # Fixes lines in some post-effects. + cpuCLUTRender: 1 # Fixes light occlusion. SLUS-21107: name: "X-Men - The Official Game" region: "NTSC-U" @@ -44470,9 +44622,11 @@ SLUS-21242: vuClampMode: 0 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: # Reads Burnout 3 and NFL 06 saves for unlockables. - "SLUS-21242" - "SLUS-21050" @@ -44623,6 +44777,7 @@ SLUS-21267: compat: 5 gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLUS-21267" - "SLUS-21351" @@ -44655,6 +44810,9 @@ SLUS-21271: compat: 5 gameFixes: - BlitInternalFPSHack # Fixes internal FPS detection. + gsHWFixes: + cpuSpriteRenderBW: 2 # Fixes some bad textures. + cpuCLUTRender: 1 # Fixes the rest of the bad textures. SLUS-21272: name: "Super Monkey Ball Adventure" region: "NTSC-U" @@ -45088,6 +45246,7 @@ SLUS-21351: compat: 5 gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). memcardFilters: - "SLUS-21267" - "SLUS-21351" @@ -45304,6 +45463,8 @@ SLUS-21385: name: "Godfather, The" region: "NTSC-U" compat: 5 + gsHWFixes: + cpuCLUTRender: 1 # Fixes light occlusion. SLUS-21386: name: "Tales of the Abyss" region: "NTSC-U" @@ -45379,6 +45540,9 @@ SLUS-21399: region: "NTSC-U" gameFixes: - BlitInternalFPSHack # Fixes internal FPS detection. + gsHWFixes: + cpuSpriteRenderBW: 2 # Fixes some bad textures. + cpuCLUTRender: 1 # Fixes the rest of the bad textures. SLUS-21400: name: "Monster House" region: "NTSC-U" @@ -45410,6 +45574,8 @@ SLUS-21407: compat: 5 clampModes: vuClampMode: 3 # Missing geometry with microVU. + gsHWFixes: + cpuCLUTRender: 1 # Fixes light occlusion. SLUS-21408: name: "FIFA World Cup Germany '06" region: "NTSC-U" @@ -45922,6 +46088,8 @@ SLUS-21501: name: "Raw Danger" region: "NTSC-U" compat: 5 + gsHWFixes: + cpuCLUTRender: 1 # Fixes some shading/shadows. SLUS-21503: name: "God Hand" region: "NTSC-U" @@ -46202,9 +46370,11 @@ SLUS-21596: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLUS-21597: name: "Medal of Honor - Vanguard" region: "NTSC-U" @@ -47052,6 +47222,9 @@ SLUS-21773: name: "PDC World Championship Darts 2008" region: "NTSC-U" compat: 5 + gsHWFixes: + autoFlush: 1 # Fixes lights not appearing. + cpuCLUTRender: 1 # Fixes lights going through darts players. SLUS-21774: name: "Dynasty Warriors 6" region: "NTSC-U" @@ -47330,6 +47503,8 @@ SLUS-21843: compat: 5 roundModes: vuRoundMode: 0 # Crashes without. + gsHWFixes: + cpuCLUTRender: 1 # Fixes bad colours during play. SLUS-21844: name: "Bolt" region: "NTSC-U" @@ -47799,6 +47974,8 @@ SLUS-28004: vuClampMode: 2 # Fixes water reflection. gameFixes: - EETimingHack # Fixes flickering graphics. + gsHWFixes: + cpuCLUTRender: 1 # Fixes shadows, object and enemy colours, platform transitions. SLUS-28006: name: "Burnout [Trade Demo]" region: "NTSC-U" @@ -48286,9 +48463,11 @@ SLUS-29113: vuClampMode: 3 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLUS-29116: name: "WWE SmackDown! vs. RAW [Public Beta Vol.1.0]" region: "NTSC-U" @@ -48392,9 +48571,11 @@ SLUS-29153: vuClampMode: 0 # Fixes buggy lighting in the garage. gsHWFixes: halfPixelOffset: 2 # Fixes depth lines. - autoFlush: 1 # Fixes blur. + autoFlush: 1 # Fixes blur and obscures sun behind objects. + preloadFrameData: 1 # Makes sun appear. mipmap: 2 # Fixes over sharpening. trilinearFiltering: 1 # Smoothes out mipmapping. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLUS-29154: name: "NHL '06 [Demo]" region: "NTSC-U" @@ -48403,6 +48584,7 @@ SLUS-29155: region: "NTSC-U" gsHWFixes: halfPixelOffset: 2 # Fixes blurriness. + cpuCLUTRender: 1 # Fixes sun penetrating bridges (along with HPO special). SLUS-29156: name: "Marvel Nemesis - Rise of the Imperfects [Demo]" region: "NTSC-U" @@ -48497,6 +48679,9 @@ SLUS-29185: region: "NTSC-U" gameFixes: - BlitInternalFPSHack # Fixes internal FPS detection. + gsHWFixes: + cpuSpriteRenderBW: 2 # Fixes some bad textures. + cpuCLUTRender: 1 # Fixes the rest of the bad textures. SLUS-29188: name: "Steambot Chronicles [Regular Demo]" region: "NTSC-U" diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp index 021aabcf9629e..be9d48ecbbb59 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.cpp @@ -236,6 +236,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget* ////////////////////////////////////////////////////////////////////////// SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.halfScreenFix, "EmuCore/GS", "UserHacks_Half_Bottom_Override", -1, -1); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuSpriteRenderBW, "EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuCLUTRender, "EmuCore/GS", "UserHacks_CPUCLUTRender", 0); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawStart, "EmuCore/GS", "UserHacks_SkipDraw_Start", 0); SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawEnd, "EmuCore/GS", "UserHacks_SkipDraw_End", 0); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hwAutoFlush, "EmuCore/GS", "UserHacks_AutoFlush", false); @@ -335,6 +336,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget* { m_ui.upscalingFixesLayout->removeRow(2); m_ui.hardwareFixesLayout->removeRow(2); + m_ui.hardwareFixesLayout->removeRow(1); m_ui.skipDrawStart = nullptr; m_ui.skipDrawEnd = nullptr; m_ui.textureOffsetX = nullptr; diff --git a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui index e91d0e8b3950a..349cc0e62f788 100644 --- a/pcsx2-qt/Settings/GraphicsSettingsWidget.ui +++ b/pcsx2-qt/Settings/GraphicsSettingsWidget.ui @@ -58,7 +58,7 @@ - 0 + 2 true @@ -388,7 +388,7 @@ - + @@ -692,14 +692,80 @@ - + + + + CPU Sprite Render Size: + + + + + + + + 0 (Disabled) + + + + + 1 (64 Max Width) + + + + + 2 (128 Max Width) + + + + + 3 (192 Max Width) + + + + + 4 (256 Max Width) + + + + + 5 (320 Max Width) + + + + + 6 (384 Max Width) + + + + + 7 (448 Max Width) + + + + + 8 (512 Max Width) + + + + + 9 (576 Max Width) + + + + + 10 (640 Max Width) + + + + + Skipdraw Range: - + @@ -717,7 +783,7 @@ - + @@ -777,15 +843,14 @@ - - - - CPU Sprite Render Size: + + + + 0 (Disabled) + + + 0 - - - - 0 (Disabled) @@ -793,56 +858,23 @@ - 1 (64 Max Width) - - - - - 2 (128 Max Width) - - - - - 3 (192 Max Width) - - - - - 4 (256 Max Width) - - - - - 5 (320 Max Width) - - - - - 6 (384 Max Width) - - - - - 7 (448 Max Width) - - - - - 8 (512 Max Width) + 1 (Normal) - 9 (576 Max Width) - - - - - 10 (640 Max Width) + 2 (Aggressive) + + + + Software CLUT Render + + + @@ -1537,6 +1569,13 @@ Rendering + + + + Texture Filtering: + + + @@ -1573,10 +1612,10 @@ - - + + - Texture Filtering: + Extra Rendering Threads: @@ -1587,13 +1626,6 @@ - - - - Extra Rendering Threads: - - - diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 4b93724d5330f..5ea866bf86efb 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -585,6 +585,7 @@ struct Pcsx2Config int UserHacks_TCOffsetX{0}; int UserHacks_TCOffsetY{0}; int UserHacks_CPUSpriteRenderBW{0}; + int UserHacks_CPUCLUTRender{ 0 }; TriFiltering TriFilter{TriFiltering::Automatic}; int OverrideTextureBarriers{-1}; int OverrideGeometryShaders{-1}; diff --git a/pcsx2/Frontend/FullscreenUI.cpp b/pcsx2/Frontend/FullscreenUI.cpp index 9d5d0cf120b0f..79e328a8de35a 100644 --- a/pcsx2/Frontend/FullscreenUI.cpp +++ b/pcsx2/Frontend/FullscreenUI.cpp @@ -2683,6 +2683,7 @@ void FullscreenUI::DrawGraphicsSettingsPage() static constexpr const char* s_cpu_sprite_render_bw_options[] = {"0 (Disabled)", "1 (64 Max Width)", "2 (128 Max Width)", "3 (192 Max Width)", "4 (256 Max Width)", "5 (320 Max Width)", "6 (384 Max Width)", "7 (448 Max Width)", "8 (512 Max Width)", "9 (576 Max Width)", "10 (640 Max Width)"}; + static constexpr const char* s_cpu_clut_render_options[] = { "0 (Disabled)", "1 (Normal)", "2 (Aggressive)" }; static constexpr const char* s_half_pixel_offset_options[] = { "Off (Default)", "Normal (Vertex)", "Special (Texture)", "Special (Texture - Aggressive)"}; static constexpr const char* s_round_sprite_options[] = {"Off (Default)", "Half", "Full"}; @@ -2691,6 +2692,8 @@ void FullscreenUI::DrawGraphicsSettingsPage() "UserHacks_Half_Bottom_Override", -1, s_generic_options, std::size(s_generic_options), -1); DrawIntListSetting(bsi, "CPU Sprite Render Size", "Uses sofware renderer to draw texture decompression-like sprites.", "EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0, s_cpu_sprite_render_bw_options, std::size(s_cpu_sprite_render_bw_options)); + DrawIntListSetting(bsi, "CPU Sprite Render Size", "Uses sofware renderer to draw texture decompression-like sprites.", + "EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0, s_cpu_clut_render_options, std::size(s_cpu_clut_render_options)); DrawIntRangeSetting( bsi, "Skip Draw Start", "Object range to skip drawing.", "EmuCore/GS", "UserHacks_SkipDraw_Start", 0, 0, 5000); DrawIntRangeSetting(bsi, "Skip Draw End", "Object range to skip drawing.", "EmuCore/GS", "UserHacks_SkipDraw_End", 0, 0, 5000); diff --git a/pcsx2/Frontend/ImGuiOverlays.cpp b/pcsx2/Frontend/ImGuiOverlays.cpp index 92cc525537225..54787acea382d 100644 --- a/pcsx2/Frontend/ImGuiOverlays.cpp +++ b/pcsx2/Frontend/ImGuiOverlays.cpp @@ -309,6 +309,8 @@ void ImGuiManager::DrawSettingsOverlay() APPEND("TCO={}/{} ", GSConfig.UserHacks_TCOffsetX, GSConfig.UserHacks_TCOffsetY); if (GSConfig.UserHacks_CPUSpriteRenderBW != 0) APPEND("CSBW={} ", GSConfig.UserHacks_CPUSpriteRenderBW); + if (GSConfig.UserHacks_CPUCLUTRender != 0) + APPEND("CCD={} ", GSConfig.UserHacks_CPUCLUTRender); if (GSConfig.SkipDrawStart != 0 || GSConfig.SkipDrawEnd != 0) APPEND("SD={}/{} ", GSConfig.SkipDrawStart, GSConfig.SkipDrawEnd); if (GSConfig.UserHacks_TextureInsideRt) diff --git a/pcsx2/GS/GS.cpp b/pcsx2/GS/GS.cpp index efac23be36387..2bbe37e39cae1 100644 --- a/pcsx2/GS/GS.cpp +++ b/pcsx2/GS/GS.cpp @@ -834,7 +834,8 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config) GSConfig.UserHacks_DisableDepthSupport != old_config.UserHacks_DisableDepthSupport || GSConfig.UserHacks_DisablePartialInvalidation != old_config.UserHacks_DisablePartialInvalidation || GSConfig.UserHacks_TextureInsideRt != old_config.UserHacks_TextureInsideRt || - GSConfig.UserHacks_CPUSpriteRenderBW != old_config.UserHacks_CPUSpriteRenderBW) + GSConfig.UserHacks_CPUSpriteRenderBW != old_config.UserHacks_CPUSpriteRenderBW || + GSConfig.UserHacks_CPUSpriteRenderBW != old_config.UserHacks_CPUCLUTRender) { g_gs_renderer->PurgeTextureCache(); g_gs_renderer->PurgePool(); @@ -1512,6 +1513,7 @@ void GSApp::Init() m_default_configuration["UserHacks_Disable_Safe_Features"] = "0"; m_default_configuration["UserHacks_DisablePartialInvalidation"] = "0"; m_default_configuration["UserHacks_CPUSpriteRenderBW"] = "0"; + m_default_configuration["UserHacks_CPUCLUTRender"] = "0"; m_default_configuration["UserHacks_CPU_FB_Conversion"] = "0"; m_default_configuration["UserHacks_Half_Bottom_Override"] = "-1"; m_default_configuration["UserHacks_HalfPixelOffset"] = "0"; diff --git a/pcsx2/GS/GSClut.cpp b/pcsx2/GS/GSClut.cpp index 02b4158dd60e6..fb667d1d0cbd6 100644 --- a/pcsx2/GS/GSClut.cpp +++ b/pcsx2/GS/GSClut.cpp @@ -28,7 +28,7 @@ GSClut::GSClut(GSLocalMemory* mem) m_clut = (u16*)&p[0]; // 1k + 1k for mirrored area simulating wrapping memory m_buff32 = (u32*)&p[2048]; // 1k m_buff64 = (u64*)&p[4096]; // 2k - m_write.dirty = true; + m_write.dirty = 1; m_read.dirty = true; for (int i = 0; i < 16; i++) @@ -103,34 +103,35 @@ GSClut::~GSClut() vmfree(m_clut, CLUT_ALLOC_SIZE); } -void GSClut::Invalidate() +u8 GSClut::IsInvalid() { - m_write.dirty = true; + return m_write.dirty; } -void GSClut::InvalidateRange(u32 start_block, u32 end_block) +u32 GSClut::GetCLUTCBP() { - u32 blocks = 4; - - if (GSLocalMemory::m_psm[m_write.TEX0.CPSM].bpp == 16) - blocks >>= 1; - - if (GSLocalMemory::m_psm[m_write.TEX0.PSM].bpp == 4) - blocks >>= 1; + return m_write.TEX0.CBP; +} - if ((m_write.TEX0.CBP + blocks) >= start_block && m_write.TEX0.CBP <= end_block) - { - m_write.dirty = true; - } +void GSClut::SetNextCLUTTEX0(u64 TEX0) +{ + m_write.next_tex0 = TEX0; } -// Check the whole page, if the CLUT is slightly offset from a page boundary it could miss it. -void GSClut::Invalidate(u32 block) +bool GSClut::InvalidateRange(u32 start_block, u32 end_block, bool is_draw) { - if (!((block ^ m_write.TEX0.CBP) & ~0x1F)) + if (m_write.dirty) + return m_write.dirty; + + GIFRegTEX0 next_cbp; + next_cbp.U64 = m_write.next_tex0; + + if ((next_cbp.CBP + 3) >= start_block && end_block >= next_cbp.CBP) { - m_write.dirty = true; + m_write.dirty |= is_draw ? 2 : 1; } + + return m_write.dirty; } bool GSClut::WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) @@ -163,14 +164,14 @@ bool GSClut::WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) m_CBP[1] = TEX0.CBP; break; case 6: - return false; // ffx2 menu + return false; // ffx2 menu. case 7: - return false; // ford mustang racing // Bouken Jidai Katsugeki Goemon + return false; // ford mustang racing // Bouken Jidai Katsugeki Goemon. default: __assume(0); } - // CLUT only reloads if PSM is a valid index type, avoid unnecessary flushes + // CLUT only reloads if PSM is a valid index type, avoid unnecessary flushes. return m_write.IsDirty(TEX0, TEXCLUT); } @@ -179,7 +180,7 @@ void GSClut::Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) m_write.TEX0 = TEX0; m_write.TEXCLUT = TEXCLUT; m_read.dirty = true; - m_write.dirty = false; + m_write.dirty = 0; (this->*m_wc[TEX0.CSM][TEX0.CPSM][TEX0.PSM])(TEX0, TEXCLUT); } @@ -775,7 +776,7 @@ bool GSClut::WriteState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TE bool is_dirty = dirty; - if (((this->TEX0.U64 ^ TEX0.U64) & mask) || (GSLocalMemory::m_psm[this->TEX0.PSM].bpp != GSLocalMemory::m_psm[TEX0.PSM].bpp)) + if (((this->TEX0.U64 ^ TEX0.U64) & mask) || (GSLocalMemory::m_psm[this->TEX0.PSM].pal != GSLocalMemory::m_psm[TEX0.PSM].pal)) is_dirty |= true; else if (TEX0.CSM == 1 && (TEXCLUT.U32[0] ^ this->TEXCLUT.U32[0])) is_dirty |= true; @@ -795,7 +796,7 @@ bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0) bool is_dirty = dirty; - if (((this->TEX0.U64 ^ TEX0.U64) & mask) || (GSLocalMemory::m_psm[this->TEX0.PSM].bpp != GSLocalMemory::m_psm[TEX0.PSM].bpp)) + if (((this->TEX0.U64 ^ TEX0.U64) & mask) || (GSLocalMemory::m_psm[this->TEX0.PSM].pal != GSLocalMemory::m_psm[TEX0.PSM].pal)) is_dirty |= true; if (!is_dirty) @@ -814,7 +815,7 @@ bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) bool is_dirty = dirty; - if (((this->TEX0.U64 ^ TEX0.U64) & tex0_mask) || (GSLocalMemory::m_psm[this->TEX0.PSM].bpp != GSLocalMemory::m_psm[TEX0.PSM].bpp)) + if (((this->TEX0.U64 ^ TEX0.U64) & tex0_mask) || (GSLocalMemory::m_psm[this->TEX0.PSM].pal != GSLocalMemory::m_psm[TEX0.PSM].pal)) is_dirty |= true; else // Just to optimise the checks. { diff --git a/pcsx2/GS/GSClut.h b/pcsx2/GS/GSClut.h index 24fe06572858d..dfa6bc979b106 100644 --- a/pcsx2/GS/GSClut.h +++ b/pcsx2/GS/GSClut.h @@ -39,7 +39,8 @@ class alignas(32) GSClut : public GSAlignedClass<32> { GIFRegTEX0 TEX0; GIFRegTEXCLUT TEXCLUT; - bool dirty; + u8 dirty; + u64 next_tex0; bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); } m_write; @@ -100,9 +101,10 @@ class alignas(32) GSClut : public GSAlignedClass<32> GSClut(GSLocalMemory* mem); virtual ~GSClut(); - void Invalidate(); - void Invalidate(u32 block); - void InvalidateRange(u32 start_block, u32 end_block); + bool InvalidateRange(u32 start_block, u32 end_block, bool is_draw = false); + u8 IsInvalid(); + u32 GetCLUTCBP(); + void SetNextCLUTTEX0(u64 CBP); bool WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); void Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); //void Read(const GIFRegTEX0& TEX0); diff --git a/pcsx2/GS/GSLocalMemory.h b/pcsx2/GS/GSLocalMemory.h index c76c150803591..1a5c7143a4385 100644 --- a/pcsx2/GS/GSLocalMemory.h +++ b/pcsx2/GS/GSLocalMemory.h @@ -444,6 +444,7 @@ class GSLocalMemory : public GSAlignedClass<32> typedef u32 (GSLocalMemory::*readTexel)(int x, int y, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA) const; typedef void (GSLocalMemory::*writePixelAddr)(u32 addr, u32 c); typedef void (GSLocalMemory::*writeFrameAddr)(u32 addr, u32 c); + typedef u32(GSLocalMemory::*PixelAddr)(int x, int y, u32 bp, u32 bw) const; typedef u32 (GSLocalMemory::*readPixelAddr)(u32 addr) const; typedef u32 (GSLocalMemory::*readTexelAddr)(u32 addr, const GIFRegTEXA& TEXA) const; typedef void (GSLocalMemory::*writeImage)(int& tx, int& ty, const u8* src, int len, GIFRegBITBLTBUF& BITBLTBUF, GIFRegTRXPOS& TRXPOS, GIFRegTRXREG& TRXREG); @@ -531,17 +532,6 @@ class GSLocalMemory : public GSAlignedClass<32> GSPixelOffset4* GetPixelOffset4(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF); std::vector* GetPage2TileMap(const GIFRegTEX0& TEX0); - static u32 GetEndBlock(int bp, int bw, int w, int h, int psm) - { - const GSLocalMemory::psm_t& dpsm = GSLocalMemory::m_psm[psm]; - const int page_width = std::max(1, w / dpsm.pgs.x); - const int page_height = std::max(1, h / dpsm.pgs.y); - const int pitch = (std::max(1, bw) * 64) / dpsm.pgs.x; - const u32 end_bp = bp + ((((page_height % dpsm.pgs.y) != 0) ? (page_width << 5) : 0) + ((page_height * pitch) << 5)); - - return end_bp; - } - // address static u32 BlockNumber32(int x, int y, u32 bp, u32 bw) diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index f88e06bc16eae..6ca46acaf7298 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -777,16 +777,8 @@ __inline void GSState::CheckFlushes() if (m_dirty_gs_regs && m_index.tail > 0) { if (TestDrawChanged()) - { Flush(GSFlushReason::CONTEXTCHANGE); - } } - if ((m_context->FRAME.FBMSK & GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk) != GSLocalMemory::m_psm[m_context->FRAME.PSM].fmsk) - m_mem.m_clut.Invalidate(m_context->FRAME.Block()); - - // Hey, why not check? I mean devs have done crazier things.. - if(!m_context->ZBUF.ZMSK) - m_mem.m_clut.Invalidate(m_context->ZBUF.Block()); } void GSState::GIFPackedRegHandlerNull(const GIFPackedReg* RESTRICT r) @@ -1073,13 +1065,14 @@ void GSState::ApplyTEX0(GIFRegTEX0& TEX0) GL_REG("Apply TEX0_%d = 0x%x_%x", i, TEX0.U32[1], TEX0.U32[0]); - // even if TEX0 did not change, a new palette may have been uploaded and will overwrite the currently queued for drawing + // Even if TEX0 did not change, a new palette may have been uploaded and will overwrite the currently queued for drawing. const bool wt = m_mem.m_clut.WriteTest(TEX0, m_env.TEXCLUT); - // clut loading already covered with WriteTest, for drawing only have to check CPSM and CSA (MGS3 intro skybox would be drawn piece by piece without this) - if (wt) + { + m_mem.m_clut.SetNextCLUTTEX0(TEX0.U64); Flush(GSFlushReason::CLUTCHANGE); + } TEX0.CPSM &= 0xa; // 1010b @@ -1097,7 +1090,7 @@ void GSState::ApplyTEX0(GIFRegTEX0& TEX0) { BITBLTBUF.SBP = TEX0.CBP; BITBLTBUF.SBW = 1; - BITBLTBUF.SPSM = TEX0.CSM; + BITBLTBUF.SPSM = TEX0.CPSM; r.left = 0; r.top = 0; @@ -1106,12 +1099,13 @@ void GSState::ApplyTEX0(GIFRegTEX0& TEX0) int blocks = 4; - if (GSLocalMemory::m_psm[TEX0.CPSM].bpp == 16) + if (GSLocalMemory::m_psm[TEX0.CPSM].trbpp == 16) blocks >>= 1; - if (GSLocalMemory::m_psm[TEX0.PSM].bpp == 4) + if (GSLocalMemory::m_psm[TEX0.PSM].trbpp == 4) blocks >>= 1; + // Invalidating videomem is slow, so *only* do it when it's definitely a CLUT draw in HW mode. for (int j = 0; j < blocks; j++, BITBLTBUF.SBP++) InvalidateLocalMem(BITBLTBUF, r, true); } @@ -1119,7 +1113,7 @@ void GSState::ApplyTEX0(GIFRegTEX0& TEX0) { BITBLTBUF.SBP = TEX0.CBP; BITBLTBUF.SBW = m_env.TEXCLUT.CBW; - BITBLTBUF.SPSM = TEX0.CSM; + BITBLTBUF.SPSM = TEX0.CPSM; r.left = m_env.TEXCLUT.COU; r.top = m_env.TEXCLUT.COV; @@ -1148,8 +1142,6 @@ void GSState::GIFRegHandlerTEX0(const GIFReg* RESTRICT r) GL_REG("TEX0_%d = 0x%x_%x", i, r->U32[1], r->U32[0]); GIFRegTEX0 TEX0 = r->TEX0; - GIFRegMIPTBP1 temp_MIPTBP1; - bool MTBAReloaded = false; // Max allowed MTBA size for 32bit swizzled textures (including 8H 4HL etc) is 512, 16bit and normal 8/4bit formats can be 1024 const u32 maxTex = (GSLocalMemory::m_psm[TEX0.PSM].bpp < 32) ? 10 : 9; @@ -1174,6 +1166,7 @@ void GSState::GIFRegHandlerTEX0(const GIFReg* RESTRICT r) // Format must be a color, Z formats do not trigger MTBA (but are valid for Mipmapping) if (m_env.CTXT[i].TEX1.MTBA && TEX0.TW >= 5 && TEX0.TW <= maxTex && (TEX0.PSM & 0x30) != 0x30) { + GIFRegMIPTBP1& mip_tbp1 = m_env.CTXT[i].MIPTBP1; // NOTE 1: TEX1.MXL must not be automatically set to 3 here and it has no effect on MTBA. // NOTE 2: Mipmap levels are packed with a minimum distance between them of 1 block, even down at 4bit textures under 16x16. // NOTE 3: Everything is derrived from the width of the texture, TBW and TH are completely ignored (useful for handling non-rectangular ones) @@ -1190,39 +1183,32 @@ void GSState::GIFRegHandlerTEX0(const GIFReg* RESTRICT r) bw = std::max(bw >> 1, 1); tex_size = std::max(tex_size >> 2, 1); - temp_MIPTBP1.TBP1 = bp; - temp_MIPTBP1.TBW1 = bw; + mip_tbp1.TBP1 = bp; + mip_tbp1.TBW1 = bw; bp += tex_size; bw = std::max(bw >> 1, 1); tex_size = std::max(tex_size >> 2, 1); - temp_MIPTBP1.TBP2 = bp; - temp_MIPTBP1.TBW2 = bw; + mip_tbp1.TBP2 = bp; + mip_tbp1.TBW2 = bw; bp += tex_size; bw = std::max(bw >> 1, 1); - temp_MIPTBP1.TBP3 = bp; - temp_MIPTBP1.TBW3 = bw; - - MTBAReloaded = true; - } - - ApplyTEX0(TEX0); - - if (MTBAReloaded) - { - m_env.CTXT[i].MIPTBP1 = temp_MIPTBP1; + mip_tbp1.TBP3 = bp; + mip_tbp1.TBW3 = bw; if (i == m_prev_env.PRIM.CTXT) { - if (m_prev_env.CTXT[i].MIPTBP1.U64 ^ m_env.CTXT[i].MIPTBP1.U64) + if (m_prev_env.CTXT[i].MIPTBP1.U64 ^ mip_tbp1.U64) m_dirty_gs_regs |= (1 << DIRTY_REG_MIPTBP1); else m_dirty_gs_regs &= ~(1 << DIRTY_REG_MIPTBP1); } } + + ApplyTEX0(TEX0); } template @@ -2009,16 +1995,19 @@ void GSState::Write(const u8* mem, int len) GIFRegTEX0& prev_tex0 = m_prev_env.CTXT[m_prev_env.PRIM.CTXT].TEX0; - const u32 write_end_bp = GSLocalMemory::GetEndBlock(blit.DBP, blit.DBW, w + static_cast(m_env.TRXPOS.DSAX), h + static_cast(m_env.TRXPOS.DSAY), blit.DPSM); - const u32 tex_end_bp = GSLocalMemory::GetEndBlock(prev_tex0.TBP0, prev_tex0.TBW, 1 << prev_tex0.TW, 1 << prev_tex0.TH, prev_tex0.PSM); + const GSLocalMemory::psm_t& tex_psm = GSLocalMemory::m_psm[prev_tex0.PSM]; + + const u32 write_start_bp = m_mem.m_psm[blit.DPSM].info.bn(m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, blit.DBP, blit.DBW); // (m_mem.*psm.pa)(static_cast(m_env.TRXPOS.DSAX), static_cast(m_env.TRXPOS.DSAY), blit.DBP, blit.DBW) >> 6; + const u32 write_end_bp = m_mem.m_psm[blit.DPSM].info.bn(m_env.TRXPOS.DSAX + w - 1, m_env.TRXPOS.DSAY + h - 1, blit.DBP, blit.DBW); // (m_mem.*psm.pa)(w + static_cast(m_env.TRXPOS.DSAX) - 1, h + static_cast(m_env.TRXPOS.DSAY) - 1, blit.DBP, blit.DBW) >> 6; + const u32 tex_end_bp = m_mem.m_psm[prev_tex0.PSM].info.bn((1 << prev_tex0.TW) - 1, (1 << prev_tex0.TH) - 1, prev_tex0.TBP0, prev_tex0.TBW); // (m_mem.*psm.pa)((1 << prev_tex0.TW) - 1, (1 << prev_tex0.TH) - 1, prev_tex0.TBP0, prev_tex0.TBW) >> 6; // Only flush on a NEW transfer if a pending one is using the same address or overlap. // Check Fast & Furious (Hardare mode) and Assault Suits Valken (either renderer) and Tomb Raider - Angel of Darkness menu (TBP != DBP but overlaps). - if (m_tr.end == 0 && m_index.tail > 0 && m_prev_env.PRIM.TME && write_end_bp >= prev_tex0.TBP0 && blit.DBP <= tex_end_bp) + if (m_tr.end == 0 && m_index.tail > 0 && m_prev_env.PRIM.TME && write_end_bp > prev_tex0.TBP0 && write_start_bp <= tex_end_bp) { Flush(GSFlushReason::UPLOADDIRTYTEX); } // Invalid the CLUT if it crosses paths. - m_mem.m_clut.InvalidateRange(blit.DBP, write_end_bp); + m_mem.m_clut.InvalidateRange(write_start_bp, write_end_bp); GL_CACHE("Write! ... => 0x%x W:%d F:%s (DIR %d%d), dPos(%d %d) size(%d %d)", blit.DBP, blit.DBW, psm_str(blit.DPSM), @@ -2156,17 +2145,20 @@ void GSState::Move() GIFRegTEX0& prev_tex0 = m_prev_env.CTXT[m_prev_env.PRIM.CTXT].TEX0; - const u32 end_bp = GSLocalMemory::GetEndBlock(dbp, dbw, w + static_cast(m_env.TRXPOS.DSAX), h + static_cast(m_env.TRXPOS.DSAY), m_env.BITBLTBUF.DPSM); - const u32 tex_end_bp = GSLocalMemory::GetEndBlock(prev_tex0.TBP0, prev_tex0.TBW, 1 << prev_tex0.TW, 1 << prev_tex0.TH, prev_tex0.PSM); + const GSLocalMemory::psm_t& tex_psm = GSLocalMemory::m_psm[prev_tex0.PSM]; + const u32 write_start_bp = m_mem.m_psm[m_env.BITBLTBUF.DPSM].info.bn(m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, dbp, dbw); // (m_mem.*dpsm.pa)(static_cast(m_env.TRXPOS.DSAX), static_cast(m_env.TRXPOS.DSAY), dbp, dbw) >> 6; + const u32 write_end_bp = m_mem.m_psm[m_env.BITBLTBUF.DPSM].info.bn(m_env.TRXPOS.DSAX + w - 1, m_env.TRXPOS.DSAY + h - 1, dbp, dbw); // (m_mem.*dpsm.pa)(w + static_cast(m_env.TRXPOS.DSAX) - 1, h + static_cast(m_env.TRXPOS.DSAY) - 1, dbp, dbw) >> 6; + const u32 tex_end_bp = m_mem.m_psm[prev_tex0.PSM].info.bn((1 << prev_tex0.TW) - 1, (1 << prev_tex0.TH) - 1, prev_tex0.TBP0, prev_tex0.TBW); // (m_mem.*dpsm.pa)((1 << prev_tex0.TW) - 1, (1 << prev_tex0.TH) - 1, prev_tex0.TBP0, prev_tex0.TBW) >> 6; // Only flush on a NEW transfer if a pending one is using the same address or overlap. // Unknown if games use this one, but best to be safe. - if (m_index.tail > 0 && m_prev_env.PRIM.TME && end_bp >= prev_tex0.TBP0 && dbp <= static_cast(tex_end_bp)) + + if (m_index.tail > 0 && m_prev_env.PRIM.TME && write_end_bp >= prev_tex0.TBP0 && write_start_bp <= tex_end_bp) { Flush(GSFlushReason::LOCALTOLOCALMOVE); } // Invalid the CLUT if it crosses paths. - m_mem.m_clut.InvalidateRange(dbp, end_bp); + m_mem.m_clut.InvalidateRange(write_start_bp, write_end_bp); auto genericCopy = [=](const GSOffset& dpo, const GSOffset& spo, auto&& getPAHelper, auto&& pxCopyFn) { @@ -2957,19 +2949,70 @@ GSState::PRIM_OVERLAP GSState::PrimitiveOverlap() __forceinline bool GSState::IsAutoFlushDraw() { + if (!PRIM->TME) + return false; + const u32 frame_mask = GSLocalMemory::m_psm[m_context->TEX0.PSM].fmsk; - const bool frame_hit = (m_context->FRAME.Block() == m_context->TEX0.TBP0) && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL == 2) && ((m_context->FRAME.FBMSK & frame_mask) != frame_mask); + const bool frame_hit = m_context->FRAME.Block() == m_context->TEX0.TBP0 && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL == 2) && ((m_context->FRAME.FBMSK & frame_mask) != frame_mask); // There's a strange behaviour we need to test on a PS2 here, if the FRAME is a Z format, like Powerdrome something swaps over, and it seems Alpha Fail of "FB Only" writes to the Z.. it's odd. const bool zbuf_hit = (m_context->ZBUF.Block() == m_context->TEX0.TBP0) && !(m_context->TEST.ATE && m_context->TEST.ATST == 0 && m_context->TEST.AFAIL != 2) && !m_context->ZBUF.ZMSK; const u32 frame_z_psm = frame_hit ? m_context->FRAME.PSM : m_context->ZBUF.PSM; const u32 frame_z_bp = frame_hit ? m_context->FRAME.Block() : m_context->ZBUF.Block(); - if (PRIM->TME && (frame_hit || zbuf_hit) && GSUtil::HasSharedBits(frame_z_bp, frame_z_psm, m_context->TEX0.TBP0, m_context->TEX0.PSM)) + if ((frame_hit || zbuf_hit) && GSUtil::HasSharedBits(frame_z_bp, frame_z_psm, m_context->TEX0.TBP0, m_context->TEX0.PSM)) return true; return false; } +__forceinline void GSState::CLUTAutoFlush() +{ + if (m_mem.m_clut.IsInvalid() & 2) + return; + + int n = 1; + + switch (PRIM->PRIM) + { + case GS_POINTLIST: + n = 1; + break; + case GS_LINELIST: + case GS_LINESTRIP: + case GS_SPRITE: + n = 2; + break; + case GS_TRIANGLELIST: + case GS_TRIANGLESTRIP: + n = 3; + break; + case GS_TRIANGLEFAN: + n = 3; + break; + case GS_INVALID: + default: + break; + } + + if ((m_index.tail > 0 || (m_vertex.tail == n-1)) && (GSLocalMemory::m_psm[m_context->TEX0.PSM].pal == 0 || !PRIM->TME)) + { + const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[m_context->FRAME.PSM]; + + if ((m_context->FRAME.FBMSK & psm.fmsk) != psm.fmsk) + { + const u32 startbp = psm.info.bn(temp_draw_rect.x, temp_draw_rect.y, m_context->FRAME.Block(), m_context->FRAME.FBW); + + // If it's a point, then we only have one coord, so the address for start and end will be the same, which is bad for the following check. + u32 endbp = startbp; + // otherwise calculate the end. + if (PRIM->PRIM != GS_POINTLIST || (m_index.tail > 1)) + endbp = psm.info.bn(temp_draw_rect.z - 1, temp_draw_rect.w - 1, m_context->FRAME.Block(), m_context->FRAME.FBW); + + m_mem.m_clut.InvalidateRange(startbp, endbp); + } + } +} + __forceinline void GSState::HandleAutoFlush() { // Kind of a cheat, making the assumption that 2 consecutive fan/strip triangles won't overlap each other (*should* be safe) @@ -3190,7 +3233,7 @@ __forceinline void GSState::VertexKick(u32 skip) ASSERT(m_vertex.tail < m_vertex.maxcount + 3); - if (auto_flush && m_index.tail > 0 && ((m_vertex.tail + 1) - m_vertex.head) >= n) + if (auto_flush && skip == 0 && m_index.tail > 0 && ((m_vertex.tail + 1) - m_vertex.head) >= n) { HandleAutoFlush(); } @@ -3403,6 +3446,39 @@ __forceinline void GSState::VertexKick(u32 skip) default: __assume(0); } + + + + GSVector4i draw_coord; + const GSVector2i offset = GSVector2i(m_context->XYOFFSET.OFX, m_context->XYOFFSET.OFY); + + for (int i = 0; i < n; i++) + { + const GSVertex* v = &m_vertex.buff[m_index.buff[(m_index.tail - n) + i]]; + draw_coord.x = (static_cast(v->XYZ.X) - offset.x) >> 4; + draw_coord.y = (static_cast(v->XYZ.Y) - offset.y) >> 4; + + if (m_vertex.tail == n && i == 0) + { + const GSVector4i scissor = GSVector4i(m_context->scissor.in); + + temp_draw_rect.x = draw_coord.x; + temp_draw_rect.y = draw_coord.y; + temp_draw_rect = temp_draw_rect.xyxy(); + } + else + { + temp_draw_rect.x = std::min(draw_coord.x, temp_draw_rect.x); + temp_draw_rect.y = std::min(draw_coord.y, temp_draw_rect.y); + temp_draw_rect.z = std::max(draw_coord.x, temp_draw_rect.z); + temp_draw_rect.w = std::max(draw_coord.y, temp_draw_rect.w); + } + } + + const GSVector4i scissor = GSVector4i(m_context->scissor.in); + temp_draw_rect.rintersect(scissor); + + CLUTAutoFlush(); } /// Checks if region repeat is used (applying it does something to at least one of the values in min...max) diff --git a/pcsx2/GS/GSState.h b/pcsx2/GS/GSState.h index 760397e2f989f..a01194dcffc63 100644 --- a/pcsx2/GS/GSState.h +++ b/pcsx2/GS/GSState.h @@ -186,6 +186,7 @@ class GSState : public GSAlignedClass<32> void GrowVertexBuffer(); bool IsAutoFlushDraw(); void HandleAutoFlush(); + void CLUTAutoFlush(); template void VertexKick(u32 skip); @@ -228,6 +229,7 @@ class GSState : public GSAlignedClass<32> GSDrawingEnvironment m_env; GSDrawingEnvironment m_backup_env; GSDrawingEnvironment m_prev_env; + GSVector4i temp_draw_rect; GSDrawingContext* m_context; u32 m_crc; CRC::Game m_game; diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 5660bb6bcd74d..87199c8e73870 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -1275,6 +1275,7 @@ void GSRendererHW::Draw() s = StringUtil::StdStringFromFormat("%05d_vertex.txt", s_n); DumpVertices(m_dump_root + s); } + if (IsBadFrame()) { GL_INS("Warning skipping a draw call (%d)", s_n); @@ -1390,6 +1391,20 @@ void GSRendererHW::Draw() return; } + // SW CLUT Render enable. + if (GSConfig.UserHacks_CPUCLUTRender > 0) + { + bool result = (GSConfig.UserHacks_CPUCLUTRender == 1) ? PossibleCLUTDraw() : PossibleCLUTDrawAggressive(); + if (result) + { + if (SwPrimRender()) + { + GL_CACHE("Possible clut draw, drawn with SwPrimRender()"); + return; + } + } + } + if (m_channel_shuffle) { m_channel_shuffle = draw_sprite_tex && (m_context->TEX0.PSM == PSM_PSMT8) && single_page; @@ -3879,6 +3894,113 @@ void GSRendererHW::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc g_gs_device->RenderHW(m_conf); } +bool GSRendererHW::PossibleCLUTDraw() +{ + if (m_channel_shuffle || m_texture_shuffle) + return false; + + // Keep the draws simple, no alpha testing, blending, mipmapping, Z writes, and make sure it's flat. + const bool fb_only = m_context->TEST.ATE && m_context->TEST.AFAIL == 1 && m_context->TEST.ATST == ATST_NEVER; + + if (!m_context->ZBUF.ZMSK && !fb_only) + return false; + + if (m_vt.m_eq.z != 0x1) + return false; + + if (m_context->TEX1.MXL) + return false; + + if (m_vt.m_min.p.x < 0 || m_vt.m_min.p.y < 0) + return false; + + // Writing to the framebuffer for output. We're not interested. - Note: This stops NFS HP2 Busted screens working, but they're glitchy anyway + // what NFS HP2 really needs is a kind of shuffle with mask, 32bit target is interpreted as 16bit and masked. + if ((m_regs->DISP[0].DISPFB.Block() == m_context->FRAME.Block()) || (m_regs->DISP[1].DISPFB.Block() == m_context->FRAME.Block())) + return false; + + // Hopefully no games draw a CLUT with a CLUT, that would be evil, most likely a channel shuffle. + if (PRIM->TME && GSLocalMemory::m_psm[m_context->TEX0.PSM].pal > 0) + return false; + + const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[m_context->FRAME.PSM]; + + // Max size for a CLUT/Current page size. + constexpr float clut_width = 16.0f; + constexpr float clut_height = 16.0f; + constexpr float min_clut_width = 7.0f; + constexpr float min_clut_height = 1.0f; + const float page_width = static_cast(psm.pgs.x); + const float page_height = static_cast(psm.pgs.y); + + // Make sure it's kinda CLUT sized, at least. Be wary, it can draw a line at a time (Guitar Hero - Metallica) + const float draw_width = (m_vt.m_max.p.x - m_vt.m_min.p.x); + const float draw_height = (m_vt.m_max.p.y - m_vt.m_min.p.y); + const bool valid_size =((draw_width >= min_clut_width || draw_height >= min_clut_height) && + m_vt.m_max.p.x <= page_width && m_vt.m_max.p.y <= page_height); + + // Klonoa draws a clut with a full page of triangles instead of a sprite, but we need to make sure it doesn't intefere with normal triangle draws. + if (m_vt.m_primclass == GS_TRIANGLE_CLASS) + { + if (draw_width != page_width || draw_height != page_height) + return false; + } + + // Make sure the draw hits the next CLUT and it's marked as invalid (kind of a sanity check). + // We can also allow draws which are of a sensible size within the page, as they could also be CLUT draws (or gradients for the CLUT). + if (!(valid_size || (m_mem.m_clut.IsInvalid() & 2))) + return false; + + if (PRIM->TME) + { + // If we're using a texture to draw our CLUT/whatever, we need the GPU to write back dirty data we need. + const GSVector4i r = GetTextureMinMax(m_context->TEX0, m_context->CLAMP, m_vt.IsLinear()).coverage; + + GIFRegBITBLTBUF BITBLTBUF; + BITBLTBUF.SBP = m_context->TEX0.TBP0; + BITBLTBUF.SBW = m_context->TEX0.TBW; + BITBLTBUF.SPSM = m_context->TEX0.PSM; + + InvalidateLocalMem(BITBLTBUF, r); + } + + return true; +} + +// Slight more aggressive version that kinda YOLO's it if the draw is anywhere near the CLUT or is point/line (providing it's not too wide of a draw and a few other parameters. +// This is pretty much tuned for the Sega Model 2 games, which draw a huge gradient, then pick lines out of it to make up CLUT's for about 4000 draws... +bool GSRendererHW::PossibleCLUTDrawAggressive() +{ + // Avoid any shuffles. + if (m_channel_shuffle || m_texture_shuffle) + return false; + + // Keep the draws simple, no alpha testing, blending, mipmapping, Z writes, and make sure it's flat. + if (m_context->TEST.ATE) + return false; + + if (PRIM->ABE) + return false; + + if (m_context->TEX1.MXL) + return false; + + if (m_context->FRAME.FBW != 1) + return false; + + if (!m_context->ZBUF.ZMSK) + return false; + + if (m_vt.m_eq.z != 0x1) + return false; + + if (!((m_vt.m_primclass == GS_POINT_CLASS || m_vt.m_primclass == GS_LINE_CLASS) || ((m_mem.m_clut.GetCLUTCBP() >> 5) >= m_context->FRAME.FBP && (m_context->FRAME.FBP + 1) >= (m_mem.m_clut.GetCLUTCBP() >> 5) && m_vt.m_primclass == GS_SPRITE_CLASS))) + return false; + + // Avoid invalidating anything here, we just want to avoid the thing being drawn on the GPU. + return true; +} + bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_tex) { // Master enable. diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.h b/pcsx2/GS/Renderers/HW/GSRendererHW.h index df9bc9d598711..14122e3c01ac8 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.h +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.h @@ -127,6 +127,8 @@ class GSRendererHW : public GSRenderer void SwSpriteRender(); bool CanUseSwSpriteRender(); + bool PossibleCLUTDraw(); + bool PossibleCLUTDrawAggressive(); bool CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_tex); bool SwPrimRender(); diff --git a/pcsx2/GameDatabase.cpp b/pcsx2/GameDatabase.cpp index e5c4d4ac78105..758cd9e5f4154 100644 --- a/pcsx2/GameDatabase.cpp +++ b/pcsx2/GameDatabase.cpp @@ -290,6 +290,7 @@ static const char* s_gs_hw_fix_names[] = { "texturePreloading", "deinterlace", "cpuSpriteRenderBW", + "cpuCLUTRender", "gpuPaletteConversion", }; static_assert(std::size(s_gs_hw_fix_names) == static_cast(GameDatabaseSchema::GSHWFixId::Count), "HW fix name lookup is correct size"); @@ -499,6 +500,9 @@ bool GameDatabaseSchema::GameEntry::configMatchesHWFix(const Pcsx2Config::GSOpti case GSHWFixId::CPUSpriteRenderBW: return (config.UserHacks_CPUSpriteRenderBW == value); + case GSHWFixId::CPUCLUTRender: + return (config.UserHacks_CPUCLUTRender == value); + case GSHWFixId::GPUPaletteConversion: return (config.GPUPaletteConversion == ((value > 1) ? (config.TexturePreloading == TexturePreloadingLevel::Full) : (value != 0))); @@ -642,6 +646,9 @@ u32 GameDatabaseSchema::GameEntry::applyGSHardwareFixes(Pcsx2Config::GSOptions& config.UserHacks_CPUSpriteRenderBW = value; break; + case GSHWFixId::CPUCLUTRender: + config.UserHacks_CPUCLUTRender = value; + break; case GSHWFixId::GPUPaletteConversion: { diff --git a/pcsx2/GameDatabase.h b/pcsx2/GameDatabase.h index 25d947b72cc3f..8e9e0cd0b6743 100644 --- a/pcsx2/GameDatabase.h +++ b/pcsx2/GameDatabase.h @@ -82,6 +82,7 @@ namespace GameDatabaseSchema TexturePreloading, Deinterlace, CPUSpriteRenderBW, + CPUCLUTRender, GPUPaletteConversion, Count diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index df4a1493dc7e4..39b547f22c10b 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -423,6 +423,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const OpEqu(UserHacks_TCOffsetX) && OpEqu(UserHacks_TCOffsetY) && OpEqu(UserHacks_CPUSpriteRenderBW) && + OpEqu(UserHacks_CPUCLUTRender) && OpEqu(OverrideTextureBarriers) && OpEqu(OverrideGeometryShaders) && @@ -616,6 +617,7 @@ void Pcsx2Config::GSOptions::ReloadIniSettings() GSSettingIntEx(UserHacks_TCOffsetX, "UserHacks_TCOffsetX"); GSSettingIntEx(UserHacks_TCOffsetY, "UserHacks_TCOffsetY"); GSSettingIntEx(UserHacks_CPUSpriteRenderBW, "UserHacks_CPUSpriteRenderBW"); + GSSettingIntEx(UserHacks_CPUCLUTRender, "UserHacks_CPUCLUTRender"); GSSettingIntEnumEx(TriFilter, "TriFilter"); GSSettingIntEx(OverrideTextureBarriers, "OverrideTextureBarriers"); GSSettingIntEx(OverrideGeometryShaders, "OverrideGeometryShaders"); @@ -663,6 +665,7 @@ void Pcsx2Config::GSOptions::MaskUserHacks() UserHacks_TCOffsetX = 0; UserHacks_TCOffsetY = 0; UserHacks_CPUSpriteRenderBW = 0; + UserHacks_CPUCLUTRender = 0; SkipDrawStart = 0; SkipDrawEnd = 0; }