forked from Mirror/Ryujinx
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);
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
|
|
|
@ -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)";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1148,12 +1148,19 @@ 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 SignedA = OpCode.Read(48);
|
||||
bool SignedB = OpCode.Read(49);
|
||||
bool HighB = OpCode.Read(52);
|
||||
bool HighA = OpCode.Read(53);
|
||||
|
||||
|
@ -1161,28 +1168,67 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
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.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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue