diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs
index 361b170610..d42dca28aa 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs
@@ -1,6 +1,7 @@
 using Ryujinx.Graphics.Gal;
 using Ryujinx.Graphics.Memory;
 using Ryujinx.Graphics.Texture;
+using Ryujinx.Profiler;
 
 namespace Ryujinx.Graphics.Graphics3d
 {
@@ -40,6 +41,8 @@ namespace Ryujinx.Graphics.Graphics3d
 
         private void TextureCopy(NvGpuVmm vmm)
         {
+            Profile.Begin(Profiles.GPU.Engine2d.TextureCopy);
+
             CopyOperation operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation);
 
             int  dstFormat = ReadRegister(NvGpuEngine2dReg.DstFormat);
@@ -221,6 +224,8 @@ namespace Ryujinx.Graphics.Graphics3d
                 dstBlitH);
 
             vmm.IsRegionModified(dstKey, ImageUtils.GetSize(dstTexture), NvGpuBufferType.Texture);
+        
+            Profile.End(Profiles.GPU.Engine2d.TextureCopy);
         }
 
         private static GalMemoryLayout GetLayout(bool linear)
@@ -255,4 +260,4 @@ namespace Ryujinx.Graphics.Graphics3d
             return Registers[(int)reg];
         }
     }
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs
index bbed642b82..29b6cc5df7 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs
@@ -5,6 +5,7 @@ using Ryujinx.Graphics.Shader;
 using Ryujinx.Graphics.Texture;
 using System;
 using System.Collections.Generic;
