Compare commits

...

11 Commits

Author SHA1 Message Date
Slayer0fRA
4c41de6013 Debugger: Disable filter search button while filter search is active 2025-07-23 22:53:16 -04:00
Slayer0fRA
96f9cde1bc Debugger: Disable filter search button while filter search is active 2025-07-23 22:53:16 -04:00
PCSX2 Bot
3feef0824c [ci skip] PAD: Update to latest controller database. 2025-07-23 03:07:03 +02:00
lightningterror
5f2ab55c93 GS/GL/MTL: Misc fixes.
MTL: Add missing shader case for RGB5A1_TO_8I.
GL: Comment out vendor Nvidia.

Fixes warnings.
2025-07-20 22:41:41 +02:00
GovanifY
0f75bfe17d Revert "GitHub: Add types to issue templates"
This reverts commit 7faa132622.
2025-07-20 12:46:38 +02:00
Berylskid
7faa132622 GitHub: Add types to issue templates 2025-07-19 15:28:51 -04:00
Ziemas
b69e6da105 Debugger: add 3 operand mult to assembler 2025-07-19 15:28:31 -04:00
JordanTheToaster
11edb128e9 GameDB: Kamen Rider Kabuto fixes 2025-07-19 20:25:57 +02:00
TJnotJT
fc4407aaef GS: Add secondary vertex buffer for copy/modifying vertices.
Currently only used in HW renderer to fix vertices for provoking-first-vertex APIs.
2025-07-19 02:39:01 +02:00
TJnotJT
2a418e3282 GS/HW: Handle first vertex provoking APIs in GSRendererHW.cpp. 2025-07-19 02:39:01 +02:00
TJnotJT
59415542ff GS: Remove all usage of provoking first/flat swapped in early pipeline.
Removes said usage from GSState and GSVertexTrace (and helper classes). The end goal is to support first-vertex-provoking APIs in GSRendererHW instead of early in the pipeline.
2025-07-19 02:39:01 +02:00
17 changed files with 212 additions and 178 deletions

View File

@@ -22205,18 +22205,28 @@ SLES-53142:
SLES-53143:
name: "Fantastic 4"
region: "PAL-E"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53144:
name: "4 Fantastiques, Les"
region: "PAL-F"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53145:
name: "Fantastic 4"
region: "PAL-G"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53146:
name: "I Fantastici Quattro"
region: "PAL-I"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53147:
name: "4 Fantásticos, Los"
region: "PAL-S"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53148:
name: "Fruitfall"
region: "PAL-E"
@@ -22461,6 +22471,8 @@ SLES-53280:
SLES-53281:
name: "Fantastic 4"
region: "PAL-NL"
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLES-53282:
name: "Harvest Fishing"
region: "PAL-E"
@@ -35029,6 +35041,9 @@ SLPM-60279:
name-en: "Kamen Rider Kabuto [Trial]"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 5 # Fixes post-processing alignment.
nativeScaling: 1 # Fixes post-processing alignment.
textureInsideRT: 1 # Fixes garbage and missing effects.
autoFlush: 1 # Fixes garbage corruptions on the bottom of the screen.
SLPM-60280:
name: "電撃PS2 PlayStation 2 SAVE DATA COLLECTION 2007"
@@ -55672,6 +55687,9 @@ SLPS-20483:
name-en: "Kamen Rider Kabuto"
region: "NTSC-J"
gsHWFixes:
halfPixelOffset: 5 # Fixes post-processing alignment.
nativeScaling: 1 # Fixes post-processing alignment.
textureInsideRT: 1 # Fixes garbage and missing effects.
autoFlush: 1 # Fixes garbage corruptions on the bottom of the screen.
SLPS-20484:
name: "SIMPLE2000シリーズ Ultimate Vol.34 魁!!男塾"
@@ -65659,6 +65677,8 @@ SLUS-20615:
name: "Fantastic 4"
region: "NTSC-U"
compat: 5
gsHWFixes:
halfPixelOffset: 5 # Fixes large depth line.
SLUS-20616:
name: "Virtua Fighter 4 - Evolution"
region: "NTSC-U"

View File

@@ -262,6 +262,8 @@
030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
03000000ac0500006b05000000000000,GT2a,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,
03000000341a00000302000000000000,Hama Scorpad,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,
030000008a2e0000dd10000000000000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Windows,
030000008a2e0000df10000000000000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Windows,
030000000d0f00004900000000000000,Hatsune Miku Sho PS3 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,
030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,
030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,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:b7,x:b2,y:b3,platform:Windows,
@@ -1130,6 +1132,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000130b000001050000,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,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000130b000005050000,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,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -1329,6 +1332,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,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,
03000000f0250000c383000010010000,GT VX2,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:Linux,
030000008a2e0000dd10000011010000,Hand Held Legend GC Ultimate,a:b0,b:b2,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,misc2:b24,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b1,y:b3,platform:Linux,
030000008a2e0000df10000011010000,Hand Held Legend ProGCC,a:b1,b:b0,back:b17,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,guide:b18,leftshoulder:b10,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b19,paddle1:b13,paddle2:b12,rightshoulder:b11,rightstick:b9,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b3,y:b2,platform:Linux,
06000000adde0000efbe000002010000,Hidromancer 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,
03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,
03000000c9110000f055000011010000,HJC Gamepad,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,
@@ -1793,10 +1798,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e040000ea02000011050000,Xbox One S 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,
030000005e040000ea02000015050000,Xbox One S 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,
030000005e040000ea02000017050000,Xbox One S 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,
060000005e040000ea0200000b050000,Xbox One S 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,
060000005e040000ea0200000d050000,Xbox One S 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,
060000005e040000ea02000016050000,Xbox One S 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,
030000005e040000ea02000017050000,Xbox One S 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,
030000005e040000120b000001050000,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,
030000005e040000120b000005050000,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,
030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -1822,8 +1827,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000130b000022050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000200b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000200b000023050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000220b000017050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
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,
03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,

