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:
gdkchan 2019-02-15 00:23:14 -03:00 committed by jduncanator
parent b126ea48c6
commit 9cbcbaa90c
4 changed files with 125 additions and 65 deletions

View file

@ -159,25 +159,23 @@ namespace Ryujinx.Graphics.Gal.OpenGL
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)
//{
// GL.FrontFace(OGLEnumConverter.GetFrontFace(New.FrontFace));
//}
if (New.CullFaceEnabled != Old.CullFaceEnabled)
{
Enable(EnableCap.CullFace, New.CullFaceEnabled);
}
//if (New.CullFaceEnabled != Old.CullFaceEnabled)
//{
// Enable(EnableCap.CullFace, New.CullFaceEnabled);
//}
//if (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)
{

View file

@ -845,9 +845,7 @@ namespace Ryujinx.Graphics.Gal.Shader
{
case GlslDecl.PointCoordAttrX: return "gl_PointCoord.x";
case GlslDecl.PointCoordAttrY: return "gl_PointCoord.y";
//Note: It's a guess that Maxwell's face is 1 when gl_FrontFacing == true
case GlslDecl.FaceAttr: return "(gl_FrontFacing ? 1 : 0)";
case GlslDecl.FaceAttr: return "(gl_FrontFacing ? -1 : 0)";
}
}

View file

@ -1148,41 +1148,87 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
//TODO: Confirm SignAB/C, it is just a guess.
//TODO: Implement Mode 3 (CSFU), what it does?
bool SignAB = OpCode.Read(48);
bool SignC = OpCode.Read(49);
bool HighB = OpCode.Read(52);
bool HighA = OpCode.Read(53);
bool SignedA = OpCode.Read(48);
bool SignedB = OpCode.Read(49);
bool HighB = OpCode.Read(52);
bool HighA = OpCode.Read(53);
int Mode = OpCode.Read(50, 7);
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)
{
case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
case ShaderOper.Imm: OperB = OpCode.Imm19_20(); break;
case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
case ShaderOper.CR: OperB = OpCode.Cbuf34(); break;
case ShaderOper.Imm: OperB = OpCode.ImmU16_20(); break;
case ShaderOper.RC: OperB = OpCode.Gpr39(); break;
case ShaderOper.RR: OperB = OpCode.Gpr20(); break;
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)
{
@ -1196,40 +1242,53 @@ namespace Ryujinx.Graphics.Gal.Shader
Merge = OpCode.Read(37);
}
switch (Mode)
{
//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);
ShaderIrOp MulOp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB2);
if (ProductShiftLeft)
{
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);
if (Merge)
{
AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, ImmMsk);
OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
}
ShaderIrOperImm Imm16Mask = new ShaderIrOperImm(0xffff);
if (Mode == 4)
{
AddOp = new ShaderIrOp(ShaderIrInst.And, AddOp, Imm16Mask);
OperB = new ShaderIrOp(ShaderIrInst.Lsl, OperB, Imm16);
AddOp = new ShaderIrOp(ShaderIrInst.Or, AddOp, OperB);
}

View file

@ -138,6 +138,11 @@ namespace Ryujinx.Graphics.Gal.Shader
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)
{
int Value = OpCode.Read(20, 0x7ffff);