diff --git a/Ryujinx.Graphics/Gal/GalTextureFormat.cs b/Ryujinx.Graphics/Gal/GalTextureFormat.cs
index 5b642961..8c2c718a 100644
--- a/Ryujinx.Graphics/Gal/GalTextureFormat.cs
+++ b/Ryujinx.Graphics/Gal/GalTextureFormat.cs
@@ -4,6 +4,7 @@ namespace Ryujinx.Graphics.Gal
     {
         A8B8G8R8 = 0x8,
         A1B5G5R5 = 0x14,
+        B5G6R5   = 0x15,
         BC1      = 0x24,
         BC2      = 0x25,
         BC3      = 0x26
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
index 6518de5f..03c3ef52 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
@@ -55,6 +55,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
             throw new ArgumentException(nameof(Type));
         }
 
+        public static (PixelFormat, PixelType) GetTextureFormat(GalTextureFormat Format)
+        {
+            switch (Format)
+            {
+                case GalTextureFormat.A8B8G8R8: return (PixelFormat.Rgba, PixelType.UnsignedByte);
+                case GalTextureFormat.A1B5G5R5: return (PixelFormat.Rgba, PixelType.UnsignedShort5551);
+                case GalTextureFormat.B5G6R5:   return (PixelFormat.Rgb,  PixelType.UnsignedShort565);
+            }
+
+            throw new NotImplementedException(Format.ToString());
+        }
+
         public static PixelInternalFormat GetCompressedTextureFormat(GalTextureFormat Format)
         {
             switch (Format)
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
index 559e0eda..681e6d67 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs
@@ -11,7 +11,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
             Textures = new int[80];
         }
 
-        public void Set(int Index, GalTexture Tex)
+        public void Set(int Index, GalTexture Texture)
         {
             GL.ActiveTexture(TextureUnit.Texture0 + Index);
 
@@ -19,29 +19,38 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
             GL.BindTexture(TextureTarget.Texture2D, Handle);
 
-            int W = Tex.Width;
-            int H = Tex.Height;
+            const int Border = 0;
 
-            byte[] Data = Tex.Data;
-
-            int Length = Data.Length;
-
-            if (IsCompressedTextureFormat(Tex.Format))
+            if (IsCompressedTextureFormat(Texture.Format))
             {
-                PixelInternalFormat Pif = OGLEnumConverter.GetCompressedTextureFormat(Tex.Format);
+                PixelInternalFormat InternalFmt = OGLEnumConverter.GetCompressedTextureFormat(Texture.Format);
 
-                GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Length, Data);
+                GL.CompressedTexImage2D(
+                    TextureTarget.Texture2D,
+                    0,
+                    InternalFmt,
+                    Texture.Width,
+                    Texture.Height,
+                    Border,
+                    Texture.Data.Length,
+                    Texture.Data);
             }
             else
             {
-                //TODO: Get those from Texture format.
-                const PixelInternalFormat Pif = PixelInternalFormat.Rgba;
+                const PixelInternalFormat InternalFmt = PixelInternalFormat.Rgba;
 
-                const PixelFormat Pf = PixelFormat.Rgba;
+                (PixelFormat, PixelType) Format = OGLEnumConverter.GetTextureFormat(Texture.Format);
 
-                const PixelType Pt = PixelType.UnsignedByte;
-
-                GL.TexImage2D(TextureTarget.Texture2D, 0, Pif, W, H, 0, Pf, Pt, Data);
+                GL.TexImage2D(
+                    TextureTarget.Texture2D,
+                    0,
+                    InternalFmt,
+                    Texture.Width,
+                    Texture.Height,
+                    Border,
+                    Format.Item1,
+                    Format.Item2,
+                    Texture.Data);
             }
         }
 
diff --git a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
index 0b7bf92a..8d8e6425 100644
--- a/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
+++ b/Ryujinx.Graphics/Gal/OpenGL/OpenGLRenderer.cs
@@ -63,7 +63,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
         public void Render()
         {
-            FbRenderer.Render();
+            //FbRenderer.Render();
         }
 
         public void SetWindowSize(int Width, int Height)
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
index 898b90b5..cd901747 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
@@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.Gal.Shader
         private const int AttrStartIndex = 8;
         private const int TexStartIndex = 8;
 
+        public const string PositionOutAttrName = "position";
+
         private const string InAttrName  = "in_attr";
         private const string OutAttrName = "out_attr";
         private const string UniformName = "c";
@@ -62,10 +64,11 @@ namespace Ryujinx.Graphics.Gal.Shader
             m_Gprs  = new Dictionary<int, ShaderDeclInfo>();
             m_Preds = new Dictionary<int, ShaderDeclInfo>();
 