+using Ryujinx.Profiler;
 
 namespace Ryujinx.Graphics.Graphics3d
 {
@@ -89,7 +90,15 @@ namespace Ryujinx.Graphics.Graphics3d
         {
             if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method))
             {
+                ProfileConfig profile = Profiles.GPU.Engine3d.CallMethod;
+
+                profile.SessionItem = method.Method.Name;
+
+                Profile.Begin(profile);
+
                 method(vmm, methCall);
+
+                Profile.End(profile);
             }
             else
             {
@@ -99,13 +108,19 @@ namespace Ryujinx.Graphics.Graphics3d
 
         private void VertexEndGl(NvGpuVmm vmm, GpuMethodCall methCall)
         {
+            Profile.Begin(Profiles.GPU.Engine3d.VertexEnd);
+
             LockCaches();
 
+            Profile.Begin(Profiles.GPU.Engine3d.ConfigureState);
+
             GalPipelineState state = new GalPipelineState();
 
             // Framebuffer must be run configured because viewport dimensions may be used in other methods
             SetFrameBuffer(state);
 
+            Profile.End(Profiles.GPU.Engine3d.ConfigureState);
+
             for (int fbIndex = 0; fbIndex < 8; fbIndex++)
             {
                 SetFrameBuffer(vmm, fbIndex);
@@ -135,6 +150,8 @@ namespace Ryujinx.Graphics.Graphics3d
             DispatchRender(vmm, state);
 
             UnlockCaches();
+
+            Profile.End(Profiles.GPU.Engine3d.VertexEnd);
         }
 
         private void LockCaches()
@@ -153,6 +170,8 @@ namespace Ryujinx.Graphics.Graphics3d
 
         private void ClearBuffers(NvGpuVmm vmm, GpuMethodCall methCall)
         {
+            Profile.Begin(Profiles.GPU.Engine3d.ClearBuffers);
+
             int attachment = (methCall.Argument >> 6) & 0xf;
 
             GalClearBufferFlags flags = (GalClearBufferFlags)(methCall.Argument & 0x3f);
@@ -178,10 +197,18 @@ namespace Ryujinx.Graphics.Graphics3d
 
             _gpu.Renderer.Pipeline.ResetDepthMask();
             _gpu.Renderer.Pipeline.ResetColorMask(attachment);
+
+            Profile.End(Profiles.GPU.Engine3d.ClearBuffers);
         }
 
         private void SetFrameBuffer(NvGpuVmm vmm, int fbIndex)
         {
+            ProfileConfig profile = Profiles.GPU.Engine3d.SetFrameBuffer;
+
+            profile.SessionItem = fbIndex.ToString();
+
+            Profile.Begin(profile);
+
             long va = MakeInt64From2xInt32(NvGpuEngine3dReg.FrameBufferNAddress + fbIndex * 0x10);
 
             int surfFormat = ReadRegister(NvGpuEngine3dReg.FrameBufferNFormat + fbIndex * 0x10);
@@ -190,6 +217,8 @@ namespace Ryujinx.Graphics.Graphics3d
             {
                 _gpu.Renderer.RenderTarget.UnbindColor(fbIndex);
 
+                Profile.End(profile);
+
                 return;
             }
 
@@ -227,6 +256,8 @@ namespace Ryujinx.Graphics.Graphics3d
             _gpu.ResourceManager.SendColorBuffer(vmm, key, fbIndex, image);
 
             _gpu.Renderer.RenderTarget.SetViewport(fbIndex, _viewportX0, _viewportY0, _viewportX1 - _viewportX0, _viewportY1 - _viewportY0);
+
+            Profile.End(profile);
         }
 
         private void SetFrameBuffer(GalPipelineState state)
@@ -248,6 +279,8 @@ namespace Ryujinx.Graphics.Graphics3d
 
         private void SetZeta(NvGpuVmm vmm)
         {
+            Profile.Begin(Profiles.GPU.Engine3d.SetZeta);
+
             long va = MakeInt64From2xInt32(NvGpuEngine3dReg.ZetaAddress);
 
             int zetaFormat = ReadRegister(NvGpuEngine3dReg.ZetaFormat);
@@ -264,6 +297,8 @@ namespace Ryujinx.Graphics.Graphics3d
             {
                 _gpu.Renderer.RenderTarget.UnbindZeta();
 
+                Profile.End(Profiles.GPU.Engine3d.SetZeta);
+
                 return;
             }
 
@@ -278,10 +313,14 @@ namespace Ryujinx.Graphics.Graphics3d
             GalImage image = new GalImage(width, height, 1, 1, 1, gobBlockHeight, 1, layout, format, GalTextureTarget.TwoD);
 
             _gpu.ResourceManager.SendZetaBuffer(vmm, key, image);
+
+            Profile.End(Profiles.GPU.Engine3d.SetZeta);
         }
 
         private long[] UploadShaders(NvGpuVmm vmm)
         {
+            Profile.Begin(Profiles.GPU.Engine3d.UploadShaders);
+
             long[] keys = new long[5];
 
             long basePosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
@@ -339,6 +378,8 @@ namespace Ryujinx.Graphics.Graphics3d
                 _gpu.Renderer.Shader.Bind(key);
             }
 
+            Profile.End(Profiles.GPU.Engine3d.UploadShaders);
+
             return keys;
         }
 
@@ -619,6 +660,8 @@ namespace Ryujinx.Graphics.Graphics3d
 
         private void UploadTextures(NvGpuVmm vmm, GalPipelineState state, long[] keys)
         {
+            Profile.Begin(Profiles.GPU.Engine3d.UploadTextures);
+
             long baseShPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.ShaderAddress);
 
             int textureCbIndex = ReadRegister(NvGpuEngine3dReg.TextureCbIndex);
@@ -660,6 +703,8 @@ namespace Ryujinx.Graphics.Graphics3d
                 _gpu.Renderer.Texture.Bind(key, index, image);
                 _gpu.Renderer.Texture.SetSampler(image, sampler);
             }
+
+            Profile.End(Profiles.GPU.Engine3d.UploadTextures);
         }
 
         private (long, GalImage, GalTextureSampler) UploadTexture(NvGpuVmm vmm, int textureHandle)
@@ -671,6 +716,8 @@ namespace Ryujinx.Graphics.Graphics3d
                 return (0, default(GalImage), default(GalTextureSampler));
             }
 
+            Profile.Begin(Profiles.GPU.Engine3d.UploadTexture);
+
             bool linkedTsc = ReadRegisterBool(NvGpuEngine3dReg.LinkedTsc);
 
             int ticIndex = (textureHandle >>  0) & 0xfffff;
@@ -702,17 +749,23 @@ namespace Ryujinx.Graphics.Graphics3d
 
             if (key == -1)
             {
+                Profile.End(Profiles.GPU.Engine3d.UploadTexture);
+
                 //FIXME: Shouldn't ignore invalid addresses.
                 return (0, default(GalImage), default(GalTextureSampler));
             }
 
             _gpu.ResourceManager.SendTexture(vmm, key, image);
 
