diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs
new file mode 100644
index 0000000000..69fce6d31d
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLExtension.cs
@@ -0,0 +1,43 @@
+using OpenTK.Graphics.OpenGL;
+
+namespace Ryujinx.Graphics.Gal.OpenGL
+{
+    static class OGLExtension
+    {
+        private static bool Initialized = false;
+
+        private static bool EnhancedLayouts;
+
+        public static bool HasEnhancedLayouts()
+        {
+            EnsureInitialized();
+
+            return EnhancedLayouts;
+        }
+
+        private static void EnsureInitialized()
+        {
+            if (Initialized)
+            {
+                return;
+            }
+
+            EnhancedLayouts = HasExtension("GL_ARB_enhanced_layouts");
+        }
+
+        private static bool HasExtension(string Name)
+        {
+            int NumExtensions = GL.GetInteger(GetPName.NumExtensions);
+
+            for (int Extension = 0; Extension < NumExtensions; Extension++)
+            {
+                if (GL.GetString(StringNameIndexed.Extensions, Extension) == Name)
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
index ad71775502..fe98aa0911 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLShader.cs
@@ -118,20 +118,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
             if (IsDualVp)
             {
-                ShaderDumper.Dump(Memory, Position  + 0x50, Type, "a");
-                ShaderDumper.Dump(Memory, PositionB + 0x50, Type, "b");
+                ShaderDumper.Dump(Memory, Position,  Type, "a");
+                ShaderDumper.Dump(Memory, PositionB, Type, "b");
 
                 Program = Decompiler.Decompile(
                     Memory,
-                    Position  + 0x50,
-                    PositionB + 0x50,
+                    Position,
+                    PositionB,
                     Type);
             }
             else
             {
-                ShaderDumper.Dump(Memory, Position + 0x50, Type);
+                ShaderDumper.Dump(Memory, Position, Type);
 
-                Program = Decompiler.Decompile(Memory, Position + 0x50, Type);
+                Program = Decompiler.Decompile(Memory, Position, Type);
             }
 
             return new ShaderStage(
@@ -198,6 +198,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
         private void Bind(ShaderStage Stage)
         {
+            if (Stage.Type == GalShaderType.Geometry)
+            {
+                //Enhanced layouts are required for Geometry shaders
+                //skip this stage if current driver has no ARB_enhanced_layouts
+                if (!OGLExtension.HasEnhancedLayouts())
+                {
+                    return;
+                }
+            }
+
             switch (Stage.Type)
             {
                 case GalShaderType.Vertex:         Current.Vertex         = Stage; break;
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
index d3284f9f55..7688545c02 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
@@ -4,13 +4,13 @@ namespace Ryujinx.Graphics.Gal.Shader
 {
     class GlslDecl
     {
+        public const int LayerAttr       = 0x064;
         public const int TessCoordAttrX  = 0x2f0;
         public const int TessCoordAttrY  = 0x2f4;
         public const int TessCoordAttrZ  = 0x2f8;
         public const int InstanceIdAttr  = 0x2f8;
         public const int VertexIdAttr    = 0x2fc;
         public const int FaceAttr        = 0x3fc;
-        public const int GlPositionWAttr = 0x7c;
 
         public const int MaxUboSize = 1024;
 
@@ -210,7 +210,8 @@ namespace Ryujinx.Graphics.Gal.Shader
                     //This is a built-in input variable.
                     if (Abuf.Offs == VertexIdAttr ||
                         Abuf.Offs == InstanceIdAttr ||
-                        Abuf.Offs == FaceAttr)
+                        Abuf.Offs == FaceAttr ||
+                        Abuf.Offs == LayerAttr)
                     {
                         break;
                     }
@@ -254,6 +255,8 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                         m_Attributes.Add(Index, DeclInfo);
                     }
+
+                    Traverse(Abuf, Abuf.Vertex);
                     break;
                 }
 
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
index 575fb72f9a..a338f40413 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
@@ -21,10 +21,14 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private const string IdentationStr = "    ";
 
+        private const int MaxVertexInput = 3;
+
         private static string[] ElemTypes = new string[] { "float", "vec2", "vec3", "vec4" };
 
         private GlslDecl Decl;
 
+        private ShaderHeader Header, HeaderB;
+
         private ShaderIrBlock[] Blocks, BlocksB;
 
         private StringBuilder SB;
@@ -50,6 +54,7 @@ namespace Ryujinx.Graphics.Gal.Shader
                 { ShaderIrInst.Cle,    GetCleExpr    },
                 { ShaderIrInst.Clt,    GetCltExpr    },
                 { ShaderIrInst.Cne,    GetCneExpr    },
+                { ShaderIrInst.Cut,    GetCutExpr    },
                 { ShaderIrInst.Exit,   GetExitExpr   },
                 { ShaderIrInst.Fabs,   GetAbsExpr    },
                 { ShaderIrInst.Fadd,   GetAddExpr    },
@@ -110,6 +115,9 @@ namespace Ryujinx.Graphics.Gal.Shader
             long          VpBPosition,
             GalShaderType ShaderType)
         {
+            Header  = new ShaderHeader(Memory, VpAPosition);
+            HeaderB = new ShaderHeader(Memory, VpBPosition);
+
             Blocks  = ShaderDecoder.Decode(Memory, VpAPosition);
             BlocksB = ShaderDecoder.Decode(Memory, VpBPosition);
 
@@ -123,6 +131,9 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         public GlslProgram Decompile(IGalMemory Memory, long Position, GalShaderType ShaderType)
         {
+            Header  = new ShaderHeader(Memory, Position);
+            HeaderB = null;
+
             Blocks  = ShaderDecoder.Decode(Memory, Position);
             BlocksB = null;
 
@@ -137,6 +148,7 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             SB.AppendLine("#version 410 core");
 
+            PrintDeclHeader();
             PrintDeclTextures();
             PrintDeclUniforms();
             PrintDeclAttributes();
@@ -170,6 +182,37 @@ namespace Ryujinx.Graphics.Gal.Shader
                 Decl.Uniforms.Values);
         }
 
+        private void PrintDeclHeader()
+        {
+            if (Decl.ShaderType == GalShaderType.Geometry)
+            {
+                int MaxVertices = Header.MaxOutputVertexCount;
+
+                string OutputTopology;
+
+                switch (Header.OutputTopology)
+                {
+                    case ShaderHeader.PointList:     OutputTopology = "points";         break;
+                    case ShaderHeader.LineStrip:     OutputTopology = "line_strip";     break;
+                    case ShaderHeader.TriangleStrip: OutputTopology = "triangle_strip"; break;
+
+                    default: throw new InvalidOperationException();
+                }
+
+                SB.AppendLine("#extension GL_ARB_enhanced_layouts : require");
+
+                SB.AppendLine();
+
+                SB.AppendLine("// Stubbed. Maxwell geometry shaders don't inform input geometry type");
+
+                SB.AppendLine("layout(triangles) in;" + Environment.NewLine);
+
+                SB.AppendLine($"layout({OutputTopology}, max_vertices = {MaxVertices}) out;");
+
+                SB.AppendLine();
+            }
+        }
+
         private void PrintDeclTextures()
         {
             PrintDecls(Decl.Textures, "uniform sampler2D");
@@ -201,7 +244,9 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private void PrintDeclAttributes()
         {
-            PrintDecls(Decl.Attributes);
+            string GeometryArray = (Decl.ShaderType == GalShaderType.Geometry) ? "[" + MaxVertexInput + "]" : "";
+
+            PrintDecls(Decl.Attributes, Suffix: GeometryArray);
         }
 
         private void PrintDeclInAttributes()
@@ -211,7 +256,27 @@ namespace Ryujinx.Graphics.Gal.Shader
                 SB.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") in vec4 " + GlslDecl.PositionOutAttrName + ";");
             }
 
-            PrintDeclAttributes(Decl.InAttributes.Values, "in");
+            if (Decl.ShaderType == GalShaderType.Geometry)
+            {
+                if (Decl.InAttributes.Count > 0)
+                {
+                    SB.AppendLine("in Vertex {");
+
+                    foreach (ShaderDeclInfo DeclInfo in Decl.InAttributes.Values.OrderBy(DeclKeySelector))
+                    {
+                        if (DeclInfo.Index >= 0)
+                        {
+                            SB.AppendLine(IdentationStr + "layout (location = " + DeclInfo.Index + ") " + GetDecl(DeclInfo) + "; ");
+                        }
+                    }
+
+                    SB.AppendLine("} block_in[];" + Environment.NewLine);
+                }
+            }
+            else
+            {
+                PrintDeclAttributes(Decl.InAttributes.Values, "in");
+            }
         }
 
         private void PrintDeclOutAttributes()
@@ -254,7 +319,7 @@ namespace Ryujinx.Graphics.Gal.Shader
             PrintDecls(Decl.Preds, "bool");
         }
 
-        private void PrintDecls(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, string CustomType = null)
+        private void PrintDecls(IReadOnlyDictionary<int, ShaderDeclInfo> Dict, string CustomType = null, string Suffix = "")
         {
             foreach (ShaderDeclInfo DeclInfo in Dict.Values.OrderBy(DeclKeySelector))
             {
@@ -262,15 +327,15 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                 if (CustomType != null)
                 {
-                    Name = CustomType + " " + DeclInfo.Name + ";";
+                    Name = CustomType + " " + DeclInfo.Name + Suffix + ";";
                 }
                 else if (DeclInfo.Name == GlslDecl.FragmentOutputName)
                 {
-                    Name = "layout (location = 0) out " + GetDecl(DeclInfo) + ";" + Environment.NewLine;
+                    Name = "layout (location = 0) out " + GetDecl(DeclInfo) + Suffix + ";" + Environment.NewLine;
                 }
                 else
                 {
-                    Name = GetDecl(DeclInfo) + ";";
+                    Name = GetDecl(DeclInfo) + Suffix + ";";
                 }
 
                 SB.AppendLine(Name);
@@ -307,7 +372,21 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                 string Swizzle = ".xyzw".Substring(0, DeclInfo.Size + 1);
 
-                SB.AppendLine(IdentationStr + Attr.Name + Swizzle + " = " + DeclInfo.Name + ";");
+                if (Decl.ShaderType == GalShaderType.Geometry)
+                {
+                    for (int Vertex = 0; Vertex < MaxVertexInput; Vertex++)
+                    {
+                        string Dst = Attr.Name + "[" + Vertex + "]" + Swizzle;
+
+                        string Src = "block_in[" + Vertex + "]." + DeclInfo.Name;
+
+                        SB.AppendLine(IdentationStr + Dst + " = " + Src + ";");
+                    }
+                }
+                else
+                {
+                    SB.AppendLine(IdentationStr + Attr.Name + Swizzle + " = " + DeclInfo.Name + ";");
+                }
             }
 
             if (BlocksB != null)
@@ -320,6 +399,16 @@ namespace Ryujinx.Graphics.Gal.Shader
                 SB.AppendLine(IdentationStr + GlslDecl.ProgramName + "();");
             }
 
+            if (Decl.ShaderType != GalShaderType.Geometry)
+            {
+                PrintAttrToOutput();
+            }
+
+            SB.AppendLine("}");
+        }
+
+        private void PrintAttrToOutput(string Identation = IdentationStr)
+        {
             foreach (KeyValuePair<int, ShaderDeclInfo> KV in Decl.OutAttributes)
             {
                 if (!Decl.Attributes.TryGetValue(KV.Key, out ShaderDeclInfo Attr))
@@ -331,21 +420,26 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                 string Swizzle = ".xyzw".Substring(0, DeclInfo.Size + 1);
 
-                SB.AppendLine(IdentationStr + DeclInfo.Name + " = " + Attr.Name + Swizzle + ";");
+                string Name = Attr.Name;
+
+                if (Decl.ShaderType == GalShaderType.Geometry)
+                {
+                    Name += "[0]";
+                }
+
+                SB.AppendLine(Identation + DeclInfo.Name + " = " + Name + Swizzle + ";");
             }
 
             if (Decl.ShaderType == GalShaderType.Vertex)
             {
-                SB.AppendLine(IdentationStr + "gl_Position.xy *= " + GlslDecl.FlipUniformName + ";");
+                SB.AppendLine(Identation + "gl_Position.xy *= " + GlslDecl.FlipUniformName + ";");
             }
 
             if (Decl.ShaderType != GalShaderType.Fragment)
             {
-                SB.AppendLine(IdentationStr + GlslDecl.PositionOutAttrName + " = gl_Position;");
-                SB.AppendLine(IdentationStr + GlslDecl.PositionOutAttrName + ".w = 1;");
+                SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + " = gl_Position;");
+                SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + ".w = 1;");
             }