-            //FIXME: Only valid for vertex shaders.
             if (ShaderType == GalShaderType.Fragment)
             {
                 m_Gprs.Add(0, new ShaderDeclInfo(FragmentOutputName, 0, 0, 4));
+
+                m_InAttributes.Add(7, new ShaderDeclInfo(PositionOutAttrName, -1, 0, 4));
             }
             else
             {
@@ -104,10 +107,9 @@ namespace Ryujinx.Graphics.Gal.Shader
                     Traverse(Op, Op.OperandB);
                     Traverse(Op, Op.OperandC);
 
-                    if (Op.Inst == ShaderIrInst.Texr ||
-                        Op.Inst == ShaderIrInst.Texg ||
-                        Op.Inst == ShaderIrInst.Texb ||
-                        Op.Inst == ShaderIrInst.Texa)
+                    if (Op.Inst == ShaderIrInst.Texq ||
+                        Op.Inst == ShaderIrInst.Texs ||
+                        Op.Inst == ShaderIrInst.Txlf)
                     {
                         int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
 
diff --git a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
index eda70cef..e155e475 100644
--- a/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
+++ b/Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
@@ -31,40 +31,51 @@ namespace Ryujinx.Graphics.Gal.Shader
         {
             InstsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
             {
-                { ShaderIrInst.And,  GetAndExpr  },
-                { ShaderIrInst.Asr,  GetAsrExpr  },
-                { ShaderIrInst.Band, GetBandExpr },
-                { ShaderIrInst.Bnot, GetBnotExpr },
-                { ShaderIrInst.Clt,  GetCltExpr  },
-                { ShaderIrInst.Ceq,  GetCeqExpr  },
-                { ShaderIrInst.Cle,  GetCleExpr  },
-                { ShaderIrInst.Cgt,  GetCgtExpr  },
-                { ShaderIrInst.Cne,  GetCneExpr  },
-                { ShaderIrInst.Cge,  GetCgeExpr  },
-                { ShaderIrInst.Exit, GetExitExpr },
-                { ShaderIrInst.Fabs, GetFabsExpr },
-                { ShaderIrInst.Fadd, GetFaddExpr },
-                { ShaderIrInst.Fcos, GetFcosExpr },
-                { ShaderIrInst.Fex2, GetFex2Expr },
-                { ShaderIrInst.Ffma, GetFfmaExpr },
-                { ShaderIrInst.Flg2, GetFlg2Expr },
-                { ShaderIrInst.Fmul, GetFmulExpr },
-                { ShaderIrInst.Fneg, GetFnegExpr },
-                { ShaderIrInst.Frcp, GetFrcpExpr },
-                { ShaderIrInst.Frsq, GetFrsqExpr },
-                { ShaderIrInst.Fsin, GetFsinExpr },
-                { ShaderIrInst.Ipa,  GetIpaExpr  },
-                { ShaderIrInst.Kil,  GetKilExpr  },
-                { ShaderIrInst.Lsr,  GetLsrExpr  },
-                { ShaderIrInst.Not,  GetNotExpr  },
-                { ShaderIrInst.Or,   GetOrExpr   },
-                { ShaderIrInst.Stof, GetStofExpr },
-                { ShaderIrInst.Utof, GetUtofExpr },
-                { ShaderIrInst.Texr, GetTexrExpr },
-                { ShaderIrInst.Texg, GetTexgExpr },
-                { ShaderIrInst.Texb, GetTexbExpr },
-                { ShaderIrInst.Texa, GetTexaExpr },
-                { 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.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   }
             };
         }
 
@@ -117,11 +128,21 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private void PrintDeclInAttributes()
         {
+            if (Decl.ShaderType == GalShaderType.Fragment)
+            {
+                SB.AppendLine("in vec4 " + GlslDecl.PositionOutAttrName + ";");
+            }
+
             PrintDeclAttributes(Decl.InAttributes.Values, "in");
         }
 
         private void PrintDeclOutAttributes()
         {
+            if (Decl.ShaderType == GalShaderType.Vertex)
+            {
+                SB.AppendLine("out vec4 " + GlslDecl.PositionOutAttrName + ";");
+            }
+
             PrintDeclAttributes(Decl.OutAttributes.Values, "out");
         }
 
@@ -133,7 +154,7 @@ namespace Ryujinx.Graphics.Gal.Shader
             {
                 if (DeclInfo.Index >= 0)
                 {
-                    SB.AppendLine($"layout (location = {DeclInfo.Index}) {InOut} {GetDecl(DeclInfo)};");
+                    SB.AppendLine("layout (location = " + DeclInfo.Index + ") " + InOut + " " + GetDecl(DeclInfo) + ";");
 
                     Count++;
                 }
@@ -222,7 +243,14 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                 if (Node is ShaderIrCond Cond)
                 {
-                    string SubScopeName = "if (" + GetSrcExpr(Cond.Pred, true) + ")";
+                    string IfExpr = GetSrcExpr(Cond.Pred, true);
+
+                    if (Cond.Not)
+                    {
+                        IfExpr = "!(" + IfExpr + ")";
+                    }
+
+                    string SubScopeName = "if (" + IfExpr + ")";
 
                     PrintBlockScope(SubScopeName, IdentationLevel + 1, Cond.Child);
                 }
@@ -236,6 +264,16 @@ namespace Ryujinx.Graphics.Gal.Shader
                 }
                 else if (Node is ShaderIrOp Op)
                 {
+                    if (Op.Inst == ShaderIrInst.Exit)
+                    {
+                        //Do everything that needs to be done before
+                        //the shader ends here.
+                        if (Decl.ShaderType == GalShaderType.Vertex)
+                        {
+                            SB.AppendLine(Identation + GlslDecl.PositionOutAttrName + " = gl_Position;");
+                        }
+                    }
+
                     SB.AppendLine(Identation + GetSrcExpr(Op, true) + ";");
                 }
                 else
@@ -321,10 +359,9 @@ namespace Ryujinx.Graphics.Gal.Shader
                     return true;
 
                 case ShaderIrInst.Ipa:
-                case ShaderIrInst.Texr:
-                case ShaderIrInst.Texg:
-                case ShaderIrInst.Texb:
-                case ShaderIrInst.Texa:
+                case ShaderIrInst.Texq:
+                case ShaderIrInst.Texs:
+                case ShaderIrInst.Txlf:
                     return false;
             }
 
@@ -349,11 +386,6 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private string GetName(ShaderIrOperAbuf Abuf)
         {
-            if (Abuf.Offs == GlslDecl.GlPositionWAttr && Decl.ShaderType == GalShaderType.Fragment)
-            {
-                return "(1f / gl_FragCoord.w)";
-            }
-
             if (Abuf.Offs == GlslDecl.VertexIdAttr)
             {
                 return "gl_VertexID";
@@ -437,6 +469,10 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private string GetBnotExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "!");
 
+        private string GetCeilExpr(ShaderIrOp Op) => GetUnaryCall(Op, "ceil");
+
+        private string GetClampExpr(ShaderIrOp Op) => GetTernaryCall(Op, "clamp");
+
         private string GetCltExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<");
         private string GetCeqExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "==");
         private string GetCleExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "<=");
@@ -458,6 +494,8 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private string GetFlg2Expr(ShaderIrOp Op) => GetUnaryCall(Op, "log2");
 
+        private string GetFloorExpr(ShaderIrOp Op) => GetUnaryCall(Op, "floor");
+
         private string GetFmulExpr(ShaderIrOp Op) => GetBinaryExpr(Op, "*");
 
         private string GetFnegExpr(ShaderIrOp Op) => GetUnaryExpr(Op, "-");
@@ -468,6 +506,16 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private string GetFsinExpr(ShaderIrOp Op) => GetUnaryCall(Op, "sin");
 
+        private string GetFtosExpr(ShaderIrOp Op)
+        {
+            return "int(" + GetOperExpr(Op, Op.OperandA) + ")";
+        }
+
+        private string GetFtouExpr(ShaderIrOp Op)
+        {
+            return "int(uint(" + GetOperExpr(Op, Op.OperandA) + "))";
+        }
+
         private string GetIpaExpr(ShaderIrOp Op) => GetSrcExpr(Op.OperandA);
 
         private string GetKilExpr(ShaderIrOp Op) => "discard";
@@ -487,6 +535,54 @@ namespace Ryujinx.Graphics.Gal.Shader
             return "float(" + GetOperExpr(Op, Op.OperandA) + ")";
         }
 
+        private string GetTexqExpr(ShaderIrOp Op)
+        {
+            ShaderIrMetaTexq Meta = (ShaderIrMetaTexq)Op.MetaData;
+
+            string Ch = "xyzw".Substring(Meta.Elem, 1);
+
+            if (Meta.Info == ShaderTexqInfo.Dimension)
+            {
+                string Sampler = GetTexSamplerName(Op);
+
+                string Lod = GetOperExpr(Op, Op.OperandA); //???
+
+                return "textureSize(" + Sampler + ", " + Lod + ")." + Ch;
+            }
+            else
+            {
+                throw new NotImplementedException(Meta.Info.ToString());
+            }
+        }
+
+        private string GetTexsExpr(ShaderIrOp Op)
+        {
+            ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
+
+            string Sampler = GetTexSamplerName(Op);
+
+            string Coords = GetTexSamplerCoords(Op);
+
+            string Ch = "rgba".Substring(Meta.Elem, 1);
+
+            return "texture(" + Sampler + ", " + Coords + ")." + Ch;
+        }
+
+        private string GetTxlfExpr(ShaderIrOp Op)
+        {
+            ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
+
+            string Sampler = GetTexSamplerName(Op);
+
+            string Coords = GetITexSamplerCoords(Op);
+
+            string Ch = "rgba".Substring(Meta.Elem, 1);
+
+            return "texelFetch(" + Sampler + ", " + Coords + ", 0)." + Ch;
+        }
+
+        private string GetTruncExpr(ShaderIrOp Op) => GetUnaryCall(Op, "trunc");
+
         private string GetUtofExpr(ShaderIrOp Op)
         {
             return "float(uint(" + GetOperExpr(Op, Op.OperandA) + "))";
@@ -499,6 +595,13 @@ namespace Ryujinx.Graphics.Gal.Shader
             return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ")";
         }
 