+            Profile.End(Profiles.GPU.Engine3d.UploadTexture);
+
             return (key, image, sampler);
         }
 
         private void UploadConstBuffers(NvGpuVmm vmm, GalPipelineState state, long[] keys)
         {
+            Profile.Begin(Profiles.GPU.Engine3d.UploadConstBuffers);
+
             for (int stage = 0; stage < keys.Length; stage++)
             {
                 foreach (CBufferDescriptor desc in _gpu.Renderer.Shader.GetConstBufferUsage(keys[stage]))
@@ -741,10 +794,14 @@ namespace Ryujinx.Graphics.Graphics3d
                     state.ConstBufferKeys[stage][desc.Slot] = key;
                 }
             }
+
+            Profile.End(Profiles.GPU.Engine3d.UploadConstBuffers);
         }
 
         private void UploadVertexArrays(NvGpuVmm vmm, GalPipelineState state)
         {
+            Profile.Begin(Profiles.GPU.Engine3d.UploadVertexArrays);
+
             long ibPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
 
             long iboKey = vmm.GetPhysicalAddress(ibPosition);
@@ -956,6 +1013,8 @@ namespace Ryujinx.Graphics.Graphics3d
                 state.VertexBindings[index].Divisor   = vertexDivisor;
                 state.VertexBindings[index].Attribs   = attribs[index].ToArray();
             }
+
+            Profile.End(Profiles.GPU.Engine3d.UploadVertexArrays);
         }
 
         private void DispatchRender(NvGpuVmm vmm, GalPipelineState state)
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs
index 45b0bbd792..172c919bd4 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs
@@ -1,6 +1,7 @@
 using Ryujinx.Graphics.Memory;
 using Ryujinx.Graphics.Texture;
 using System.Collections.Generic;
+using Ryujinx.Profiler;
 
 namespace Ryujinx.Graphics.Graphics3d
 {
@@ -37,7 +38,13 @@ namespace Ryujinx.Graphics.Graphics3d
         {
             if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method))
             {
+                ProfileConfig profile = Profiles.GPU.EngineM2mf.CallMethod;
+
+                profile.SessionItem = method.Method.Name;
+
+                Profile.Begin(profile);
                 method(vmm, methCall);
+                Profile.End(profile);
             }
             else
             {
@@ -47,6 +54,8 @@ namespace Ryujinx.Graphics.Graphics3d
 
         private void Execute(NvGpuVmm vmm, GpuMethodCall methCall)
         {
+            Profile.Begin(Profiles.GPU.EngineM2mf.Execute);
+
             //TODO: Some registers and copy modes are still not implemented.
             int control = methCall.Argument;
 
@@ -176,6 +185,8 @@ namespace Ryujinx.Graphics.Graphics3d
             {
                 vmm.Memory.CopyBytes(srcPa, dstPa, xCount);
             }
+
+            Profile.End(Profiles.GPU.EngineM2mf.Execute);
         }
 
         private long MakeInt64From2xInt32(NvGpuEngineM2mfReg reg)
@@ -200,4 +211,4 @@ namespace Ryujinx.Graphics.Graphics3d
             Registers[(int)reg] = value;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs
index d24f2303d9..83ad0e704d 100644
--- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs
+++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs
@@ -1,6 +1,7 @@
 using Ryujinx.Graphics.Memory;
 using Ryujinx.Graphics.Texture;
 using System.Collections.Generic;
+using Ryujinx.Profiler;
 
 namespace Ryujinx.Graphics.Graphics3d
 {
@@ -54,7 +55,13 @@ namespace Ryujinx.Graphics.Graphics3d
         {
             if (_methods.TryGetValue(methCall.Method, out NvGpuMethod method))
             {
+                ProfileConfig profile = Profiles.GPU.EngineP2mf.PushData;
+
+                profile.SessionItem = method.Method.Name;
+
+                Profile.Begin(profile);
                 method(vmm, methCall);
+                Profile.End(profile);
             }
             else
             {
@@ -64,6 +71,8 @@ namespace Ryujinx.Graphics.Graphics3d
 
         private void Execute(NvGpuVmm vmm, GpuMethodCall methCall)
         {
+            Profile.Begin(Profiles.GPU.EngineP2mf.Execute);
+
             //TODO: Some registers and copy modes are still not implemented.
             int control = methCall.Argument;
 
@@ -97,6 +106,8 @@ namespace Ryujinx.Graphics.Graphics3d
             _copySize   = lineLengthIn * lineCount;
 
             _buffer = new byte[_copySize];
+
+            Profile.End(Profiles.GPU.EngineP2mf.Execute);
         }
 
         private void PushData(NvGpuVmm vmm, GpuMethodCall methCall)
@@ -106,6 +117,8 @@ namespace Ryujinx.Graphics.Graphics3d
                 return;
             }
 
+            Profile.Begin(Profiles.GPU.EngineP2mf.PushData);
+
             for (int shift = 0; shift < 32 && _copyOffset < _copySize; shift += 8, _copyOffset++)
             {
                 _buffer[_copyOffset] = (byte)(methCall.Argument >> shift);
@@ -137,6 +150,8 @@ namespace Ryujinx.Graphics.Graphics3d
 
                 _buffer = null;
             }
+
+            Profile.End(Profiles.GPU.EngineP2mf.PushData);
         }
 
         private long MakeInt64From2xInt32(NvGpuEngineP2mfReg reg)
@@ -161,4 +176,4 @@ namespace Ryujinx.Graphics.Graphics3d
             Registers[(int)reg] = value;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Profiler/ProfileConfig.cs b/Ryujinx.Profiler/ProfileConfig.cs
index 6a2b2bc084..d70da6023e 100644
--- a/Ryujinx.Profiler/ProfileConfig.cs
+++ b/Ryujinx.Profiler/ProfileConfig.cs
@@ -105,6 +105,132 @@ namespace Ryujinx.Profiler
             };
         }
 
