diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2018-04-25 23:11:26 -0300 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-04-25 23:12:26 -0300 |
| commit | a38a72b0622f89897bdcd01b6d00ea6bc142c34f (patch) | |
| tree | 2025cdddaa7ef6769ac69c51eeede0924ffcba5f /Ryujinx.Graphics | |
| parent | 211f7f69db4d84b82caa3ee62d4ecdfbbd95604d (diff) | |
Some small sync primitive fixes, logging fixes, started to implement the 2D engine on the GPU, fixed DrawArrays, implemented a few more shader instructions, made a start on nvdrv refactor, etc...
Diffstat (limited to 'Ryujinx.Graphics')
19 files changed, 592 insertions, 93 deletions
diff --git a/Ryujinx.Graphics/Gal/IGalRenderer.cs b/Ryujinx.Graphics/Gal/IGalRenderer.cs index af88412a..e4aef206 100644 --- a/Ryujinx.Graphics/Gal/IGalRenderer.cs +++ b/Ryujinx.Graphics/Gal/IGalRenderer.cs @@ -44,6 +44,8 @@ namespace Ryujinx.Graphics.Gal void SetViewport(int X, int Y, int Width, int Height); + void GetFrameBufferData(long Tag, Action<byte[]> Callback); + //Rasterizer void ClearBuffers(int RtIndex, GalClearBufferFlags Flags); @@ -51,7 +53,7 @@ namespace Ryujinx.Graphics.Gal void SetIndexArray(byte[] Buffer, GalIndexFormat Format); - void DrawArrays(int VbIndex, GalPrimitiveType PrimType); + void DrawArrays(int VbIndex, int First, int PrimCount, GalPrimitiveType PrimType); void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs index 05a7288a..8f265f54 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs @@ -270,6 +270,31 @@ namespace Ryujinx.Graphics.Gal.OpenGL } } + public void GetBufferData(long Tag, Action<byte[]> Callback) + { + if (Fbs.TryGetValue(Tag, out FrameBuffer Fb)) + { + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, Fb.Handle); + + byte[] Data = new byte[Fb.Width * Fb.Height * 4]; + + (PixelFormat Format, PixelType Type) = OGLEnumConverter.GetTextureFormat(GalTextureFormat.A8B8G8R8); + + GL.ReadPixels( + 0, + 0, + Fb.Width, + Fb.Height, + Format, + Type, + Data); + + Callback(Data); + + GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, CurrFbHandle); + } + } + private void SetViewport(Rect Viewport) { GL.Viewport( diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs index 9e0d4523..b1504563 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs @@ -48,8 +48,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL { public int VaoHandle; public int VboHandle; - - public int PrimCount; } private struct IbInfo @@ -102,8 +100,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL { EnsureVbInitialized(VbIndex); - VertexBuffers[VbIndex].PrimCount = Buffer.Length / Stride; - VbInfo Vb = VertexBuffers[VbIndex]; IntPtr Length = new IntPtr(Buffer.Length); @@ -171,29 +167,24 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.BindBuffer(BufferTarget.ElementArrayBuffer, 0); } - public void DrawArrays(int VbIndex, GalPrimitiveType PrimType) + public void DrawArrays(int VbIndex, int First, int PrimCount, GalPrimitiveType PrimType) { - VbInfo Vb = VertexBuffers[VbIndex]; - - if (Vb.PrimCount == 0) + if (PrimCount == 0) { return; } + VbInfo Vb = VertexBuffers[VbIndex]; + GL.BindVertexArray(Vb.VaoHandle); - GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), 0, Vb.PrimCount); + GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, PrimCount); } public void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType) { VbInfo Vb = VertexBuffers[VbIndex]; - if (Vb.PrimCount == 0) - { - return; - } - PrimitiveType Mode = OGLEnumConverter.GetPrimitiveType(PrimType); GL.BindVertexArray(Vb.VaoHandle); diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs index cf2da91c..f9410573 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs @@ -146,6 +146,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL ActionsQueue.Enqueue(() => FrameBuffer.SetViewport(X, Y, Width, Height)); } + public void GetFrameBufferData(long Tag, Action<byte[]> Callback) + { + ActionsQueue.Enqueue(() => FrameBuffer.GetBufferData(Tag, Callback)); + } + public void ClearBuffers(int RtIndex, GalClearBufferFlags Flags) { ActionsQueue.Enqueue(() => Rasterizer.ClearBuffers(RtIndex, Flags)); @@ -173,14 +178,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL ActionsQueue.Enqueue(() => Rasterizer.SetIndexArray(Buffer, Format)); } - public void DrawArrays(int VbIndex, GalPrimitiveType PrimType) + public void DrawArrays(int VbIndex, int First, int PrimCount, GalPrimitiveType PrimType) { if ((uint)VbIndex > 31) { throw new ArgumentOutOfRangeException(nameof(VbIndex)); } - ActionsQueue.Enqueue(() => Rasterizer.DrawArrays(VbIndex, PrimType)); + ActionsQueue.Enqueue(() => Rasterizer.DrawArrays(VbIndex, First, PrimCount, PrimType)); } public void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType) diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs index d7173bcd..c22f5926 100644 --- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs +++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs @@ -31,51 +31,53 @@ namespace Ryujinx.Graphics.Gal.Shader { InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>() { - { ShaderIrInst.And, GetAndExpr }, - { ShaderIrInst.Asr, GetAsrExpr }, - { ShaderIrInst.Band, GetBandExpr }, - { ShaderIrInst.Bnot, GetBnotExpr }, - { ShaderIrInst.Ceil, GetCeilExpr }, - { ShaderIrInst.Ceq, GetCeqExpr }, - { ShaderIrInst.Cge, GetCgeExpr }, - { ShaderIrInst.Cgt, GetCgtExpr }, - { ShaderIrInst.Clamp, GetClampExpr }, - { ShaderIrInst.Cle, GetCleExpr }, - { ShaderIrInst.Clt, GetCltExpr }, - { ShaderIrInst.Cne, GetCneExpr }, - { ShaderIrInst.Exit, GetExitExpr }, - { ShaderIrInst.Fabs, GetFabsExpr }, - { ShaderIrInst.Fadd, GetFaddExpr }, - { ShaderIrInst.Fceq, GetCeqExpr }, - { ShaderIrInst.Fcge, GetCgeExpr }, - { ShaderIrInst.Fcgt, GetCgtExpr }, - { ShaderIrInst.Fcle, GetCleExpr }, - { ShaderIrInst.Fclt, GetCltExpr }, - { ShaderIrInst.Fcne, GetCneExpr }, - { ShaderIrInst.Fcos, GetFcosExpr }, - { ShaderIrInst.Fex2, GetFex2Expr }, - { ShaderIrInst.Ffma, GetFfmaExpr }, - { ShaderIrInst.Flg2, GetFlg2Expr }, - { ShaderIrInst.Floor, GetFloorExpr }, - { ShaderIrInst.Fmul, GetFmulExpr }, - { ShaderIrInst.Fneg, GetFnegExpr }, - { ShaderIrInst.Frcp, GetFrcpExpr }, - { ShaderIrInst.Frsq, GetFrsqExpr }, - { ShaderIrInst.Fsin, GetFsinExpr }, - { ShaderIrInst.Ftos, GetFtosExpr }, - { ShaderIrInst.Ftou, GetFtouExpr }, - { ShaderIrInst.Ipa, GetIpaExpr }, - { ShaderIrInst.Kil, GetKilExpr }, - { ShaderIrInst.Lsr, GetLsrExpr }, - { ShaderIrInst.Not, GetNotExpr }, - { ShaderIrInst.Or, GetOrExpr }, - { ShaderIrInst.Stof, GetStofExpr }, - { ShaderIrInst.Texq, GetTexqExpr }, - { ShaderIrInst.Texs, GetTexsExpr }, - { ShaderIrInst.Trunc, GetTruncExpr }, - { ShaderIrInst.Txlf, GetTxlfExpr }, - { ShaderIrInst.Utof, GetUtofExpr }, - { ShaderIrInst.Xor, GetXorExpr } + { ShaderIrInst.And, GetAndExpr }, + { ShaderIrInst.Asr, GetAsrExpr }, + { ShaderIrInst.Band, GetBandExpr }, + { ShaderIrInst.Bnot, GetBnotExpr }, + { ShaderIrInst.Ceil, GetCeilExpr }, + { ShaderIrInst.Ceq, GetCeqExpr }, + { ShaderIrInst.Cge, GetCgeExpr }, + { ShaderIrInst.Cgt, GetCgtExpr }, + { ShaderIrInst.Clamps, GetClampsExpr }, + { ShaderIrInst.Clampu, GetClampuExpr }, + { ShaderIrInst.Cle, GetCleExpr }, + { ShaderIrInst.Clt, GetCltExpr }, + { ShaderIrInst.Cne, GetCneExpr }, + { ShaderIrInst.Exit, GetExitExpr }, + { ShaderIrInst.Fabs, GetFabsExpr }, + { ShaderIrInst.Fadd, GetFaddExpr }, + { ShaderIrInst.Fceq, GetCeqExpr }, + { ShaderIrInst.Fcge, GetCgeExpr }, + { ShaderIrInst.Fcgt, GetCgtExpr }, + { ShaderIrInst.Fclamp, GetFclampExpr }, + { ShaderIrInst.Fcle, GetCleExpr }, + { ShaderIrInst.Fclt, GetCltExpr }, + { ShaderIrInst.Fcne, GetCneExpr }, + { ShaderIrInst.Fcos, GetFcosExpr }, + { ShaderIrInst.Fex2, GetFex2Expr }, + { ShaderIrInst.Ffma, GetFfmaExpr }, + { ShaderIrInst.Flg2, GetFlg2Expr }, + { ShaderIrInst.Floor, GetFloorExpr }, + { ShaderIrInst.Fmul, GetFmulExpr }, + { ShaderIrInst.Fneg, GetFnegExpr }, + { ShaderIrInst.Frcp, GetFrcpExpr }, + { ShaderIrInst.Frsq, GetFrsqExpr }, + { ShaderIrInst.Fsin, GetFsinExpr }, + { ShaderIrInst.Ftos, GetFtosExpr }, + { ShaderIrInst.Ftou, GetFtouExpr }, + { ShaderIrInst.Ipa, GetIpaExpr }, + { ShaderIrInst.Kil, GetKilExpr }, + { ShaderIrInst.Lsr, GetLsrExpr }, + { ShaderIrInst.Not, GetNotExpr }, + { ShaderIrInst.Or, GetOrExpr }, + { ShaderIrInst.Stof, GetStofExpr }, + { ShaderIrInst.Texq, GetTexqExpr }, + { ShaderIrInst.Texs, GetTexsExpr }, + { ShaderIrInst.Trunc, GetTruncExpr }, + { ShaderIrInst.Txlf, GetTxlfExpr }, + { ShaderIrInst.Utof, GetUtofExpr }, + { ShaderIrInst.Xor, GetXorExpr } }; } @@ -478,7 +480,19 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetCeilExpr(ShaderIrOp Op) => GetUnaryCall(Op, "ceil"); - private string GetClampExpr(ShaderIrOp Op) => GetTernaryCall(Op, "clamp"); + private string GetClampsExpr(ShaderIrOp Op) + { + return "clamp(" + GetOperExpr(Op, Op.OperandA) + ", " + + GetOperExpr(Op, Op.OperandB) + ", " + + GetOperExpr(Op, Op.OperandC) + ")"; + } + + private string GetClampuExpr(ShaderIrOp Op) + { + return "int(clamp(uint(" + GetOperExpr(Op, Op.OperandA) + "), " + + "uint(" + GetOperExpr(Op, Op.OperandB) + "), " + + "uint(" + GetOperExpr(Op, Op.OperandC) + ")))"; + } private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<"); private string GetCeqExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "=="); @@ -499,6 +513,8 @@ namespace Ryujinx.Graphics.Gal.Shader private string GetFfmaExpr(ShaderIrOp Op) => GetTernaryExpr(Op, "*", "+"); + private string GetFclampExpr(ShaderIrOp Op) => GetTernaryCall(Op, "clamp"); + private string GetFlg2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "log2"); private string GetFloorExpr(ShaderIrOp Op) => GetUnaryCall(Op, "floor"); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs index 830aeb8c..42609bce 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs @@ -66,6 +66,21 @@ namespace Ryujinx.Graphics.Gal.Shader EmitAluBinaryF(Block, OpCode, ShaderOper.RR, ShaderIrInst.Fmul); } + public static void Fset_C(ShaderIrBlock Block, long OpCode) + { + EmitFset(Block, OpCode, ShaderOper.CR); + } + + public static void Fset_I(ShaderIrBlock Block, long OpCode) + { + EmitFset(Block, OpCode, ShaderOper.Immf); + } + + public static void Fset_R(ShaderIrBlock Block, long OpCode) + { + EmitFset(Block, OpCode, ShaderOper.RR); + } + public static void Fsetp_C(ShaderIrBlock Block, long OpCode) { EmitFsetp(Block, OpCode, ShaderOper.CR); @@ -279,6 +294,78 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } + private static void EmitFset(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + EmitSet(Block, OpCode, true, Oper); + } + + private static void EmitIset(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + EmitSet(Block, OpCode, false, Oper); + } + + private static void EmitSet(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper) + { + bool Na = ((OpCode >> 43) & 1) != 0; + bool Ab = ((OpCode >> 44) & 1) != 0; + bool Nb = ((OpCode >> 53) & 1) != 0; + bool Aa = ((OpCode >> 54) & 1) != 0; + + ShaderIrNode OperA = GetOperGpr8(OpCode), OperB; + + switch (Oper) + { + case ShaderOper.CR: OperB = GetOperCbuf34 (OpCode); break; + case ShaderOper.Imm: OperB = GetOperImm19_20 (OpCode); break; + case ShaderOper.Immf: OperB = GetOperImmf19_20(OpCode); break; + case ShaderOper.RR: OperB = GetOperGpr20 (OpCode); break; + + default: throw new ArgumentException(nameof(Oper)); + } + + ShaderIrInst CmpInst; + + if (IsFloat) + { + OperA = GetAluAbsNeg(OperA, Aa, Na); + OperB = GetAluAbsNeg(OperB, Ab, Nb); + + CmpInst = GetCmpF(OpCode); + } + else + { + CmpInst = GetCmp(OpCode); + } + + ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB); + + ShaderIrInst LopInst = GetBLop(OpCode); + + ShaderIrOperPred PNode = GetOperPred39(OpCode); + + ShaderIrOperImmf Imm0 = new ShaderIrOperImmf(0); + ShaderIrOperImmf Imm1 = new ShaderIrOperImmf(1); + + ShaderIrNode Asg0 = new ShaderIrAsg(GetOperGpr0(OpCode), Imm0); + ShaderIrNode Asg1 = new ShaderIrAsg(GetOperGpr0(OpCode), Imm1); + + if (LopInst != ShaderIrInst.Band || !PNode.IsConst) + { + ShaderIrOp Op2 = new ShaderIrOp(LopInst, Op, PNode); + + Asg0 = new ShaderIrCond(Op2, Asg0, Not: true); + Asg1 = new ShaderIrCond(Op2, Asg1, Not: false); + } + else + { + Asg0 = new ShaderIrCond(Op, Asg0, Not: true); + Asg1 = new ShaderIrCond(Op, Asg1, Not: false); + } + + Block.AddNode(GetPredNode(Asg0, OpCode)); + Block.AddNode(GetPredNode(Asg1, OpCode)); + } + private static void EmitFsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper) { EmitSetp(Block, OpCode, true, Oper); diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs index 6d30cfed..b9cf02f1 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs @@ -70,6 +70,21 @@ namespace Ryujinx.Graphics.Gal.Shader EmitI2f(Block, OpCode, ShaderOper.RR); } + public static void I2i_C(ShaderIrBlock Block, long OpCode) + { + EmitI2i(Block, OpCode, ShaderOper.CR); + } + + public static void I2i_I(ShaderIrBlock Block, long OpCode) + { + EmitI2i(Block, OpCode, ShaderOper.Imm); + } + + public static void I2i_R(ShaderIrBlock Block, long OpCode) + { + EmitI2i(Block, OpCode, ShaderOper.RR); + } + public static void Mov_C(ShaderIrBlock Block, long OpCode) { ShaderIrOperCbuf Cbuf = GetOperCbuf34(OpCode); @@ -183,7 +198,7 @@ namespace Ryujinx.Graphics.Gal.Shader ShaderIrOperImmf IMin = new ShaderIrOperImmf(CMin); ShaderIrOperImmf IMax = new ShaderIrOperImmf(CMax); - OperA = new ShaderIrOp(ShaderIrInst.Clamp, OperA, IMin, IMax); + OperA = new ShaderIrOp(ShaderIrInst.Fclamp, OperA, IMin, IMax); } ShaderIrInst Inst = Signed @@ -252,6 +267,81 @@ namespace Ryujinx.Graphics.Gal.Shader Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode)); } + private static void EmitI2i(ShaderIrBlock Block, long OpCode, ShaderOper Oper) + { + IntType Type = GetIntType(OpCode); + + if (Type == IntType.U64 || + Type == IntType.S64) + { + //TODO: 64-bits support. + //Note: GLSL doesn't support 64-bits integers. + throw new NotImplementedException(); + } + + int Sel = (int)(OpCode >> 41) & 3; + + bool NegA = ((OpCode >> 45) & 1) != 0; + bool AbsA = ((OpCode >> 49) & 1) != 0; + bool SatA = ((OpCode >> 50) & 1) != 0; + + ShaderIrNode OperA; + + switch (Oper) + { + case ShaderOper.CR: OperA = GetOperCbuf34 (OpCode); break; + case ShaderOper.Immf: OperA = GetOperImmf19_20(OpCode); break; + case ShaderOper.RR: OperA = GetOperGpr20 (OpCode); break; + + default: throw new ArgumentException(nameof(Oper)); + } + + OperA = GetAluAbsNeg(OperA, AbsA, NegA); + + bool Signed = Type >= IntType.S8; + + int Shift = Sel * 8; + + int Size = 8 << ((int)Type & 3); + + if (Shift != 0) + { + OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift)); + } + + if (Size < 32) + { + uint Mask = uint.MaxValue >> (32 - Size); + + if (SatA) + { + uint CMin = 0; + uint CMax = Mask; + + if (Signed) + { + uint HalfMask = Mask >> 1; + + CMin -= HalfMask + 1; + CMax = HalfMask; + } + + ShaderIrOperImm IMin = new ShaderIrOperImm((int)CMin); + ShaderIrOperImm IMax = new ShaderIrOperImm((int)CMax); + + OperA = new ShaderIrOp(Signed + ? ShaderIrInst.Clamps + : ShaderIrInst.Clampu, OperA, IMin, IMax); + } + else + { + OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm((int)Mask)); + } + } + + Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode)); + } + private static IntType GetIntType(long OpCode) { bool Signed = ((OpCode >> 13) & 1) != 0; diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs index 1b72f647..ce2b98fe 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Gal.Shader F_Start, Ceil, - Clamp, + Fabs, Fadd, Fceq, @@ -22,6 +22,7 @@ namespace Ryujinx.Graphics.Gal.Shader Fcgeu, Fcgt, Fcgtu, + Fclamp, Fcle, Fcleu, Fclt, @@ -53,6 +54,8 @@ namespace Ryujinx.Graphics.Gal.Shader Ceq, Cge, Cgt, + Clamps, + Clampu, Cle, Clt, Cne, diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs index 762544cb..65e24928 100644 --- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs +++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs @@ -6,11 +6,24 @@ namespace Ryujinx.Graphics.Gal.Shader { private const int EncodingBits = 14; - private static ShaderDecodeFunc[] OpCodes; + private class ShaderDecodeEntry + { + public ShaderDecodeFunc Func; + + public int XBits; + + public ShaderDecodeEntry(ShaderDecodeFunc Func, int XBits) + { + this.Func = Func; + this.XBits = XBits; + } + } + + private static ShaderDecodeEntry[] OpCodes; static ShaderOpCodeTable() { - OpCodes = new ShaderDecodeFunc[1 << EncodingBits]; + OpCodes = new ShaderDecodeEntry[1 << EncodingBits]; #region Instructions Set("111000110000xx", ShaderDecode.Exit); @@ -31,12 +44,18 @@ namespace Ryujinx.Graphics.Gal.Shader Set("0100110001101x", ShaderDecode.Fmul_C); Set("0011100x01101x", ShaderDecode.Fmul_I); Set("0101110001101x", ShaderDecode.Fmul_R); + Set("0100100xxxxxxx", ShaderDecode.Fset_C); + Set("0011000xxxxxxx", ShaderDecode.Fset_I); + Set("01011000xxxxxx", ShaderDecode.Fset_R); Set("010010111011xx", ShaderDecode.Fsetp_C); Set("0011011x1011xx", ShaderDecode.Fsetp_I); Set("010110111011xx", ShaderDecode.Fsetp_R); Set("0100110010111x", ShaderDecode.I2f_C); Set("0011100x10111x", ShaderDecode.I2f_I); Set("0101110010111x", ShaderDecode.I2f_R); + Set("0100110011100x", ShaderDecode.I2i_C); + Set("0011100x11100x", ShaderDecode.I2i_I); + Set("0101110011100x", ShaderDecode.I2i_R); Set("11100000xxxxxx", ShaderDecode.Ipa); Set("010010110110xx", ShaderDecode.Isetp_C); Set("0011011x0110xx", ShaderDecode.Isetp_I); @@ -91,6 +110,8 @@ namespace Ryujinx.Graphics.Gal.Shader XMask = ~XMask; + ShaderDecodeEntry Entry = new ShaderDecodeEntry(Func, XBits); + for (int Index = 0; Index < (1 << XBits); Index++) { Value &= XMask; @@ -100,13 +121,16 @@ namespace Ryujinx.Graphics.Gal.Shader Value |= ((Index >> X) & 1) << XPos[X]; } - OpCodes[Value] = Func; + if (OpCodes[Value] == null || OpCodes[Value].XBits > XBits) + { + OpCodes[Value] = Entry; + } } } public static ShaderDecodeFunc GetDecoder(long OpCode) { - return OpCodes[(ulong)OpCode >> (64 - EncodingBits)]; + return OpCodes[(ulong)OpCode >> (64 - EncodingBits)]?.Func; } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NsGpu.cs b/Ryujinx.Graphics/Gpu/NsGpu.cs index 9a2e9012..e1088982 100644 --- a/Ryujinx.Graphics/Gpu/NsGpu.cs +++ b/Ryujinx.Graphics/Gpu/NsGpu.cs @@ -7,10 +7,11 @@ namespace Ryujinx.Graphics.Gpu { public IGalRenderer Renderer { get; private set; } - internal NsGpuMemoryMgr MemoryMgr { get; private set; } + public NsGpuMemoryMgr MemoryMgr { get; private set; } public NvGpuFifo Fifo { get; private set; } + public NvGpuEngine2d Engine2d { get; private set; } public NvGpuEngine3d Engine3d { get; private set; } private Thread FifoProcessing; @@ -25,6 +26,7 @@ namespace Ryujinx.Graphics.Gpu Fifo = new NvGpuFifo(this); + Engine2d = new NvGpuEngine2d(this); Engine3d = new NvGpuEngine3d(this); KeepRunning = true; diff --git a/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs b/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs index 7f50640d..eff51783 100644 --- a/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs +++ b/Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs @@ -1,6 +1,6 @@ namespace Ryujinx.Graphics.Gpu { - class NsGpuMemoryMgr + public class NsGpuMemoryMgr { private const long AddrSize = 1L << 40; @@ -50,12 +50,20 @@ namespace Ryujinx.Graphics.Gpu return GpuAddr; } + public void Unmap(long Position, long Size) + { + for (long Offset = 0; Offset < Size; Offset += PageSize) + { + SetPTAddr(Position + Offset, PteUnmapped); + } + } + public long Map(long CpuAddr, long Size) { CpuAddr &= ~PageMask; long Position = GetFreePosition(Size); - + if (Position != -1) { for (long Offset = 0; Offset < Size; Offset += PageSize) diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine2d.cs b/Ryujinx.Graphics/Gpu/NvGpuEngine2d.cs new file mode 100644 index 00000000..c2bee167 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/NvGpuEngine2d.cs @@ -0,0 +1,158 @@ +using ChocolArm64.Memory; +using Ryujinx.Graphics.Gal; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Gpu +{ + public class NvGpuEngine2d : INvGpuEngine + { + private enum CopyOperation + { + SrcCopyAnd, + RopAnd, + Blend, + SrcCopy, + Rop, + SrcCopyPremult, + BlendPremult + } + + public int[] Registers { get; private set; } + + private NsGpu Gpu; + + private Dictionary<int, NvGpuMethod> Methods; + + public NvGpuEngine2d(NsGpu Gpu) + { + this.Gpu = Gpu; + + Registers = new int[0xe00]; + + Methods = new Dictionary<int, NvGpuMethod>(); + + void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method) + { + while (Count-- > 0) + { + Methods.Add(Meth, Method); + + Meth += Stride; + } + } + + AddMethod(0xb5, 1, 1, TextureCopy); + } + + public void CallMethod(AMemory Memory, NsGpuPBEntry PBEntry) + { + if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method)) + { + Method(Memory, PBEntry); + } + else + { + WriteRegister(PBEntry); + } + } + + private void TextureCopy(AMemory Memory, NsGpuPBEntry PBEntry) + { + CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation); + + bool SrcLinear = ReadRegister(NvGpuEngine2dReg.SrcLinear) != 0; + int SrcWidth = ReadRegister(NvGpuEngine2dReg.SrcWidth); + int SrcHeight = ReadRegister(NvGpuEngine2dReg.SrcHeight); + + bool DstLinear = ReadRegister(NvGpuEngine2dReg.DstLinear) != 0; + int DstWidth = ReadRegister(NvGpuEngine2dReg.DstWidth); + int DstHeight = ReadRegister(NvGpuEngine2dReg.DstHeight); + int DstPitch = ReadRegister(NvGpuEngine2dReg.DstPitch); + int DstBlkDim = ReadRegister(NvGpuEngine2dReg.DstBlockDimensions); + + TextureSwizzle DstSwizzle = DstLinear + ? TextureSwizzle.Pitch + : TextureSwizzle.BlockLinear; + + int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); + + long Tag = MakeInt64From2xInt32(NvGpuEngine2dReg.SrcAddress); + + TryGetCpuAddr(NvGpuEngine2dReg.SrcAddress, out long SrcAddress); + TryGetCpuAddr(NvGpuEngine2dReg.DstAddress, out long DstAddress); + + bool IsFbTexture = Gpu.Engine3d.IsFrameBufferPosition(Tag); + + if (IsFbTexture && DstLinear) + { + DstSwizzle = TextureSwizzle.BlockLinear; + } + + Texture DstTexture = new Texture( + DstAddress, + DstWidth, + DstHeight, + DstBlockHeight, + DstBlockHeight, + DstSwizzle, + GalTextureFormat.A8B8G8R8); + + if (IsFbTexture) + { + Gpu.Renderer.GetFrameBufferData(Tag, (byte[] Buffer) => + { + CopyTexture(Memory, DstTexture, Buffer); + }); + } + else + { + long Size = SrcWidth * SrcHeight * 4; + + byte[] Buffer = AMemoryHelper.ReadBytes(Memory, SrcAddress, Size); + + CopyTexture(Memory, DstTexture, Buffer); + } + } + + private void CopyTexture(AMemory Memory, Texture Texture, byte[] Buffer) + { + TextureWriter.Write(Memory, Texture, Buffer); + } + + private bool TryGetCpuAddr(NvGpuEngine2dReg Reg, out long Position) + { + Position = MakeInt64From2xInt32(Reg); + + Position = Gpu.GetCpuAddr(Position); + + return Position != -1; + } + + private long MakeInt64From2xInt32(NvGpuEngine2dReg Reg) + { + return + (long)Registers[(int)Reg + 0] << 32 | + (uint)Registers[(int)Reg + 1]; + } + + private void WriteRegister(NsGpuPBEntry PBEntry) + { + int ArgsCount = PBEntry.Arguments.Count; + + if (ArgsCount > 0) + { + Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1]; + } + } + + private int ReadRegister(NvGpuEngine2dReg Reg) + { + return Registers[(int)Reg]; + } + + private void WriteRegister(NvGpuEngine2dReg Reg, int Value) + { + Registers[(int)Reg] = Value; + } + } +}
\ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine2dReg.cs b/Ryujinx.Graphics/Gpu/NvGpuEngine2dReg.cs new file mode 100644 index 00000000..903baca8 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/NvGpuEngine2dReg.cs @@ -0,0 +1,25 @@ +namespace Ryujinx.Graphics.Gpu +{ + enum NvGpuEngine2dReg + { + DstFormat = 0x80, + DstLinear = 0x81, + DstBlockDimensions = 0x82, + DstDepth = 0x83, + DstLayer = 0x84, + DstPitch = 0x85, + DstWidth = 0x86, + DstHeight = 0x87, + DstAddress = 0x88, + SrcFormat = 0x8c, + SrcLinear = 0x8d, + SrcBlockDimensions = 0x8e, + SrcDepth = 0x8f, + SrcLayer = 0x90, + SrcPitch = 0x91, + SrcWidth = 0x92, + SrcHeight = 0x93, + SrcAddress = 0x94, + CopyOperation = 0xab + } +}
\ No newline at end of file diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs b/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs index 88ad7633..bf04db36 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs +++ b/Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs @@ -360,6 +360,9 @@ namespace Ryujinx.Graphics.Gpu for (int Index = 0; Index < 32; Index++) { + int VertexFirst = ReadRegister(NvGpuEngine3dReg.VertexArrayFirst); + int VertexCount = ReadRegister(NvGpuEngine3dReg.VertexArrayCount); + int Control = ReadRegister(NvGpuEngine3dReg.VertexArrayNControl + Index * 4); bool Enable = (Control & 0x1000) != 0; @@ -394,7 +397,7 @@ namespace Ryujinx.Graphics.Gpu } else { - Gpu.Renderer.DrawArrays(Index, PrimType); + Gpu.Renderer.DrawArrays(Index, VertexFirst, VertexCount, PrimType); } } } diff --git a/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs b/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs index 605ca9da..0d995619 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs +++ b/Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs @@ -12,6 +12,8 @@ namespace Ryujinx.Graphics.Gpu ViewportTranslateX = 0x283, ViewportTranslateY = 0x284, ViewportTranslateZ = 0x285, + VertexArrayFirst = 0x35d, + VertexArrayCount = 0x35e, VertexAttribNFormat = 0x458, IBlendEnable = 0x4b9, BlendSeparateAlpha = 0x4cf, diff --git a/Ryujinx.Graphics/Gpu/NvGpuFifo.cs b/Ryujinx.Graphics/Gpu/NvGpuFifo.cs index df765895..68c2902a 100644 --- a/Ryujinx.Graphics/Gpu/NvGpuFifo.cs +++ b/Ryujinx.Graphics/Gpu/NvGpuFifo.cs @@ -139,11 +139,17 @@ namespace Ryujinx.Graphics.Gpu { switch (SubChannels[PBEntry.SubChannel]) { + case NvGpuEngine._2d: Call2dMethod(Memory, PBEntry); break; case NvGpuEngine._3d: Call3dMethod(Memory, PBEntry); break; } } } + private void Call2dMethod(AMemory Memory, NsGpuPBEntry PBEntry) + { + Gpu.Engine2d.CallMethod(Memory, PBEntry); + } + private void Call3dMethod(AMemory Memory, NsGpuPBEntry PBEntry) { if (PBEntry.Method < 0xe00) diff --git a/Ryujinx.Graphics/Gpu/TextureHelper.cs b/Ryujinx.Graphics/Gpu/TextureHelper.cs new file mode 100644 index 00000000..d3c2ac14 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/TextureHelper.cs @@ -0,0 +1,23 @@ +using System; + +namespace Ryujinx.Graphics.Gpu +{ + static class TextureHelper + { + public static ISwizzle GetSwizzle(Texture Texture, int Width, int Bpp) + { + switch (Texture.Swizzle) + { + case TextureSwizzle.Pitch: + case TextureSwizzle.PitchColorKey: + return new LinearSwizzle(Texture.Pitch, Bpp); + + case TextureSwizzle.BlockLinear: + case TextureSwizzle.BlockLinearColorKey: + return new BlockLinearSwizzle(Width, Bpp, Texture.BlockHeight); + } + + throw new NotImplementedException(Texture.Swizzle.ToString()); + } + } +} diff --git a/Ryujinx.Graphics/Gpu/TextureReader.cs b/Ryujinx.Graphics/Gpu/TextureReader.cs index 4c3b4fb1..17fd95c5 100644 --- a/Ryujinx.Graphics/Gpu/TextureReader.cs +++ b/Ryujinx.Graphics/Gpu/TextureReader.cs @@ -30,7 +30,7 @@ namespace Ryujinx.Graphics.Gpu byte[] Output = new byte[Width * Height * 2]; - ISwizzle Swizzle = GetSwizzle(Texture, Width, 2); + ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 2); fixed (byte* BuffPtr = Output) { @@ -59,7 +59,7 @@ namespace Ryujinx.Graphics.Gpu byte[] Output = new byte[Width * Height * 4]; - ISwizzle Swizzle = GetSwizzle(Texture, Width, 4); + ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4); fixed (byte* BuffPtr = Output) { @@ -88,7 +88,7 @@ namespace Ryujinx.Graphics.Gpu byte[] Output = new byte[Width * Height * 8]; - ISwizzle Swizzle = GetSwizzle(Texture, Width, 8); + ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 8); fixed (byte* BuffPtr = Output) { @@ -117,7 +117,7 @@ namespace Ryujinx.Graphics.Gpu byte[] Output = new byte[Width * Height * 16]; - ISwizzle Swizzle = GetSwizzle(Texture, Width, 16); + ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 16); fixed (byte* BuffPtr = Output) { @@ -140,21 +140,5 @@ namespace Ryujinx.Graphics.Gpu return Output; } - - private static ISwizzle GetSwizzle(Texture Texture, int Width, int Bpp) - { - switch (Texture.Swizzle) - { - case TextureSwizzle.Pitch: - case TextureSwizzle.PitchColorKey: - return new LinearSwizzle(Texture.Pitch, Bpp); - - case TextureSwizzle.BlockLinear: - case TextureSwizzle.BlockLinearColorKey: - return new BlockLinearSwizzle(Width, Bpp, Texture.BlockHeight); - } - - throw new NotImplementedException(Texture.Swizzle.ToString()); - } } } diff --git a/Ryujinx.Graphics/Gpu/TextureWriter.cs b/Ryujinx.Graphics/Gpu/TextureWriter.cs new file mode 100644 index 00000000..2f25de73 --- /dev/null +++ b/Ryujinx.Graphics/Gpu/TextureWriter.cs @@ -0,0 +1,45 @@ +using ChocolArm64.Memory; +using Ryujinx.Graphics.Gal; +using System; + +namespace Ryujinx.Graphics.Gpu +{ + public static class TextureWriter + { + public static void Write(AMemory Memory, Texture Texture, byte[] Data) + { + switch (Texture.Format) + { + case GalTextureFormat.A8B8G8R8: Write4Bpp(Memory, Texture, Data); break; + + default: + throw new NotImplementedException(Texture.Format.ToString()); + } + } + + private unsafe static void Write4Bpp(AMemory Memory, Texture Texture, byte[] Data) + { + int Width = Texture.Width; + int Height = Texture.Height; + + ISwizzle Swizzle = TextureHelper.GetSwizzle(Texture, Width, 4); + + fixed (byte* BuffPtr = Data) + { + long InOffs = 0; + + for (int Y = 0; Y < Height; Y++) + for (int X = 0; X < Width; X++) + { + long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); + + int Pixel = *(int*)(BuffPtr + InOffs); + + Memory.WriteInt32Unchecked(Texture.Position + Offset, Pixel); + + InOffs += 4; + } + } + } + } +} |