+        private string GetTernaryCall(ShaderIrOp Op, string FuncName)
+        {
+            return FuncName + "(" + GetOperExpr(Op, Op.OperandA) + ", " +
+                                    GetOperExpr(Op, Op.OperandB) + ", " +
+                                    GetOperExpr(Op, Op.OperandC) + ")";
+        }
+
         private string GetUnaryExpr(ShaderIrOp Op, string Opr)
         {
             return Opr + GetOperExpr(Op, Op.OperandA);
@@ -517,16 +620,6 @@ namespace Ryujinx.Graphics.Gal.Shader
                    GetOperExpr(Op, Op.OperandC);
         }
 
-        private string GetTexrExpr(ShaderIrOp Op) => GetTexExpr(Op, 'r');
-        private string GetTexgExpr(ShaderIrOp Op) => GetTexExpr(Op, 'g');
-        private string GetTexbExpr(ShaderIrOp Op) => GetTexExpr(Op, 'b');
-        private string GetTexaExpr(ShaderIrOp Op) => GetTexExpr(Op, 'a');
-
-        private string GetTexExpr(ShaderIrOp Op, char Ch)
-        {
-            return $"texture({GetTexSamplerName(Op)}, {GetTexSamplerCoords(Op)}).{Ch}";
-        }
-
         private string GetTexSamplerName(ShaderIrOp Op)
         {
             ShaderIrOperImm Node = (ShaderIrOperImm)Op.OperandC;
@@ -547,6 +640,12 @@ namespace Ryujinx.Graphics.Gal.Shader
                              GetOperExpr(Op, Op.OperandB) + ")";
         }
 
+        private string GetITexSamplerCoords(ShaderIrOp Op)
+        {
+            return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
+                              GetOperExpr(Op, Op.OperandB) + ")";
+        }
+
         private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper)
         {
             return GetExprWithCast(Op, Oper, GetSrcExpr(Oper));
@@ -571,13 +670,31 @@ namespace Ryujinx.Graphics.Gal.Shader
                     throw new InvalidOperationException();
                 }
 
-                //For integer immediates being used as float,
-                //it's better (for readability) to just return the float value.
-                if (Src is ShaderIrOperImm Imm && DstType == OperType.F32)
+                switch (Src)
                 {
-                    float Value = BitConverter.Int32BitsToSingle(Imm.Value);
+                    case ShaderIrOperGpr Gpr:
+                    {
+                        //When the Gpr is ZR, just return the 0 value directly,
+                        //since the float encoding for 0 is 0.
+                        if (Gpr.IsConst)
+                        {
+                            return "0";
+                        }
+                        break;
+                    }
 
-                    return Value.ToString(CultureInfo.InvariantCulture) + "f";
+                    case ShaderIrOperImm Imm:
+                    {
+                        //For integer immediates being used as float,
+                        //it's better (for readability) to just return the float value.
+                        if (DstType == OperType.F32)
+                        {
+                            float Value = BitConverter.Int32BitsToSingle(Imm.Value);
+
+                            return Value.ToString(CultureInfo.InvariantCulture) + "f";
+                        }
+                        break;
+                    }
                 }
 
                 switch (DstType)
@@ -592,12 +709,20 @@ namespace Ryujinx.Graphics.Gal.Shader
 
         private static OperType GetDstNodeType(ShaderIrNode Node)
         {
+            //Special case instructions with the result type different
+            //from the input types (like integer <-> float conversion) here.
             if (Node is ShaderIrOp Op)
             {
                 switch (Op.Inst)
                 {
-                    case ShaderIrInst.Stof: return OperType.F32;
-                    case ShaderIrInst.Utof: return OperType.F32;
+                    case ShaderIrInst.Stof:
+                    case ShaderIrInst.Txlf:
+                    case ShaderIrInst.Utof:
+                        return OperType.F32;
+
+                    case ShaderIrInst.Ftos:
+                    case ShaderIrInst.Ftou:
+                        return OperType.I32;
                 }
             }
 
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
index 5c2f493e..b796ab28 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
@@ -81,6 +81,21 @@ namespace Ryujinx.Graphics.Gal.Shader
             Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
         }
 