-
-            SB.AppendLine("}");
         }
 
         private void PrintBlockScope(
@@ -484,11 +578,17 @@ namespace Ryujinx.Graphics.Gal.Shader
                         {
                             SB.AppendLine(Identation + "continue;");
                         }
-
-                        continue;
                     }
+                    else if (Op.Inst == ShaderIrInst.Emit)
+                    {
+                        PrintAttrToOutput(Identation);
 
-                    SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
+                        SB.AppendLine(Identation + "EmitVertex();");
+                    }
+                    else
+                    {
+                        SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
+                    }
                 }
                 else if (Node is ShaderIrCmnt Cmnt)
                 {
@@ -634,6 +734,14 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private string GetOutAbufName(ShaderIrOperAbuf Abuf)
         {
+            if (Decl.ShaderType == GalShaderType.Geometry)
+            {
+                switch (Abuf.Offs)
+                {
+                    case GlslDecl.LayerAttr: return "gl_Layer";
+                }
+            }
+
             return GetAttrTempName(Abuf);
         }
 
@@ -692,7 +800,16 @@ namespace Ryujinx.Graphics.Gal.Shader
                 throw new InvalidOperationException();
             }
 
-            return DeclInfo.Name + Swizzle;
+            if (Decl.ShaderType == GalShaderType.Geometry)
+            {
+                string Vertex = "floatBitsToInt(" + GetSrcExpr(Abuf.Vertex) + ")";
+
+                return DeclInfo.Name + "[" + Vertex + "]" + Swizzle;
+            }
+            else
+            {
+                return DeclInfo.Name + Swizzle;
+            }
         }
 
         private string GetName(ShaderIrOperGpr Gpr)