View File

@@ -1301,9 +1301,7 @@ VS_OUTPUT vs_main_expand(uint vid : SV_VertexID)
uint vid_base = vid >> 2;
bool is_bottom = vid & 2;
bool is_right = vid & 1;
// All lines will be a pair of vertices next to each other
// Since DirectX uses provoking vertex first, the bottom point will be the lower of the two
uint vid_other = is_bottom ? vid_base + 1 : vid_base - 1;
uint vid_other = is_bottom ? vid_base - 1 : vid_base + 1;
VS_OUTPUT vtx = vs_main(load_vertex(vid_base));
VS_OUTPUT other = vs_main(load_vertex(vid_other));

View File

@@ -174,11 +174,7 @@ void main()
bool is_bottom = (vid & 2u) != 0u;
bool is_right = (vid & 1u) != 0u;
#ifdef VS_PROVOKING_VERTEX_LAST
uint vid_other = is_bottom ? vid_base - 1 : vid_base + 1;
#else
uint vid_other = is_bottom ? vid_base + 1 : vid_base - 1;
#endif
vtx = load_vertex(vid_base);
ProcessedVertex other = load_vertex(vid_other);

View File

@@ -599,6 +599,7 @@ void MemorySearchView::onSearchButtonClicked()
connect(workerWatcher, &QFutureWatcher<std::vector<u32>>::finished, onSearchFinished);
m_ui.btnSearch->setDisabled(true);
m_ui.btnFilterSearch->setDisabled(true);
if (!isFilterSearch)
{
m_searchResults.clear();

View File

@@ -205,8 +205,10 @@ const tMipsOpcode MipsOpcodes[] = {
{ "dsrav", "d,s", MIPS_SPECIAL(0x17), MA_MIPS3, MO_64BIT|MO_RDT },
{ "clo", "d,s", MIPS_SPECIAL(0x17), MA_PSP, 0 },
{ "mult", "s,t", MIPS_SPECIAL(0x18), MA_MIPS1, 0 },
{ "mult", "d,s,t", MIPS_SPECIAL(0x18), MA_PS2, 0 },
{ "mult", "r\x0,s,t", MIPS_SPECIAL(0x18), MA_MIPS1, 0 },
{ "multu", "s,t", MIPS_SPECIAL(0x19), MA_MIPS1, 0 },
{ "multu", "d,s,t", MIPS_SPECIAL(0x19), MA_PS2, 0 },
{ "multu", "r\x0,s,t", MIPS_SPECIAL(0x19), MA_MIPS1, 0 },
{ "div", "s,t", MIPS_SPECIAL(0x1A), MA_MIPS1, 0 },
{ "div", "r\x0,s,t", MIPS_SPECIAL(0x1A), MA_MIPS1, 0 },

View File

@@ -27,11 +27,6 @@ static __fi bool IsAutoFlushEnabled()
return GSIsHardwareRenderer() ? (GSConfig.UserHacks_AutoFlush != GSHWAutoFlushLevel::Disabled) : GSConfig.AutoFlushSW;
}
static __fi bool IsFirstProvokingVertex()
{
return (GSIsHardwareRenderer() && !g_gs_device->Features().provoking_vertex_last);
}
constexpr int GSState::GetSaveStateSize(int version)
{
int size = 0;
@@ -99,7 +94,7 @@ constexpr int GSState::GetSaveStateSize(int version)
}
GSState::GSState()
: m_vt(this, IsFirstProvokingVertex())
: m_vt(this)
{
// m_nativeres seems to be a hack. Unfortunately it impacts draw call number which make debug painful in the replayer.
// Let's keep it disabled to ease debug.
@@ -130,6 +125,8 @@ GSState::~GSState()
{
if (m_vertex.buff)
_aligned_free(m_vertex.buff);
if (m_vertex.buff_copy)
_aligned_free(m_vertex.buff_copy);
if (m_index.buff)
_aligned_free(m_index.buff);
if (m_draw_vertex.buff)
@@ -206,29 +203,29 @@ void GSState::Reset(bool hardware_reset)
memcpy(&m_prev_env, &m_env, sizeof(m_prev_env));
}
template<bool auto_flush, bool index_swap>
template<bool auto_flush>
void GSState::SetPrimHandlers()
{
#define SetHandlerXYZ(P, auto_flush, index_swap) \
m_fpGIFPackedRegHandlerXYZ[P][0] = &GSState::GIFPackedRegHandlerXYZF2<P, 0, auto_flush, index_swap>; \
m_fpGIFPackedRegHandlerXYZ[P][1] = &GSState::GIFPackedRegHandlerXYZF2<P, 1, auto_flush, index_swap>; \
m_fpGIFPackedRegHandlerXYZ[P][2] = &GSState::GIFPackedRegHandlerXYZ2<P, 0, auto_flush, index_swap>; \
m_fpGIFPackedRegHandlerXYZ[P][3] = &GSState::GIFPackedRegHandlerXYZ2<P, 1, auto_flush, index_swap>; \
m_fpGIFRegHandlerXYZ[P][0] = &GSState::GIFRegHandlerXYZF2<P, 0, auto_flush, index_swap>; \
m_fpGIFRegHandlerXYZ[P][1] = &GSState::GIFRegHandlerXYZF2<P, 1, auto_flush, index_swap>; \
m_fpGIFRegHandlerXYZ[P][2] = &GSState::GIFRegHandlerXYZ2<P, 0, auto_flush, index_swap>; \
m_fpGIFRegHandlerXYZ[P][3] = &GSState::GIFRegHandlerXYZ2<P, 1, auto_flush, index_swap>; \
m_fpGIFPackedRegHandlerSTQRGBAXYZF2[P] = &GSState::GIFPackedRegHandlerSTQRGBAXYZF2<P, auto_flush, index_swap>; \
m_fpGIFPackedRegHandlerSTQRGBAXYZ2[P] = &GSState::GIFPackedRegHandlerSTQRGBAXYZ2<P, auto_flush, index_swap>;
#define SetHandlerXYZ(P, auto_flush) \
m_fpGIFPackedRegHandlerXYZ[P][0] = &GSState::GIFPackedRegHandlerXYZF2<P, 0, auto_flush>; \
m_fpGIFPackedRegHandlerXYZ[P][1] = &GSState::GIFPackedRegHandlerXYZF2<P, 1, auto_flush>; \
m_fpGIFPackedRegHandlerXYZ[P][2] = &GSState::GIFPackedRegHandlerXYZ2<P, 0, auto_flush>; \
m_fpGIFPackedRegHandlerXYZ[P][3] = &GSState::GIFPackedRegHandlerXYZ2<P, 1, auto_flush>; \
m_fpGIFRegHandlerXYZ[P][0] = &GSState::GIFRegHandlerXYZF2<P, 0, auto_flush>; \
m_fpGIFRegHandlerXYZ[P][1] = &GSState::GIFRegHandlerXYZF2<P, 1, auto_flush>; \
m_fpGIFRegHandlerXYZ[P][2] = &GSState::GIFRegHandlerXYZ2<P, 0, auto_flush>; \
m_fpGIFRegHandlerXYZ[P][3] = &GSState::GIFRegHandlerXYZ2<P, 1, auto_flush>; \
m_fpGIFPackedRegHandlerSTQRGBAXYZF2[P] = &GSState::GIFPackedRegHandlerSTQRGBAXYZF2<P, auto_flush>; \
m_fpGIFPackedRegHandlerSTQRGBAXYZ2[P] = &GSState::GIFPackedRegHandlerSTQRGBAXYZ2<P, auto_flush>;
SetHandlerXYZ(GS_POINTLIST, true, false);
SetHandlerXYZ(GS_LINELIST, auto_flush, index_swap);
SetHandlerXYZ(GS_LINESTRIP, auto_flush, index_swap);
SetHandlerXYZ(GS_TRIANGLELIST, auto_flush, index_swap);
SetHandlerXYZ(GS_TRIANGLESTRIP, auto_flush, index_swap);
SetHandlerXYZ(GS_TRIANGLEFAN, auto_flush, index_swap);
SetHandlerXYZ(GS_SPRITE, auto_flush, false);
SetHandlerXYZ(GS_INVALID, auto_flush, false);
SetHandlerXYZ(GS_POINTLIST, true);
SetHandlerXYZ(GS_LINELIST, auto_flush);
SetHandlerXYZ(GS_LINESTRIP, auto_flush);
SetHandlerXYZ(GS_TRIANGLELIST, auto_flush);
SetHandlerXYZ(GS_TRIANGLESTRIP, auto_flush);
SetHandlerXYZ(GS_TRIANGLEFAN, auto_flush);
SetHandlerXYZ(GS_SPRITE, auto_flush);
SetHandlerXYZ(GS_INVALID, auto_flush);
#undef SetHandlerXYZ
}
@@ -249,11 +246,10 @@ void GSState::ResetHandlers()
m_fpGIFPackedRegHandlers[GIF_REG_A_D] = &GSState::GIFPackedRegHandlerA_D;
m_fpGIFPackedRegHandlers[GIF_REG_NOP] = &GSState::GIFPackedRegHandlerNOP;
// swap first/last indices when the provoking vertex is the first (D3D/Vulkan)
if (IsAutoFlushEnabled())
IsFirstProvokingVertex() ? SetPrimHandlers<true, true>() : SetPrimHandlers<true, false>();
SetPrimHandlers<true>();
else
IsFirstProvokingVertex() ? SetPrimHandlers<false, true>() : SetPrimHandlers<false, false>();
SetPrimHandlers<false>();
std::fill(std::begin(m_fpGIFRegHandlers), std::end(m_fpGIFRegHandlers), &GSState::GIFRegHandlerNull);
@@ -606,7 +602,7 @@ void GSState::GIFPackedRegHandlerUV_Hack(const GIFPackedReg* RESTRICT r)
m_isPackedUV_HackFlag = true;
}
template <u32 prim, u32 adc, bool auto_flush, bool index_swap>
template <u32 prim, u32 adc, bool auto_flush>
void GSState::GIFPackedRegHandlerXYZF2(const GIFPackedReg* RESTRICT r)
{
const bool skip = adc || r->XYZF2.Skip();
@@ -622,10 +618,10 @@ void GSState::GIFPackedRegHandlerXYZF2(const GIFPackedReg* RESTRICT r)
m_v.m[1] = xy.upl32(zf);
VertexKick<prim, auto_flush, index_swap>(skip);
VertexKick<prim, auto_flush>(skip);
}
template <u32 prim, u32 adc, bool auto_flush, bool index_swap>
template <u32 prim, u32 adc, bool auto_flush>
void GSState::GIFPackedRegHandlerXYZ2(const GIFPackedReg* RESTRICT r)
{
const bool skip = adc || r->XYZ2.Skip();
@@ -639,7 +635,7 @@ void GSState::GIFPackedRegHandlerXYZ2(const GIFPackedReg* RESTRICT r)
m_v.m[1] = xyz.upl64(GSVector4i::loadl(&m_v.UV));
VertexKick<prim, auto_flush, index_swap>(skip);
VertexKick<prim, auto_flush>(skip);
}
void GSState::GIFPackedRegHandlerFOG(const GIFPackedReg* RESTRICT r)
@@ -656,7 +652,7 @@ void GSState::GIFPackedRegHandlerNOP(const GIFPackedReg* RESTRICT r)
{
}
template <u32 prim, bool auto_flush, bool index_swap>
template <u32 prim, bool auto_flush>
void GSState::GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u32 size)
{
pxAssert(size > 0 && size % 3 == 0);
@@ -682,7 +678,7 @@ void GSState::GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u3
m_v.m[1] = xy.upl32(zf); // TODO: only store the last one
VertexKick<prim, auto_flush, index_swap>(r[2].XYZF2.Skip());
VertexKick<prim, auto_flush>(r[2].XYZF2.Skip());
r += 3;
}
@@ -690,7 +686,7 @@ void GSState::GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u3
m_q = r[-3].STQ.Q; // remember the last one, STQ outputs this to the temp Q each time
}
template <u32 prim, bool auto_flush, bool index_swap>
template <u32 prim, bool auto_flush>
void GSState::GIFPackedRegHandlerSTQRGBAXYZ2(const GIFPackedReg* RESTRICT r, u32 size)
{
pxAssert(size > 0 && size % 3 == 0);
@@ -715,7 +711,7 @@ void GSState::GIFPackedRegHandlerSTQRGBAXYZ2(const GIFPackedReg* RESTRICT r, u32
m_v.m[1] = xyz.upl64(GSVector4i::loadl(&m_v.UV)); // TODO: only store the last one
VertexKick<prim, auto_flush, index_swap>(r[2].XYZ2.Skip());
VertexKick<prim, auto_flush>(r[2].XYZ2.Skip());
r += 3;
}
@@ -749,7 +745,7 @@ __forceinline void GSState::ApplyPRIM(u32 prim)
UpdateVertexKick();
pxAssert(m_index.tail == 0 || !g_gs_device->Features().provoking_vertex_last || m_index.buff[m_index.tail - 1] + 1 == m_vertex.next);
pxAssert(m_index.tail == 0 || m_index.buff[m_index.tail - 1] + 1 == m_vertex.next);
if (m_index.tail == 0)
m_vertex.next = 0;
@@ -800,7 +796,7 @@ void GSState::GIFRegHandlerUV_Hack(const GIFReg* RESTRICT r)
m_isPackedUV_HackFlag = false;
}
template <u32 prim, u32 adc, bool auto_flush, bool index_swap>
template <u32 prim, u32 adc, bool auto_flush>
void GSState::GIFRegHandlerXYZF2(const GIFReg* RESTRICT r)
{
if (!adc || GSUtil::GetPrimClass(m_prev_env.PRIM.PRIM) != GSUtil::GetPrimClass(m_env.PRIM.PRIM) || (m_dirty_gs_regs & (1 << DIRTY_REG_XYOFFSET)))
@@ -812,10 +808,10 @@ void GSState::GIFRegHandlerXYZF2(const GIFReg* RESTRICT r)
m_v.m[1] = xyz.upl64(uvf);
VertexKick<prim, auto_flush, index_swap>(adc);
VertexKick<prim, auto_flush>(adc);
}
template <u32 prim, u32 adc, bool auto_flush, bool index_swap>
template <u32 prim, u32 adc, bool auto_flush>
void GSState::GIFRegHandlerXYZ2(const GIFReg* RESTRICT r)
{
if (!adc || GSUtil::GetPrimClass(m_prev_env.PRIM.PRIM) != GSUtil::GetPrimClass(m_env.PRIM.PRIM) || (m_dirty_gs_regs & (1 << DIRTY_REG_XYOFFSET)))
@@ -823,7 +819,7 @@ void GSState::GIFRegHandlerXYZ2(const GIFReg* RESTRICT r)
m_v.m[1] = GSVector4i::load(&r->XYZ, &m_v.UV);
VertexKick<prim, auto_flush, index_swap>(adc);
VertexKick<prim, auto_flush>(adc);
}
template <int i>
@@ -2908,56 +2904,53 @@ void GSState::UpdateVertexKick()
void GSState::GrowVertexBuffer()
{
const u32 maxcount = std::max<u32>(m_vertex.maxcount * 3 / 2, 10000);
const u32 old_vertex_size = sizeof(GSVertex) * m_vertex.tail;
const u32 new_vertex_size = sizeof(GSVertex) * maxcount;
const u32 old_index_size = sizeof(u16) * m_index.tail;
const u32 new_index_size = sizeof(u16) * maxcount * 6; // Worst case index list is a list of points with vs expansion, 6 indices per point
GSVertex* vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
GSVertex* draw_vertex = static_cast<GSVertex*>(_aligned_malloc(sizeof(GSVertex) * maxcount, 32));
// Worst case index list is a list of points with vs expansion, 6 indices per point
u16* index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));
u16* draw_index = static_cast<u16*>(_aligned_malloc(sizeof(u16) * maxcount * 6, 32));
if (!vertex || !index)
// Structure describing buffers to reallocate
struct AllocDesc
{
const u32 vert_byte_count = sizeof(GSVertex) * maxcount;
const u32 idx_byte_count = sizeof(u16) * maxcount * 3;
void** pbuff;
u32 old_size;
u32 new_size;
};
std::vector<AllocDesc> alloc_desc = {
{reinterpret_cast<void**>(&m_vertex.buff), old_vertex_size, new_vertex_size},
// discard contents of buff_copy by setting old_size = 0
{reinterpret_cast<void**>(&m_vertex.buff_copy), 0, new_vertex_size},
{reinterpret_cast<void**>(&m_draw_vertex.buff), old_vertex_size, new_vertex_size},
{reinterpret_cast<void**>(&m_index.buff), old_index_size, new_index_size},
{reinterpret_cast<void**>(&m_draw_index.buff), old_index_size, new_index_size}
};
Console.Error("GS: failed to allocate %zu bytes for vertices and %zu for indices.",
vert_byte_count, idx_byte_count);
pxFailRel("Memory allocation failed");
// For logging
u32 total_size = 0;
for (const auto& desc : alloc_desc)
total_size += desc.new_size;
// Reallocate each of the needed buffers
for (const auto [pbuff, old_size, new_size] : alloc_desc)
{
void* new_buff = _aligned_malloc(new_size, 32);
if (!new_buff)
{
Console.Error("GS: failed to allocate %zu bytes for vertices and indices.", total_size);
pxFailRel("Memory allocation failed");
}
if (*pbuff)
{
if (old_size)
{
std::memcpy(new_buff, *pbuff, old_size);
}
_aligned_free(*pbuff);
}
*pbuff = new_buff;
}
if (m_vertex.buff)
{
std::memcpy(vertex, m_vertex.buff, sizeof(GSVertex) * m_vertex.tail);
_aligned_free(m_vertex.buff);
}
if (m_index.buff)
{
std::memcpy(index, m_index.buff, sizeof(u16) * m_index.tail);
_aligned_free(m_index.buff);
}
if (m_draw_vertex.buff)
{
std::memcpy(draw_vertex, m_draw_vertex.buff, sizeof(GSVertex) * m_vertex.tail);
_aligned_free(m_draw_vertex.buff);
}
if (m_draw_index.buff)
{
std::memcpy(draw_index, m_draw_index.buff, sizeof(u16) * m_index.tail);
_aligned_free(m_draw_index.buff);
}
m_draw_vertex.buff = draw_vertex;
m_draw_index.buff = draw_index;
m_vertex.buff = vertex;
m_vertex.maxcount = maxcount - 3; // -3 to have some space at the end of the buffer before DrawingKick can grow it
m_index.buff = index;
}
bool GSState::TrianglesAreQuads(bool shuffle_check)
@@ -3424,7 +3417,7 @@ __forceinline void GSState::CheckCLUTValidity(u32 prim)
}
}
template<u32 prim, bool index_swap>
template<u32 prim>
__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)
@@ -3520,9 +3513,8 @@ __forceinline void GSState::HandleAutoFlush()
if (tex_rect.y == tex_rect.w)
tex_rect += GSVector4i::cxpr(0, 0, 0, 1);
const bool swap_index = index_swap && GSUtil::GetPrimClass(m_prev_env.PRIM.PRIM) != GS_SPRITE_CLASS;
// Get the last texture position from the last draw.
const GSVertex* v = &m_vertex.buff[m_index.buff[m_index.tail - (swap_index ? n : 1)]];
const GSVertex* v = &m_vertex.buff[m_index.buff[m_index.tail - 1]];
if (PRIM->FST)
{
@@ -3700,7 +3692,7 @@ __forceinline void GSState::HandleAutoFlush()
}
}
template <u32 prim, bool auto_flush, bool index_swap>
template <u32 prim, bool auto_flush>
__forceinline void GSState::VertexKick(u32 skip)
{
constexpr u32 n = NumIndicesForPrim(prim);
@@ -3716,7 +3708,7 @@ __forceinline void GSState::VertexKick(u32 skip)
if (auto_flush && skip == 0 && m_index.tail > 0 && ((m_vertex.tail + 1) - m_vertex.head) >= n)
{
HandleAutoFlush<prim, index_swap>();
HandleAutoFlush<prim>();
}
u32 head = m_vertex.head;
@@ -3878,8 +3870,8 @@ __forceinline void GSState::VertexKick(u32 skip)
m_index.tail += 1;
break;
case GS_LINELIST:
buff[0] = static_cast<u16>(head + (index_swap ? 1 : 0));
buff[1] = static_cast<u16>(head + (index_swap ? 0 : 1));
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
m_vertex.head = head + 2;
m_vertex.next = head + 2;
m_index.tail += 2;
@@ -3892,16 +3884,16 @@ __forceinline void GSState::VertexKick(u32 skip)
head = next;
m_vertex.tail = next + 2;
}
buff[0] = static_cast<u16>(head + (index_swap ? 1 : 0));
buff[1] = static_cast<u16>(head + (index_swap ? 0 : 1));
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
m_vertex.head = head + 1;
m_vertex.next = head + 2;
m_index.tail += 2;
break;
case GS_TRIANGLELIST:
buff[0] = static_cast<u16>(head + (index_swap ? 2 : 0));
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
buff[2] = static_cast<u16>(head + (index_swap ? 0 : 2));
buff[2] = static_cast<u16>(head + 2);
m_vertex.head = head + 3;
m_vertex.next = head + 3;
m_index.tail += 3;
@@ -3915,18 +3907,18 @@ __forceinline void GSState::VertexKick(u32 skip)
head = next;
m_vertex.tail = next + 3;
}
buff[0] = static_cast<u16>(head + (index_swap ? 2 : 0));
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(head + 1);
buff[2] = static_cast<u16>(head + (index_swap ? 0 : 2));
buff[2] = static_cast<u16>(head + 2);
m_vertex.head = head + 1;
m_vertex.next = head + 3;
m_index.tail += 3;
break;
case GS_TRIANGLEFAN:
// TODO: remove gaps, next == head && head < tail - 3 || next > head && next < tail - 2 (very rare)
buff[0] = static_cast<u16>(index_swap ? (tail - 1) : (head + 0));
buff[0] = static_cast<u16>(head + 0);
buff[1] = static_cast<u16>(tail - 2);
buff[2] = static_cast<u16>(index_swap ? (head + 0) : (tail - 1));
buff[2] = static_cast<u16>(tail - 1);
m_vertex.next = tail;
m_index.tail += 3;
break;

