aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-04-25 23:11:26 -0300
committergdkchan <gab.dark.100@gmail.com>2018-04-25 23:12:26 -0300
commita38a72b0622f89897bdcd01b6d00ea6bc142c34f (patch)
tree2025cdddaa7ef6769ac69c51eeede0924ffcba5f /Ryujinx.Graphics
parent211f7f69db4d84b82caa3ee62d4ecdfbbd95604d (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')
-rw-r--r--Ryujinx.Graphics/Gal/IGalRenderer.cs4
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLFrameBuffer.cs25
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OGLRasterizer.cs19
-rw-r--r--Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs9
-rw-r--r--Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs108
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs87
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs92
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs5
-rw-r--r--Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs32
-rw-r--r--Ryujinx.Graphics/Gpu/NsGpu.cs4
-rw-r--r--Ryujinx.Graphics/Gpu/NsGpuMemoryMgr.cs12
-rw-r--r--Ryujinx.Graphics/Gpu/NvGpuEngine2d.cs158
-rw-r--r--Ryujinx.Graphics/Gpu/NvGpuEngine2dReg.cs25
-rw-r--r--Ryujinx.Graphics/Gpu/NvGpuEngine3d.cs5
-rw-r--r--Ryujinx.Graphics/Gpu/NvGpuEngine3dReg.cs2
-rw-r--r--Ryujinx.Graphics/Gpu/NvGpuFifo.cs6
-rw-r--r--Ryujinx.Graphics/Gpu/TextureHelper.cs23
-rw-r--r--Ryujinx.Graphics/Gpu/TextureReader.cs24
-rw-r--r--Ryujinx.Graphics/Gpu/TextureWriter.cs45
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;
+ }
+ }
+ }
+ }
+}