+        public static void Isetp_C(ShaderIrBlock Block, long OpCode)
+        {
+            EmitIsetp(Block, OpCode, ShaderOper.CR);
+        }
+
+        public static void Isetp_I(ShaderIrBlock Block, long OpCode)
+        {
+            EmitIsetp(Block, OpCode, ShaderOper.Imm);
+        }
+
+        public static void Isetp_R(ShaderIrBlock Block, long OpCode)
+        {
+            EmitIsetp(Block, OpCode, ShaderOper.RR);
+        }
+
         public static void Lop32i(ShaderIrBlock Block, long OpCode)
         {
             int SubOp = (int)(OpCode >> 53) & 3;
@@ -258,6 +273,16 @@ namespace Ryujinx.Graphics.Gal.Shader
         }
 
         private static void EmitFsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+        {
+            EmitSetp(Block, OpCode, true, Oper);
+        }
+
+        private static void EmitIsetp(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+        {
+            EmitSetp(Block, OpCode, false, Oper);
+        }
+
+        private static void EmitSetp(ShaderIrBlock Block, long OpCode, bool IsFloat, ShaderOper Oper)
         {
             bool Aa = ((OpCode >>  7) & 1) != 0;
             bool Np = ((OpCode >> 42) & 1) != 0;
@@ -269,17 +294,28 @@ namespace Ryujinx.Graphics.Gal.Shader
             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 = GetCmp(OpCode);
+            ShaderIrInst CmpInst;
 
-            ShaderIrOp Op = new ShaderIrOp(CmpInst,
-                GetAluAbsNeg(OperA, Aa, Na),
-                GetAluAbs   (OperB, Ab));
+            if (IsFloat)
+            {
+                OperA = GetAluAbsNeg(OperA, Aa, Na);
+                OperB = GetAluAbs   (OperB, Ab);
+
+                CmpInst = GetCmpF(OpCode);
+            }
+            else
+            {
+                CmpInst = GetCmp(OpCode);
+            }
+
+            ShaderIrOp Op = new ShaderIrOp(CmpInst, OperA, OperB);
 
             ShaderIrOperPred P0Node = GetOperPred3 (OpCode);
             ShaderIrOperPred P1Node = GetOperPred0 (OpCode);
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
index 7989570d..de932dce 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
@@ -60,7 +60,17 @@ namespace Ryujinx.Graphics.Gal.Shader
             return new ShaderIrOperGpr((int)(OpCode >> 28) & 0xff);
         }
 
-        public static ShaderIrNode GetOperImm19_20(long OpCode)
+        public static ShaderIrOperImm GetOperImm13_36(long OpCode)
+        {
+            return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
+        }
+
+        public static ShaderIrOperImm GetOperImm32_20(long OpCode)
+        {
+            return new ShaderIrOperImm((int)(OpCode >> 20));
+        }
+
+        public static ShaderIrOperImm GetOperImm19_20(long OpCode)
         {
             int Value = (int)(OpCode >> 20) & 0x7ffff;
 
@@ -74,7 +84,7 @@ namespace Ryujinx.Graphics.Gal.Shader
             return new ShaderIrOperImm((int)Value);
         }
 
-        public static ShaderIrNode GetOperImmf19_20(long OpCode)
+        public static ShaderIrOperImmf GetOperImmf19_20(long OpCode)
         {
             uint Imm = (uint)(OpCode >> 20) & 0x7ffff;
 
@@ -92,16 +102,6 @@ namespace Ryujinx.Graphics.Gal.Shader
             return new ShaderIrOperImmf(Value);
         }
 
-        public static ShaderIrOperImm GetOperImm13_36(long OpCode)
-        {
-            return new ShaderIrOperImm((int)(OpCode >> 36) & 0x1fff);
-        }
-
-        public static ShaderIrOperImm GetOperImm32_20(long OpCode)
-        {
-            return new ShaderIrOperImm((int)(OpCode >> 20));
-        }
-
         public static ShaderIrOperPred GetOperPred3(long OpCode)
         {
             return new ShaderIrOperPred((int)(OpCode >> 3) & 7);
@@ -130,23 +130,38 @@ namespace Ryujinx.Graphics.Gal.Shader
         }
 
         public static ShaderIrInst GetCmp(long OpCode)
+        {
+            switch ((int)(OpCode >> 49) & 7)
+            {
+                case 1: return ShaderIrInst.Clt;
+                case 2: return ShaderIrInst.Ceq;
+                case 3: return ShaderIrInst.Cle;
+                case 4: return ShaderIrInst.Cgt;
+                case 5: return ShaderIrInst.Cne;
+                case 6: return ShaderIrInst.Cge;
+            }
+
+            throw new ArgumentException(nameof(OpCode));
+        }
+
+        public static ShaderIrInst GetCmpF(long OpCode)
         {
             switch ((int)(OpCode >> 48) & 0xf)
             {
-                case 0x1: return ShaderIrInst.Clt;
-                case 0x2: return ShaderIrInst.Ceq;
-                case 0x3: return ShaderIrInst.Cle;
-                case 0x4: return ShaderIrInst.Cgt;
-                case 0x5: return ShaderIrInst.Cne;
-                case 0x6: return ShaderIrInst.Cge;
-                case 0x7: return ShaderIrInst.Cnum;
-                case 0x8: return ShaderIrInst.Cnan;
-                case 0x9: return ShaderIrInst.Cltu;
-                case 0xa: return ShaderIrInst.Cequ;
-                case 0xb: return ShaderIrInst.Cleu;
-                case 0xc: return ShaderIrInst.Cgtu;
-                case 0xd: return ShaderIrInst.Cneu;
-                case 0xe: return ShaderIrInst.Cgeu;
+                case 0x1: return ShaderIrInst.Fclt;
+                case 0x2: return ShaderIrInst.Fceq;
+                case 0x3: return ShaderIrInst.Fcle;
+                case 0x4: return ShaderIrInst.Fcgt;
+                case 0x5: return ShaderIrInst.Fcne;
+                case 0x6: return ShaderIrInst.Fcge;
+                case 0x7: return ShaderIrInst.Fcnum;
+                case 0x8: return ShaderIrInst.Fcnan;
+                case 0x9: return ShaderIrInst.Fcltu;
+                case 0xa: return ShaderIrInst.Fcequ;
+                case 0xb: return ShaderIrInst.Fcleu;
+                case 0xc: return ShaderIrInst.Fcgtu;
+                case 0xd: return ShaderIrInst.Fcneu;
+                case 0xe: return ShaderIrInst.Fcgeu;
             }
 
             throw new ArgumentException(nameof(OpCode));
@@ -170,7 +185,9 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             if (Pred.Index != ShaderIrOperPred.UnusedIndex)
             {
-                Node = new ShaderIrCond(Pred, Node);
+                bool Inv = ((OpCode >> 19) & 1) != 0;
+
+                Node = new ShaderIrCond(Pred, Node, Inv);
             }
 
             return Node;
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
index fd18ce07..6553cfcf 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
@@ -36,24 +36,56 @@ namespace Ryujinx.Graphics.Gal.Shader
             }
         }
 
+        public static void Texq(ShaderIrBlock Block, long OpCode)
+        {
+            ShaderIrNode OperD = GetOperGpr0(OpCode);
+            ShaderIrNode OperA = GetOperGpr8(OpCode);
+
+            ShaderTexqInfo Info = (ShaderTexqInfo)((OpCode >> 22) & 0x1f);
+
+            ShaderIrMetaTexq Meta0 = new ShaderIrMetaTexq(Info, 0);
+            ShaderIrMetaTexq Meta1 = new ShaderIrMetaTexq(Info, 1);
+
+            ShaderIrNode OperC = GetOperImm13_36(OpCode);
+
+            ShaderIrOp Op0 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta0);
+            ShaderIrOp Op1 = new ShaderIrOp(ShaderIrInst.Texq, OperA, null, OperC, Meta1);
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(OperD, Op0), OpCode));
+            Block.AddNode(GetPredNode(new ShaderIrAsg(OperA, Op1), OpCode)); //Is this right?
+        }
+
         public static void Texs(ShaderIrBlock Block, long OpCode)
+        {
+            EmitTex(Block, OpCode, ShaderIrInst.Texs);
+        }
+
+        public static void Tlds(ShaderIrBlock Block, long OpCode)
+        {
+            EmitTex(Block, OpCode, ShaderIrInst.Txlf);
+        }
+
+        private static void EmitTex(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
         {
             //TODO: Support other formats.
-            ShaderIrNode OperA = GetOperGpr8    (OpCode);
-            ShaderIrNode OperB = GetOperGpr20   (OpCode);
-            ShaderIrNode OperC = GetOperGpr28   (OpCode);
-            ShaderIrNode OperD = GetOperImm13_36(OpCode);
+            ShaderIrNode OperA  = GetOperGpr8    (OpCode);
+            ShaderIrNode OperB  = GetOperGpr20   (OpCode);
+            ShaderIrNode OperC  = GetOperImm13_36(OpCode);
 
             for (int Ch = 0; Ch < 4; Ch++)
             {
-                ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Texr + Ch, OperA, OperB, OperD);
+                ShaderIrOperGpr Dst = (Ch >> 1) != 0
+                    ? GetOperGpr28(OpCode)
+                    : GetOperGpr0 (OpCode);
 
-                ShaderIrOperGpr Dst = GetOperGpr0(OpCode);
+                Dst.Index += Ch & 1;
 
-                Dst.Index += Ch;
+                ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
 
-                Block.AddNode(new ShaderIrAsg(Dst, Op));
-            }            
+                ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta);
+
+                Block.AddNode(GetPredNode(new ShaderIrAsg(Dst, Op), OpCode));
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
index 50c740bf..6d30cfed 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
@@ -25,6 +25,36 @@ namespace Ryujinx.Graphics.Gal.Shader
             F64 = 3
         }
 
