Compare commits

...

3 Commits

Author SHA1 Message Date
Ty
282317c46e Debugger: Add opcodes and fixes to the assembler (#12267) 2025-02-03 16:52:27 -05:00
refractionpcsx2
2d6a42ac06 GS/HW: Reduce number of copies for HDR 2025-02-03 16:48:47 -05:00
PCSX2 Bot
cd98f72f10 [ci skip] PAD: Update to latest controller database. 2025-02-03 20:21:41 +01:00
19 changed files with 1145 additions and 503 deletions

View File

@@ -211,7 +211,7 @@
03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows,
03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows,
03000000b40400001024000000000000,Flydigi Apex,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,
03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,misc1:b15,paddle1:b11,paddle2:b10,paddle3:b13,paddle4:b12,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows,
03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows,
03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows,
03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows,
@@ -1265,6 +1265,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
05000000b40400001224000001010000,Flydigi APEX 4,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b20,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
@@ -1500,6 +1501,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,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,
030000006f0e0000d802000006640000,PDP 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,
030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired 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,
030000006f0e0000f102000000000000,PDP Xbox Atomic,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
03000000c62400000053000000010000,PowerA,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,
03000000c62400003a54000001010000,PowerA 1428124-01,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,
03000000d62000000540000001010000,PowerA Advantage Xbox Series X 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,
@@ -1592,6 +1594,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000003215000000090000163a0000,Razer Serval,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:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
0300000032150000030a000001010000,Razer Wildcat,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,
03000000321500000b10000011010000,Razer Wolverine PS5 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
0300000032150000140a000001010000,Razer Wolverine Ultimate Xbox,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,
030000000d0f0000c100000010010000,Retro Bit Legacy16,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b12,leftshoulder:b4,lefttrigger:b6,misc1:b13,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f0000c100000072056800,Retro Bit Legacy16,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:+a4,misc1:b11,rightshoulder:b10,righttrigger:+a5,start:b6,x:b3,y:b2,platform:Linux,
03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux,

View File

@@ -799,7 +799,8 @@ void ps_fbmask(inout float4 C, float2 pos_xy)
{
if (PS_FBMASK)
{
float4 RT = trunc(RtTexture.Load(int3(pos_xy, 0)) * 255.0f + 0.1f);
float multi = PS_HDR ? 65535.0f : 255.0f;
float4 RT = trunc(RtTexture.Load(int3(pos_xy, 0)) * multi + 0.1f);
C = (float4)(((uint4)C & ~FbMask) | ((uint4)RT & FbMask));
}
}
@@ -895,7 +896,8 @@ void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
}
float Ad = PS_RTA_CORRECTION ? trunc(RT.a * 128.0f + 0.1f) / 128.0f : trunc(RT.a * 255.0f + 0.1f) / 128.0f;
float3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
float color_multi = PS_HDR ? 65535.0f : 255.0f;
float3 Cd = trunc(RT.rgb * color_multi + 0.1f);
float3 Cs = Color.rgb;
float3 A = (PS_BLEND_A == 0) ? Cs : ((PS_BLEND_A == 1) ? Cd : (float3)0.0f);

View File

@@ -708,7 +708,11 @@ void ps_fbmask(inout vec4 C)
{
// FIXME do I need special case for 16 bits
#if PS_FBMASK
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
#if PS_HDR == 1
vec4 RT = trunc(fetch_rt() * 65535.0f);
#else
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
#endif
C = vec4((uvec4(C) & ~FbMask) | (uvec4(RT) & FbMask));
#endif
}
@@ -823,7 +827,11 @@ float As = As_rgba.a;
#endif
// Let the compiler do its jobs !
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
#if PS_HDR == 1
vec3 Cd = trunc(RT.rgb * 65535.0f);
#else
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
#endif
vec3 Cs = Color.rgb;
#if PS_BLEND_A == 0

View File

@@ -972,7 +972,12 @@ vec4 ps_color()
void ps_fbmask(inout vec4 C)
{
#if PS_FBMASK
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
#if PS_HDR == 1
vec4 RT = trunc(sample_from_rt() * 65535.0f);
#else
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
#endif
C = vec4((uvec4(C) & ~FbMask) | (uvec4(RT) & FbMask));
#endif
}
@@ -1090,7 +1095,11 @@ void ps_blend(inout vec4 Color, inout vec4 As_rgba)
#endif
// Let the compiler do its jobs !
#if PS_HDR == 1
vec3 Cd = trunc(RT.rgb * 65535.0f);
#else
vec3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
#endif
vec3 Cs = Color.rgb;
#if PS_BLEND_A == 0

View File

@@ -25,6 +25,7 @@
#define DECODE_C0BC ((disasmOpcode >> 16) & 0x03)
#define DECODE_C1BC ((disasmOpcode >> 16) & 0x03)
#define DECODE_C2BC ((disasmOpcode >> 16) & 0x03)
#define DECODE_ILOCK (disasmOpcode & 1)
//IOP

View File

