Fix XMAD shader instruction, gl_FrontFacing and enable face culling (#583)
* Fix XMAD shader instruction implementation * Fix gl_FrontFacing constant value * Enable face culling again * Fix typo
This commit is contained in:
parent
b126ea48c6
commit
9cbcbaa90c
4 changed files with 125 additions and 65 deletions
|
@ -159,25 +159,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
||||||
Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
|
Shader.SetExtraData(New.FlipX, New.FlipY, New.Instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Note: Uncomment SetFrontFace and SetCullFace when flipping issues are solved
|
if (New.FrontFace != Old.FrontFace)
|
||||||
|
{
|
||||||
|
GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace));
|
||||||
|
}
|
||||||
|
|
||||||
//if (New.FrontFace != Old.FrontFace)
|
if (New.CullFaceEnabled != Old.CullFaceEnabled)
|
||||||
//{
|
{
|
||||||
// GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace));
|
Enable(EnableCap.CullFace, New.CullFaceEnabled);
|
||||||
//}
|
}
|
||||||
|
|
||||||
//if (New.CullFaceEnabled != Old.CullFaceEnabled)
|
if (New.CullFaceEnabled)
|
||||||
//{
|
{
|
||||||
// Enable(EnableCap.CullFace, New.CullFaceEnabled);
|
if (New.CullFace != Old.CullFace)
|
||||||
//}
|
{
|
||||||
|
GL.CullFace(OGLEnumConverter.GetCullFace(New.CullFace));
|
||||||
//if (New.CullFaceEnabled)
|
}
|
||||||
//{
|
}
|
||||||
// if (New.CullFace != Old.CullFace)
|
|
||||||
// {
|
|
||||||
// GL.CullFace(OGLEnumConverter.GetCullFace(New.CullFace));
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (New.DepthTestEnabled != Old.DepthTestEnabled)
|
if (New.DepthTestEnabled != Old.DepthTestEnabled)
|
||||||
{
|
{
|
||||||
|
|
|
@ -845,9 +845,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{
|
{
|
||||||
case GlslDecl.PointCoordAttrX: return "gl_PointCoord.x";
|
case GlslDecl.PointCoordAttrX: return "gl_PointCoord.x";
|
||||||
case GlslDecl.PointCoordAttrY: return "gl_PointCoord.y";
|
case GlslDecl.PointCoordAttrY: return "gl_PointCoord.y";
|
||||||
|
case GlslDecl.FaceAttr: return "(gl_FrontFacing ? -1 : 0)";
|
||||||
//Note: It's a guess that Maxwell's face is 1 when gl_FrontFacing == true
|
|
||||||
case GlslDecl.FaceAttr: return "(gl_FrontFacing ? 1 : 0)";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1148,41 +1148,87 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum XmadMode
|
||||||
|
{
|
||||||
|
Cfull = 0,
|
||||||
|
Clo = 1,
|
||||||
|
Chi = 2,
|
||||||
|
Csfu = 3,
|
||||||
|
Cbcc = 4
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
private static void EmitXmad(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||||
{
|
{
|
||||||
//TODO: Confirm SignAB/C, it is just a guess.
|
bool SignedA = OpCode.Read(48);
|
||||||
//TODO: Implement Mode 3 (CSFU), what it does?
|
bool SignedB = OpCode.Read(49);
|
||||||
bool SignAB = OpCode.Read(48);
|
bool HighB = OpCode.Read(52);
|
||||||
bool SignC = OpCode.Read(49);
|
bool HighA = OpCode.Read(53);
|
||||||
bool HighB = OpCode.Read(52);
|
|
||||||
bool HighA = OpCode.Read(53);
|
|
||||||
|
|
||||||
int Mode = OpCode.Read(50, 7);
|
int Mode = OpCode.Read(50, 7);
|
||||||
|
|
||||||
ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
|
ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
|
||||||
|
|
||||||
ShaderIrOperImm Imm16 = new ShaderIrOperImm(16);
|
|
||||||
ShaderIrOperImm ImmMsk = new ShaderIrOperImm(0xffff);
|
|
||||||
|
|
||||||
ShaderIrInst ShiftAB = SignAB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
|
||||||
ShaderIrInst ShiftC = SignC ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
|
||||||
|
|
||||||
if (HighA)
|
|
||||||
{
|
|
||||||
OperA = new ShaderIrOp(ShiftAB, OperA, Imm16);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Oper)
|
switch (Oper)
|
||||||
{
|
{
|
||||||
case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
|
case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
|
||||||
case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
|
case ShaderOper.Imm: OperB = OpCode.ImmU16_20(); break;
|
||||||
case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
|
case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
|
||||||
case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
|
case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
|
||||||
|
|
||||||
default: throw new ArgumentException(nameof(Oper));
|
default: throw new ArgumentException(nameof(Oper));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProductShiftLeft = false, Merge = false;
|
ShaderIrNode OperB2 = OperB;
|
||||||
|
|
||||||
|
if (Oper == ShaderOper.Imm)
|
||||||
|
{
|
||||||
|
int Imm = ((ShaderIrOperImm)OperB2).Value;
|
||||||
|
|
||||||
|
if (!HighB)
|
||||||
|
{
|
||||||
|
Imm <<= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SignedB)
|
||||||
|
{
|
||||||
|
Imm >>= 16;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Imm = (int)((uint)Imm >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
OperB2 = new ShaderIrOperImm(Imm);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrOperImm Imm16 = new ShaderIrOperImm(16);
|
||||||
|
|
||||||
|
//If we are working with the lower 16-bits of the A/B operands,
|
||||||
|
//we need to shift the lower 16-bits to the top 16-bits. Later,
|
||||||
|
//they will be right shifted. For U16 types, this will be a logical
|
||||||
|
//right shift, and for S16 types, a arithmetic right shift.
|
||||||
|
if (!HighA)
|
||||||
|
{
|
||||||
|
OperA = new ShaderIrOp(ShaderIrInst.Lsl, OperA, Imm16);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HighB && Oper != ShaderOper.Imm)
|
||||||
|
{
|
||||||
|
OperB2 = new ShaderIrOp(ShaderIrInst.Lsl, OperB2, Imm16);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderIrInst ShiftA = SignedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||||
|
ShaderIrInst ShiftB = SignedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
|
||||||
|
|
||||||
|
OperA = new ShaderIrOp(ShiftA, OperA, Imm16);
|
||||||
|
|
||||||
|
if (Oper != ShaderOper.Imm)
|
||||||
|
{
|
||||||
|
OperB2 = new ShaderIrOp(ShiftB, OperB2, Imm16);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProductShiftLeft = false;
|
||||||
|
bool Merge = false;
|
||||||
|
|
||||||
if (Oper == ShaderOper.RC)
|
if (Oper == ShaderOper.RC)
|
||||||
{
|
{
|
||||||
|
@ -1196,40 +1242,53 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Merge = OpCode.Read(37);
|
Merge = OpCode.Read(37);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (Mode)
|
ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB2);
|
||||||
{
|
|
||||||
//CLO.
|
|
||||||
case 1: OperC = ExtendTo32(OperC, SignC, 16); break;
|
|
||||||
|
|
||||||
//CHI.
|
|
||||||
case 2: OperC = new ShaderIrOp(ShiftC, OperC, Imm16); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderIrNode OperBH = OperB;
|
|
||||||
|
|
||||||
if (HighB)
|
|
||||||
{
|
|
||||||
OperBH = new ShaderIrOp(ShiftAB, OperBH, Imm16);
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperBH);
|
|
||||||
|
|
||||||
if (ProductShiftLeft)
|
if (ProductShiftLeft)
|
||||||
{
|
{
|
||||||
MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16);
|
MulOp = new ShaderIrOp(ShaderIrInst.Lsl, MulOp, Imm16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch ((XmadMode)Mode)
|
||||||
|
{
|
||||||
|
case XmadMode.Clo: OperC = ExtendTo32(OperC, Signed: false, Size: 16); break;
|
||||||
|
|
||||||
|
case XmadMode.Chi: OperC = new ShaderIrOp(ShaderIrInst.Lsr, OperC, Imm16); break;
|
||||||
|
|
||||||
|
case XmadMode.Cbcc:
|
||||||
|
{
|
||||||
|
ShaderIrOp OperBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
|
||||||
|
|
||||||
|
OperC = new ShaderIrOp(ShaderIrInst.Add, OperC, OperBLsh16);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case XmadMode.Csfu:
|
||||||
|
{
|
||||||
|
ShaderIrOperImm Imm31 = new ShaderIrOperImm(31);
|
||||||
|
|
||||||
|
ShaderIrOp SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, OperA, Imm31);
|
||||||
|
ShaderIrOp SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, OperB2, Imm31);
|
||||||
|
|
||||||
|
SignAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustA, Imm16);
|
||||||
|
SignAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, SignAdjustB, Imm16);
|
||||||
|
|
||||||
|
ShaderIrOp SignAdjust = new ShaderIrOp(ShaderIrInst.Add, SignAdjustA, SignAdjustB);
|
||||||
|
|
||||||
|
OperC = new ShaderIrOp(ShaderIrInst.Sub, OperC, SignAdjust);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC);
|
ShaderIrOp AddOp = new ShaderIrOp(ShaderIrInst.Add, MulOp, OperC);
|
||||||
|
|
||||||
if (Merge)
|
if (Merge)
|
||||||
{
|
{
|
||||||
AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, ImmMsk);
|
ShaderIrOperImm Imm16Mask = new ShaderIrOperImm(0xffff);
|
||||||
OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
|
|
||||||
AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Mode == 4)
|
AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, Imm16Mask);
|
||||||
{
|
|
||||||
OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
|
OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
|
||||||
AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
|
AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,6 +138,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return new ShaderIrOperImmf(BitConverter.Int32BitsToSingle((int)(OpCode >> 20)));
|
return new ShaderIrOperImmf(BitConverter.Int32BitsToSingle((int)(OpCode >> 20)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ShaderIrOperImm ImmU16_20(this long OpCode)
|
||||||
|
{
|
||||||
|
return new ShaderIrOperImm(OpCode.Read(20, 0xffff));
|
||||||
|
}
|
||||||
|
|
||||||
private static ShaderIrOperImm Imm19_20(this long OpCode)
|
private static ShaderIrOperImm Imm19_20(this long OpCode)
|
||||||
{
|
{
|
||||||
int Value = OpCode.Read(20, 0x7ffff);
|
int Value = OpCode.Read(20, 0x7ffff);
|
||||||
|
|
Reference in a new issue