View File

@@ -38,8 +38,8 @@ private:
void GIFPackedRegHandlerSTQ(const GIFPackedReg* RESTRICT r);
void GIFPackedRegHandlerUV(const GIFPackedReg* RESTRICT r);
void GIFPackedRegHandlerUV_Hack(const GIFPackedReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush, bool index_swap> void GIFPackedRegHandlerXYZF2(const GIFPackedReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush, bool index_swap> void GIFPackedRegHandlerXYZ2(const GIFPackedReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush> void GIFPackedRegHandlerXYZF2(const GIFPackedReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush> void GIFPackedRegHandlerXYZ2(const GIFPackedReg* RESTRICT r);
void GIFPackedRegHandlerFOG(const GIFPackedReg* RESTRICT r);
void GIFPackedRegHandlerA_D(const GIFPackedReg* RESTRICT r);
void GIFPackedRegHandlerNOP(const GIFPackedReg* RESTRICT r);
@@ -55,8 +55,8 @@ private:
GIFPackedRegHandlerC m_fpGIFPackedRegHandlerSTQRGBAXYZF2[8] = {};
GIFPackedRegHandlerC m_fpGIFPackedRegHandlerSTQRGBAXYZ2[8] = {};
template<u32 prim, bool auto_flush, bool index_swap> void GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u32 size);
template<u32 prim, bool auto_flush, bool index_swap> void GIFPackedRegHandlerSTQRGBAXYZ2(const GIFPackedReg* RESTRICT r, u32 size);
template<u32 prim, bool auto_flush> void GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u32 size);
template<u32 prim, bool auto_flush> void GIFPackedRegHandlerSTQRGBAXYZ2(const GIFPackedReg* RESTRICT r, u32 size);
void GIFPackedRegHandlerNOP(const GIFPackedReg* RESTRICT r, u32 size);
template<int i> void ApplyTEX0(GIFRegTEX0& TEX0);
@@ -68,8 +68,8 @@ private:
void GIFRegHandlerST(const GIFReg* RESTRICT r);
void GIFRegHandlerUV(const GIFReg* RESTRICT r);
void GIFRegHandlerUV_Hack(const GIFReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush, bool index_swap> void GIFRegHandlerXYZF2(const GIFReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush, bool index_swap> void GIFRegHandlerXYZ2(const GIFReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush> void GIFRegHandlerXYZF2(const GIFReg* RESTRICT r);
template<u32 prim, u32 adc, bool auto_flush> void GIFRegHandlerXYZ2(const GIFReg* RESTRICT r);
template<int i> void GIFRegHandlerTEX0(const GIFReg* RESTRICT r);
template<int i> void GIFRegHandlerCLAMP(const GIFReg* RESTRICT r);
void GIFRegHandlerFOG(const GIFReg* RESTRICT r);
@@ -102,8 +102,7 @@ private:
void GIFRegHandlerTRXDIR(const GIFReg* RESTRICT r);
void GIFRegHandlerHWREG(const GIFReg* RESTRICT r);
template<bool auto_flush, bool index_swap>
void SetPrimHandlers();
template<bool auto_flush> void SetPrimHandlers();
struct GSTransferBuffer
{
@@ -137,6 +136,7 @@ protected:
struct
{
GSVertex* buff;
GSVertex* buff_copy; // same size buffer to copy/modify the original buffer
u32 head, tail, next, maxcount; // head: first vertex, tail: last vertex + 1, next: last indexed + 1
u32 xy_tail;
GSVector4i xy[4];
@@ -171,12 +171,10 @@ protected:
void GrowVertexBuffer();
bool IsAutoFlushDraw(u32 prim);
template<u32 prim, bool index_swap>
void HandleAutoFlush();
template<u32 prim> void HandleAutoFlush();
void CheckCLUTValidity(u32 prim);
template <u32 prim, bool auto_flush, bool index_swap>
void VertexKick(u32 skip);
template <u32 prim, bool auto_flush> void VertexKick(u32 skip);
// following functions need m_vt to be initialized

View File

@@ -7,10 +7,10 @@
#include "common/Console.h"
GSVertexTrace::GSVertexTrace(const GSState* state, bool provoking_vertex_first)
GSVertexTrace::GSVertexTrace(const GSState* state)
: m_state(state)
{
MULTI_ISA_SELECT(GSVertexTracePopulateFunctions)(*this, provoking_vertex_first);
MULTI_ISA_SELECT(GSVertexTracePopulateFunctions)(*this);
}
void GSVertexTrace::Update(const void* vertex, const u16* index, int v_count, int i_count, GS_PRIM_CLASS primclass)

View File

@@ -15,7 +15,7 @@ class GSState;
class GSVertexTrace;
MULTI_ISA_DEF(class GSVertexTraceFMM;)
MULTI_ISA_DEF(void GSVertexTracePopulateFunctions(GSVertexTrace& vt, bool provoking_vertex_first);)
MULTI_ISA_DEF(void GSVertexTracePopulateFunctions(GSVertexTrace& vt);)
class alignas(32) GSVertexTrace final : public GSAlignedClass<32>
{
@@ -63,7 +63,7 @@ public:
GSVector2 m_lod = {}; // x = min, y = max
public:
GSVertexTrace(const GSState* state, bool provoking_vertex_first);
GSVertexTrace(const GSState* state);
void Update(const void* vertex, const u16* index, int v_count, int i_count, GS_PRIM_CLASS primclass);

View File

@@ -9,41 +9,36 @@ class CURRENT_ISA::GSVertexTraceFMM
{
static constexpr GSVector4 s_minmax = GSVector4::cxpr(FLT_MAX, -FLT_MAX, 0.f, 0.f);
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color, bool flat_swapped>
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
static void FindMinMax(GSVertexTrace& vt, const void* vertex, const u16* index, int count);
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
static constexpr GSVertexTrace::FindMinMaxPtr GetFMM(bool provoking_vertex_first);
static constexpr GSVertexTrace::FindMinMaxPtr GetFMM();
public:
static void Populate(GSVertexTrace& vt, bool provoking_vertex_first);
static void Populate(GSVertexTrace& vt);
};
MULTI_ISA_UNSHARED_IMPL;
void CURRENT_ISA::GSVertexTracePopulateFunctions(GSVertexTrace& vt, bool provoking_vertex_first)
void CURRENT_ISA::GSVertexTracePopulateFunctions(GSVertexTrace& vt)
{
GSVertexTraceFMM::Populate(vt, provoking_vertex_first);
GSVertexTraceFMM::Populate(vt);
}
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
constexpr GSVertexTrace::FindMinMaxPtr GSVertexTraceFMM::GetFMM(bool provoking_vertex_first)
constexpr GSVertexTrace::FindMinMaxPtr GSVertexTraceFMM::GetFMM()
{
constexpr bool real_iip = primclass == GS_SPRITE_CLASS ? false : iip;
constexpr bool real_fst = tme ? fst : false;
constexpr bool provoking_vertex_first_class = primclass == GS_LINE_CLASS || primclass == GS_TRIANGLE_CLASS;
const bool swap = provoking_vertex_first_class && !iip && provoking_vertex_first;
if (swap)
return FindMinMax<primclass, real_iip, tme, real_fst, color, true>;
else
return FindMinMax<primclass, real_iip, tme, real_fst, color, false>;
return FindMinMax<primclass, real_iip, tme, real_fst, color>;
}
void GSVertexTraceFMM::Populate(GSVertexTrace& vt, bool provoking_vertex_first)
void GSVertexTraceFMM::Populate(GSVertexTrace& vt)
{
#define InitUpdate3(P, IIP, TME, FST, COLOR) \
vt.m_fmm[COLOR][FST][TME][IIP][P] = GetFMM<P, IIP, TME, FST, COLOR>(provoking_vertex_first);
vt.m_fmm[COLOR][FST][TME][IIP][P] = GetFMM<P, IIP, TME, FST, COLOR>();
#define InitUpdate2(P, IIP, TME) \
InitUpdate3(P, IIP, TME, 0, 0) \
@@ -63,7 +58,7 @@ void GSVertexTraceFMM::Populate(GSVertexTrace& vt, bool provoking_vertex_first)
InitUpdate(GS_SPRITE_CLASS);
}
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color, bool flat_swapped>
template <GS_PRIM_CLASS primclass, u32 iip, u32 tme, u32 fst, u32 color>
void GSVertexTraceFMM::FindMinMax(GSVertexTrace& vt, const void* vertex, const u16* index, int count)
{
const GSDrawingContext* context = vt.m_state->m_context;
@@ -110,7 +105,7 @@ void GSVertexTraceFMM::FindMinMax(GSVertexTrace& vt, const void* vertex, const u
{
// For even n, we process v1 and v2 of the same prim
// (For odd n, we process one vertex from each of two prims)
GSVector4i c = flat_swapped ? c0 : c1;
GSVector4i c = c1; // second color is provoking in flat-shaded primitives
cmin = cmin.min_u8(c);
cmax = cmax.max_u8(c);
}
@@ -196,26 +191,16 @@ void GSVertexTraceFMM::FindMinMax(GSVertexTrace& vt, const void* vertex, const u
int i = 0;
for (; i < (count - 3); i += 6)
{
processVertices(v[index[i + 0]], v[index[i + 3]], flat_swapped);
processVertices(v[index[i + 0]], v[index[i + 3]], false);
processVertices(v[index[i + 1]], v[index[i + 4]], false);
processVertices(v[index[i + 2]], v[index[i + 5]], !flat_swapped);
processVertices(v[index[i + 2]], v[index[i + 5]], true);
}
if (count & 1)
{
if (flat_swapped)
{
processVertices(v[index[i + 1]], v[index[i + 2]], false);
// Compiler optimizations go!
// (And if they don't, it's only one vertex out of many)
processVertices(v[index[i + 0]], v[index[i + 0]], true);
}
else
{
processVertices(v[index[i + 0]], v[index[i + 1]], false);
// Compiler optimizations go!
// (And if they don't, it's only one vertex out of many)
processVertices(v[index[i + 2]], v[index[i + 2]], true);
}
processVertices(v[index[i + 0]], v[index[i + 1]], false);
// Compiler optimizations go!
// (And if they don't, it's only one vertex out of many)
processVertices(v[index[i + 2]], v[index[i + 2]], true);
}
}
else

View File

@@ -4791,21 +4791,10 @@ bool GSRendererHW::VerifyIndices()
return false;
// Expect each line to be a pair next to each other
// VS expand relies on this!
if (g_gs_device->Features().provoking_vertex_last)
for (u32 i = 0; i < m_index.tail; i += 2)
{
for (u32 i = 0; i < m_index.tail; i += 2)
{
if (m_index.buff[i] + 1 != m_index.buff[i + 1])
return false;
}
}
else
{
for (u32 i = 0; i < m_index.tail; i += 2)
{
if (m_index.buff[i] != m_index.buff[i + 1] + 1)
return false;
}
if (m_index.buff[i] + 1 != m_index.buff[i + 1])
return false;
}
break;
case GS_TRIANGLE_CLASS:
@@ -4818,6 +4807,52 @@ bool GSRendererHW::VerifyIndices()
return true;
}
// Fix the colors in vertices in case the API only supports "provoking first vertex"
// (i.e., when using flat shading the color comes from the first vertex, unlike PS2
// which is "provoking last vertex").
void GSRendererHW::HandleProvokingVertexFirst()
{
// Early exit conditions:
if (g_gs_device->Features().provoking_vertex_last || // device supports provoking last vertex
m_conf.vs.iip || // we are doing Gouraud shading
m_vt.m_primclass == GS_POINT_CLASS || // drawing points (one vertex per primitive; color is unambiguous)
m_vt.m_primclass == GS_SPRITE_CLASS) // drawing sprites (handled by the sprites -> triangles expand shader)
return;
const int n = GSUtil::GetClassVertexCount(m_vt.m_primclass);
// If all first/last vertices have the same color there is nothing to do.
bool first_eq_last = true;
for (u32 i = 0; i < m_index.tail; i += n)
{
if (m_vertex.buff[m_index.buff[i]].RGBAQ.U32[0] != m_vertex.buff[m_index.buff[i + n - 1]].RGBAQ.U32[0])
{
first_eq_last = false;
break;
}
}
if (first_eq_last)
return;
// De-index the vertices using the copy buffer
while (m_vertex.maxcount < m_index.tail)
GrowVertexBuffer();
for (int i = static_cast<int>(m_index.tail) - 1; i >= 0; i--)
{
m_vertex.buff_copy[i] = m_vertex.buff[m_index.buff[i]];
m_index.buff[i] = static_cast<u16>(i);
}
std::swap(m_vertex.buff, m_vertex.buff_copy);
m_vertex.head = m_vertex.next = m_vertex.tail = m_index.tail;
// Put correct color in the first vertex
for (u32 i = 0; i < m_index.tail; i += n)
{
m_vertex.buff[i].RGBAQ.U32[0] = m_vertex.buff[i + n - 1].RGBAQ.U32[0];
m_vertex.buff[i + n - 1].RGBAQ.U32[0] = 0xff; // Make last vertex red for debugging if used improperly
}
}
void GSRendererHW::SetupIA(float target_scale, float sx, float sy, bool req_vert_backup)
{
GL_PUSH("HW: IA");
@@ -7899,6 +7934,8 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
m_conf.drawarea = m_channel_shuffle ? scissor : scissor.rintersect(ComputeBoundingBox(rtsize, rtscale));
m_conf.scissor = (DATE && !DATE_BARRIER) ? m_conf.drawarea : scissor;
HandleProvokingVertexFirst();
SetupIA(rtscale, sx, sy, m_channel_shuffle_width != 0);
if (ate_second_pass)

View File

@@ -92,6 +92,7 @@ private:
void DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Target* ds, GSTextureCache::Source* tex, const TextureMinMaxResult& tmm);
void ResetStates();
void HandleProvokingVertexFirst();
void SetupIA(float target_scale, float sx, float sy, bool req_vert_backup);
void EmulateTextureShuffleAndFbmask(GSTextureCache::Target* rt, GSTextureCache::Source* tex);
bool EmulateChannelShuffle(GSTextureCache::Target* src, bool test_only, GSTextureCache::Target* rt = nullptr);

View File

@@ -1146,6 +1146,7 @@ bool GSDeviceMTL::Create(GSVSyncMode vsync_mode, bool allow_present_throttle)
case ShaderConvert::COPY:
case ShaderConvert::DOWNSAMPLE_COPY:
case ShaderConvert::RGBA_TO_8I: // Yes really
case ShaderConvert::RGB5A1_TO_8I:
case ShaderConvert::RTA_CORRECTION:
case ShaderConvert::RTA_DECORRECTION:
case ShaderConvert::TRANSPARENCY_FILTER:

View File

@@ -233,9 +233,7 @@ vertex MainVSOut vs_main_expand(
uint vid_base = vid >> 2;
bool is_bottom = vid & 2;
bool is_right = vid & 1;
// All lines will be a pair of vertices next to each other
// Since Metal uses provoking vertex first, the bottom point will be the lower of the two
uint vid_other = is_bottom ? vid_base + 1 : vid_base - 1;
uint vid_other = is_bottom ? vid_base - 1 : vid_base + 1;
MainVSOut point = vs_main_run(load_vertex(vertices[vid_base]), cb);
MainVSOut other = vs_main_run(load_vertex(vertices[vid_other]), cb);

View File

@@ -605,7 +605,7 @@ bool GSDeviceOGL::CreateTextureFX()
bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
{
//bool vendor_id_amd = false;
bool vendor_id_nvidia = false;
//bool vendor_id_nvidia = false;
//bool vendor_id_intel = false;
const char* vendor = (const char*)glGetString(GL_VENDOR);
@@ -618,7 +618,7 @@ bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
else if (std::strstr(vendor, "NVIDIA Corporation"))
{
Console.WriteLn(Color_StrongGreen, "GL: NVIDIA GPU detected.");
vendor_id_nvidia = true;
//vendor_id_nvidia = true;
}
else if (std::strstr(vendor, "Intel"))
{

View File

@@ -3,4 +3,4 @@
/// Version number for GS and other shaders. Increment whenever any of the contents of the
/// shaders change, to invalidate the cache.
static constexpr u32 SHADER_CACHE_VERSION = 68;
static constexpr u32 SHADER_CACHE_VERSION = 69;