@@ -1073,11 +1073,11 @@ void MTSAH( std::string& output ) { _sap("mtsah\t%s, 0x%04X") GPR_REG[DECODE_R
//***************************SPECIAL 2 CPU OPCODES*******************
const char* pmfhl_sub[] = {"lw", "uw", "slw", "lh", "sh", "??", "??", "??"};
void MADD( std::string& output ) { _sap("madd\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void MADDU( std::string& output ) { _sap("maddu\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);}
void MADD( std::string& output ) { _sap("madd\t%s, %s, %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void MADDU( std::string& output ) { _sap("maddu\t%s, %s, %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]);}
void PLZCW( std::string& output ) { _sap("plzcw\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS]); }
void MADD1( std::string& output ) { _sap("madd1\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void MADDU1( std::string& output ) { _sap("maddu1\t%s, %s %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void MADD1( std::string& output ) { _sap("madd1\t%s, %s, %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void MADDU1( std::string& output ) { _sap("maddu1\t%s, %s, %s") GPR_REG[DECODE_RD],GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void MFHI1( std::string& output ) { _sap("mfhi1\t%s") GPR_REG[DECODE_RD]); }
void MTHI1( std::string& output ) { _sap("mthi1\t%s") GPR_REG[DECODE_RS]); }
void MFLO1( std::string& output ) { _sap("mflo1\t%s") GPR_REG[DECODE_RD]); }
@@ -1125,11 +1125,11 @@ void PEXT5( std::string& output ) { _sap( "pext5\t%s, %s") GPR_REG[DECODE_R
void PPAC5( std::string& output ) { _sap( "ppac5\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); }
//**********END OF MMI0 OPCODES*********************************
//**********MMI1 OPCODES**************************************
void PABSW( std::string& output ){ _sap( "pabsw%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); }
void PABSW( std::string& output ){ _sap( "pabsw\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); }
void PCEQW( std::string& output ){ _sap( "pceqw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void PMINW( std::string& output ){ _sap( "pminw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void PADSBH( std::string& output ){ _sap( "padsbh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void PABSH( std::string& output ){ _sap( "pabsh%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); }
void PABSH( std::string& output ){ _sap( "pabsh\t%s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RT]); }
void PCEQH( std::string& output ){ _sap( "pceqh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void PMINH( std::string& output ){ _sap( "pminh\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void PCEQB( std::string& output ){ _sap( "pceqb\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
@@ -1148,7 +1148,7 @@ void QFSRV( std::string& output ) { _sap( "qfsrv\t%s, %s, %s") GPR_REG[DECODE_
void PMADDW( std::string& output ){ _sap( "pmaddw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void PSLLVW( std::string& output ){ _sap( "psllvw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void PSRLVW( std::string& output ){ _sap( "psrlvw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void PMSUBW( std::string& output ){ _sap( "msubw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void PMSUBW( std::string& output ){ _sap( "pmsubw\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
void PMFHI( std::string& output ){ _sap( "pmfhi\t%s") GPR_REG[DECODE_RD]); }
void PMFLO( std::string& output ){ _sap( "pmflo\t%s") GPR_REG[DECODE_RD]); }
void PINTH( std::string& output ){ _sap( "pinth\t%s, %s, %s") GPR_REG[DECODE_RD], GPR_REG[DECODE_RS], GPR_REG[DECODE_RT]); }
@@ -1247,10 +1247,10 @@ void CVT_S( std::string& output ){ _sap("cvt.s.w\t%s, %s") COP1_REG_FP[DECODE
//****************************************************************************
//** COP2 - (VU0) **
//****************************************************************************
void P_QMFC2( std::string& output ){ _sap("qmfc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_FP[DECODE_FS]); }
void P_CFC2( std::string& output ){ _sap("cfc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_CTL[DECODE_FS]); }
void P_QMTC2( std::string& output ){ _sap("qmtc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_FP[DECODE_FS]); }
void P_CTC2( std::string& output ){ _sap("ctc2\t%s, %s") GPR_REG[DECODE_RT], COP2_REG_CTL[DECODE_FS]); }
void P_QMFC2( std::string& output ){ _sap("qmfc2%s\t%s, %s") DECODE_ILOCK ? ".i" : "", GPR_REG[DECODE_RT], COP2_REG_FP[DECODE_FS]); }
void P_CFC2( std::string& output ){ _sap("cfc2%s\t%s, %s") DECODE_ILOCK ? ".i" : "", GPR_REG[DECODE_RT], COP2_REG_CTL[DECODE_FS]); }
void P_QMTC2( std::string& output ){ _sap("qmtc2%s\t%s, %s") DECODE_ILOCK ? ".i" : "", GPR_REG[DECODE_RT], COP2_REG_FP[DECODE_FS]); }
void P_CTC2( std::string& output ){ _sap("ctc2%s\t%s, %s") DECODE_ILOCK ? ".i" : "", GPR_REG[DECODE_RT], COP2_REG_CTL[DECODE_FS]); }
void P_BC2F( std::string& output ){ output += "bc2f\t"; offset_decode(output); }
void P_BC2T( std::string& output ){ output += "bc2t\t"; offset_decode(output); }
void P_BC2FL( std::string& output ){ output += "bc2fl\t"; offset_decode(output); }

View File

@@ -3,7 +3,10 @@
#include "MipsAssembler.h"
#include <cstring>
#include <array>
#include <algorithm>
#include <cctype>
#include <string_view>
// just an empty class, so that it's not necessary to remove all the calls manually
// will make it easier to update if there are changes later on
@@ -24,133 +27,176 @@ public:
};
constexpr auto MipsRegisters = std::to_array<tMipsRegister>({
{ "r0", 0}, { "zero", 0}, { "$0", 0 }, { "$zero", 0 },
{ "at", 1}, { "r1", 1}, { "$1", 1 }, { "$at", 1 },
{ "v0", 2}, { "r2", 2}, { "$v0", 2 },
{ "v1", 3}, { "r3", 3}, { "$v1", 3 },
{ "a0", 4}, { "r4", 4}, { "$a0", 4 },
{ "a1", 5}, { "r5", 5}, { "$a1", 5 },
{ "a2", 6}, { "r6", 6}, { "$a2", 6 },
{ "a3", 7}, { "r7", 7}, { "$a3", 7 },
{ "t0", 8}, { "r8", 8}, { "$t0", 8 },
{ "t1", 9}, { "r9", 9}, { "$t1", 9 },
{ "t2", 10}, { "r10", 10}, { "$t2", 10 },
{ "t3", 11}, { "r11", 11}, { "$t3", 11 },
{ "t4", 12}, { "r12", 12}, { "$t4", 12 },
{ "t5", 13}, { "r13", 13}, { "$t5", 13 },
{ "t6", 14}, { "r14", 14}, { "$t6", 14 },
{ "t7", 15}, { "r15", 15}, { "$t7", 15 },
{ "s0", 16}, { "r16", 16}, { "$s0", 16 },
{ "s1", 17}, { "r17", 17}, { "$s1", 17 },
{ "s2", 18}, { "r18", 18}, { "$s2", 18 },
{ "s3", 19}, { "r19", 19}, { "$s3", 19 },
{ "s4", 20}, { "r20", 20}, { "$s4", 20 },
{ "s5", 21}, { "r21", 21}, { "$s5", 21 },
{ "s6", 22}, { "r22", 22}, { "$s6", 22 },
{ "s7", 23}, { "r23", 23}, { "$s7", 23 },
{ "t8", 24}, { "r24", 24}, { "$t8", 24 },
{ "t9", 25}, { "r25", 25}, { "$t9", 25 },
{ "k0", 26}, { "r26", 26}, { "$k0", 26 },
{ "k1", 27}, { "r27", 27}, { "$k1", 27 },
{ "gp", 28}, { "r28", 28}, { "$gp", 28 },
{ "sp", 29}, { "r29", 29}, { "$sp", 29 },
{ "fp", 30}, { "r30", 30}, { "$fp", 30 },
{ "ra", 31}, { "r31", 31}, { "$ra", 31 }
});
const tMipsRegister MipsRegister[] = {
{ "r0", 0, 2 }, { "zero", 0, 4}, { "$0", 0, 2 }, { "$zero", 0, 5 },
{ "at", 1, 2 }, { "r1", 1, 2 }, { "$1", 1, 2 }, { "$at", 1, 3 },
{ "v0", 2, 2 }, { "r2", 2, 2 }, { "$v0", 2, 3 },
{ "v1", 3, 2 }, { "r3", 3, 2 }, { "$v1", 3, 3 },
{ "a0", 4, 2 }, { "r4", 4, 2 }, { "$a0", 4, 3 },
{ "a1", 5, 2 }, { "r5", 5, 2 }, { "$a1", 5, 3 },
{ "a2", 6, 2 }, { "r6", 6, 2 }, { "$a2", 6, 3 },
{ "a3", 7, 2 }, { "r7", 7, 2 }, { "$a3", 7, 3 },
{ "t0", 8, 2 }, { "r8", 8, 2 }, { "$t0", 8, 3 },
{ "t1", 9, 2 }, { "r9", 9, 2 }, { "$t1", 9, 3 },
{ "t2", 10, 2 }, { "r10", 10, 3 }, { "$t2", 10, 3 },
{ "t3", 11, 2 }, { "r11", 11, 3 }, { "$t3", 11, 3 },
{ "t4", 12, 2 }, { "r12", 12, 3 }, { "$t4", 12, 3 },
{ "t5", 13, 2 }, { "r13", 13, 3 }, { "$t5", 13, 3 },
{ "t6", 14, 2 }, { "r14", 14, 3 }, { "$t6", 14, 3 },
{ "t7", 15, 2 }, { "r15", 15, 3 }, { "$t7", 15, 3 },
{ "s0", 16, 2 }, { "r16", 16, 3 }, { "$s0", 16, 3 },
{ "s1", 17, 2 }, { "r17", 17, 3 }, { "$s1", 17, 3 },
{ "s2", 18, 2 }, { "r18", 18, 3 }, { "$s2", 18, 3 },
{ "s3", 19, 2 }, { "r19", 19, 3 }, { "$s3", 19, 3 },
{ "s4", 20, 2 }, { "r20", 20, 3 }, { "$s4", 20, 3 },
{ "s5", 21, 2 }, { "r21", 21, 3 }, { "$s5", 21, 3 },
{ "s6", 22, 2 }, { "r22", 22, 3 }, { "$s6", 22, 3 },
{ "s7", 23, 2 }, { "r23", 23, 3 }, { "$s7", 23, 3 },
{ "t8", 24, 2 }, { "r24", 24, 3 }, { "$t8", 24, 3 },
{ "t9", 25, 2 }, { "r25", 25, 3 }, { "$t9", 25, 3 },
{ "k0", 26, 2 }, { "r26", 26, 3 }, { "$k0", 26, 3 },
{ "k1", 27, 2 }, { "r27", 27, 3 }, { "$k1", 27, 3 },
{ "gp", 28, 2 }, { "r28", 28, 3 }, { "$gp", 28, 3 },
{ "sp", 29, 2 }, { "r29", 29, 3 }, { "$sp", 29, 3 },
{ "fp", 30, 2 }, { "r30", 30, 3 }, { "$fp", 30, 3 },
{ "ra", 31, 2 }, { "r31", 31, 3 }, { "$ra", 31, 3 },
{ NULL, -1, 0}
};
constexpr auto MipsFloatRegisters = std::to_array<tMipsRegister>({
{ "f0", 0, }, { "$f0", 0 },
{ "f1", 1, }, { "$f1", 1 },
{ "f2", 2, }, { "$f2", 2 },
{ "f3", 3, }, { "$f3", 3 },
{ "f4", 4, }, { "$f4", 4 },
{ "f5", 5, }, { "$f5", 5 },
{ "f6", 6, }, { "$f6", 6 },
{ "f7", 7, }, { "$f7", 7 },
{ "f8", 8, }, { "$f8", 8 },
{ "f9", 9, }, { "$f9", 9 },
{ "f00", 0,}, { "$f00", 0 },
{ "f01", 1,}, { "$f01", 1 },
{ "f02", 2,}, { "$f02", 2 },
{ "f03", 3,}, { "$f03", 3 },
{ "f04", 4,}, { "$f04", 4 },
{ "f05", 5,}, { "$f05", 5 },
{ "f06", 6,}, { "$f06", 6 },
{ "f07", 7,}, { "$f07", 7 },
{ "f08", 8,}, { "$f08", 8 },
{ "f09", 9,}, { "$f09", 9 },
{ "f10", 10 }, { "$f10", 10 },
{ "f11", 11 }, { "$f11", 11 },
{ "f12", 12 }, { "$f12", 12 },
{ "f13", 13 }, { "$f13", 13 },
{ "f14", 14 }, { "$f14", 14 },
{ "f15", 15 }, { "$f15", 15 },
{ "f16", 16 }, { "$f16", 16 },
{ "f17", 17 }, { "$f17", 17 },
{ "f18", 18 }, { "$f18", 18 },
{ "f19", 19 }, { "$f19", 19 },
{ "f20", 20 }, { "$f20", 20 },
{ "f21", 21 }, { "$f21", 21 },
{ "f22", 22 }, { "$f22", 22 },
{ "f23", 23 }, { "$f23", 23 },
{ "f24", 24 }, { "$f24", 24 },
{ "f25", 25 }, { "$f25", 25 },
{ "f26", 26 }, { "$f26", 26 },
{ "f27", 27 }, { "$f27", 27 },
{ "f28", 28 }, { "$f28", 28 },
{ "f29", 29 }, { "$f29", 29 },
{ "f30", 30 }, { "$f30", 30 },
{ "f31", 31 }, { "$f31", 31 }
});
constexpr auto MipsPs2Cop2FpRegisters = std::to_array<tMipsRegister>({
{ "vf0", 0 }, { "$vf0", 0 },
{ "vf1", 1 }, { "$vf1", 1 },
{ "vf2", 2 }, { "$vf2", 2 },
{ "vf3", 3 }, { "$vf3", 3 },
{ "vf4", 4 }, { "$vf4", 4 },
{ "vf5", 5 }, { "$vf5", 5 },
{ "vf6", 6 }, { "$vf6", 6 },
{ "vf7", 7 }, { "$vf7", 7 },
{ "vf8", 8 }, { "$vf8", 8 },
{ "vf9", 9 }, { "$vf9", 9 },
{ "vf00", 0 }, { "$vf00", 0 },
{ "vf01", 1 }, { "$vf01", 1 },
{ "vf02", 2 }, { "$vf02", 2 },
{ "vf03", 3 }, { "$vf03", 3 },
{ "vf04", 4 }, { "$vf04", 4 },
{ "vf05", 5 }, { "$vf05", 5 },
{ "vf06", 6 }, { "$vf06", 6 },
{ "vf07", 7 }, { "$vf07", 7 },
{ "vf08", 8 }, { "$vf08", 8 },
{ "vf09", 9 }, { "$vf09", 9 },
{ "vf10", 10 }, { "$vf10", 10 },
{ "vf11", 11 }, { "$vf11", 11 },
{ "vf12", 12 }, { "$vf12", 12 },
{ "vf13", 13 }, { "$vf13", 13 },
{ "vf14", 14 }, { "$vf14", 14 },
{ "vf15", 15 }, { "$vf15", 15 },
{ "vf16", 16 }, { "$vf16", 16 },
{ "vf17", 17 }, { "$vf17", 17 },
{ "vf18", 18 }, { "$vf18", 18 },
{ "vf19", 19 }, { "$vf19", 19 },
{ "vf20", 20 }, { "$vf20", 20 },
{ "vf21", 21 }, { "$vf21", 21 },
{ "vf22", 22 }, { "$vf22", 22 },
{ "vf23", 23 }, { "$vf23", 23 },
{ "vf24", 24 }, { "$vf24", 24 },
{ "vf25", 25 }, { "$vf25", 25 },
{ "vf26", 26 }, { "$vf26", 26 },
{ "vf27", 27 }, { "$vf27", 27 },
{ "vf28", 28 }, { "$vf28", 28 },
{ "vf29", 29 }, { "$vf29", 29 },
{ "vf30", 30 }, { "$vf30", 30 },
{ "vf31", 31 }, { "$vf31", 31 }
});
const tMipsRegister MipsFloatRegister[] = {
{ "f0", 0, 2}, { "$f0", 0, 3 },
{ "f1", 1, 2}, { "$f1", 1, 3 },
{ "f2", 2, 2}, { "$f2", 2, 3 },
{ "f3", 3, 2}, { "$f3", 3, 3 },
{ "f4", 4, 2}, { "$f4", 4, 3 },
{ "f5", 5, 2}, { "$f5", 5, 3 },
{ "f6", 6, 2}, { "$f6", 6, 3 },
{ "f7", 7, 2}, { "$f7", 7, 3 },
{ "f8", 8, 2}, { "$f8", 8, 3 },
{ "f9", 9, 2}, { "$f9", 9, 3 },
{ "f00", 0, 3}, { "$f00", 0, 4 },
{ "f01", 1, 3}, { "$f01", 1, 4 },
{ "f02", 2, 3}, { "$f02", 2, 4 },
{ "f03", 3, 3}, { "$f03", 3, 4 },
{ "f04", 4, 3}, { "$f04", 4, 4 },
{ "f05", 5, 3}, { "$f05", 5, 4 },
{ "f06", 6, 3}, { "$f06", 6, 4 },
{ "f07", 7, 3}, { "$f07", 7, 4 },
{ "f08", 8, 3}, { "$f08", 8, 4 },
{ "f09", 9, 3}, { "$f09", 9, 4 },
{ "f10", 10, 3}, { "$f10", 10, 4 },
{ "f11", 11, 3}, { "$f11", 11, 4 },
{ "f12", 12, 3}, { "$f12", 12, 4 },
{ "f13", 13, 3}, { "$f13", 13, 4 },
{ "f14", 14, 3}, { "$f14", 14, 4 },
{ "f15", 15, 3}, { "$f15", 15, 4 },
{ "f16", 16, 3}, { "$f16", 16, 4 },
{ "f17", 17, 3}, { "$f17", 17, 4 },
{ "f18", 18, 3}, { "$f18", 18, 4 },
{ "f19", 19, 3}, { "$f19", 19, 4 },
{ "f20", 20, 3}, { "$f20", 20, 4 },
{ "f21", 21, 3}, { "$f21", 21, 4 },
{ "f22", 22, 3}, { "$f22", 22, 4 },
{ "f23", 23, 3}, { "$f23", 23, 4 },
{ "f24", 24, 3}, { "$f24", 24, 4 },
{ "f25", 25, 3}, { "$f25", 25, 4 },
{ "f26", 26, 3}, { "$f26", 26, 4 },
{ "f27", 27, 3}, { "$f27", 27, 4 },
{ "f28", 28, 3}, { "$f28", 28, 4 },
{ "f29", 29, 3}, { "$f29", 29, 4 },
{ "f30", 30, 3}, { "$f30", 30, 4 },
{ "f31", 31, 3}, { "$f31", 31, 4 }
};
constexpr auto MipsPs2Cop2IRegisters = std::to_array<tMipsRegister>({
{ "vi0", 0 }, { "$vi0", 0 },
{ "vi1", 1 }, { "$vi1", 1 },
{ "vi2", 2 }, { "$vi2", 2 },
{ "vi3", 3 }, { "$vi3", 3 },
{ "vi4", 4 }, { "$vi4", 4 },
{ "vi5", 5 }, { "$vi5", 5 },
{ "vi6", 6 }, { "$vi6", 6 },
{ "vi7", 7 }, { "$vi7", 7 },
{ "vi8", 8 }, { "$vi8", 8 },
{ "vi9", 9 }, { "$vi9", 9 },
{ "vi00", 0 }, { "$vi00", 0 },
{ "vi01", 1 }, { "$vi01", 1 },
{ "vi02", 2 }, { "$vi02", 2 },
{ "vi03", 3 }, { "$vi03", 3 },
{ "vi04", 4 }, { "$vi04", 4 },
{ "vi05", 5 }, { "$vi05", 5 },
{ "vi06", 6 }, { "$vi06", 6 },
{ "vi07", 7 }, { "$vi07", 7 },
{ "vi08", 8 }, { "$vi08", 8 },
{ "vi09", 9 }, { "$vi09", 9 },
{ "vi10", 10 }, { "$vi10", 10 },
{ "vi11", 11 }, { "$vi11", 11 },
{ "vi12", 12 }, { "$vi12", 12 },
{ "vi13", 13 }, { "$vi13", 13 },
{ "vi14", 14 }, { "$vi14", 14 },
{ "vi15", 15 }, { "$vi15", 15 }
});
const tMipsRegister MipsPs2Cop2FpRegister[] = {
{ "vf0", 0, 3}, { "$vf0", 0, 4 },
{ "vf1", 1, 3}, { "$vf1", 1, 4 },
{ "vf2", 2, 3}, { "$vf2", 2, 4 },
{ "vf3", 3, 3}, { "$vf3", 3, 4 },
{ "vf4", 4, 3}, { "$vf4", 4, 4 },
{ "vf5", 5, 3}, { "$vf5", 5, 4 },
{ "vf6", 6, 3}, { "$vf6", 6, 4 },
{ "vf7", 7, 3}, { "$vf7", 7, 4 },
{ "vf8", 8, 3}, { "$vf8", 8, 4 },
{ "vf9", 9, 3}, { "$vf9", 9, 4 },
{ "vf00", 0, 4}, { "$vf00", 0, 5 },
{ "vf01", 1, 4}, { "$vf01", 1, 5 },
{ "vf02", 2, 4}, { "$vf02", 2, 5 },
{ "vf03", 3, 4}, { "$vf03", 3, 5 },
{ "vf04", 4, 4}, { "$vf04", 4, 5 },
{ "vf05", 5, 4}, { "$vf05", 5, 5 },
{ "vf06", 6, 4}, { "$vf06", 6, 5 },
{ "vf07", 7, 4}, { "$vf07", 7, 5 },
{ "vf08", 8, 4}, { "$vf08", 8, 5 },
{ "vf09", 9, 4}, { "$vf09", 9, 5 },
{ "vf10", 10, 4}, { "$vf10", 10, 5 },
{ "vf11", 11, 4}, { "$vf11", 11, 5 },
{ "vf12", 12, 4}, { "$vf12", 12, 5 },
{ "vf13", 13, 4}, { "$vf13", 13, 5 },
{ "vf14", 14, 4}, { "$vf14", 14, 5 },
{ "vf15", 15, 4}, { "$vf15", 15, 5 },
{ "vf16", 16, 4}, { "$vf16", 16, 5 },
{ "vf17", 17, 4}, { "$vf17", 17, 5 },
{ "vf18", 18, 4}, { "$vf18", 18, 5 },
{ "vf19", 19, 4}, { "$vf19", 19, 5 },
{ "vf20", 20, 4}, { "$vf20", 20, 5 },
{ "vf21", 21, 4}, { "$vf21", 21, 5 },
{ "vf22", 22, 4}, { "$vf22", 22, 5 },
{ "vf23", 23, 4}, { "$vf23", 23, 5 },
{ "vf24", 24, 4}, { "$vf24", 24, 5 },
{ "vf25", 25, 4}, { "$vf25", 25, 5 },
{ "vf26", 26, 4}, { "$vf26", 26, 5 },
{ "vf27", 27, 4}, { "$vf27", 27, 5 },
{ "vf28", 28, 4}, { "$vf28", 28, 5 },
{ "vf29", 29, 4}, { "$vf29", 29, 5 },
{ "vf30", 30, 4}, { "$vf30", 30, 5 },
{ "vf31", 31, 4}, { "$vf31", 31, 5 }
};
bool charEquals(char a, char b)
{
return std::tolower(a) == std::tolower(b);
}
bool strEquals(std::string_view lhs, std::string_view rhs)
{
const size_t compare_to = std::min(lhs.size(), rhs.size());
return std::ranges::equal(lhs.begin(), lhs.begin() + compare_to, rhs.begin(), rhs.begin() + compare_to, charEquals);
}
bool isValidRegisterTrail(std::string_view source, size_t idx)
{
return source.size() <= idx || source[idx] == ',' || source[idx] == '\n' || source[idx] == 0
|| source[idx] == ')' || source[idx] == '(' || source[idx] == '-';
}
void SplitLine(const char* Line, char* Name, char* Arguments)
{
@@ -200,102 +246,29 @@ bool MipsAssembleOpcode(const char* line, DebugInterface* cpu, u32 address, u32&
return true;
}
bool MipsGetRegister(const char* source, int& RetLen, MipsRegisterInfo& Result)
template<std::size_t SIZE>
bool MipsGetRegister(const char* source, int& RetLen, MipsRegisterInfo& Result, const std::array<tMipsRegister, SIZE>& RegisterList)
{
for (int z = 0; MipsRegister[z].name != NULL; z++)
{
int len = MipsRegister[z].len;
if (strncmp(MipsRegister[z].name,source,len) == 0) // okay so far
for (const auto& reg : RegisterList) {
if(strEquals(reg.name, source) && isValidRegisterTrail(source, strlen(reg.name)))
{
if (source[len] == ',' || source[len] == '\n' || source[len] == 0
|| source[len] == ')' || source[len] == '(' || source[len] == '-') // one of these has to come after a register
{
memcpy(Result.name,source,len);
Result.name[len] = 0;
Result.num = MipsRegister[z].num;
RetLen = len;
return true;
}
std::strncpy(Result.name, source, strlen(reg.name));
Result.num = reg.num;
RetLen = static_cast<int>(strlen(reg.name)); // grrr... should be unsigned!!
return true;
}
}
return false;
}
int MipsGetRegister(const char* source, int& RetLen)
template<std::size_t SIZE>
int MipsGetRegister(const char* source, int& RetLen, const std::array<tMipsRegister, SIZE>& RegisterList)
{
for (int z = 0; MipsRegister[z].name != NULL; z++)
{
int len = MipsRegister[z].len;
if (strncmp(MipsRegister[z].name,source,len) == 0) // okay so far
for (const auto& reg : RegisterList) {
if(strEquals(reg.name, source) && isValidRegisterTrail(source, strlen(reg.name)))
{
if (source[len] == ',' || source[len] == '\n' || source[len] == 0
|| source[len] == ')' || source[len] == '(' || source[len] == '-') // one of these has to come after a register
{
RetLen = len;
return MipsRegister[z].num;
}
}
}
return -1;
}
bool MipsGetFloatRegister(const char* source, int& RetLen, MipsRegisterInfo& Result)
{
for (int z = 0; MipsFloatRegister[z].name != NULL; z++)
{
int len = MipsFloatRegister[z].len;
if (strncmp(MipsFloatRegister[z].name,source,len) == 0) // okay so far
{
if (source[len] == ',' || source[len] == '\n' || source[len] == 0
|| source[len] == ')' || source[len] == '(' || source[len] == '-') // one of these has to come after a register
{
memcpy(Result.name,source,len);
Result.name[len] = 0;
Result.num = MipsFloatRegister[z].num;
RetLen = len;
return true;
}
}
}
return false;
}
bool MipsGetPs2VectorRegister(const char* source, int& RetLen, MipsRegisterInfo& Result)
{
for (int z = 0; MipsPs2Cop2FpRegister[z].name != NULL; z++)
{
int len = MipsPs2Cop2FpRegister[z].len;
if (strncmp(MipsPs2Cop2FpRegister[z].name,source,len) == 0) // okay so far
{
if (source[len] == ',' || source[len] == '\n' || source[len] == 0
|| source[len] == ')' || source[len] == '(' || source[len] == '-') // one of these has to come after a register
{
memcpy(Result.name,source,len);
Result.name[len] = 0;
Result.num = MipsPs2Cop2FpRegister[z].num;
RetLen = len;
return true;
}
}
}
return false;
}
int MipsGetFloatRegister(const char* source, int& RetLen)
{
for (int z = 0; MipsFloatRegister[z].name != NULL; z++)
{
int len = MipsFloatRegister[z].len;
if (strncmp(MipsFloatRegister[z].name,source,len) == 0) // okay so far
{
if (source[len] == ',' || source[len] == '\n' || source[len] == 0
|| source[len] == ')' || source[len] == '(' || source[len] == '-') // one of these has to come after a register
{
RetLen = len;
return MipsFloatRegister[z].num;
}
RetLen = static_cast<int>(strlen(reg.name)); // grrr... should be unsigned!!
return reg.num;
}
}
return -1;
@@ -308,7 +281,7 @@ bool MipsCheckImmediate(const char* Source, DebugInterface* cpu, int& dest, int&
int BufferPos = 0;
int l;
if (MipsGetRegister(Source,l) != -1) // error
if (MipsGetRegister(Source,l, MipsRegisters) != -1) // error
{
return false;
}
@@ -341,7 +314,7 @@ bool MipsCheckImmediate(const char* Source, DebugInterface* cpu, int& dest, int&
if (*Source == '(') // could be part of the opcode
{
if (MipsGetRegister(Source+1,l) != -1) // end
if (MipsGetRegister(Source+1,l, MipsRegisters) != -1) // end
{
Buffer[BufferPos] = 0;
break;
@@ -488,32 +461,32 @@ bool CMipsInstruction::LoadEncoding(const tMipsOpcode& SourceOpcode, const char*
switch (*SourceEncoding)
{
case 'T': // float reg
if (!MipsGetFloatRegister(Line,RetLen,registers.frt)) return false;
if (!MipsGetRegister(Line,RetLen,registers.frt, MipsFloatRegisters)) return false;
Line += RetLen;
SourceEncoding++;
break;
case 'D': // float reg
if (!MipsGetFloatRegister(Line,RetLen,registers.frd)) return false;
if (!MipsGetRegister(Line,RetLen,registers.frd, MipsFloatRegisters)) return false;
Line += RetLen;
SourceEncoding++;
break;
case 'S': // float reg
if (!MipsGetFloatRegister(Line,RetLen,registers.frs)) return false;
if (!MipsGetRegister(Line,RetLen,registers.frs, MipsFloatRegisters)) return false;
Line += RetLen;
SourceEncoding++;
break;
case 't':
if (!MipsGetRegister(Line,RetLen,registers.grt)) return false;
if (!MipsGetRegister(Line,RetLen,registers.grt, MipsRegisters)) return false;
Line += RetLen;
SourceEncoding++;
break;
case 'd':
if (!MipsGetRegister(Line,RetLen,registers.grd)) return false;
if (!MipsGetRegister(Line,RetLen,registers.grd, MipsRegisters)) return false;
Line += RetLen;
SourceEncoding++;
break;
case 's':
if (!MipsGetRegister(Line,RetLen,registers.grs)) return false;
if (!MipsGetRegister(Line,RetLen,registers.grs, MipsRegisters)) return false;
Line += RetLen;
SourceEncoding++;
break;
@@ -521,17 +494,35 @@ bool CMipsInstruction::LoadEncoding(const tMipsOpcode& SourceOpcode, const char*
switch (*(SourceEncoding+1))
{
case 's':
if (!MipsGetPs2VectorRegister(Line,RetLen,registers.ps2vrs)) return false;
if (!MipsGetRegister(Line,RetLen,registers.ps2vrs, MipsPs2Cop2FpRegisters)) return false;
Line += RetLen;
break;
case 't':
if (!MipsGetPs2VectorRegister(Line,RetLen,registers.ps2vrt)) return false;
if (!MipsGetRegister(Line,RetLen,registers.ps2vrt, MipsPs2Cop2FpRegisters)) return false;
Line += RetLen;
break;
case 'd':
if (!MipsGetPs2VectorRegister(Line,RetLen,registers.ps2vrd)) return false;
if (!MipsGetRegister(Line,RetLen,registers.ps2vrd, MipsPs2Cop2FpRegisters)) return false;
Line += RetLen;
break;
case 'i':
switch(*(SourceEncoding+2))
{
case 's':
if (!MipsGetRegister(Line,RetLen,registers.ps2vrs, MipsPs2Cop2IRegisters)) return false;
Line += RetLen;
break;
case 't':
if (!MipsGetRegister(Line,RetLen,registers.ps2vrt, MipsPs2Cop2IRegisters)) return false;
Line += RetLen;
break;
case 'd':
if (!MipsGetRegister(Line,RetLen,registers.ps2vrd, MipsPs2Cop2IRegisters)) return false;
Line += RetLen;
break;
}
SourceEncoding += 1;
break;
default:
return false;
}
@@ -562,7 +553,7 @@ bool CMipsInstruction::LoadEncoding(const tMipsOpcode& SourceOpcode, const char*
SourceEncoding++;
break;
case 'r': // forced register
if (MipsGetRegister(Line,RetLen) != *(SourceEncoding+1)) return false;
if (MipsGetRegister(Line,RetLen, MipsRegisters) != *(SourceEncoding+1)) return false;
Line += RetLen;
SourceEncoding += 2;
break;
@@ -685,7 +676,7 @@ void CMipsInstruction::encodeNormal()
if (registers.frd.num != -1) encoding |= MIPS_FD(registers.frd.num); // float dest reg
if (registers.ps2vrt.num != -1) encoding |= (registers.ps2vrt.num << 16); // ps2 vector target reg
if (registers.ps2vrs.num != -1) encoding |= (registers.ps2vrs.num << 21); // ps2 vector source reg
if (registers.ps2vrs.num != -1) encoding |= (registers.ps2vrs.num << 11); // ps2 vector source reg
if (registers.ps2vrd.num != -1) encoding |= (registers.ps2vrd.num << 6); // ps2 vector dest reg
switch (immediateType)

View File

@@ -13,7 +13,6 @@ enum MipsArchType { MARCH_PSX = 0, MARCH_N64, MARCH_PS2, MARCH_PSP, MARCH_INVALI
typedef struct {
const char* name;
short num;
short len;
} tMipsRegister;
typedef struct {

View File

@@ -304,6 +304,275 @@ const tMipsOpcode MipsOpcodes[] = {
{ "mtsab", "s,i", MIPS_REGIMM(0x18), MA_PS2, 0 },
{ "mtsah", "s,i", MIPS_REGIMM(0x19), MA_PS2, 0 },
// 31---------26------------------------------------------5--------0
// |= MMI| | function|
// ------6----------------------------------------------------6-----
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
// 000 | MADD | MADDU | --- | --- | PLZCW | --- | --- | --- | 00-07
// 001 | MMI0 | MMI2 | --- | --- | --- | --- | --- | --- | 08-0F
// 010 | MFHI1 | MTHI1 | MFLO1 | MTLO1 | --- | --- | --- | --- | 10-17
// 011 | MULT1 | MULTU1| DIV1 | DIVU1 | --- | --- | --- | --- | 18-1F
// 100 | MADD1 | MADDU1| --- | --- | --- | --- | --- | --- | 20..27
// 101 | MMI1 | MMI3 | --- | --- | --- | --- | --- | --- | 28..2F
// 110 | PMFHL | PMTHL | --- | --- | PSLLH | --- | --- | PSRAH | 30..37
// 111 | --- | --- | --- | --- | PSLLW | --- | PSRLW | PSRAW | 38..3F
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
{ "madd", "d,s,t", MIPS_MMI(0x00), MA_PS2, 0 },
{ "madd", "s,t", MIPS_MMI(0x00), MA_PS2, MO_RSD },
{ "maddu", "d,s,t", MIPS_MMI(0x01), MA_PS2, 0 },
{ "maddu", "s,t", MIPS_MMI(0x01), MA_PS2, MO_RSD },
{ "plzcw", "d,s", MIPS_MMI(0x04), MA_PS2, 0 },
{ "mfhi1", "d", MIPS_MMI(0x10), MA_PS2, 0 },
{ "mthi1", "s", MIPS_MMI(0x11), MA_PS2, 0 },
{ "mflo1", "d", MIPS_MMI(0x12), MA_PS2, 0 },
{ "mtlo1", "s", MIPS_MMI(0x13), MA_PS2, 0 },
{ "mult1", "d,s,t", MIPS_MMI(0x18), MA_PS2, 0 },
{ "mult1", "s,t", MIPS_MMI(0x18), MA_PS2, MO_RSD },
{ "multu1", "d,s,t", MIPS_MMI(0x19), MA_PS2, 0 },
{ "multu1", "s,t", MIPS_MMI(0x19), MA_PS2, MO_RSD },
{ "div1", "s,t", MIPS_MMI(0x1A), MA_PS2, 0 },
{ "divu1", "s,t", MIPS_MMI(0x1B), MA_PS2, 0 },
{ "madd1", "d,s,t", MIPS_MMI(0x20), MA_PS2, 0 },
{ "madd1", "s,t", MIPS_MMI(0x20), MA_PS2, MO_RSD },
{ "maddu1", "d,s,t", MIPS_MMI(0x21), MA_PS2, 0 },
{ "maddu1", "s,t", MIPS_MMI(0x21), MA_PS2, MO_RSD },
{ "pmfhl", "d", MIPS_PMFHL(0), MA_PS2, 0 },
{ "pmfhl.lw", "d", MIPS_PMFHL(0), MA_PS2, 0 },
{ "pmfhl.uw", "d", MIPS_PMFHL(1), MA_PS2, 0 },
{ "pmfhl.slw", "d", MIPS_PMFHL(2), MA_PS2, 0 },
{ "pmfhl.lh", "d", MIPS_PMFHL(3), MA_PS2, 0 },
{ "pmfhl.sh", "d", MIPS_PMFHL(4), MA_PS2, 0 },
{ "pmthl.lw", "s", MIPS_PMTHL(0), MA_PS2, 0 },
{ "pmthl", "s", MIPS_PMTHL(0), MA_PS2, 0 },
{ "psllh", "d,t,a", MIPS_MMI(0x34), MA_PS2, 0 },
{ "psrah", "d,t,a", MIPS_MMI(0x37), MA_PS2, 0 },
{ "psllw", "d,t,a", MIPS_MMI(0x3C), MA_PS2, 0 },
{ "psrlw", "d,t,a", MIPS_MMI(0x3E), MA_PS2, 0 },
{ "psraw", "d,t,a", MIPS_MMI(0x3F), MA_PS2, 0 },
// 31---------26--------------------------------10--------6-5-------0
// |= MMI| | function | MMI0 |
// -----6--------------------------------------------5---------6-----
// |---00---|---01---|---10---|---11---| lo
// 000 | PADDW | PSUBW | PCGTW | PMAXW | 00..03
// 001 | PADDH | PSUBH | PCGTH | PMAXH | 04..07
// 010 | PADDB | PSUBB | PCGTB | ---- | 08..0B
// 011 | ---- | ---- | ---- | ---- | 0C..0F
// 100 | PADDSW | PSUBSW | PEXTLW | PPACW | 10..13
// 101 | PADDSH | PSUBSH | PEXTLH | PPACH | 14..17
// 110 | PADDSB | PSUBSB | PEXTLB | PPACB | 18..1B
// 111 | ---- | --- | PEXT5 | PPAC5 | 1C..1F
// hi |--------|--------|--------|--------|
{ "paddw", "d,s,t", MIPS_MMI0(0x00), MA_PS2, 0 },
{ "paddw", "s,t", MIPS_MMI0(0x00), MA_PS2, MO_RSD },
{ "psubw", "d,s,t", MIPS_MMI0(0x01), MA_PS2, 0 },
{ "psubw", "s,t", MIPS_MMI0(0x01), MA_PS2, MO_RSD },
{ "pcgtw", "d,s,t", MIPS_MMI0(0x02), MA_PS2, 0 },
{ "pcgtw", "s,t", MIPS_MMI0(0x02), MA_PS2, MO_RSD },
{ "pmaxw", "d,s,t", MIPS_MMI0(0x03), MA_PS2, 0 },
{ "pmaxw", "s,t", MIPS_MMI0(0x03), MA_PS2, MO_RSD },
{ "paddh", "d,s,t", MIPS_MMI0(0x04), MA_PS2, 0 },
{ "paddh", "s,t", MIPS_MMI0(0x04), MA_PS2, MO_RSD },
{ "psubh", "d,s,t", MIPS_MMI0(0x05), MA_PS2, 0 },
{ "psubh", "s,t", MIPS_MMI0(0x05), MA_PS2, MO_RSD },
{ "pcgth", "d,s,t", MIPS_MMI0(0x06), MA_PS2, 0 },
{ "pcgth", "s,t", MIPS_MMI0(0x06), MA_PS2, MO_RSD },
{ "pmaxh", "d,s,t", MIPS_MMI0(0x07), MA_PS2, 0 },
{ "pmaxh", "s,t", MIPS_MMI0(0x07), MA_PS2, MO_RSD },
{ "paddb", "d,s,t", MIPS_MMI0(0x08), MA_PS2, 0 },
{ "paddb", "s,t", MIPS_MMI0(0x08), MA_PS2, MO_RSD },
{ "psubb", "d,s,t", MIPS_MMI0(0x09), MA_PS2, 0 },
{ "psubb", "s,t", MIPS_MMI0(0x09), MA_PS2, MO_RSD },
{ "pcgtb", "d,s,t", MIPS_MMI0(0x0A), MA_PS2, 0 },
{ "pcgtb", "s,t", MIPS_MMI0(0x0A), MA_PS2, MO_RSD },
{ "paddsw", "d,s,t", MIPS_MMI0(0x10), MA_PS2, 0 },
{ "paddsw", "s,t", MIPS_MMI0(0x10), MA_PS2, MO_RSD },
{ "psubsw", "d,s,t", MIPS_MMI0(0x11), MA_PS2, 0 },
{ "psubsw", "s,t", MIPS_MMI0(0x11), MA_PS2, MO_RSD },
{ "pextlw", "d,s,t", MIPS_MMI0(0x12), MA_PS2, 0 },
{ "pextlw", "s,t", MIPS_MMI0(0x12), MA_PS2, MO_RSD },
{ "ppacw", "d,s,t", MIPS_MMI0(0x13), MA_PS2, 0 },
{ "ppacw", "s,t", MIPS_MMI0(0x13), MA_PS2, MO_RSD },
{ "paddsh", "d,s,t", MIPS_MMI0(0x14), MA_PS2, 0 },
{ "paddsh", "s,t", MIPS_MMI0(0x14), MA_PS2, MO_RSD },
{ "psubsh", "d,s,t", MIPS_MMI0(0x15), MA_PS2, 0 },
{ "psubsh", "s,t", MIPS_MMI0(0x15), MA_PS2, MO_RSD },
{ "pextlh", "d,s,t", MIPS_MMI0(0x16), MA_PS2, 0 },
{ "pextlh", "s,t", MIPS_MMI0(0x16), MA_PS2, MO_RSD },
{ "ppach", "d,s,t", MIPS_MMI0(0x17), MA_PS2, 0 },
{ "ppach", "s,t", MIPS_MMI0(0x17), MA_PS2, MO_RSD },
{ "paddsb", "d,s,t", MIPS_MMI0(0x18), MA_PS2, 0 },
{ "paddsb", "s,t", MIPS_MMI0(0x18), MA_PS2, MO_RSD },
{ "psubsb", "d,s,t", MIPS_MMI0(0x19), MA_PS2, 0 },
{ "psubsb", "s,t", MIPS_MMI0(0x19), MA_PS2, MO_RSD },
{ "pextlb", "d,s,t", MIPS_MMI0(0x1A), MA_PS2, 0 },
{ "pextlb", "s,t", MIPS_MMI0(0x1A), MA_PS2, MO_RSD },
{ "ppacb", "d,s,t", MIPS_MMI0(0x1B), MA_PS2, 0 },
{ "ppacb", "s,t", MIPS_MMI0(0x1B), MA_PS2, MO_RSD },
{ "pext5", "d,t", MIPS_MMI0(0x1E), MA_PS2, 0 },
{ "ppac5", "d,t", MIPS_MMI0(0x1F), MA_PS2, 0 },
// 31---------26--------------------------------10--------6-5-------0
// |= MMI| | function | MMI1 |
// -----6--------------------------------------------5---------6-----
// |---00---|---01---|---10---|---11---| lo
// 000 | ---- | PABSW | PCEQW | PMINW | 00..03
// 001 | PADSBH | PABSH | PCEQH | PMINH | 04..07
// 010 | ---- | ---- | PCEQB | ---- | 08..0B
// 011 | ---- | ---- | ---- | ---- | 0C..0F
// 100 | PADDUW | PSUBUW | PEXTUW | PPACW | 10..13
// 101 | PADDUH | PSUBUH | PEXTUH | PPACH | 14..17
// 110 | PADDUB | PSUBUB | PEXTUB | QFSRV | 18..1B
// 111 | ---- | --- | ---- | ---- | 1C..1F
// hi |--------|--------|--------|--------|
{ "pabsw", "d,t", MIPS_MMI1(0x01), MA_PS2, 0 },
{ "pceqw", "d,s,t", MIPS_MMI1(0x02), MA_PS2, 0 },
{ "pceqw", "s,t", MIPS_MMI1(0x02), MA_PS2, MO_RSD },
{ "pminw", "d,s,t", MIPS_MMI1(0x03), MA_PS2, 0 },
{ "pminw", "s,t", MIPS_MMI1(0x03), MA_PS2, MO_RSD },
{ "padsbh", "d,s,t", MIPS_MMI1(0x04), MA_PS2, 0 },
{ "padsbh", "s,t", MIPS_MMI1(0x04), MA_PS2, MO_RSD },
{ "pabsh", "d,t", MIPS_MMI1(0x05), MA_PS2, 0 },
{ "pceqh", "d,s,t", MIPS_MMI1(0x06), MA_PS2, 0 },
{ "pceqh", "s,t", MIPS_MMI1(0x06), MA_PS2, MO_RSD },
{ "pminh", "d,s,t", MIPS_MMI1(0x07), MA_PS2, 0 },
{ "pminh", "s,t", MIPS_MMI1(0x07), MA_PS2, MO_RSD },
{ "pceqb", "d,s,t", MIPS_MMI1(0x0A), MA_PS2, 0 },
{ "pceqb", "s,t", MIPS_MMI1(0x0A), MA_PS2, MO_RSD },
{ "padduw", "d,s,t", MIPS_MMI1(0x10), MA_PS2, 0 },
{ "padduw", "s,t", MIPS_MMI1(0x10), MA_PS2, MO_RSD },
{ "psubuw", "d,s,t", MIPS_MMI1(0x11), MA_PS2, 0 },
{ "psubuw", "s,t", MIPS_MMI1(0x11), MA_PS2, MO_RSD },
{ "pextuw", "d,s,t", MIPS_MMI1(0x12), MA_PS2, 0 },
{ "pextuw", "s,t", MIPS_MMI1(0x12), MA_PS2, MO_RSD },
{ "ppacw", "d,s,t", MIPS_MMI1(0x13), MA_PS2, 0 },
{ "ppacw", "s,t", MIPS_MMI1(0x13), MA_PS2, MO_RSD },
{ "padduh", "d,s,t", MIPS_MMI1(0x14), MA_PS2, 0 },
{ "padduh", "s,t", MIPS_MMI1(0x14), MA_PS2, MO_RSD },
{ "psubuh", "d,s,t", MIPS_MMI1(0x15), MA_PS2, 0 },
{ "psubuh", "s,t", MIPS_MMI1(0x15), MA_PS2, MO_RSD },
{ "pextuh", "d,s,t", MIPS_MMI1(0x16), MA_PS2, 0 },
{ "pextuh", "s,t", MIPS_MMI1(0x16), MA_PS2, MO_RSD },
{ "ppach", "d,s,t", MIPS_MMI1(0x17), MA_PS2, 0 },
{ "ppach", "s,t", MIPS_MMI1(0x17), MA_PS2, MO_RSD },
{ "paddub", "d,s,t", MIPS_MMI1(0x18), MA_PS2, 0 },
{ "paddub", "s,t", MIPS_MMI1(0x18), MA_PS2, MO_RSD },
{ "psubub", "d,s,t", MIPS_MMI1(0x19), MA_PS2, 0 },
{ "psubub", "s,t", MIPS_MMI1(0x19), MA_PS2, MO_RSD },
{ "pextub", "d,s,t", MIPS_MMI1(0x1A), MA_PS2, 0 },
{ "pextub", "s,t", MIPS_MMI1(0x1A), MA_PS2, MO_RSD },
{ "qfsrv", "d,s,t", MIPS_MMI1(0x1B), MA_PS2, 0 },
{ "qfsrv", "s,t", MIPS_MMI1(0x1B), MA_PS2, MO_RSD },
// 31---------26--------------------------------10--------6-5-------0
// |= MMI| | function | MMI2 |
// -----6--------------------------------------------5---------6-----
// |---00---|---01---|---10---|---11---| lo
// 000 | PMADDW | ---- | PSLLVW | PSRLVW | 00..03
// 001 | PMSUBW | ---- | ---- | ---- | 04..07
// 010 | PMFHI | PMFLO | PINTH | ---- | 08..0B
// 011 | PMULTW | PDIVW | PCPYLD | ---- | 0C..0F
// 100 | PMADDH | PHMADH | PAND | PXOR | 10..13
// 101 | PMSUBH | PHMSBH | ---- | ---- | 14..17
// 110 | ---- | ---- | PEXEH | PREVH | 18..1B
// 111 | PMULTH | PDIVBW | PEXEW | PROT3W | 1C..1F
// hi |--------|--------|--------|--------|
{ "pmaddw", "d,s,t", MIPS_MMI2(0x00), MA_PS2, 0 },
{ "pmaddw", "s,t", MIPS_MMI2(0x00), MA_PS2, MO_RSD },
{ "psllvw", "d,s,t", MIPS_MMI2(0x02), MA_PS2, 0 },
{ "psllvw", "s,t", MIPS_MMI2(0x02), MA_PS2, MO_RSD },
{ "psrlvw", "d,s,t", MIPS_MMI2(0x03), MA_PS2, 0 },
{ "psrlvw", "s,t", MIPS_MMI2(0x03), MA_PS2, MO_RSD },
{ "pmsubw", "d,s,t", MIPS_MMI2(0x04), MA_PS2, 0 },
{ "pmsubw", "s,t", MIPS_MMI2(0x04), MA_PS2, MO_RSD },
{ "pmfhi", "d", MIPS_MMI2(0x08), MA_PS2, 0 },
{ "pmflo", "d", MIPS_MMI2(0x09), MA_PS2, 0 },
{ "pinth", "d,s,t", MIPS_MMI2(0x0A), MA_PS2, 0 },
{ "pinth", "s,t", MIPS_MMI2(0x0A), MA_PS2, MO_RSD },
{ "pmultw", "d,s,t", MIPS_MMI2(0x0C), MA_PS2, 0 },
{ "pmultw", "s,t", MIPS_MMI2(0x0C), MA_PS2, MO_RSD },
{ "pdivw", "s,t", MIPS_MMI2(0x0D), MA_PS2, 0 },
{ "pcpyld", "d,s,t", MIPS_MMI2(0x0E), MA_PS2, 0 },
{ "pcpyld", "s,t", MIPS_MMI2(0x0E), MA_PS2, MO_RSD },
{ "pmaddh", "d,s,t", MIPS_MMI2(0x10), MA_PS2, 0 },
{ "pmaddh", "s,t", MIPS_MMI2(0x10), MA_PS2, MO_RSD },
{ "phmadh", "d,s,t", MIPS_MMI2(0x11), MA_PS2, 0 },
{ "phmadh", "s,t", MIPS_MMI2(0x11), MA_PS2, MO_RSD },
{ "pand", "d,s,t", MIPS_MMI2(0x12), MA_PS2, 0 },
{ "pand", "s,t", MIPS_MMI2(0x12), MA_PS2, MO_RSD },
{ "pxor", "d,s,t", MIPS_MMI2(0x13), MA_PS2, 0 },
{ "pxor", "s,t", MIPS_MMI2(0x13), MA_PS2, MO_RSD },
{ "pmsubh", "d,s,t", MIPS_MMI2(0x14), MA_PS2, 0 },
{ "pmsubh", "s,t", MIPS_MMI2(0x14), MA_PS2, MO_RSD },
{ "phmsbh", "d,s,t", MIPS_MMI2(0x15), MA_PS2, 0 },
{ "phmsbh", "s,t", MIPS_MMI2(0x15), MA_PS2, MO_RSD },
{ "pexeh", "d,t", MIPS_MMI2(0x1A), MA_PS2, 0 },
{ "prevh", "d,t", MIPS_MMI2(0x1B), MA_PS2, 0 },
{ "pmulth", "d,s,t", MIPS_MMI2(0x1C), MA_PS2, 0 },
{ "pmulth", "s,t", MIPS_MMI2(0x1C), MA_PS2, MO_RSD },
{ "pdivbw", "s,t", MIPS_MMI2(0x1D), MA_PS2, 0 },
{ "pexew", "d,t", MIPS_MMI2(0x1E), MA_PS2, 0 },
{ "prot3w", "d,t", MIPS_MMI2(0x1F), MA_PS2, 0 },
// 31---------26--------------------------------10--------6-5-------0
// |= MMI| | function | MMI3 |
// -----6--------------------------------------------5---------6-----
// |---00---|---01---|---10---|---11---| lo
// 000 | PMADDUW| ---- | ---- | PSRAVW | 00..03
// 001 | ---- | ---- | ---- | ---- | 04..07
// 010 | PMTHI | PMTLO | PINTEH | ---- | 08..0B
// 011 | PMULTUW| PDIVUW | PCPYUD | ---- | 0C..0F
// 100 | ---- | ---- | POR | PNOR | 10..13
// 101 | ---- | ---- | ---- | ---- | 14..17
// 110 | ---- | ---- | PEXCH | PCPYH | 18..1B
// 111 | ---- | ---- | PEXCW | ---- | 1C..1F
// hi |--------|--------|--------|--------|
{ "pmadduw","d,s,t", MIPS_MMI3(0x00), MA_PS2, 0 },
{ "pmadduw","s,t", MIPS_MMI3(0x00), MA_PS2, MO_RSD },
{ "psravw", "d,s,t", MIPS_MMI3(0x03), MA_PS2, 0 },
{ "psravw", "s,t", MIPS_MMI3(0x03), MA_PS2, MO_RSD },
{ "pmthi", "s", MIPS_MMI3(0x08), MA_PS2, 0 },
{ "pmtlo", "s", MIPS_MMI3(0x09), MA_PS2, 0 },
{ "pinteh", "d,s,t", MIPS_MMI3(0x0A), MA_PS2, 0 },
{ "pinteh", "s,t", MIPS_MMI3(0x0A), MA_PS2, MO_RSD },
{ "pmultuw","d,s,t", MIPS_MMI3(0x0C), MA_PS2, 0 },
{ "pmultuw","s,t", MIPS_MMI3(0x0C), MA_PS2, MO_RSD },
{ "pdivuw", "s,t", MIPS_MMI3(0x0D), MA_PS2, 0 },
{ "pcpyud", "d,s,t", MIPS_MMI3(0x0E), MA_PS2, 0 },
{ "pcpyud", "s,t", MIPS_MMI3(0x0E), MA_PS2, MO_RSD },
{ "por", "d,s,t", MIPS_MMI3(0x12), MA_PS2, 0 },
{ "por", "s,t", MIPS_MMI3(0x12), MA_PS2, MO_RSD },
{ "pnor", "d,s,t", MIPS_MMI3(0x13), MA_PS2, 0 },
{ "pnor", "s,t", MIPS_MMI3(0x13), MA_PS2, MO_RSD },
{ "pexch", "d,t", MIPS_MMI3(0x1A), MA_PS2, 0 },
{ "pcpyh", "d,s,t", MIPS_MMI3(0x1B), MA_PS2, 0 },
{ "pcpyh", "s,t", MIPS_MMI3(0x1B), MA_PS2, MO_RSD },
{ "pexcw", "d,t", MIPS_MMI3(0x1E), MA_PS2, 0 },
// COP2 (VU0 Macro Mode)
// Incomplete, only field type 11 supported (top bit of opcode is unset)
// 31-------26---------21----------------------------------------1-0
// |= COP2| opcode | |I|
// -----6---------5-----------------------------------------------1-
// |--000--|--001--|--010--|--011--|--100--|--101--|--110--|--111--| lo
// 00 | --- | QMFC2 | CFC2 | --- | --- | QMTC2 | CTC2 | --- | 00..07
// 01 | --- | --- | --- | --- | --- | --- | --- | --- | 08..0F
// 10 | --- | --- | --- | --- | --- | --- | --- | --- | 10..17
// 11 | --- | --- | --- | --- | --- | --- | --- | --- | 18..1F
// hi |-------|-------|-------|-------|-------|-------|-------|-------|
{ "qmfc2", "t,Vs", MIPS_COP2_NI(0x01), MA_PS2, 0 },
{ "qmfc2.ni", "t,Vs", MIPS_COP2_NI(0x01), MA_PS2, 0 },
{ "qmfc2.i", "t,Vs", MIPS_COP2_I(0x01), MA_PS2, 0 },
{ "cfc2", "t,Vis",MIPS_COP2_NI(0x02), MA_PS2, 0 },
{ "cfc2.ni", "t,Vis",MIPS_COP2_NI(0x02), MA_PS2, 0 },
{ "cfc2.i", "t,Vis",MIPS_COP2_I(0x02), MA_PS2, 0 },
{ "qmtc2", "t,Vs", MIPS_COP2_NI(0x05), MA_PS2, 0 },
{ "qmtc2.ni", "t,Vs", MIPS_COP2_NI(0x05), MA_PS2, 0 },
{ "qmtc2.i", "t,Vs", MIPS_COP2_I(0x05), MA_PS2, 0 },
{ "ctc2", "t,Vis",MIPS_COP2_NI(0x06), MA_PS2, 0 },
{ "ctc2.ni", "t,Vis",MIPS_COP2_NI(0x06), MA_PS2, 0 },
{ "ctc2.i", "t,Vis",MIPS_COP2_I(0x06), MA_PS2, 0 },
// 31-------26------21---------------------------------------------0
// |= COP1| rs | |
// -----6-------5---------------------------------------------------
@@ -317,7 +586,7 @@ const tMipsOpcode MipsOpcodes[] = {
{ "cfc1", "t,S", MIPS_COP1(0x02), MA_MIPS2, 0 },
{ "mtc1", "t,S", MIPS_COP1(0x04), MA_MIPS2, 0 },
{ "ctc1", "t,S", MIPS_COP1(0x06), MA_MIPS2, 0 },
// 31---------21-------16------------------------------------------0
// |= COP1BC| rt | |
// ------11---------5-----------------------------------------------

View File

@@ -54,12 +54,23 @@
#define MIPS_COP1BC(VALUE) (MIPS_COP1(8) | MIPS_RT(VALUE))
#define MIPS_COP1S(VALUE) (MIPS_COP1(16) | MIPS_FUNC(VALUE))
#define MIPS_COP1W(VALUE) (MIPS_COP1(20) | MIPS_FUNC(VALUE))
#define MIPS_MMI(VALUE) (MIPS_OP(28) | MIPS_FUNC(VALUE))
#define MIPS_MMI0(VALUE) (MIPS_MMI(8) | MIPS_SECFUNC(VALUE))
#define MIPS_MMI1(VALUE) (MIPS_MMI(40) | MIPS_SECFUNC(VALUE))
#define MIPS_MMI2(VALUE) (MIPS_MMI(9) | MIPS_SECFUNC(VALUE))
#define MIPS_MMI3(VALUE) (MIPS_MMI(41) | MIPS_SECFUNC(VALUE))
#define MIPS_COP2_NI(VALUE) (MIPS_OP(18) | MIPS_RS(VALUE) | 0)
#define MIPS_COP2_I(VALUE) (MIPS_OP(18) | MIPS_RS(VALUE) | 1)
#define MIPS_VFPUSIZE(VALUE) ( (((VALUE) & 1) << 7) | (((VALUE) & 2) << 14) )
#define MIPS_VFPU0(VALUE) (MIPS_OP(0x18) | BITFIELD(23,3,(VALUE)))
#define MIPS_ALLEGREX0(VALUE) (MIPS_SPECIAL(32) | MIPS_SECFUNC(VALUE))
#define MIPS_PMFHL(VALUE) (MIPS_MMI(0x30) | MIPS_SECFUNC(VALUE))
#define MIPS_PMTHL(VALUE) (MIPS_MMI(0x31) | MIPS_SECFUNC(VALUE))
struct MipsArchDefinition
{
const char* name;

View File

@@ -8,6 +8,7 @@
#include "GS/GS.h"
#include "GS/Renderers/Common/GSFastList.h"
#include "GS/Renderers/Common/GSTexture.h"
#include "GS/Renderers/Vulkan/GSTextureVK.h"
#include "GS/Renderers/Common/GSVertex.h"
#include "GS/GSAlignedClass.h"
#include "GS/GSExtra.h"
@@ -674,6 +675,15 @@ struct alignas(16) GSHWDrawConfig
Full, ///< Full emulation (using barriers / ROV)
};
enum class HDRMode : u8
{
NoModify = 0,
ConvertOnly = 1,
ResolveOnly = 2,
ConvertAndResolve = 3,
EarlyResolve = 4
};
GSTexture* rt; ///< Render target
GSTexture* ds; ///< Depth stencil
GSTexture* tex; ///< Source texture
@@ -730,6 +740,11 @@ struct alignas(16) GSHWDrawConfig
VSConstantBuffer cb_vs;
PSConstantBuffer cb_ps;
// These are here as they need to be preserved between draws, and the state clear only does up to the constant buffers.
HDRMode hdr_mode;
GIFRegFRAME hdr_frame;
GSVector4i hdr_update_area; ///< Area in the framebuffer which HDR will modify;
};
class GSDevice : public GSAlignedClass<32>
@@ -850,6 +865,7 @@ protected:
GSTexture* m_target_tmp = nullptr;
GSTexture* m_current = nullptr;
GSTexture* m_cas = nullptr;
GSTexture* m_hdr_rt = nullptr; ///< Temp HDR texture
bool AcquireWindow(bool recreate_window);
@@ -874,6 +890,10 @@ public:
/// Returns a string containing current adapter in use.
const std::string& GetName() const { return m_name; }
GSTexture* GetHDRTexture() const { return m_hdr_rt; }
void SetHDRTexture(GSTexture* tex) { m_hdr_rt = tex; }
/// Returns a string representing the specified API.
static const char* RenderAPIToString(RenderAPI api);

View File

@@ -2521,6 +2521,47 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
GSTexture* hdr_rt = g_gs_device->GetHDRTexture();
if (hdr_rt)
{
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
{
const GSVector2i size = config.rt->GetSize();
const GSVector4 dRect(config.hdr_update_area);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(hdr_rt);
g_gs_device->SetHDRTexture(nullptr);
hdr_rt = nullptr;
}
else
config.ps.hdr = 1;
}
if (config.ps.hdr)
{
if (!hdr_rt)
{
config.hdr_update_area = config.drawarea;
const GSVector4 dRect = GSVector4((config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor);
if (!hdr_rt)
return;
g_gs_device->SetHDRTexture(hdr_rt);
// Warning: StretchRect must be called before BeginScene otherwise
// vertices will be overwritten. Trust me you don't want to do that.
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
}
GSTexture* primid_tex = nullptr;
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking)
{
@@ -2528,7 +2569,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
if (!primid_tex)
return;
StretchRect(config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(),
StretchRect(hdr_rt ? hdr_rt : config.rt, GSVector4(config.drawarea) / GSVector4(rtsize).xyxy(),
primid_tex, GSVector4(config.drawarea), m_date.primid_init_ps[static_cast<u8>(config.datm)].get(), nullptr, false);
}
else if (config.destination_alpha != GSHWDrawConfig::DestinationAlphaMode::Off)
@@ -2544,22 +2585,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
{GSVector4(dst.z, -dst.w, 0.5f, 1.0f), GSVector2(src.z, src.w)},
};
SetupDATE(config.rt, config.ds, vertices, config.datm);
}
GSTexture* hdr_rt = nullptr;
if (config.ps.hdr)
{
const GSVector4 dRect(config.drawarea);
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor);
if (!hdr_rt)
return;
// Warning: StretchRect must be called before BeginScene otherwise
// vertices will be overwritten. Trust me you don't want to do that.
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
SetupDATE(hdr_rt ? hdr_rt : config.rt, config.ds, vertices, config.datm);
}
if (config.vs.expand != GSHWDrawConfig::VSExpand::None)
@@ -2623,7 +2649,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
// Do not always bind the rt when it's not needed,
// only bind it when effects use it such as fbmask emulation currently
// because we copy the frame buffer and it is quite slow.
CloneTexture(config.rt, &rt_copy, config.drawarea);
CloneTexture(hdr_rt ? hdr_rt : config.rt, &rt_copy, config.drawarea);
if (rt_copy)
{
if (config.require_one_barrier)
@@ -2690,11 +2716,18 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
if (hdr_rt)
{
const GSVector2i size = config.rt->GetSize();
const GSVector4 dRect(config.drawarea);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(hdr_rt);
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
if (config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve)
{
const GSVector2i size = config.rt->GetSize();
const GSVector4 dRect(config.hdr_update_area);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(hdr_rt);
g_gs_device->SetHDRTexture(nullptr);
}
}
}

View File

@@ -3816,18 +3816,64 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
// Destination Alpha Setup
const bool stencil_DATE = (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::Stencil ||
config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::StencilOne);
GSTexture12* hdr_rt = static_cast<GSTexture12*>(g_gs_device->GetHDRTexture());
GSTexture12* draw_rt = static_cast<GSTexture12*>(config.rt);
GSTexture12* draw_ds = static_cast<GSTexture12*>(config.ds);
GSTexture12* draw_rt_clone = nullptr;
// Align the render area to 128x128, hopefully avoiding render pass restarts for small render area changes (e.g. Ratchet and Clank).
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
PipelineSelector& pipe = m_pipeline_selector;
// figure out the pipeline
UpdateHWPipelineSelector(config);
// now blit the hdr texture back to the original target
if (hdr_rt)
{
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
{
GL_PUSH("Blit HDR back to RT");
EndRenderPass();
hdr_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
draw_rt = static_cast<GSTexture12*>(config.rt);
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
BeginRenderPass(GetLoadOpForTexture(draw_rt), D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
GetLoadOpForTexture(draw_ds),
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
draw_rt->GetUNormClearColor(), 0.0f, 0);
const GSVector4 sRect(GSVector4(config.hdr_update_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
SetPipeline(m_hdr_finish_pipelines[pipe.ds].get());
SetUtilityTexture(hdr_rt, m_point_sampler_cpu);
DrawStretchRect(sRect, GSVector4(config.hdr_update_area), rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(hdr_rt);
g_gs_device->SetHDRTexture(nullptr);
}
else
{
draw_rt = hdr_rt;
pipe.ps.hdr = 1;
}
}
if (stencil_DATE)
SetupDATE(config.rt, config.ds, config.datm, config.drawarea);
SetupDATE(draw_rt, config.ds, config.datm, config.drawarea);
// stream buffer in first, in case we need to exec
SetVSConstantBuffer(config.cb_vs);
SetPSConstantBuffer(config.cb_ps);
// figure out the pipeline
UpdateHWPipelineSelector(config);
// bind textures before checking the render pass, in case we need to transition them
PipelineSelector& pipe = m_pipeline_selector;
if (config.tex)
{
PSSetShaderResource(0, config.tex, config.tex != config.rt);
@@ -3843,7 +3889,10 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
GSTexture12* date_image = nullptr;
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking)
{
GSTexture* backup_rt = config.rt;
config.rt = draw_rt;
date_image = SetupPrimitiveTrackingDATE(config, pipe);
config.rt = backup_rt;
if (!date_image)
{
Console.WriteLn("D3D12: Failed to allocate DATE image, aborting draw.");
@@ -3851,57 +3900,10 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
}
}
// Align the render area to 128x128, hopefully avoiding render pass restarts for small render area changes (e.g. Ratchet and Clank).
const int render_area_alignment = 128 * GSConfig.UpscaleMultiplier;
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
const GSVector4i render_area(
config.ps.hdr ? config.drawarea :
GSVector4i(Common::AlignDownPow2(config.scissor.left, render_area_alignment),
Common::AlignDownPow2(config.scissor.top, render_area_alignment),
std::min(Common::AlignUpPow2(config.scissor.right, render_area_alignment), rtsize.x),
std::min(Common::AlignUpPow2(config.scissor.bottom, render_area_alignment), rtsize.y)));
GSTexture12* draw_rt = static_cast<GSTexture12*>(config.rt);
GSTexture12* draw_ds = static_cast<GSTexture12*>(config.ds);
GSTexture12* draw_rt_clone = nullptr;
GSTexture12* hdr_rt = nullptr;
// Switch to hdr target for colclip rendering
if (pipe.ps.hdr)
{
EndRenderPass();
hdr_rt = static_cast<GSTexture12*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
if (!hdr_rt)
{
Console.WriteLn("D3D12: Failed to allocate HDR render target, aborting draw.");
if (date_image)
Recycle(date_image);
return;
}
// propagate clear value through if the hdr render is the first
if (draw_rt->GetState() == GSTexture::State::Cleared)
{
hdr_rt->SetState(GSTexture::State::Cleared);
hdr_rt->SetClearColor(draw_rt->GetClearColor());
}
else if (draw_rt->GetState() == GSTexture::State::Dirty)
{
GL_PUSH_("HDR Render Target Setup");
draw_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
}
// we're not drawing to the RT, so we can use it as a source
if (config.require_one_barrier)
PSSetShaderResource(2, draw_rt, true);
draw_rt = hdr_rt;
}
else if (config.require_one_barrier)
if (config.require_one_barrier)
{
// requires a copy of the RT
draw_rt_clone = static_cast<GSTexture12*>(CreateTexture(rtsize.x, rtsize.y, 1, GSTexture::Format::Color, true));
draw_rt_clone = static_cast<GSTexture12*>(CreateTexture(rtsize.x, rtsize.y, 1, hdr_rt ? GSTexture::Format::HDRColor : GSTexture::Format::Color, true));
if (draw_rt_clone)
{
EndRenderPass();
@@ -3915,8 +3917,50 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
}
}
// Switch to hdr target for colclip rendering
if (pipe.ps.hdr)
{
if (!hdr_rt)
{
config.hdr_update_area = config.drawarea;
EndRenderPass();
hdr_rt = static_cast<GSTexture12*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
if (!hdr_rt)
{
Console.WriteLn("D3D12: Failed to allocate HDR render target, aborting draw.");
if (date_image)
Recycle(date_image);
return;
}
g_gs_device->SetHDRTexture(static_cast<GSTexture*>(hdr_rt));
// propagate clear value through if the hdr render is the first
if (draw_rt->GetState() == GSTexture::State::Cleared)
{
hdr_rt->SetState(GSTexture::State::Cleared);
hdr_rt->SetClearColor(draw_rt->GetClearColor());
}
else if (draw_rt->GetState() == GSTexture::State::Dirty)
{
GL_PUSH_("HDR Render Target Setup");
draw_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
}
// we're not drawing to the RT, so we can use it as a source
if (config.require_one_barrier)
PSSetShaderResource(2, draw_rt, true);
}
draw_rt = hdr_rt;
}
// clear texture binding when it's bound to RT or DS
if (((config.rt && static_cast<GSTexture12*>(config.rt)->GetSRVDescriptor() == m_tfx_textures[0]) ||
if (((draw_rt && static_cast<GSTexture12*>(draw_rt)->GetSRVDescriptor() == m_tfx_textures[0]) ||
(config.ds && static_cast<GSTexture12*>(config.ds)->GetSRVDescriptor() == m_tfx_textures[0])))
{
PSSetShaderResource(0, nullptr, false);
@@ -3964,13 +4008,14 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
}
// rt -> hdr blit if enabled
if (hdr_rt && config.rt->GetState() == GSTexture::State::Dirty)
if (hdr_rt && (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve) && config.rt->GetState() == GSTexture::State::Dirty)
{
SetUtilityTexture(static_cast<GSTexture12*>(config.rt), m_point_sampler_cpu);
SetPipeline(m_hdr_setup_pipelines[pipe.ds].get());
const GSVector4 sRect(GSVector4(render_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
DrawStretchRect(sRect, GSVector4(render_area), rtsize);
const GSVector4 drawareaf = GSVector4((config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
const GSVector4 sRect(drawareaf / GSVector4(rtsize.x, rtsize.y).xyxy());
DrawStretchRect(sRect, GSVector4(drawareaf), rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GL_POP();
@@ -4025,28 +4070,34 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
// now blit the hdr texture back to the original target
if (hdr_rt)
{
GL_PUSH("Blit HDR back to RT");
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
EndRenderPass();
hdr_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
if ((config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve))
{
GL_PUSH("Blit HDR back to RT");
draw_rt = static_cast<GSTexture12*>(config.rt);
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
EndRenderPass();
hdr_rt->TransitionToState(D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
BeginRenderPass(GetLoadOpForTexture(draw_rt), D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
GetLoadOpForTexture(draw_ds),
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
draw_rt->GetUNormClearColor(), 0.0f, 0);
draw_rt = static_cast<GSTexture12*>(config.rt);
OMSetRenderTargets(draw_rt, draw_ds, config.scissor);
const GSVector4 sRect(GSVector4(render_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
SetPipeline(m_hdr_finish_pipelines[pipe.ds].get());
SetUtilityTexture(hdr_rt, m_point_sampler_cpu);
DrawStretchRect(sRect, GSVector4(render_area), rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
BeginRenderPass(GetLoadOpForTexture(draw_rt), D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE,
GetLoadOpForTexture(draw_ds),
draw_ds ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE : D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS, D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS,
draw_rt->GetUNormClearColor(), 0.0f, 0);
Recycle(hdr_rt);
const GSVector4 sRect(GSVector4(config.hdr_update_area) / GSVector4(rtsize.x, rtsize.y).xyxy());
SetPipeline(m_hdr_finish_pipelines[pipe.ds].get());
SetUtilityTexture(hdr_rt, m_point_sampler_cpu);
DrawStretchRect(sRect, GSVector4(config.hdr_update_area), rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(hdr_rt);
g_gs_device->SetHDRTexture(nullptr);
}
}
}

View File

@@ -970,6 +970,21 @@ GSVector2i GSRendererHW::GetTargetSize(const GSTextureCache::Source* tex, const
return g_texture_cache->GetTargetSize(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, valid_size.x, valid_size.y, can_expand);
}
bool GSRendererHW::NextDrawHDR() const
{
const int get_next_ctx = (m_state_flush_reason == CONTEXTCHANGE) ? m_env.PRIM.CTXT : m_backed_up_ctx;
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
// If it wasn't a context change we can't guarantee the next draw is going to be set up
if (m_state_flush_reason != GSFlushReason::CONTEXTCHANGE || m_env.COLCLAMP.CLAMP != 0 || m_env.PRIM.ABE == 0 ||
(m_context->FRAME.U64 ^ next_ctx.FRAME.U64) != 0 || (m_env.PRIM.TME && next_ctx.TEX0.TBP0 == m_context->FRAME.Block()))
{
return false;
}
return true;
}
bool GSRendererHW::IsPossibleChannelShuffle() const
{
if (!PRIM->TME || m_cached_ctx.TEX0.PSM != PSMT8 || // 8-bit texture draw
@@ -2150,6 +2165,35 @@ void GSRendererHW::Draw()
return;
}
// I hate that I have to do this, but some games (like Pac-Man World Rally) troll us by causing a flush with degenerate triangles, so we don't have all available information about the next draw.
// So we have to check when the next draw happens if our frame has changed or if it's become recursive.
const bool has_HDR_texture = g_gs_device->GetHDRTexture() != nullptr;
if (!no_rt && has_HDR_texture && (m_conf.hdr_frame.FBP != m_cached_ctx.FRAME.FBP || m_conf.hdr_frame.Block() == m_cached_ctx.TEX0.TBP0))
{
GIFRegTEX0 FRAME;
FRAME.TBP0 = m_conf.hdr_frame.Block();
FRAME.TBW = m_conf.hdr_frame.FBW;
FRAME.PSM = m_conf.hdr_frame.PSM;
GSTextureCache::Target* old_rt = g_texture_cache->LookupTarget(FRAME, GSVector2i(1, 1), GetTextureScaleFactor(), GSTextureCache::RenderTarget, true,
fm, false, false, true, true, GSVector4i(0, 0, 1, 1), true, false, false);
if (old_rt)
{
GL_CACHE("Pre-draw resolve of HDR! Address: %x", FRAME.TBP0);
GSTexture* hdr_texture = g_gs_device->GetHDRTexture();
g_gs_device->StretchRect(hdr_texture, GSVector4(m_conf.hdr_update_area) / GSVector4(GSVector4i(hdr_texture->GetSize()).xyxy()), old_rt->m_texture, GSVector4(m_conf.hdr_update_area),
ShaderConvert::HDR_RESOLVE, false);
g_gs_device->Recycle(hdr_texture);
g_gs_device->SetHDRTexture(nullptr);
}
else
DevCon.Warning("Error resolving HDR texture for pre-draw resolve");
}
const bool draw_sprite_tex = PRIM->TME && (m_vt.m_primclass == GS_SPRITE_CLASS);
// We trigger the sw prim render here super early, to avoid creating superfluous render targets.
@@ -3413,10 +3457,19 @@ void GSRendererHW::Draw()
GSTextureCache::RenderTarget, m_cached_ctx.ZBUF.Block(), m_cached_ctx.ZBUF.PSM, zm);
}
//
if (GSConfig.DumpGSData)
{
const bool writeback_HDR_texture = g_gs_device->GetHDRTexture() != nullptr;
if (writeback_HDR_texture)
{
GSTexture* hdr_texture = g_gs_device->GetHDRTexture();
g_gs_device->StretchRect(hdr_texture, GSVector4(m_conf.hdr_update_area) / GSVector4(GSVector4i(hdr_texture->GetSize()).xyxy()), rt->m_texture, GSVector4(m_conf.hdr_update_area),
ShaderConvert::HDR_RESOLVE, false);
}
const u64 frame = g_perfmon.GetFrame();
std::string s;
@@ -4404,14 +4457,36 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
// Color clip
if (COLCLAMP.CLAMP == 0)
{
const bool free_colclip = features.framebuffer_fetch || no_prim_overlap || blend_non_recursive;
bool has_HDR_texture = g_gs_device->GetHDRTexture() != nullptr;
// Don't know any game that resizes the RT mid HDR, but gotta be careful.
if (has_HDR_texture)
{
GSTexture* hdr_texture = g_gs_device->GetHDRTexture();
if (hdr_texture->GetSize() != rt->m_texture->GetSize())
{
GL_CACHE("Pre-Blend resolve of HDR due to size change! Address: %x", rt->m_TEX0.TBP0);
g_gs_device->StretchRect(hdr_texture, GSVector4(m_conf.hdr_update_area) / GSVector4(GSVector4i(hdr_texture->GetSize()).xyxy()), rt->m_texture, GSVector4(m_conf.hdr_update_area),
ShaderConvert::HDR_RESOLVE, false);
g_gs_device->Recycle(hdr_texture);
g_gs_device->SetHDRTexture(nullptr);
has_HDR_texture = false;
}
}
const bool free_colclip = !has_HDR_texture && (features.framebuffer_fetch || no_prim_overlap || blend_non_recursive);
GL_DBG("COLCLIP Info (Blending: %u/%u/%u/%u, OVERLAP: %d)", m_conf.ps.blend_a, m_conf.ps.blend_b, m_conf.ps.blend_c, m_conf.ps.blend_d, m_prim_overlap);
if (color_dest_blend || color_dest_blend2 || blend_zero_to_one_range)
{
// No overflow, disable colclip.
GL_INS("COLCLIP mode DISABLED");
sw_blending = false;
m_conf.hdr_mode = (has_HDR_texture && !NextDrawHDR()) ? GSHWDrawConfig::HDRMode::ResolveOnly : GSHWDrawConfig::HDRMode::NoModify;
}
else if (free_colclip)
{
@@ -4422,6 +4497,7 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
// Disable the HDR algo
accumulation_blend = false;
blend_mix = false;
m_conf.hdr_mode = (has_HDR_texture && !NextDrawHDR()) ? GSHWDrawConfig::HDRMode::ResolveOnly : GSHWDrawConfig::HDRMode::NoModify;
}
else if (accumulation_blend)
{
@@ -4429,18 +4505,24 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
GL_INS("COLCLIP Fast HDR mode ENABLED");
m_conf.ps.hdr = 1;
sw_blending = true; // Enable sw blending for the HDR algo
m_conf.hdr_mode = has_HDR_texture ? (NextDrawHDR() ? GSHWDrawConfig::HDRMode::NoModify : GSHWDrawConfig::HDRMode::ResolveOnly) : (NextDrawHDR() ? GSHWDrawConfig::HDRMode::ConvertOnly : GSHWDrawConfig::HDRMode::ConvertAndResolve);
}
else if (sw_blending)
{
// A slow algo that could requires several passes (barely used)
GL_INS("COLCLIP SW mode ENABLED");
m_conf.ps.colclip = 1;
m_conf.hdr_mode = (has_HDR_texture && !NextDrawHDR()) ? GSHWDrawConfig::HDRMode::ResolveOnly : GSHWDrawConfig::HDRMode::NoModify;
}
else
{
GL_INS("COLCLIP HDR mode ENABLED");
m_conf.ps.hdr = 1;
m_conf.hdr_mode = has_HDR_texture ? (NextDrawHDR() ? GSHWDrawConfig::HDRMode::NoModify : GSHWDrawConfig::HDRMode::ResolveOnly) : (NextDrawHDR() ? GSHWDrawConfig::HDRMode::ConvertOnly : GSHWDrawConfig::HDRMode::ConvertAndResolve);
}
m_conf.hdr_frame = m_cached_ctx.FRAME;
}
// Per pixel alpha blending
@@ -4474,8 +4556,10 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
// HDR mode should be disabled when doing sw blend, swap with sw colclip.
if (m_conf.ps.hdr)
{
bool has_HDR_texture = g_gs_device->GetHDRTexture() != nullptr;
m_conf.ps.hdr = 0;
m_conf.ps.colclip = 1;
m_conf.hdr_mode = has_HDR_texture ? GSHWDrawConfig::HDRMode::EarlyResolve : GSHWDrawConfig::HDRMode::NoModify;
}
}
else

View File

@@ -111,7 +111,7 @@ private:
void EmulateATST(float& AREF, GSHWDrawConfig::PSSelector& ps, bool pass_2);
void SetTCOffset();
bool NextDrawHDR() const;
bool IsPossibleChannelShuffle() const;
bool NextDrawMatchesShuffle() const;
bool IsSplitTextureShuffle(GSTextureCache::Target* rt);

View File

@@ -2135,6 +2135,64 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
GSTexture* stencil = nullptr;
GSTexture* primid_tex = nullptr;
GSTexture* rt = config.rt;
GSTexture* hdr_rt = g_gs_device->GetHDRTexture();
if (hdr_rt)
{
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
{
BeginRenderPass(@"HDR Resolve", config.rt, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare);
RenderCopy(hdr_rt, m_hdr_resolve_pipeline, config.hdr_update_area);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(hdr_rt);
g_gs_device->SetHDRTexture(nullptr);
hdr_rt = nullptr;
}
else
config.ps.hdr = 1;
}
if (config.ps.hdr)
{
if (!hdr_rt)
{
config.hdr_update_area = config.drawarea;
GSVector2i size = config.rt->GetSize();
rt = hdr_rt = CreateRenderTarget(size.x, size.y, GSTexture::Format::HDRColor, false);
g_gs_device->SetHDRTexture(hdr_rt);
const GSVector4i copy_rect = (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(size) : config.drawarea;
switch (config.rt->GetState())
{
case GSTexture::State::Dirty:
BeginRenderPass(@"HDR Init", hdr_rt, MTLLoadActionDontCare, nullptr, MTLLoadActionDontCare);
RenderCopy(config.rt, m_hdr_init_pipeline, copy_rect);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
break;
case GSTexture::State::Cleared:
{
BeginRenderPass(@"HDR Clear", hdr_rt, MTLLoadActionDontCare, nullptr, MTLLoadActionDontCare);
GSVector4 color = GSVector4::rgba32(config.rt->GetClearColor()) / GSVector4::cxpr(65535, 65535, 65535, 255);
[m_current_render.encoder setFragmentBytes:&color length:sizeof(color) atIndex:GSMTLBufferIndexUniforms];
RenderCopy(nullptr, m_hdr_clear_pipeline, copy_rect);
break;
}
case GSTexture::State::Invalidated:
break;
}
}
rt = hdr_rt;
}
switch (config.destination_alpha)
{
case GSHWDrawConfig::DestinationAlphaMode::Off:
@@ -2142,18 +2200,18 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
break; // No setup
case GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking:
{
FlushClears(config.rt);
GSVector2i size = config.rt->GetSize();
FlushClears(rt);
GSVector2i size = rt->GetSize();
primid_tex = CreateRenderTarget(size.x, size.y, GSTexture::Format::PrimID);
DepthStencilSelector dsel = config.depth;
dsel.zwe = 0;
GSTexture* depth = dsel.key == DepthStencilSelector::NoDepth().key ? nullptr : config.ds;
BeginRenderPass(@"PrimID Destination Alpha Init", primid_tex, MTLLoadActionDontCare, depth, MTLLoadActionLoad);
RenderCopy(config.rt, m_primid_init_pipeline[static_cast<bool>(depth)][static_cast<u8>(config.datm)], config.drawarea);
RenderCopy(rt, m_primid_init_pipeline[static_cast<bool>(depth)][static_cast<u8>(config.datm)], config.drawarea);
MRESetDSS(dsel);
pxAssert(config.ps.date == 1 || config.ps.date == 2);
if (config.ps.tex_is_fb)
MRESetTexture(config.rt, GSMTLTextureIndexRenderTarget);
MRESetTexture(rt, GSMTLTextureIndexRenderTarget);
config.require_one_barrier = false; // Ending render pass is our barrier
pxAssert(config.require_full_barrier == false && config.drawlist == nullptr);
MRESetHWPipelineState(config.vs, config.ps, {}, {});
@@ -2170,38 +2228,11 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
stencil = config.ds;
break;
case GSHWDrawConfig::DestinationAlphaMode::Stencil:
SetupDestinationAlpha(config.rt, config.ds, config.drawarea, config.datm);
SetupDestinationAlpha(rt, config.ds, config.drawarea, config.datm);
stencil = config.ds;
break;
}
GSTexture* hdr_rt = nullptr;
if (config.ps.hdr)
{
GSVector2i size = config.rt->GetSize();
rt = hdr_rt = CreateRenderTarget(size.x, size.y, GSTexture::Format::HDRColor, false);
switch (config.rt->GetState())
{
case GSTexture::State::Dirty:
BeginRenderPass(@"HDR Init", hdr_rt, MTLLoadActionDontCare, nullptr, MTLLoadActionDontCare);
RenderCopy(config.rt, m_hdr_init_pipeline, config.drawarea);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
break;
case GSTexture::State::Cleared:
{
BeginRenderPass(@"HDR Clear", hdr_rt, MTLLoadActionDontCare, nullptr, MTLLoadActionDontCare);
GSVector4 color = GSVector4::rgba32(config.rt->GetClearColor()) / GSVector4::cxpr(65535, 65535, 65535, 255);
[m_current_render.encoder setFragmentBytes:&color length:sizeof(color) atIndex:GSMTLBufferIndexUniforms];
RenderCopy(nullptr, m_hdr_clear_pipeline, config.drawarea);
break;
}
case GSTexture::State::Invalidated:
break;
}
}
// Try to reduce render pass restarts
if (!config.ds && m_current_render.color_target == rt && stencil == m_current_render.stencil_target && m_current_render.depth_target != config.tex)
config.ds = m_current_render.depth_target;
@@ -2224,7 +2255,7 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
[mtlenc setStencilReferenceValue:1];
MREInitHWDraw(config, allocation);
if (config.require_one_barrier || config.require_full_barrier)
MRESetTexture(config.rt, GSMTLTextureIndexRenderTarget);
MRESetTexture(rt, GSMTLTextureIndexRenderTarget);
if (primid_tex)
MRESetTexture(primid_tex, GSMTLTextureIndexPrimIDs);
if (config.blend.constant_enable)
@@ -2248,11 +2279,18 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
if (hdr_rt)
{
BeginRenderPass(@"HDR Resolve", config.rt, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare);
RenderCopy(hdr_rt, m_hdr_resolve_pipeline, config.drawarea);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
Recycle(hdr_rt);
if ((config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve))
{
BeginRenderPass(@"HDR Resolve", config.rt, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare);
RenderCopy(hdr_rt, m_hdr_resolve_pipeline, config.hdr_update_area);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(hdr_rt);
g_gs_device->SetHDRTexture(nullptr);
}
}
if (primid_tex)

View File

@@ -856,7 +856,10 @@ struct PSMain
void ps_fbmask(thread float4& C)
{
if (PS_FBMASK)
C = float4((uint4(int4(C)) & (cb.fbmask ^ 0xff)) | (uint4(current_color * 255.5) & cb.fbmask));
{
float multi = PS_HDR ? 65535.0 : 255.5;
C = float4((uint4(int4(C)) & (cb.fbmask ^ 0xff)) | (uint4(current_color * float4(multi, multi, multi, 255)) & cb.fbmask));
}
}
void ps_dither(thread float4& C, float As)
@@ -956,8 +959,8 @@ struct PSMain
current_color.a = float(denorm_rt.g & 0x80);
}
}
float3 Cd = trunc(current_color.rgb * 255.5f);
float multi = PS_HDR ? 65535.0 : 255.5;
float3 Cd = trunc(current_color.rgb * multi);
float3 Cs = Color.rgb;
float3 A = pick(PS_BLEND_A, Cs, Cd, float3(0.f));

View File

@@ -2414,6 +2414,45 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
GSTexture* primid_texture = nullptr;
GSTexture* hdr_rt = g_gs_device->GetHDRTexture();
if (hdr_rt)
{
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
{
const GSVector2i size = config.rt->GetSize();
const GSVector4 dRect(config.hdr_update_area);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
Recycle(hdr_rt);
g_gs_device->SetHDRTexture(nullptr);
hdr_rt = nullptr;
}
else
{
config.ps.hdr = 1;
}
}
if (config.ps.hdr)
{
if (!hdr_rt)
{
config.hdr_update_area = config.drawarea;
hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false);
OMSetRenderTargets(hdr_rt, config.ds, nullptr);
g_gs_device->SetHDRTexture(hdr_rt);
const GSVector4 dRect = GSVector4((config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false);
}
}
// Destination Alpha Setup
switch (config.destination_alpha)
@@ -2422,7 +2461,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
case GSHWDrawConfig::DestinationAlphaMode::Full:
break; // No setup
case GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking:
primid_texture = InitPrimDateTexture(config.rt, config.drawarea, config.datm);
primid_texture = InitPrimDateTexture(hdr_rt ? hdr_rt : config.rt, config.drawarea, config.datm);
break;
case GSHWDrawConfig::DestinationAlphaMode::StencilOne:
if (m_features.texture_barrier)
@@ -2442,29 +2481,20 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
{GSVector4(dst.x, dst.w, 0.0f, 0.0f), GSVector2(src.x, src.w)},
{GSVector4(dst.z, dst.w, 0.0f, 0.0f), GSVector2(src.z, src.w)},
};
SetupDATE(config.rt, config.ds, vertices, config.datm);
SetupDATE(hdr_rt ? hdr_rt : config.rt, config.ds, vertices, config.datm);
}
}
GSTexture* hdr_rt = nullptr;
GSTexture* draw_rt_clone = nullptr;
if (config.ps.hdr)
{
hdr_rt = CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false);
OMSetRenderTargets(hdr_rt, config.ds, &config.scissor);
GSVector4 dRect(config.drawarea);
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
StretchRect(config.rt, sRect, hdr_rt, dRect, ShaderConvert::HDR_INIT, false);
}
else if (config.require_one_barrier && !m_features.texture_barrier)
if (config.require_one_barrier && !m_features.texture_barrier)
{
// Requires a copy of the RT
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, GSTexture::Format::Color, true);
draw_rt_clone = CreateTexture(rtsize.x, rtsize.y, 1, hdr_rt ? GSTexture::Format::HDRColor : GSTexture::Format::Color, true);
GL_PUSH("Copy RT to temp texture for fbmask {%d,%d %dx%d}",
config.drawarea.left, config.drawarea.top,
config.drawarea.width(), config.drawarea.height());
CopyRect(config.rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
CopyRect(hdr_rt ? hdr_rt : config.rt, draw_rt_clone, config.drawarea, config.drawarea.left, config.drawarea.top);
}
else if (config.tex && config.tex == config.ds)
{
@@ -2510,7 +2540,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
if (draw_rt_clone)
PSSetShaderResource(2, draw_rt_clone);
else if (config.require_one_barrier || config.require_full_barrier)
PSSetShaderResource(2, config.rt);
PSSetShaderResource(2, hdr_rt ? hdr_rt : config.rt);
SetupSampler(config.sampler);
@@ -2669,12 +2699,19 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
if (hdr_rt)
{
GSVector2i size = config.rt->GetSize();
GSVector4 dRect(config.drawarea);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
Recycle(hdr_rt);
if ((config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve))
{
const GSVector2i size = config.rt->GetSize();
const GSVector4 dRect(config.hdr_update_area);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(hdr_rt, sRect, config.rt, dRect, ShaderConvert::HDR_RESOLVE, false);
Recycle(hdr_rt);
g_gs_device->SetHDRTexture(nullptr);
}
}
}

View File

@@ -9,6 +9,7 @@
#include "GS/Renderers/Vulkan/VKBuilders.h"
#include "GS/Renderers/Vulkan/VKShaderCache.h"
#include "GS/Renderers/Vulkan/VKSwapChain.h"
#include "GS/Renderers/Common/GSDevice.h"
#include "BuildVersion.h"
#include "Host.h"
@@ -5589,28 +5590,12 @@ GSTextureVK* GSDeviceVK::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config)
void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
{
// Destination Alpha Setup
switch (config.destination_alpha)
{
case GSHWDrawConfig::DestinationAlphaMode::Off: // No setup
case GSHWDrawConfig::DestinationAlphaMode::Full: // No setup
case GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking: // Setup is done below
break;
case GSHWDrawConfig::DestinationAlphaMode::StencilOne: // setup is done below
{
// we only need to do the setup here if we don't have barriers, in which case do full DATE.
if (!m_features.texture_barrier)
{
SetupDATE(config.rt, config.ds, config.datm, config.drawarea);
config.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Stencil;
}
}
break;
case GSHWDrawConfig::DestinationAlphaMode::Stencil:
SetupDATE(config.rt, config.ds, config.datm, config.drawarea);
break;
}
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
GSTextureVK* draw_rt = static_cast<GSTextureVK*>(config.rt);
GSTextureVK* draw_ds = static_cast<GSTextureVK*>(config.ds);
GSTextureVK* draw_rt_clone = nullptr;
GSTextureVK* hdr_rt = static_cast<GSTextureVK*>(g_gs_device->GetHDRTexture());
// stream buffer in first, in case we need to exec
SetVSConstantBuffer(config.cb_vs);
@@ -5632,68 +5617,112 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
SetLineWidth(config.line_expand ? config.cb_ps.ScaleFactor.z : 1.0f);
// Primitive ID tracking DATE setup.
// Needs to be done before
GSTextureVK* date_image = nullptr;
if (config.destination_alpha == GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking)
{
// If we have a HDR in progress, we need to use the HDR texture, but we can't check this later as there's a chicken/egg problem with the pipe setup.
GSTexture* backup_rt = config.rt;
if(hdr_rt)
config.rt = hdr_rt;
date_image = SetupPrimitiveTrackingDATE(config);
if (!date_image)
{
Console.WriteLn("Failed to allocate DATE image, aborting draw.");
return;
}
config.rt = backup_rt;
}
// figure out the pipeline
PipelineSelector& pipe = m_pipeline_selector;
UpdateHWPipelineSelector(config, pipe);
const GSVector2i rtsize(config.rt ? config.rt->GetSize() : config.ds->GetSize());
GSTextureVK* draw_rt = static_cast<GSTextureVK*>(config.rt);
GSTextureVK* draw_ds = static_cast<GSTextureVK*>(config.ds);
GSTextureVK* draw_rt_clone = nullptr;
GSTextureVK* hdr_rt = nullptr;
// Switch to hdr target for colclip rendering
if (pipe.ps.hdr)
// now blit the hdr texture back to the original target
if (hdr_rt)
{
EndRenderPass();
hdr_rt = static_cast<GSTextureVK*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
if (!hdr_rt)
if (config.hdr_mode == GSHWDrawConfig::HDRMode::EarlyResolve)
{
Console.WriteLn("Failed to allocate HDR render target, aborting draw.");
if (date_image)
Recycle(date_image);
GL_POP();
return;
}
GL_PUSH("Blit HDR back to RT");
// propagate clear value through if the hdr render is the first
if (draw_rt->GetState() == GSTexture::State::Cleared)
EndRenderPass();
hdr_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
draw_rt = static_cast<GSTextureVK*>(config.rt);
OMSetRenderTargets(draw_rt, draw_ds, GSVector4i::loadh(rtsize), static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
if (draw_rt->GetState() == GSTexture::State::Cleared)
{
alignas(16) VkClearValue cvs[2];
u32 cv_count = 0;
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
if (draw_ds)
cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1};
BeginClearRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_CLEAR,
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
draw_rt->GetRect(), cvs, cv_count);
draw_rt->SetState(GSTexture::State::Dirty);
}
else
{
BeginRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_LOAD,
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
draw_rt->GetRect());
}
const GSVector4 drawareaf = GSVector4(config.hdr_update_area);
const GSVector4 sRect(drawareaf / GSVector4(rtsize).xyxy());
SetPipeline(m_hdr_finish_pipelines[pipe.ds][pipe.IsRTFeedbackLoop()]);
SetUtilityTexture(hdr_rt, m_point_sampler);
DrawStretchRect(sRect, drawareaf, rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(hdr_rt);
g_gs_device->SetHDRTexture(nullptr);
hdr_rt = nullptr;
}
else
{
hdr_rt->SetState(GSTexture::State::Cleared);
hdr_rt->SetClearColor(draw_rt->GetClearColor());
// If depth is cleared, we need to commit it, because we're only going to draw to the active part of the FB.
if (draw_ds && draw_ds->GetState() == GSTexture::State::Cleared && !config.drawarea.eq(GSVector4i::loadh(rtsize)))
draw_ds->CommitClear(m_current_command_buffer);
pipe.ps.hdr = 1;
draw_rt = hdr_rt;
}
else if (draw_rt->GetState() == GSTexture::State::Dirty)
{
GL_PUSH_("HDR Render Target Setup");
draw_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
}
// we're not drawing to the RT, so we can use it as a source
if (config.require_one_barrier && !m_features.texture_barrier)
PSSetShaderResource(2, draw_rt, true);
draw_rt = hdr_rt;
}
else if (config.require_one_barrier && !m_features.texture_barrier)
// Destination Alpha Setup
switch (config.destination_alpha)
{
case GSHWDrawConfig::DestinationAlphaMode::Off: // No setup
case GSHWDrawConfig::DestinationAlphaMode::Full: // No setup
case GSHWDrawConfig::DestinationAlphaMode::PrimIDTracking: // Setup is done below
break;
case GSHWDrawConfig::DestinationAlphaMode::StencilOne: // setup is done below
{
// we only need to do the setup here if we don't have barriers, in which case do full DATE.
if (!m_features.texture_barrier)
{
SetupDATE(draw_rt, config.ds, config.datm, config.drawarea);
config.destination_alpha = GSHWDrawConfig::DestinationAlphaMode::Stencil;
}
}
break;
case GSHWDrawConfig::DestinationAlphaMode::Stencil:
SetupDATE(draw_rt, config.ds, config.datm, config.drawarea);
break;
}
if (config.require_one_barrier && !m_features.texture_barrier)
{
// requires a copy of the RT
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, 1, GSTexture::Format::Color, true));
draw_rt_clone = static_cast<GSTextureVK*>(CreateTexture(rtsize.x, rtsize.y, 1, hdr_rt ? GSTexture::Format::HDRColor : GSTexture::Format::Color, true));
if (draw_rt_clone)
{
EndRenderPass();
@@ -5706,6 +5735,49 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
}
}
// Switch to hdr target for colclip rendering
if (pipe.ps.hdr)
{
if (!hdr_rt)
{
config.hdr_update_area = config.drawarea;
EndRenderPass();
hdr_rt = static_cast<GSTextureVK*>(CreateRenderTarget(rtsize.x, rtsize.y, GSTexture::Format::HDRColor, false));
if (!hdr_rt)
{
Console.WriteLn("Failed to allocate HDR render target, aborting draw.");
if (date_image)
Recycle(date_image);
GL_POP();
return;
}
g_gs_device->SetHDRTexture(static_cast<GSTexture*>(hdr_rt));
// propagate clear value through if the hdr render is the first
if (draw_rt->GetState() == GSTexture::State::Cleared)
{
hdr_rt->SetState(GSTexture::State::Cleared);
hdr_rt->SetClearColor(draw_rt->GetClearColor());
// If depth is cleared, we need to commit it, because we're only going to draw to the active part of the FB.
if (draw_ds && draw_ds->GetState() == GSTexture::State::Cleared && !config.drawarea.eq(GSVector4i::loadh(rtsize)))
draw_ds->CommitClear(m_current_command_buffer);
}
else if (draw_rt->GetState() == GSTexture::State::Dirty)
{
GL_PUSH_("HDR Render Target Setup");
draw_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
}
// we're not drawing to the RT, so we can use it as a source
if (config.require_one_barrier && !m_features.texture_barrier)
PSSetShaderResource(2, draw_rt, true);
}
draw_rt = hdr_rt;
}
// clear texture binding when it's bound to RT or DS.
if (!config.tex && ((config.rt && static_cast<GSTextureVK*>(config.rt) == m_tfx_textures[0]) ||
(config.ds && static_cast<GSTextureVK*>(config.ds) == m_tfx_textures[0])))
@@ -5714,7 +5786,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
}
// render pass restart optimizations
if (hdr_rt)
if (hdr_rt && (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly))
{
// HDR requires blitting.
EndRenderPass();
@@ -5774,7 +5846,7 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
// Only draw to the active area of the HDR target. Except when depth is cleared, we need to use the full
// buffer size, otherwise it'll only clear the draw part of the depth buffer.
const GSVector4i render_area = (pipe.ps.hdr && ds_op != VK_ATTACHMENT_LOAD_OP_CLEAR) ? config.drawarea :
const GSVector4i render_area = (pipe.ps.hdr && (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve) && ds_op != VK_ATTACHMENT_LOAD_OP_CLEAR) ? config.drawarea :
GSVector4i::loadh(rtsize);
if (is_clearing_rt)
@@ -5813,17 +5885,19 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
}
// rt -> hdr blit if enabled
if (hdr_rt && config.rt->GetState() == GSTexture::State::Dirty)
if (hdr_rt && (config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve) && config.rt->GetState() == GSTexture::State::Dirty)
{
OMSetRenderTargets(draw_rt, draw_ds, GSVector4i::loadh(rtsize), static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
SetUtilityTexture(static_cast<GSTextureVK*>(config.rt), m_point_sampler);
SetPipeline(m_hdr_setup_pipelines[pipe.ds][pipe.IsRTFeedbackLoop()]);
const GSVector4 drawareaf = GSVector4(config.drawarea);
const GSVector4 drawareaf = GSVector4((config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
const GSVector4 sRect(drawareaf / GSVector4(rtsize).xyxy());
DrawStretchRect(sRect, drawareaf, rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GL_POP();
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
}
// VB/IB upload, if we did DATE setup and it's not HDR this has already been done
@@ -5880,46 +5954,55 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
// now blit the hdr texture back to the original target
if (hdr_rt)
{
GL_PUSH("Blit HDR back to RT");
config.hdr_update_area = config.hdr_update_area.runion(config.drawarea);
EndRenderPass();
hdr_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
draw_rt = static_cast<GSTextureVK*>(config.rt);
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
if (draw_rt->GetState() == GSTexture::State::Cleared)
if ((config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly || config.hdr_mode == GSHWDrawConfig::HDRMode::ConvertAndResolve))
{
alignas(16) VkClearValue cvs[2];
u32 cv_count = 0;
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
if (draw_ds)
cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1};
GL_PUSH("Blit HDR back to RT");
BeginClearRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_CLEAR,
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
draw_rt->GetRect(), cvs, cv_count);
draw_rt->SetState(GSTexture::State::Dirty);
EndRenderPass();
hdr_rt->TransitionToLayout(GSTextureVK::Layout::ShaderReadOnly);
draw_rt = static_cast<GSTextureVK*>(config.rt);
OMSetRenderTargets(draw_rt, draw_ds, (config.hdr_mode == GSHWDrawConfig::HDRMode::ResolveOnly) ? GSVector4i::loadh(rtsize) : config.scissor, static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
// if this target was cleared and never drawn to, perform the clear as part of the resolve here.
if (draw_rt->GetState() == GSTexture::State::Cleared)
{
alignas(16) VkClearValue cvs[2];
u32 cv_count = 0;
GSVector4::store<true>(&cvs[cv_count++].color, draw_rt->GetUNormClearColor());
if (draw_ds)
cvs[cv_count++].depthStencil = {draw_ds->GetClearDepth(), 1};
BeginClearRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_CLEAR,
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
draw_rt->GetRect(), cvs, cv_count);
draw_rt->SetState(GSTexture::State::Dirty);
}
else
{
BeginRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_LOAD,
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
draw_rt->GetRect());
}
const GSVector4 drawareaf = GSVector4(config.hdr_update_area);
const GSVector4 sRect(drawareaf / GSVector4(rtsize).xyxy());
SetPipeline(m_hdr_finish_pipelines[pipe.ds][pipe.IsRTFeedbackLoop()]);
SetUtilityTexture(hdr_rt, m_point_sampler);
DrawStretchRect(sRect, drawareaf, rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(hdr_rt);
g_gs_device->SetHDRTexture(nullptr);
}
else
{
BeginRenderPass(GetTFXRenderPass(true, pipe.ds, false, false, pipe.IsRTFeedbackLoop(),
pipe.IsTestingAndSamplingDepth(), VK_ATTACHMENT_LOAD_OP_LOAD,
pipe.ds ? VK_ATTACHMENT_LOAD_OP_LOAD : VK_ATTACHMENT_LOAD_OP_DONT_CARE),
draw_rt->GetRect());
}
const GSVector4 drawareaf = GSVector4(config.drawarea);
const GSVector4 sRect(drawareaf / GSVector4(rtsize).xyxy());
SetPipeline(m_hdr_finish_pipelines[pipe.ds][pipe.IsRTFeedbackLoop()]);
SetUtilityTexture(hdr_rt, m_point_sampler);
DrawStretchRect(sRect, drawareaf, rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(hdr_rt);
}
config.hdr_mode = GSHWDrawConfig::HDRMode::NoModify;
}
void GSDeviceVK::UpdateHWPipelineSelector(GSHWDrawConfig& config, PipelineSelector& pipe)