+        public static void F2f_C(ShaderIrBlock Block, long OpCode)
+        {
+            EmitF2f(Block, OpCode, ShaderOper.CR);
+        }
+
+        public static void F2f_I(ShaderIrBlock Block, long OpCode)
+        {
+            EmitF2f(Block, OpCode, ShaderOper.Immf);
+        }
+
+        public static void F2f_R(ShaderIrBlock Block, long OpCode)
+        {
+            EmitF2f(Block, OpCode, ShaderOper.RR);
+        }
+
+        public static void F2i_C(ShaderIrBlock Block, long OpCode)
+        {
+            EmitF2i(Block, OpCode, ShaderOper.CR);
+        }
+
+        public static void F2i_I(ShaderIrBlock Block, long OpCode)
+        {
+            EmitF2i(Block, OpCode, ShaderOper.Immf);
+        }
+
+        public static void F2i_R(ShaderIrBlock Block, long OpCode)
+        {
+            EmitF2i(Block, OpCode, ShaderOper.RR);
+        }
+
         public static void I2f_C(ShaderIrBlock Block, long OpCode)
         {
             EmitI2f(Block, OpCode, ShaderOper.CR);
@@ -40,6 +70,131 @@ namespace Ryujinx.Graphics.Gal.Shader
             EmitI2f(Block, OpCode, ShaderOper.RR);
         }
 
+        public static void Mov_C(ShaderIrBlock Block, long OpCode)
+        {
+            ShaderIrOperCbuf Cbuf = GetOperCbuf34(OpCode);
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Cbuf), OpCode));
+        }
+
+        public static void Mov_I(ShaderIrBlock Block, long OpCode)
+        {
+            ShaderIrOperImm Imm = GetOperImm19_20(OpCode);
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
+        }
+
+        public static void Mov_R(ShaderIrBlock Block, long OpCode)
+        {
+            ShaderIrOperGpr Gpr = GetOperGpr20(OpCode);
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Gpr), OpCode));
+        }
+
+        public static void Mov32i(ShaderIrBlock Block, long OpCode)
+        {
+            ShaderIrOperImm Imm = GetOperImm32_20(OpCode);
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
+        }
+
+        private static void EmitF2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
+        {
+            bool Na = ((OpCode >> 45) & 1) != 0;
+            bool Aa = ((OpCode >> 49) & 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, Aa, Na);
+
+            ShaderIrInst RoundInst = GetRoundInst(OpCode);
+
+            if (RoundInst != ShaderIrInst.Invalid)
+            {
+                OperA = new ShaderIrOp(RoundInst, OperA);
+            }
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), OperA), OpCode));
+        }
+
+        private static void EmitF2i(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();
+            }
+
+            bool Na = ((OpCode >> 45) & 1) != 0;
+            bool Aa = ((OpCode >> 49) & 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, Aa, Na);
+
+            ShaderIrInst RoundInst = GetRoundInst(OpCode);
+
+            if (RoundInst != ShaderIrInst.Invalid)
+            {
+                OperA = new ShaderIrOp(RoundInst, OperA);
+            }
+
+            bool Signed = Type >= IntType.S8;
+
+            int Size = 8 << ((int)Type & 3);
+
+            if (Size < 32)
+            {
+                uint Mask = uint.MaxValue >> (32 - Size);
+
+                float CMin = 0;
+                float CMax = Mask;
+
+                if (Signed)
+                {
+                    uint HalfMask = Mask >> 1;
+
+                    CMin -= HalfMask + 1;
+                    CMax  = HalfMask;
+                }
+
+                ShaderIrOperImmf IMin = new ShaderIrOperImmf(CMin);
+                ShaderIrOperImmf IMax = new ShaderIrOperImmf(CMax);
+
+                OperA = new ShaderIrOp(ShaderIrInst.Clamp, OperA, IMin, IMax);
+            }
+
+            ShaderIrInst Inst = Signed
+                ? ShaderIrInst.Ftos
+                : ShaderIrInst.Ftou;
+
+            ShaderIrNode Op = new ShaderIrOp(Inst, OperA);
+
+            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
+        }
+
         private static void EmitI2f(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
         {
             IntType Type = GetIntType(OpCode);
@@ -76,18 +231,16 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             int Size = 8 << ((int)Type & 3);
 
-            ulong Mask = ulong.MaxValue >> (64 - Size);
-
-            int Mask32 = (int)Mask;
-
             if (Shift != 0)
             {
                 OperA = new ShaderIrOp(ShaderIrInst.Asr, OperA, new ShaderIrOperImm(Shift));
             }
 
-            if (Mask != uint.MaxValue)
+            if (Size < 32)
             {
-                OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm(Mask32));
+                uint Mask = uint.MaxValue >> (32 - Size);
+
+                OperA = new ShaderIrOp(ShaderIrInst.And, OperA, new ShaderIrOperImm((int)Mask));
             }
 
             ShaderIrInst Inst = Signed
@@ -99,13 +252,6 @@ namespace Ryujinx.Graphics.Gal.Shader
             Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Op), OpCode));
         }
 
