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<int, NvGpuMethod> Methods;
+
+        public NvGpuEngineDma(NvGpu Gpu)
+        {
+            this.Gpu = Gpu;
+
+            Registers = new int[0x1d6];
+
+            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(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