@@ -805,6 +922,8 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private string GetCneExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "!=");
 
+        private string GetCutExpr(ShaderIrOp Op) => "EndPrimitive()";
+
         private string GetCneuExpr(ShaderIrOp Op) => GetBinaryExprWithNaN(Op, "!=");
 
         private string GetCnumExpr(ShaderIrOp Op) => GetUnaryCall(Op, "!isnan");
@@ -1104,8 +1223,9 @@ namespace Ryujinx.Graphics.Gal.Shader
             switch (Node)
             {
                 case ShaderIrOperAbuf Abuf:
-                    return Abuf.Offs == GlslDecl.VertexIdAttr ||
+                    return Abuf.Offs == GlslDecl.LayerAttr ||
                            Abuf.Offs == GlslDecl.InstanceIdAttr ||
+                           Abuf.Offs == GlslDecl.VertexIdAttr ||
                            Abuf.Offs == GlslDecl.FaceAttr
                         ? OperType.I32
                         : OperType.F32;
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
index a44073513c..00f072f192 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
@@ -442,6 +442,41 @@ namespace Ryujinx.Graphics.Gal.Shader
             return Signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
         }
 
+        public static void Vmad(ShaderIrBlock Block, long OpCode)
+        {
+            ShaderIrNode OperA = GetOperGpr8(OpCode);
+
+            ShaderIrNode OperB;
+
+            if (((OpCode >> 50) & 1) != 0)
+            {
+                OperB = GetOperGpr20(OpCode);
+            }
+            else
+            {
+                OperB = GetOperImm19_20(OpCode);
+            }
+
+            ShaderIrOperGpr OperC = GetOperGpr39(OpCode);
+
+            ShaderIrNode Tmp = new ShaderIrOp(ShaderIrInst.Mul, OperA, OperB);
+
+            ShaderIrNode Final = new ShaderIrOp(ShaderIrInst.Add, Tmp, OperC);
+
+            int Shr = (int)((OpCode >> 51) & 3);
+
+            if (Shr != 0)
+            {
+                int Shift = (Shr == 2) ? 15 : 7;
+
+                Final = new ShaderIrOp(ShaderIrInst.Lsr, Final, new ShaderIrOperImm(Shift));
+            }
+
+            Block.AddNode(new ShaderIrCmnt("Stubbed. Instruction is reduced to a * b + c"));
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Final), OpCode));
+        }
+
         public static void Xmad_CR(ShaderIrBlock Block, long OpCode)
         {
             EmitXmad(Block, OpCode, ShaderOper.CR);
@@ -819,6 +854,8 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             OperA = GetAluFabsFneg(OperA, AbsA, NegA);
 
+            Block.AddNode(new ShaderIrCmnt("Stubbed."));
+
             Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode));
         }
 
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
index 1f1b158ef8..7d7b2f6c6d 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
@@ -7,14 +7,15 @@ namespace Ryujinx.Graphics.Gal.Shader
         public static ShaderIrOperAbuf[] GetOperAbuf20(long OpCode)
         {
             int Abuf = (int)(OpCode >> 20) & 0x3ff;
-            int Reg  = (int)(OpCode >> 39) & 0xff;
             int Size = (int)(OpCode >> 47) & 3;
 
+            ShaderIrOperGpr Vertex = GetOperGpr39(OpCode);
+
             ShaderIrOperAbuf[] Opers = new ShaderIrOperAbuf[Size + 1];
 
             for (int Index = 0; Index <= Size; Index++)
             {
-                Opers[Index] = new ShaderIrOperAbuf(Abuf + Index * 4, Reg);
+                Opers[Index] = new ShaderIrOperAbuf(Abuf + Index * 4, Vertex);
             }
 
             return Opers;
@@ -23,9 +24,8 @@ namespace Ryujinx.Graphics.Gal.Shader
         public static ShaderIrOperAbuf GetOperAbuf28(long OpCode)
         {
             int Abuf = (int)(OpCode >> 28) & 0x3ff;
-            int Reg  = (int)(OpCode >> 39) & 0xff;
 
-            return new ShaderIrOperAbuf(Abuf, Reg);
+            return new ShaderIrOperAbuf(Abuf, GetOperGpr39(OpCode));
         }
 
         public static ShaderIrOperCbuf GetOperCbuf34(long OpCode)
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
index 083b0c63a1..aea7e744dc 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
@@ -35,6 +35,9 @@ namespace Ryujinx.Graphics.Gal.Shader
         {
             ShaderIrNode[] Opers = GetOperAbuf20(OpCode);
 
+            //Used by GS
+            ShaderIrOperGpr Vertex = GetOperGpr39(OpCode);
+
             int Index = 0;
 
             foreach (ShaderIrNode OperA in Opers)
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
index 4c9e59cf0c..c6b71fb01a 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
@@ -85,6 +85,16 @@ namespace Ryujinx.Graphics.Gal.Shader
             EmitI2i(Block, OpCode, ShaderOper.RR);
         }
 
+        public static void Isberd(ShaderIrBlock Block, long OpCode)
+        {
+            //This instruction seems to be used to translate from an address to a vertex index in a GS
+            //Stub it as such
+
+            Block.AddNode(new ShaderIrCmnt("Stubbed."));
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), GetOperGpr8(OpCode)), OpCode));
+        }
+
         public static void Mov_C(ShaderIrBlock Block, long OpCode)
         {
             ShaderIrOperCbuf Cbuf = GetOperCbuf34(OpCode);
@@ -128,6 +138,16 @@ namespace Ryujinx.Graphics.Gal.Shader
             EmitSel(Block, OpCode, ShaderOper.RR);
         }
 
