diff --git a/Ryujinx.HLE/Gpu/NvGpu.cs b/Ryujinx.HLE/Gpu/NvGpu.cs index 1e433fa4b..0301fcf22 100644 --- a/Ryujinx.HLE/Gpu/NvGpu.cs +++ b/Ryujinx.HLE/Gpu/NvGpu.cs @@ -9,8 +9,9 @@ namespace Ryujinx.HLE.Gpu public NvGpuFifo Fifo { get; private set; } - public NvGpuEngine2d Engine2d { get; private set; } - public NvGpuEngine3d Engine3d { get; private set; } + public NvGpuEngine2d Engine2d { get; private set; } + public NvGpuEngine3d Engine3d { get; private set; } + public NvGpuEngineDma EngineDma { get; private set; } private Thread FifoProcessing; @@ -22,8 +23,9 @@ namespace Ryujinx.HLE.Gpu Fifo = new NvGpuFifo(this); - Engine2d = new NvGpuEngine2d(this); - Engine3d = new NvGpuEngine3d(this); + Engine2d = new NvGpuEngine2d(this); + Engine3d = new NvGpuEngine3d(this); + EngineDma = new NvGpuEngineDma(this); KeepRunning = true; diff --git a/Ryujinx.HLE/Gpu/NvGpuEngineDma.cs b/Ryujinx.HLE/Gpu/NvGpuEngineDma.cs new file mode 100644 index 000000000..48a19047b --- /dev/null +++ b/Ryujinx.HLE/Gpu/NvGpuEngineDma.cs @@ -0,0 +1,142 @@ +using Ryujinx.Graphics.Gal; +using System.Collections.Generic; + +namespace Ryujinx.HLE.Gpu +{ + class NvGpuEngineDma : INvGpuEngine + { + public int[] Registers { get; private set; } + + private NvGpu Gpu; + + private Dictionary Methods; + + public NvGpuEngineDma(NvGpu Gpu) + { + this.Gpu = Gpu; + + Registers = new int[0x1d6]; + + Methods = new Dictionary(); + + void AddMethod(int Meth, int Count, int Stride, NvGpuMethod Method) + { + while (Count-- > 0) + { + Methods.Add(Meth, Method); + + Meth += Stride; + } + } + + AddMethod(0xc0, 1, 1, Execute); + } + + public void CallMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + if (Methods.TryGetValue(PBEntry.Method, out NvGpuMethod Method)) + { + Method(Vmm, PBEntry); + } + else + { + WriteRegister(PBEntry); + } + } + + private void Execute(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + int Control = PBEntry.Arguments[0]; + + bool SrcLinear = ((Control >> 7) & 1) != 0; + bool DstLinear = ((Control >> 8) & 1) != 0; + + long SrcAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.SrcAddress); + long DstAddress = MakeInt64From2xInt32(NvGpuEngineDmaReg.DstAddress); + + int SrcPitch = ReadRegister(NvGpuEngineDmaReg.SrcPitch); + int DstPitch = ReadRegister(NvGpuEngineDmaReg.DstPitch); + + int DstBlkDim = ReadRegister(NvGpuEngineDmaReg.DstBlkDim); + int DstSizeX = ReadRegister(NvGpuEngineDmaReg.DstSizeX); + int DstSizeY = ReadRegister(NvGpuEngineDmaReg.DstSizeY); + int DstSizeZ = ReadRegister(NvGpuEngineDmaReg.DstSizeZ); + int DstPosXY = ReadRegister(NvGpuEngineDmaReg.DstPosXY); + int DstPosZ = ReadRegister(NvGpuEngineDmaReg.DstPosZ); + + int SrcBlkDim = ReadRegister(NvGpuEngineDmaReg.SrcBlkDim); + int SrcSizeX = ReadRegister(NvGpuEngineDmaReg.SrcSizeX); + int SrcSizeY = ReadRegister(NvGpuEngineDmaReg.SrcSizeY); + int SrcSizeZ = ReadRegister(NvGpuEngineDmaReg.SrcSizeZ); + int SrcPosXY = ReadRegister(NvGpuEngineDmaReg.SrcPosXY); + int SrcPosZ = ReadRegister(NvGpuEngineDmaReg.SrcPosZ); + + int DstPosX = (DstPosXY >> 0) & 0xffff; + int DstPosY = (DstPosXY >> 16) & 0xffff; + + int SrcPosX = (SrcPosXY >> 0) & 0xffff; + int SrcPosY = (SrcPosXY >> 16) & 0xffff; + + int SrcBlockHeight = 1 << ((SrcBlkDim >> 4) & 0xf); + int DstBlockHeight = 1 << ((DstBlkDim >> 4) & 0xf); + + ISwizzle SrcSwizzle; + + if (SrcLinear) + { + SrcSwizzle = new LinearSwizzle(SrcPitch, 1); + } + else + { + SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, 1, SrcBlockHeight); + } + + ISwizzle DstSwizzle; + + if (DstLinear) + { + DstSwizzle = new LinearSwizzle(DstPitch, 1); + } + else + { + DstSwizzle = new BlockLinearSwizzle(DstSizeX, 1, DstBlockHeight); + } + + for (int Y = 0; Y < DstSizeY; Y++) + for (int X = 0; X < DstSizeX; X++) + { + long SrcOffset = SrcAddress + (uint)SrcSwizzle.GetSwizzleOffset(X, Y); + long DstOffset = DstAddress + (uint)DstSwizzle.GetSwizzleOffset(X, Y); + + Vmm.WriteByte(DstOffset, Vmm.ReadByte(SrcOffset)); + } + } + + private long MakeInt64From2xInt32(NvGpuEngineDmaReg Reg) + { + return + (long)Registers[(int)Reg + 0] << 32 | + (uint)Registers[(int)Reg + 1]; + } + + private void WriteRegister(NvGpuPBEntry PBEntry) + { + int ArgsCount = PBEntry.Arguments.Count; + + if (ArgsCount > 0) + { + Registers[PBEntry.Method] = PBEntry.Arguments[ArgsCount - 1]; + } + } + + private int ReadRegister(NvGpuEngineDmaReg Reg) + { + return Registers[(int)Reg]; + } + + private void WriteRegister(NvGpuEngineDmaReg Reg, int Value) + { + Registers[(int)Reg] = Value; + } + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/NvGpuEngineDmaReg.cs b/Ryujinx.HLE/Gpu/NvGpuEngineDmaReg.cs new file mode 100644 index 000000000..55b404c5e --- /dev/null +++ b/Ryujinx.HLE/Gpu/NvGpuEngineDmaReg.cs @@ -0,0 +1,22 @@ +namespace Ryujinx.HLE.Gpu +{ + enum NvGpuEngineDmaReg + { + SrcAddress = 0x100, + DstAddress = 0x102, + SrcPitch = 0x104, + DstPitch = 0x105, + DstBlkDim = 0x1c3, + DstSizeX = 0x1c4, + DstSizeY = 0x1c5, + DstSizeZ = 0x1c6, + DstPosZ = 0x1c7, + DstPosXY = 0x1c8, + SrcBlkDim = 0x1ca, + SrcSizeX = 0x1cb, + SrcSizeY = 0x1cc, + SrcSizeZ = 0x1cd, + SrcPosZ = 0x1ce, + SrcPosXY = 0x1cf + } +} \ No newline at end of file diff --git a/Ryujinx.HLE/Gpu/NvGpuFifo.cs b/Ryujinx.HLE/Gpu/NvGpuFifo.cs index 0df37edc7..f115e8db2 100644 --- a/Ryujinx.HLE/Gpu/NvGpuFifo.cs +++ b/Ryujinx.HLE/Gpu/NvGpuFifo.cs @@ -136,8 +136,9 @@ namespace Ryujinx.HLE.Gpu { switch (SubChannels[PBEntry.SubChannel]) { - case NvGpuEngine._2d: Call2dMethod(Vmm, PBEntry); break; - case NvGpuEngine._3d: Call3dMethod(Vmm, PBEntry); break; + case NvGpuEngine._2d: Call2dMethod (Vmm, PBEntry); break; + case NvGpuEngine._3d: Call3dMethod (Vmm, PBEntry); break; + case NvGpuEngine.Dma: CallDmaMethod(Vmm, PBEntry); break; } } } @@ -170,5 +171,10 @@ namespace Ryujinx.HLE.Gpu } } } + + private void CallDmaMethod(NvGpuVmm Vmm, NvGpuPBEntry PBEntry) + { + Gpu.EngineDma.CallMethod(Vmm, PBEntry); + } } } \ No newline at end of file