-        public static void Mov32i(ShaderIrBlock Block, long OpCode)
-        {
-            ShaderIrOperImm Imm = GetOperImm32_20(OpCode);
-
-            Block.AddNode(GetPredNode(new ShaderIrAsg(GetOperGpr0(OpCode), Imm), OpCode));
-        }
-
         private static IntType GetIntType(long OpCode)
         {
             bool Signed = ((OpCode >> 13) & 1) != 0;
@@ -124,5 +270,17 @@ namespace Ryujinx.Graphics.Gal.Shader
         {
             return (FloatType)((OpCode >> 8) & 3);
         }
+
+        private static ShaderIrInst GetRoundInst(long OpCode)
+        {
+            switch ((OpCode >> 39) & 3)
+            {
+                case 1: return ShaderIrInst.Floor;
+                case 2: return ShaderIrInst.Ceil;
+                case 3: return ShaderIrInst.Trunc;
+            }
+
+            return ShaderIrInst.Invalid;
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
index 779bbf92..7bebea62 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
@@ -8,6 +8,15 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             while (Offset + 2 <= Code.Length)
             {
+                //Ignore scheduling instructions, which are
+                //written every 32 bytes.
+                if ((Offset & 7) == 0)
+                {
+                    Offset += 2;
+
+                    continue;
+                }
+
                 uint Word0 = (uint)Code[Offset++];
                 uint Word1 = (uint)Code[Offset++];
 
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs
index d8c87b49..8fb01660 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs
@@ -5,10 +5,13 @@ namespace Ryujinx.Graphics.Gal.Shader
         public ShaderIrNode Pred  { get; set; }
         public ShaderIrNode Child { get; set; }
 
-        public ShaderIrCond(ShaderIrNode Pred, ShaderIrNode Child)
+        public bool Not { get; private set; }
+
+        public ShaderIrCond(ShaderIrNode Pred, ShaderIrNode Child, bool Not)
         {
             this.Pred  = Pred;
             this.Child = Child;
+            this.Not   = Not;
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
index b6f4e80b..1b72f647 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
@@ -2,53 +2,66 @@ namespace Ryujinx.Graphics.Gal.Shader
 {
     enum ShaderIrInst
     {
+        Invalid,
+
         B_Start,
         Band,
         Bnot,
         Bor,
         Bxor,
-        Clt,
-        Ceq,
-        Cle,
-        Cgt,
-        Cne,
-        Cge,
-        Cnum,
-        Cnan,
-        Cltu,
-        Cequ,
-        Cleu,
-        Cgtu,
-        Cneu,
-        Cgeu,
         B_End,
 
         F_Start,
+        Ceil,
+        Clamp,
         Fabs,
         Fadd,
+        Fceq,
+        Fcequ,
+        Fcge,
+        Fcgeu,
+        Fcgt,
+        Fcgtu,
+        Fcle,
+        Fcleu,
+        Fclt,
+        Fcltu,
+        Fcnan,
+        Fcne,
+        Fcneu,
+        Fcnum,
         Fcos,
         Fex2,
         Ffma,
         Flg2,
+        Floor,
         Fmul,
         Fneg,
         Frcp,
         Frsq,
         Fsin,
+        Ftos,
+        Ftou,
         Ipa,
-        Texr,
-        Texg,
-        Texb,
-        Texa,
+        Texs,
+        Trunc,
         F_End,
 
         I_Start,
         And,
         Asr,
+        Ceq,
+        Cge,
+        Cgt,
+        Cle,
+        Clt,
+        Cne,
         Lsr,
         Not,
         Or,
         Stof,
+        Texq,
+        Txlf,
         Utof,
         Xor,
         I_End,
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs
new file mode 100644
index 00000000..afb7503b
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs
@@ -0,0 +1,4 @@
+namespace Ryujinx.Graphics.Gal.Shader
+{
+    class ShaderIrMeta { }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs
new file mode 100644
index 00000000..82f3bb77
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Graphics.Gal.Shader
+{
+    class ShaderIrMetaTex : ShaderIrMeta
+    {
+        public int Elem { get; private set; }
+
+        public ShaderIrMetaTex(int Elem)
+        {
+            this.Elem = Elem;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs
new file mode 100644
index 00000000..92871137
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs
@@ -0,0 +1,15 @@
+namespace Ryujinx.Graphics.Gal.Shader
+{
+    class ShaderIrMetaTexq : ShaderIrMeta
+    {
+        public ShaderTexqInfo Info { get; private set; }
+
+        public int Elem { get; private set; }
+
+        public ShaderIrMetaTexq(ShaderTexqInfo Info, int Elem)
+        {
+            this.Info = Info;
+            this.Elem = Elem;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs b/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs
index cd210757..12a6123c 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs
@@ -6,17 +6,20 @@ namespace Ryujinx.Graphics.Gal.Shader
         public ShaderIrNode OperandA { get; set; }
         public ShaderIrNode OperandB { get; set; }
         public ShaderIrNode OperandC { get; set; }
+        public ShaderIrMeta MetaData { get; set; }
 
         public ShaderIrOp(
             ShaderIrInst Inst,
             ShaderIrNode OperandA = null,
             ShaderIrNode OperandB = null,
-            ShaderIrNode OperandC = null)
+            ShaderIrNode OperandC = null,
+            ShaderIrMeta MetaData = null)
         {
             this.Inst     = Inst;
             this.OperandA = OperandA;
             this.OperandB = OperandB;
             this.OperandC = OperandC;
+            this.MetaData = MetaData;
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
index 48c3b2ee..a234f7f7 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
@@ -14,6 +14,12 @@ namespace Ryujinx.Graphics.Gal.Shader
 
 #region Instructions
             Set("111000110000xx", ShaderDecode.Exit);
+            Set("0100110010101x", ShaderDecode.F2f_C);
+            Set("0011100x10101x", ShaderDecode.F2f_I);
+            Set("0101110010101x", ShaderDecode.F2f_R);
+            Set("0100110010110x", ShaderDecode.F2i_C);
+            Set("0011100x10110x", ShaderDecode.F2i_I);
+            Set("0101110010110x", ShaderDecode.F2i_R);
             Set("0100110001011x", ShaderDecode.Fadd_C);
             Set("0011100x01011x", ShaderDecode.Fadd_I);
             Set("0101110001011x", ShaderDecode.Fadd_R);
@@ -31,16 +37,24 @@ namespace Ryujinx.Graphics.Gal.Shader
             Set("0011100x10111x", ShaderDecode.I2f_I);
             Set("0101110010111x", ShaderDecode.I2f_R);
             Set("11100000xxxxxx", ShaderDecode.Ipa);
+            Set("010010110110xx", ShaderDecode.Isetp_C);
+            Set("0011011x0110xx", ShaderDecode.Isetp_I);
+            Set("010110110110xx", ShaderDecode.Isetp_R);
             Set("111000110011xx", ShaderDecode.Kil);
             Set("1110111111011x", ShaderDecode.Ld_A);
             Set("000001xxxxxxxx", ShaderDecode.Lop32i);
+            Set("0100110010011x", ShaderDecode.Mov_C);
+            Set("0011100x10011x", ShaderDecode.Mov_I);
+            Set("0101110010011x", ShaderDecode.Mov_R);
             Set("000000010000xx", ShaderDecode.Mov32i);
             Set("0101000010000x", ShaderDecode.Mufu);
             Set("0100110000101x", ShaderDecode.Shr_C);
             Set("0011100x00101x", ShaderDecode.Shr_I);
             Set("0101110000101x", ShaderDecode.Shr_R);
             Set("1110111111110x", ShaderDecode.St_A);
+            Set("1101111101001x", ShaderDecode.Texq);
             Set("1101100xxxxxxx", ShaderDecode.Texs);
+            Set("1101101xxxxxxx", ShaderDecode.Tlds);
 #endregion
         }
 
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs
index 7989deed..aa485482 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOper.cs
@@ -3,9 +3,9 @@ namespace Ryujinx.Graphics.Gal.Shader
     enum ShaderOper
     {
         CR,
-        RC,
-        RR,
         Imm,
-        Immf
+        Immf,
+        RC,
+        RR
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderOptExprProp.cs b/Ryujinx.Graphics/Gal/Shader/ShaderOptExprProp.cs
index 69457aeb..9ce7cbe3 100644
--- a/Ryujinx.Graphics/Gal/Shader/ShaderOptExprProp.cs
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderOptExprProp.cs
@@ -7,13 +7,22 @@ namespace Ryujinx.Graphics.Gal.Shader
     {
         private struct UseSite
         {
-            public object Parent;
+            public ShaderIrNode Parent { get; private set; }
+            public ShaderIrCond Cond   { get; private set; }
 
-            public int OperIndex;
+            public int UseIndex { get; private set; }
 
-            public UseSite(object Parent, int OperIndex)
+            public int OperIndex { get; private set; }
+
+            public UseSite(
+                ShaderIrNode Parent,
+                ShaderIrCond Cond,
+                int          UseIndex,
+                int          OperIndex)
             {
                 this.Parent    = Parent;
+                this.Cond      = Cond;
+                this.UseIndex  = UseIndex;
                 this.OperIndex = OperIndex;
             }
         }
@@ -24,7 +33,9 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             public int AsgIndex { get; private set; }
 
-            private bool Propagate;
+            public int LastSiteIndex { get; private set; }
+
+            public ShaderIrCond Cond { get; private set; }
 
             private List<UseSite> Sites;
 
@@ -35,6 +46,11 @@ namespace Ryujinx.Graphics.Gal.Shader
 
             public void AddUseSite(UseSite Site)
             {
+                if (LastSiteIndex < Site.UseIndex)
+                {
+                    LastSiteIndex = Site.UseIndex;
+                }
+
                 Sites.Add(Site);
             }
 
@@ -42,14 +58,27 @@ namespace Ryujinx.Graphics.Gal.Shader
             {
                 //This happens when a untiliazied register is used,
                 //this usually indicates a decoding error, but may also
-                //be cased by bogus programs (?). In any case, we just
+                //be caused by bogus programs (?). In any case, we just
                 //keep the unitialized access and avoid trying to propagate
                 //the expression (since we can't propagate what doesn't yet exist).
-                if (Asg == null || !Propagate)
+                if (Asg == null)
                 {
                     return false;
                 }
 
+                if (Cond != null)
+                {
+                    //If the assignment is conditional, we can only propagate
+                    //to the use sites that shares the same condition of the assignment.
+                    foreach (UseSite Site in Sites)
+                    {
+                        if (!IsSameCondition(Cond, Site.Cond))
+                        {
+                            return false;
+                        }
+                    }
+                }
+
                 if (Sites.Count > 0)
                 {
                     foreach (UseSite Site in Sites)
@@ -89,11 +118,13 @@ namespace Ryujinx.Graphics.Gal.Shader
                 return true;
             }
 
-            public void SetNewAsg(ShaderIrAsg Asg, int AsgIndex, bool Propagate)
+            public void SetNewAsg(ShaderIrAsg Asg, int AsgIndex, ShaderIrCond Cond)
             {
-                this.Asg       = Asg;
-                this.AsgIndex  = AsgIndex;
-                this.Propagate = Propagate;
+                this.Asg      = Asg;
+                this.AsgIndex = AsgIndex;
+                this.Cond     = Cond;
+
+                LastSiteIndex = 0;
 
                 Sites.Clear();
             }
@@ -137,38 +168,52 @@ namespace Ryujinx.Graphics.Gal.Shader
                 return GetUse(GetPredKey(PredIndex));
             }
 
-            void FindRegUses(List<(int, UseSite)> UseList, object Parent, ShaderIrNode Node, int OperIndex = 0)
+            void RemoveUse(RegUse Use)
             {
-                if (Node is ShaderIrAsg Asg)
+                if (!Nodes.Remove((ShaderIrNode)Use.Cond ?? Use.Asg))
                 {
-                    FindRegUses(UseList, Asg, Asg.Src);
-                }
-                else if (Node is ShaderIrCond Cond)
-                {
-                    FindRegUses(UseList, Cond, Cond.Pred,  0);
-                    FindRegUses(UseList, Cond, Cond.Child, 1);
-                }
-                else if (Node is ShaderIrOp Op)
-                {
-                    FindRegUses(UseList, Op, Op.OperandA, 0);
-                    FindRegUses(UseList, Op, Op.OperandB, 1);
-                    FindRegUses(UseList, Op, Op.OperandC, 2);
-                }
-                else if (Node is ShaderIrOperGpr Gpr && Gpr.Index != ShaderIrOperGpr.ZRIndex)
-                {
-                    UseList.Add((GetGprKey(Gpr.Index), new UseSite(Parent, OperIndex)));
-                }
-                else if (Node is ShaderIrOperPred Pred)
-                {
-                    UseList.Add((GetPredKey(Pred.Index), new UseSite(Parent, OperIndex)));
+                    throw new InvalidOperationException();
                 }
             }
 
-            void TryAddRegUseSite(ShaderIrNode Node)
+            void FindRegUses(
+                List<(int, UseSite)> UseList,
+                ShaderIrNode         Parent,
+                ShaderIrNode         Node,
+                ShaderIrCond         CondNode,
+                int                  UseIndex,
+                int                  OperIndex = 0)
+            {
+                if (Node is ShaderIrAsg Asg)
+                {
+                    FindRegUses(UseList, Asg, Asg.Src, CondNode, UseIndex);
+                }
+                else if (Node is ShaderIrCond Cond)
+                {
+                    FindRegUses(UseList, Cond, Cond.Pred,  CondNode, UseIndex, 0);
+                    FindRegUses(UseList, Cond, Cond.Child, CondNode, UseIndex, 1);
+                }
+                else if (Node is ShaderIrOp Op)
+                {
+                    FindRegUses(UseList, Op, Op.OperandA, CondNode, UseIndex, 0);
+                    FindRegUses(UseList, Op, Op.OperandB, CondNode, UseIndex, 1);
+                    FindRegUses(UseList, Op, Op.OperandC, CondNode, UseIndex, 2);
+                }
+                else if (Node is ShaderIrOperGpr Gpr && !Gpr.IsConst)
+                {
+                    UseList.Add((GetGprKey(Gpr.Index), new UseSite(Parent, CondNode, UseIndex, OperIndex)));
+                }
+                else if (Node is ShaderIrOperPred Pred)
+                {
+                    UseList.Add((GetPredKey(Pred.Index), new UseSite(Parent, CondNode, UseIndex, OperIndex)));
+                }
+            }
+
+            void TryAddRegUseSite(ShaderIrNode Node, ShaderIrCond CondNode, int UseIndex)
             {
                 List<(int, UseSite)> UseList = new List<(int, UseSite)>();
 
-                FindRegUses(UseList, null, Node);
+                FindRegUses(UseList, null, Node, CondNode, UseIndex);
 
                 foreach ((int Key, UseSite Site) in UseList)
                 {
@@ -190,10 +235,22 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                 List<(int, UseSite)> UseList = new List<(int, UseSite)>();
 
-                FindRegUses(UseList, Use.Asg, Use.Asg.Src);
+                if (Use.Cond != null)
+                {
+                    FindRegUses(UseList, null, Use.Cond, null, 0);
+                }
+                else
+                {
+                    FindRegUses(UseList, Use.Asg, Use.Asg.Src, null, 0);
+                }
 
                 foreach ((int Key, UseSite Site) in UseList)
                 {
+                    //TODO: Build an assignment list inside RegUse,
+                    //and check if there is an assignment inside the
+                    //range of Use.AsgIndex and Use.LastSiteIndex,
+                    //and if that's the case, then we should return false.
+                    //The current method is too conservative.
                     if (GetUse(Key).AsgIndex >= Use.AsgIndex)
                     {
                         return false;
@@ -203,13 +260,18 @@ namespace Ryujinx.Graphics.Gal.Shader
                 return Use.TryPropagate();
             }
 
-            for (int Index = 0, AsgIndex = 0; Index < Nodes.Count; Index++, AsgIndex++)
+            for (int Index = 0, IterCount = 0; Index < Nodes.Count; Index++, IterCount++)
             {
                 ShaderIrNode Node = Nodes[Index];
 
-                bool IsConditional = Node is ShaderIrCond;
+                ShaderIrCond CondNode = null;
 
-                TryAddRegUseSite(Node);
+                if (Node is ShaderIrCond)
+                {
+                    CondNode = (ShaderIrCond)Node;
+                }
+
+                TryAddRegUseSite(Node, CondNode, IterCount);;
 
                 while (Node is ShaderIrCond Cond)
                 {
@@ -223,7 +285,7 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                 RegUse Use = null;
 
-                if (Asg.Dst is ShaderIrOperGpr Gpr && Gpr.Index != ShaderIrOperGpr.ZRIndex)
+                if (Asg.Dst is ShaderIrOperGpr Gpr && !Gpr.IsConst)
                 {
                     Use = GetGprUse(Gpr.Index);
                 }
@@ -232,16 +294,22 @@ namespace Ryujinx.Graphics.Gal.Shader
                     Use = GetPredUse(Pred.Index);
                 }
 
-                if (!IsConditional && TryPropagate(Use))
-                {
-                    Nodes.Remove(Use.Asg);
+                bool CanRemoveAsg = CondNode == null;
 
+                CanRemoveAsg |= IsSameCondition(CondNode, Use?.Cond);
+
+                if (CanRemoveAsg && TryPropagate(Use))
+                {
+                    RemoveUse(Use);
+
+                    //Note: Only decrement if the removal was successful.
+                    //RemoveUse throws when this is not the case so we should be good.
                     Index--;
                 }
 
                 //All nodes inside conditional nodes can't be propagated,
                 //as we don't even know if they will be executed to begin with.
-                Use?.SetNewAsg(Asg, AsgIndex, !IsConditional);
+                Use?.SetNewAsg(Asg, IterCount, CondNode);
             }
 
             foreach (RegUse Use in Uses.Values)
@@ -258,9 +326,41 @@ namespace Ryujinx.Graphics.Gal.Shader
 
                 if (TryPropagate(Use))
                 {
-                    Nodes.Remove(Use.Asg);
+                    RemoveUse(Use);
                 }
             }
         }
+
+        private static bool IsSameCondition(ShaderIrCond CondA, ShaderIrCond CondB)
+        {
+            if (CondA == null || CondB == null)
+            {
+                return CondA == CondB;
+            }
+
+            if (CondA.Not != CondB.Not)
+            {
+                return false;
+            }
+
+            if (CondA.Pred is ShaderIrOperPred PredA)
+            {
+                if (!(CondB.Pred is ShaderIrOperPred PredB))
+                {
+                    return false;
+                }
+
+                if (PredA.Index != PredB.Index)
+                {
+                    return false;
+                }
+            }
+            else if (CondA.Pred != CondB.Pred)
+            {
+                return false;
+            }
+
+            return true;
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs b/Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs
new file mode 100644
index 00000000..9158662c
--- /dev/null
+++ b/Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs
@@ -0,0 +1,13 @@
+namespace Ryujinx.Graphics.Gal.Shader
+{
+    enum ShaderTexqInfo
+    {
+        Dimension   = 1,
+        TextureType = 2,
+        SamplePos   = 5,
+        Filter      = 16,
+        Lod         = 18,
+        Wrap        = 20,
+        BorderColor = 22
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics/Gpu/TextureReader.cs b/Ryujinx.Graphics/Gpu/TextureReader.cs
index 60285aed..715578b5 100644
--- a/Ryujinx.Graphics/Gpu/TextureReader.cs
+++ b/Ryujinx.Graphics/Gpu/TextureReader.cs
@@ -12,6 +12,7 @@ namespace Ryujinx.Graphics.Gpu
             {
                 case GalTextureFormat.A8B8G8R8: return Read4Bpp    (Memory, Texture);
                 case GalTextureFormat.A1B5G5R5: return Read2Bpp    (Memory, Texture);
+                case GalTextureFormat.B5G6R5:   return Read2Bpp    (Memory, Texture);
                 case GalTextureFormat.BC1:      return Read8Bpt4x4 (Memory, Texture);
                 case GalTextureFormat.BC2:      return Read16Bpt4x4(Memory, Texture);
                 case GalTextureFormat.BC3:      return Read16Bpt4x4(Memory, Texture);
@@ -20,35 +21,6 @@ namespace Ryujinx.Graphics.Gpu
             throw new NotImplementedException(Texture.Format.ToString());
         }
 
-        private unsafe static byte[] Read4Bpp(AMemory Memory, Texture Texture)
-        {
-            int Width  = Texture.Width;
-            int Height = Texture.Height;
-
-            byte[] Output = new byte[Width * Height * 4];
-
-            ISwizzle Swizzle = GetSwizzle(Texture, 4);
-
-            fixed (byte* BuffPtr = Output)
-            {
-                long OutOffs = 0;
-
-                for (int Y = 0; Y < Height; Y++)
-                for (int X = 0; X < Width;  X++)
-                {
-                    long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
-
-                    int Pixel = Memory.ReadInt32Unchecked(Texture.Position + Offset);
-
-                    *(int*)(BuffPtr + OutOffs) = Pixel;
-
-                    OutOffs += 4;
-                }
-            }
-
-            return Output;
-        }
-
         private unsafe static byte[] Read2Bpp(AMemory Memory, Texture Texture)
         {
             int Width  = Texture.Width;
@@ -56,7 +28,7 @@ namespace Ryujinx.Graphics.Gpu
 
             byte[] Output = new byte[Width * Height * 2];
 
-            ISwizzle Swizzle = GetSwizzle(Texture, 2);
+            ISwizzle Swizzle = GetSwizzle(Texture, Width, 2);
 
             fixed (byte* BuffPtr = Output)
             {
@@ -78,6 +50,35 @@ namespace Ryujinx.Graphics.Gpu
             return Output;
         }
 
+        private unsafe static byte[] Read4Bpp(AMemory Memory, Texture Texture)
+        {
+            int Width  = Texture.Width;
+            int Height = Texture.Height;
+
+            byte[] Output = new byte[Width * Height * 4];
+
+            ISwizzle Swizzle = GetSwizzle(Texture, Width, 4);
+
+            fixed (byte* BuffPtr = Output)
+            {
+                long OutOffs = 0;
+
+                for (int Y = 0; Y < Height; Y++)
+                for (int X = 0; X < Width;  X++)
+                {
+                    long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
+
+                    int Pixel = Memory.ReadInt32Unchecked(Texture.Position + Offset);
+
+                    *(int*)(BuffPtr + OutOffs) = Pixel;
+
+                    OutOffs += 4;
+                }
+            }
+
+            return Output;
+        }
+
         private unsafe static byte[] Read8Bpt4x4(AMemory Memory, Texture Texture)
         {
             int Width  = (Texture.Width  + 3) / 4;
@@ -85,7 +86,7 @@ namespace Ryujinx.Graphics.Gpu
 
             byte[] Output = new byte[Width * Height * 8];
 
-            ISwizzle Swizzle = GetSwizzle(Texture, 8);
+            ISwizzle Swizzle = GetSwizzle(Texture, Width, 8);
 
             fixed (byte* BuffPtr = Output)
             {
@@ -114,7 +115,7 @@ namespace Ryujinx.Graphics.Gpu
 
             byte[] Output = new byte[Width * Height * 16];
 
-            ISwizzle Swizzle = GetSwizzle(Texture, 16);
+            ISwizzle Swizzle = GetSwizzle(Texture, Width, 16);
 
             fixed (byte* BuffPtr = Output)
             {
@@ -138,7 +139,7 @@ namespace Ryujinx.Graphics.Gpu
             return Output;
         }
 
-        private static ISwizzle GetSwizzle(Texture Texture, int Bpp)
+        private static ISwizzle GetSwizzle(Texture Texture, int Width, int Bpp)
         {
             switch (Texture.Swizzle)
             {
@@ -148,7 +149,7 @@ namespace Ryujinx.Graphics.Gpu
 
                 case TextureSwizzle.BlockLinear:
                 case TextureSwizzle.BlockLinearColorKey:
-                    return new BlockLinearSwizzle(Texture.Width, Bpp, Texture.BlockHeight);
+                    return new BlockLinearSwizzle(Width, Bpp, Texture.BlockHeight);
             }
 
             throw new NotImplementedException(Texture.Swizzle.ToString());