+        public static class GPU
+        {
+            public static class Engine2d
+            {
+                public static ProfileConfig TextureCopy = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine2D",
+                    SessionGroup = "TextureCopy"
+                };
+            }
+
+            public static class Engine3d
+            {
+                public static ProfileConfig CallMethod = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "CallMethod",
+                };
+
+                public static ProfileConfig VertexEnd = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "VertexEnd"
+                };
+
+                public static ProfileConfig ClearBuffers = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "ClearBuffers"
+                };
+
+                public static ProfileConfig SetFrameBuffer = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "SetFrameBuffer",
+                };
+
+                public static ProfileConfig SetZeta = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "SetZeta"
+                };
+
+                public static ProfileConfig UploadShaders = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "UploadShaders"
+                };
+
+                public static ProfileConfig UploadTextures = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "UploadTextures"
+                };
+
+                public static ProfileConfig UploadTexture = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "UploadTexture"
+                };
+
+                public static ProfileConfig UploadConstBuffers = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "UploadConstBuffers"
+                };
+
+                public static ProfileConfig UploadVertexArrays = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "UploadVertexArrays"
+                };
+
+                public static ProfileConfig ConfigureState = new ProfileConfig()
+                {
+                    Category     = "GPU.Engine3D",
+                    SessionGroup = "ConfigureState"
+                };
+            }
+
+            public static class EngineM2mf
+            {
+                public static ProfileConfig CallMethod = new ProfileConfig()
+                {
+                    Category     = "GPU.EngineM2mf",
+                    SessionGroup = "CallMethod",
+                };
+
+                public static ProfileConfig Execute = new ProfileConfig()
+                {
+                    Category     = "GPU.EngineM2mf",
+                    SessionGroup = "Execute",
+                };
+            }
+
+            public static class EngineP2mf
+            {
+                public static ProfileConfig CallMethod = new ProfileConfig()
+                {
+                    Category     = "GPU.EngineP2mf",
+                    SessionGroup = "CallMethod",
+                };
+
+                public static ProfileConfig Execute = new ProfileConfig()
+                {
+                    Category     = "GPU.EngineP2mf",
+                    SessionGroup = "Execute",
+                };
+
+                public static ProfileConfig PushData = new ProfileConfig()
+                {
+                    Category     = "GPU.EngineP2mf",
+                    SessionGroup = "PushData",
+                };
+            }
+
+            public static class Shader
+            {
+                public static ProfileConfig Decompile = new ProfileConfig()
+                {
+                    Category     = "GPU.Shader",
+                    SessionGroup = "Decompile",
+                };
+            }
+        }
+
         public static ProfileConfig ServiceCall = new ProfileConfig()
         {
             Category = "ServiceCall",