+        public static void Mov_S(ShaderIrBlock Block, long OpCode)
+        {
+            Block.AddNode(new ShaderIrCmnt("Stubbed."));
+
+            //Zero is used as a special number to get a valid "0 * 0 + VertexIndex" in a GS
+            ShaderIrNode Source = new ShaderIrOperImm(0);
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Source), OpCode));
+        }
+
         private static void EmitF2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
         {
             bool NegA = ((OpCode >> 45) & 1) != 0;
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs
new file mode 100644
index 0000000000..591631ff99
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs
@@ -0,0 +1,29 @@
+using System;
+
+using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
+
+namespace Ryujinx.Graphics.Gal.Shader
+{
+    static partial class ShaderDecode
+    {
+        public static void Out_R(ShaderIrBlock Block, long OpCode)
+        {
+            //TODO: Those registers have to be used for something
+            ShaderIrOperGpr Gpr0  = GetOperGpr0(OpCode);
+            ShaderIrOperGpr Gpr8  = GetOperGpr8(OpCode);
+            ShaderIrOperGpr Gpr20 = GetOperGpr20(OpCode);
+
+            int Type = (int)((OpCode >> 39) & 3);
+
+            if ((Type & 1) != 0)
+            {
+                Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Emit), OpCode));
+            }
+
+            if ((Type & 2) != 0)
+            {
+                Block.AddNode(GetPredNode(new ShaderIrOp(ShaderIrInst.Cut), OpCode));
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
index 85522ff950..98f371b573 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
@@ -4,6 +4,8 @@ namespace Ryujinx.Graphics.Gal.Shader
 {
     static class ShaderDecoder
     {
+        private const long HeaderSize = 0x50;
+
         private const bool AddDbgComments = true;
 
         public static ShaderIrBlock[] Decode(IGalMemory Memory, long Start)
@@ -32,13 +34,13 @@ namespace Ryujinx.Graphics.Gal.Shader
                 return Output;
             }
 
-            ShaderIrBlock Entry = Enqueue(Start);
+            ShaderIrBlock Entry = Enqueue(Start + HeaderSize);
 
             while (Blocks.Count > 0)
             {
                 ShaderIrBlock Current = Blocks.Dequeue();
 
-                FillBlock(Memory, Current);
+                FillBlock(Memory, Current, Start + HeaderSize);
 
                 //Set child blocks. "Branch" is the block the branch instruction
                 //points to (when taken), "Next" is the block at the next address,
@@ -122,14 +124,14 @@ namespace Ryujinx.Graphics.Gal.Shader
             return Graph;
         }
 
-        private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block)
+        private static void FillBlock(IGalMemory Memory, ShaderIrBlock Block, long Beginning)
         {
             long Position = Block.Position;
 
             do
             {
                 //Ignore scheduling instructions, which are written every 32 bytes.
-                if ((Position & 0x1f) == 0)
+                if (((Position - Beginning) & 0x1f) == 0)
                 {
                     Position += 8;
 
@@ -147,7 +149,7 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                 if (AddDbgComments)
                 {
-                    string DbgOpCode = $"0x{(Position - 8):x16}: 0x{OpCode:x16} ";
+                    string DbgOpCode = $"0x{(Position - Beginning - 8):x16}: 0x{OpCode:x16} ";
 
                     DbgOpCode += (Decode?.Method.Name ?? "???");
 
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs b/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs
new file mode 100644
index 0000000000..8e5057ed9e
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs
@@ -0,0 +1,73 @@
+namespace Ryujinx.Graphics.Gal.Shader
+{
+    class ShaderHeader
+    {
+        public const int PointList     = 1;
+        public const int LineStrip     = 6;
+        public const int TriangleStrip = 7;
+
+        public int  SphType         { get; private set; }
+        public int  Version         { get; private set; }
+        public int  ShaderType      { get; private set; }
+        public bool MrtEnable       { get; private set; }
+        public bool KillsPixels     { get; private set; }
+        public bool DoesGlobalStore { get; private set; }
+        public int  SassVersion     { get; private set; }
+        public bool DoesLoadOrStore { get; private set; }
+        public bool DoesFp64        { get; private set; }
+        public int  StreamOutMask   { get; private set; }
+
+        public int ShaderLocalMemoryLowSize { get; private set; }
+        public int PerPatchAttributeCount   { get; private set; }
+
+        public int ShaderLocalMemoryHighSize { get; private set; }
+        public int ThreadsPerInputPrimitive  { get; private set; }
+
+        public int ShaderLocalMemoryCrsSize { get; private set; }
+        public int OutputTopology           { get; private set; }
+
+        public int MaxOutputVertexCount { get; private set; }
+        public int StoreReqStart        { get; private set; }
+        public int StoreReqEnd          { get; private set; }
+
+        public ShaderHeader(IGalMemory Memory, long Position)
+        {
+            uint CommonWord0 = (uint)Memory.ReadInt32(Position + 0);
+            uint CommonWord1 = (uint)Memory.ReadInt32(Position + 4);
+            uint CommonWord2 = (uint)Memory.ReadInt32(Position + 8);
+            uint CommonWord3 = (uint)Memory.ReadInt32(Position + 12);
+            uint CommonWord4 = (uint)Memory.ReadInt32(Position + 16);
+
+            SphType         = ReadBits(CommonWord0,  0, 5);
+            Version         = ReadBits(CommonWord0,  5, 5);
+            ShaderType      = ReadBits(CommonWord0, 10, 4);
+            MrtEnable       = ReadBits(CommonWord0, 14, 1) != 0;
+            KillsPixels     = ReadBits(CommonWord0, 15, 1) != 0;
+            DoesGlobalStore = ReadBits(CommonWord0, 16, 1) != 0;
+            SassVersion     = ReadBits(CommonWord0, 17, 4);
+            DoesLoadOrStore = ReadBits(CommonWord0, 26, 1) != 0;
+            DoesFp64        = ReadBits(CommonWord0, 27, 1) != 0;
+            StreamOutMask   = ReadBits(CommonWord0, 28, 4);
+
+            ShaderLocalMemoryLowSize = ReadBits(CommonWord1,  0, 24);
+            PerPatchAttributeCount   = ReadBits(CommonWord1, 24,  8);
+
+            ShaderLocalMemoryHighSize = ReadBits(CommonWord2,  0, 24);
+            ThreadsPerInputPrimitive  = ReadBits(CommonWord2, 24,  8);
+
+            ShaderLocalMemoryCrsSize = ReadBits(CommonWord3,  0, 24);
+            OutputTopology           = ReadBits(CommonWord3, 24,  4);
+
+            MaxOutputVertexCount = ReadBits(CommonWord4,  0, 12);
+            StoreReqStart        = ReadBits(CommonWord4, 12,  8);
+            StoreReqEnd          = ReadBits(CommonWord4, 24,  8);
+        }
+
+        private static int ReadBits(uint Word, int Offset, int BitWidth)
+        {
+            uint Mask = (1u << BitWidth) - 1u;
+
+            return (int)((Word >> Offset) & Mask);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
index 9841f58ff0..fd86cadb10 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
@@ -82,6 +82,9 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         Bra,
         Exit,
-        Kil
+        Kil,
+        
+        Emit,
+        Cut
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs
index fa612de76a..f17d9c0e62 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs
@@ -2,13 +2,14 @@ namespace Ryujinx.Graphics.Gal.Shader
 {
     class ShaderIrOperAbuf : ShaderIrNode
     {
-        public int Offs     { get; private set; }
-        public int GprIndex { get; private set; }
+        public int Offs { get; private set; }
 
-        public ShaderIrOperAbuf(int Offs, int GprIndex)
+        public ShaderIrNode Vertex { get; private set; }
+
+        public ShaderIrOperAbuf(int Offs, ShaderIrNode Vertex)
         {
-            this.Offs     = Offs;
-            this.GprIndex = GprIndex;
+            this.Offs   = Offs;
+            this.Vertex = Vertex;
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
index 1ac1178512..3f20dc4465 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
@@ -74,6 +74,7 @@ namespace Ryujinx.Graphics.Gal.Shader
             Set("0100110000100x", ShaderDecode.Imnmx_C);
             Set("0011100x00100x", ShaderDecode.Imnmx_I);
             Set("0101110000100x", ShaderDecode.Imnmx_R);
+            Set("1110111111010x", ShaderDecode.Isberd);
             Set("11100000xxxxxx", ShaderDecode.Ipa);
             Set("0100110000011x", ShaderDecode.Iscadd_C);
             Set("0011100x00011x", ShaderDecode.Iscadd_I);
@@ -95,7 +96,9 @@ namespace Ryujinx.Graphics.Gal.Shader
             Set("0011100x10011x", ShaderDecode.Mov_I);
             Set("000000010000xx", ShaderDecode.Mov_I32);
             Set("0101110010011x", ShaderDecode.Mov_R);
+            Set("1111000011001x", ShaderDecode.Mov_S);
             Set("0101000010000x", ShaderDecode.Mufu);
+            Set("1111101111100x", ShaderDecode.Out_R);
             Set("0101000010010x", ShaderDecode.Psetp);
             Set("0100110010010x", ShaderDecode.Rro_C);
             Set("0011100x10010x", ShaderDecode.Rro_I);
@@ -114,6 +117,7 @@ namespace Ryujinx.Graphics.Gal.Shader
             Set("1101111101001x", ShaderDecode.Texq);
             Set("1101100xxxxxxx", ShaderDecode.Texs);
             Set("1101101xxxxxxx", ShaderDecode.Tlds);
+            Set("01011111xxxxxx", ShaderDecode.Vmad);
             Set("0100111xxxxxxx", ShaderDecode.Xmad_CR);
             Set("0011011x00xxxx", ShaderDecode.Xmad_I);
             Set("010100010xxxxx", ShaderDecode.Xmad_RC);
diff --git a/Ryujinx.Graphics/Gal/ShaderDumper.cs b/Ryujinx.Graphics/Gal/ShaderDumper.cs
index 7cd56b21ef..541368e89b 100644
--- a/Ryujinx.Graphics/Gal/ShaderDumper.cs
+++ b/Ryujinx.Graphics/Gal/ShaderDumper.cs
@@ -18,13 +18,21 @@ namespace Ryujinx.Graphics.Gal
 
             string FileName = "Shader" + DumpIndex.ToString("d4") + "." + ShaderExtension(Type) + ExtSuffix + ".bin";
 
-            string FilePath = Path.Combine(DumpDir(), FileName);
+            string FullPath = Path.Combine(FullDir(), FileName);
+            string CodePath = Path.Combine(CodeDir(), FileName);
 
             DumpIndex++;
 
-            using (FileStream Output = File.Create(FilePath))
-            using (BinaryWriter Writer = new BinaryWriter(Output))
+            using (FileStream FullFile = File.Create(FullPath))
+            using (FileStream CodeFile = File.Create(CodePath))
+            using (BinaryWriter FullWriter = new BinaryWriter(FullFile))
+            using (BinaryWriter CodeWriter = new BinaryWriter(CodeFile))
             {
+                for (long i = 0; i < 0x50; i += 4)
+                {
+                    FullWriter.Write(Memory.ReadInt32(Position + i));
+                }
+
                 long Offset = 0;
 
                 ulong Instruction = 0;
@@ -32,8 +40,8 @@ namespace Ryujinx.Graphics.Gal
                 //Dump until a NOP instruction is found
                 while ((Instruction >> 52 & 0xfff8) != 0x50b0)
                 {
-                    uint Word0 = (uint)Memory.ReadInt32(Position + Offset + 0);
-                    uint Word1 = (uint)Memory.ReadInt32(Position + Offset + 4);
+                    uint Word0 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 0);
+                    uint Word1 = (uint)Memory.ReadInt32(Position + 0x50 + Offset + 4);
 
                     Instruction = Word0 | (ulong)Word1 << 32;
 
@@ -44,7 +52,8 @@ namespace Ryujinx.Graphics.Gal
                         break;
                     }
 
-                    Writer.Write(Instruction);
+                    FullWriter.Write(Instruction);
+                    CodeWriter.Write(Instruction);
 
                     Offset += 8;
                 }
@@ -52,13 +61,24 @@ namespace Ryujinx.Graphics.Gal
                 //Align to meet nvdisasm requeriments
                 while (Offset % 0x20 != 0)
                 {
-                    Writer.Write(0);
+                    FullWriter.Write(0);
+                    CodeWriter.Write(0);
 
                     Offset += 4;
                 }
             }
         }
 
+        private static string FullDir()
+        {
+            return CreateAndReturn(Path.Combine(DumpDir(), "Full"));
+        }
+
+        private static string CodeDir()
+        {
+            return CreateAndReturn(Path.Combine(DumpDir(), "Code"));
+        }
+
         private static string DumpDir()
         {
             if (string.IsNullOrEmpty(RuntimeDir))
@@ -79,6 +99,16 @@ namespace Ryujinx.Graphics.Gal
             return RuntimeDir;
         }
 
+        private static string CreateAndReturn(string Dir)
+        {
+            if (!Directory.Exists(Dir))
+            {
+                Directory.CreateDirectory(Dir);
+            }
+
+            return Dir;
+        }
+
         private static string ShaderExtension(GalShaderType Type)
         {
             switch (Type)