From 9cbcbaa90c2af78873d145850e0676b19b2ae79e Mon Sep 17 00:00:00 2001 From: gdkchan Date: Fri, 15 Feb 2019 00:23:14 -0300 Subject: [PATCH] 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 --- Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs | 32 ++-- Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs | 4 +- .../Gal/Shader/ShaderDecodeAlu.cs | 149 ++++++++++++------ .../Gal/Shader/ShaderDecodeOpCode.cs | 5 + 4 files changed, 125 insertions(+), 65 deletions(-) diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs index deccd890..6a928603 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLPipeline.cs @@ -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) { diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index 77a451e9..854c827e 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -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)"; } } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs index 24c85c8f..469092a2 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs @@ -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); } diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs index 6531138e..f0f92148 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs @@ -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);