Browse Source

New shader translator implementation (#654)

* Start implementing a new shader translator

* Fix shift instructions and a typo

* Small refactoring on StructuredProgram, move RemovePhis method to a separate class

* Initial geometry shader support

* Implement TLD4

* Fix -- There's no negation on FMUL32I

* Add constant folding and algebraic simplification optimizations, nits

* Some leftovers from constant folding

* Avoid cast for constant assignments

* Add a branch elimination pass, and misc small fixes

* Remove redundant branches, add expression propagation and other improvements on the code

* Small leftovers -- add missing break and continue, remove unused properties, other improvements

* Add null check to handle empty block cases on block visitor

* Add HADD2 and HMUL2 half float shader instructions

* Optimize pack/unpack sequences, some fixes related to half float instructions

* Add TXQ, TLD, TLDS and TLD4S shader texture instructions, and some support for bindless textures, some refactoring on codegen

* Fix copy paste mistake that caused RZ to be ignored on the AST instruction

* Add workaround for conditional exit, and fix half float instruction with constant buffer

* Add missing 0.0 source for TLDS.LZ variants

* Simplify the switch for TLDS.LZ

* Texture instructions related fixes

* Implement the HFMA instruction, and some misc. fixes

* Enable constant folding on UnpackHalf2x16 instructions

* Refactor HFMA to use OpCode* for opcode decoding rather than on the helper methods

* Remove the old shader translator

* Remove ShaderDeclInfo and other unused things

* Add dual vertex shader support

* Add ShaderConfig, used to pass shader type and maximum cbuffer size

* Move and rename some instruction enums

* Move texture instructions into a separate file

* Move operand GetExpression and locals management to OperandManager

* Optimize opcode decoding using a simple list and binary search

* Add missing condition for do-while on goto elimination

* Misc. fixes on texture instructions

* Simplify TLDS switch

* Address PR feedback, and a nit
gdkchan 7 years ago
parent
commit
6b23a2c125
100 changed files with 2764 additions and 6274 deletions
  1. 3 2
      Ryujinx.Graphics/Gal/IGalShader.cs
  2. 3 2
      Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs
  3. 22 29
      Ryujinx.Graphics/Gal/OpenGL/OglShader.cs
  4. 7 6
      Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs
  5. 0 420
      Ryujinx.Graphics/Gal/Shader/GlslDecl.cs
  6. 0 1679
      Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs
  7. 0 22
      Ryujinx.Graphics/Gal/Shader/GlslProgram.cs
  8. 0 1299
      Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs
  9. 0 57
      Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs
  10. 0 4
      Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs
  11. 0 78
      Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs
  12. 0 878
      Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs
  13. 0 431
      Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs
  14. 0 313
      Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs
  15. 0 25
      Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs
  16. 0 218
      Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs
  17. 0 146
      Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs
  18. 0 10
      Ryujinx.Graphics/Gal/Shader/ShaderIpaMode.cs
  19. 0 14
      Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs
  20. 0 46
      Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs
  21. 0 12
      Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs
  22. 0 17
      Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs
  23. 0 94
      Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs
  24. 0 4
      Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs
  25. 0 12
      Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs
  26. 0 24
      Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs
  27. 0 15
      Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs
  28. 0 4
      Ryujinx.Graphics/Gal/Shader/ShaderIrNode.cs
  29. 0 25
      Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs
  30. 0 15
      Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs
  31. 0 17
      Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs
  32. 0 36
      Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs
  33. 0 12
      Ryujinx.Graphics/Gal/Shader/ShaderIrOperImm.cs
  34. 0 12
      Ryujinx.Graphics/Gal/Shader/ShaderIrOperImmf.cs
  35. 0 17
      Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs
  36. 0 190
      Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs
  37. 0 11
      Ryujinx.Graphics/Gal/Shader/ShaderOper.cs
  38. 0 9
      Ryujinx.Graphics/Gal/Shader/ShaderRegisterSize.cs
  39. 0 13
      Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs
  40. 0 45
      Ryujinx.Graphics/Gal/ShaderDeclInfo.cs
  41. 14 11
      Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs
  42. 15 0
      Ryujinx.Graphics/Shader/CBufferDescriptor.cs
  43. 90 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/CodeGenContext.cs
  44. 206 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/Declarations.cs
  45. 17 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/DefaultNames.cs
  46. 133 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslGenerator.cs
  47. 20 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslProgram.cs
  48. 110 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGen.cs
  49. 170 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs
  50. 244 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
  51. 45 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs
  52. 18 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstInfo.cs
  53. 27 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstType.cs
  54. 104 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/NumberFormatter.cs
  55. 239 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs
  56. 85 0
      Ryujinx.Graphics/Shader/CodeGen/Glsl/TypeConversion.cs
  57. 25 0
      Ryujinx.Graphics/Shader/Decoders/BitfieldExtensions.cs
  58. 117 0
      Ryujinx.Graphics/Shader/Decoders/Block.cs
  59. 45 0
      Ryujinx.Graphics/Shader/Decoders/Condition.cs
  60. 10 0
      Ryujinx.Graphics/Shader/Decoders/ConditionalOperation.cs
  61. 406 0
      Ryujinx.Graphics/Shader/Decoders/Decoder.cs
  62. 58 0
      Ryujinx.Graphics/Shader/Decoders/DecoderHelper.cs
  63. 10 0
      Ryujinx.Graphics/Shader/Decoders/FPHalfSwizzle.cs
  64. 9 0
      Ryujinx.Graphics/Shader/Decoders/FPType.cs
  65. 13 0
      Ryujinx.Graphics/Shader/Decoders/FmulScale.cs
  66. 16 0
      Ryujinx.Graphics/Shader/Decoders/IOpCode.cs
  67. 12 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeAlu.cs
  68. 8 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeCbuf.cs
  69. 12 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeFArith.cs
  70. 13 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeHfma.cs
  71. 7 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeImm.cs
  72. 7 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeImmF.cs
  73. 10 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeLop.cs
  74. 7 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeRa.cs
  75. 7 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeRc.cs
  76. 7 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeRd.cs
  77. 7 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeReg.cs
  78. 8 0
      Ryujinx.Graphics/Shader/Decoders/IOpCodeRegCbuf.cs
  79. 18 0
      Ryujinx.Graphics/Shader/Decoders/IntegerCondition.cs
  80. 9 0
      Ryujinx.Graphics/Shader/Decoders/IntegerHalfPart.cs
  81. 9 0
      Ryujinx.Graphics/Shader/Decoders/IntegerShift.cs
  82. 12 0
      Ryujinx.Graphics/Shader/Decoders/IntegerSize.cs
  83. 14 0
      Ryujinx.Graphics/Shader/Decoders/IntegerType.cs
  84. 10 0
      Ryujinx.Graphics/Shader/Decoders/LogicalOperation.cs
  85. 15 0
      Ryujinx.Graphics/Shader/Decoders/MufuOperation.cs
  86. 30 0
      Ryujinx.Graphics/Shader/Decoders/OpCode.cs
  87. 34 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeAlu.cs
  88. 16 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeAluCbuf.cs
  89. 14 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm.cs
  90. 14 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm2x10.cs
  91. 18 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm32.cs
  92. 14 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeAluReg.cs
  93. 18 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeAluRegCbuf.cs
  94. 16 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeAttribute.cs
  95. 19 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeBranch.cs
  96. 14 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeExit.cs
  97. 24 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeFArith.cs
  98. 16 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeFArithCbuf.cs
  99. 14 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm.cs
  100. 30 0
      Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm32.cs

+ 3 - 2
Ryujinx.Graphics/Gal/IGalShader.cs

@@ -1,3 +1,4 @@
+using Ryujinx.Graphics.Shader;
 using System.Collections.Generic;
 
 namespace Ryujinx.Graphics.Gal
@@ -8,8 +9,8 @@ namespace Ryujinx.Graphics.Gal
 
         void Create(IGalMemory memory, long vpAPos, long key, GalShaderType type);
 
-        IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long key);
-        IEnumerable<ShaderDeclInfo> GetTextureUsage(long key);
+        IEnumerable<CBufferDescriptor> GetConstBufferUsage(long key);
+        IEnumerable<TextureDescriptor> GetTextureUsage(long key);
 
         void Bind(long key);
 

+ 3 - 2
Ryujinx.Graphics/Gal/OpenGL/OglPipeline.cs

@@ -1,4 +1,5 @@
 using OpenTK.Graphics.OpenGL;
+using Ryujinx.Graphics.Shader;
 using System;
 using System.Collections.Generic;
 
@@ -529,9 +530,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
             {
                 if (stage != null)
                 {
-                    foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage)
+                    foreach (CBufferDescriptor desc in stage.ConstBufferUsage)
                     {
-                        long key = New.ConstBufferKeys[(int)stage.Type][declInfo.Cbuf];
+                        long key = New.ConstBufferKeys[(int)stage.Type][desc.Slot];
 
                         if (key != 0 && _buffer.TryGetUbo(key, out int uboHandle))
                         {

+ 22 - 29
Ryujinx.Graphics/Gal/OpenGL/OglShader.cs

@@ -1,5 +1,6 @@
 using OpenTK.Graphics.OpenGL;
-using Ryujinx.Graphics.Gal.Shader;
+using Ryujinx.Graphics.Shader;
+using Ryujinx.Graphics.Shader.Translation;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
@@ -51,54 +52,54 @@ namespace Ryujinx.Graphics.Gal.OpenGL
             bool          isDualVp,
             GalShaderType type)
         {
-            GlslProgram program;
+            ShaderConfig config = new ShaderConfig(type, OglLimit.MaxUboSize);
 
-            GlslDecompiler decompiler = new GlslDecompiler(OglLimit.MaxUboSize, OglExtension.NvidiaDriver);
-
-            int shaderDumpIndex = ShaderDumper.DumpIndex;
+            ShaderProgram program;
 
             if (isDualVp)
             {
                 ShaderDumper.Dump(memory, position,  type, "a");
                 ShaderDumper.Dump(memory, positionB, type, "b");
 
-                program = decompiler.Decompile(memory, position, positionB, type);
+                program = Translator.Translate(memory, (ulong)position, (ulong)positionB, config);
             }
             else
             {
                 ShaderDumper.Dump(memory, position, type);
 
-                program = decompiler.Decompile(memory, position, type);
+                program = Translator.Translate(memory, (ulong)position, config);
             }
 
             string code = program.Code;
 
             if (ShaderDumper.IsDumpEnabled())
             {
+                int shaderDumpIndex = ShaderDumper.DumpIndex;
+
                 code = "//Shader " + shaderDumpIndex + Environment.NewLine + code;
             }
 
-            return new OglShaderStage(type, code, program.Uniforms, program.Textures);
+            return new OglShaderStage(type, code, program.Info.CBuffers, program.Info.Textures);
         }
 
-        public IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long key)
+        public IEnumerable<CBufferDescriptor> GetConstBufferUsage(long key)
         {
             if (_stages.TryGetValue(key, out OglShaderStage stage))
             {
                 return stage.ConstBufferUsage;
             }
 
-            return Enumerable.Empty<ShaderDeclInfo>();
+            return Enumerable.Empty<CBufferDescriptor>();
         }
 
-        public IEnumerable<ShaderDeclInfo> GetTextureUsage(long key)
+        public IEnumerable<TextureDescriptor> GetTextureUsage(long key)
         {
             if (_stages.TryGetValue(key, out OglShaderStage stage))
             {
                 return stage.TextureUsage;
             }
 
-            return Enumerable.Empty<ShaderDeclInfo>();
+            return Enumerable.Empty<TextureDescriptor>();
         }
 
         public unsafe void SetExtraData(float flipX, float flipY, int instance)
@@ -130,16 +131,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
         private void Bind(OglShaderStage 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.EnhancedLayouts)
-                {
-                    return;
-                }
-            }
-
             switch (stage.Type)
             {
                 case GalShaderType.Vertex:         Current.Vertex         = stage; break;
@@ -221,7 +212,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
         private void BindUniformBlocks(int programHandle)
         {
-            int extraBlockindex = GL.GetUniformBlockIndex(programHandle, GlslDecl.ExtraUniformBlockName);
+            int extraBlockindex = GL.GetUniformBlockIndex(programHandle, "Extra");
 
             GL.UniformBlockBinding(programHandle, extraBlockindex, 0);
 
@@ -231,14 +222,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
             {
                 if (stage != null)
                 {
-                    foreach (ShaderDeclInfo declInfo in stage.ConstBufferUsage)
+                    foreach (CBufferDescriptor desc in stage.ConstBufferUsage)
                     {
-                        int blockIndex = GL.GetUniformBlockIndex(programHandle, declInfo.Name);
+                        int blockIndex = GL.GetUniformBlockIndex(programHandle, desc.Name);
 
                         if (blockIndex < 0)
                         {
-                            //It is expected that its found, if it's not then driver might be in a malfunction
-                            throw new InvalidOperationException();
+                            //This may be fine, the compiler may optimize away unused uniform buffers,
+                            //and in this case the above call would return -1 as the buffer has been
+                            //optimized away.
+                            continue;
                         }
 
                         GL.UniformBlockBinding(programHandle, blockIndex, freeBinding);
@@ -263,9 +256,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
             {
                 if (stage != null)
                 {
-                    foreach (ShaderDeclInfo decl in stage.TextureUsage)
+                    foreach (TextureDescriptor desc in stage.TextureUsage)
                     {
-                        int location = GL.GetUniformLocation(programHandle, decl.Name);
+                        int location = GL.GetUniformLocation(programHandle, desc.Name);
 
                         GL.Uniform1(location, index);
 

+ 7 - 6
Ryujinx.Graphics/Gal/OpenGL/OglShaderProgram.cs

@@ -1,4 +1,5 @@
 using OpenTK.Graphics.OpenGL;
+using Ryujinx.Graphics.Shader;
 using System;
 using System.Collections.Generic;
 
@@ -23,14 +24,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
 
         public string Code { get; private set; }
 
-        public IEnumerable<ShaderDeclInfo> ConstBufferUsage { get; private set; }
-        public IEnumerable<ShaderDeclInfo> TextureUsage     { get; private set; }
+        public IEnumerable<CBufferDescriptor> ConstBufferUsage { get; private set; }
+        public IEnumerable<TextureDescriptor> TextureUsage     { get; private set; }
 
         public OglShaderStage(
-            GalShaderType               type,
-            string                      code,
-            IEnumerable<ShaderDeclInfo> constBufferUsage,
-            IEnumerable<ShaderDeclInfo> textureUsage)
+            GalShaderType                  type,
+            string                         code,
+            IEnumerable<CBufferDescriptor> constBufferUsage,
+            IEnumerable<TextureDescriptor> textureUsage)
         {
             Type             = type;
             Code             = code;

+ 0 - 420
Ryujinx.Graphics/Gal/Shader/GlslDecl.cs

@@ -1,420 +0,0 @@
-using Ryujinx.Graphics.Texture;
-using System;
-using System.Collections.Generic;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class GlslDecl
-    {
-        public const int LayerAttr       = 0x064;
-        public const int PointSizeAttr   = 0x06c;
-        public const int PointCoordAttrX = 0x2e0;
-        public const int PointCoordAttrY = 0x2e4;
-        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 GlPositionVec4Index = 7;
-
-        public const int PositionOutAttrLocation = 15;
-
-        private const int AttrStartIndex = 8;
-        private const int TexStartIndex  = 8;
-
-        public const string PositionOutAttrName = "position";
-
-        private const string TextureName = "tex";
-        private const string UniformName = "c";
-
-        private const string AttrName    = "attr";
-        private const string InAttrName  = "in_"  + AttrName;
-        private const string OutAttrName = "out_" + AttrName;
-
-        private const string GprName  = "gpr";
-        private const string PredName = "pred";
-
-        public const string FragmentOutputName = "FragColor";
-
-        public const string ExtraUniformBlockName = "Extra";
-        public const string FlipUniformName = "flip";
-        public const string InstanceUniformName = "instance";
-
-        public const string BasicBlockName  = "bb";
-        public const string BasicBlockAName = BasicBlockName + "_a";
-        public const string BasicBlockBName = BasicBlockName + "_b";
-
-        public const int SsyStackSize = 16;
-        public const string SsyStackName = "ssy_stack";
-        public const string SsyCursorName = "ssy_cursor";
-
-        private string[] _stagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
-
-        private string _stagePrefix;
-
-        private Dictionary<ShaderIrOp, ShaderDeclInfo> m_CbTextures;
-
-        private Dictionary<int, ShaderDeclInfo> m_Textures;
-        private Dictionary<int, ShaderDeclInfo> m_Uniforms;
-
-        private Dictionary<int, ShaderDeclInfo> m_Attributes;
-        private Dictionary<int, ShaderDeclInfo> m_InAttributes;
-        private Dictionary<int, ShaderDeclInfo> m_OutAttributes;
-
-        private Dictionary<int, ShaderDeclInfo> m_Gprs;
-        private Dictionary<int, ShaderDeclInfo> m_GprsHalf;
-        private Dictionary<int, ShaderDeclInfo> m_Preds;
-
-        public IReadOnlyDictionary<ShaderIrOp, ShaderDeclInfo> CbTextures => m_CbTextures;
-
-        public IReadOnlyDictionary<int, ShaderDeclInfo> Textures => m_Textures;
-        public IReadOnlyDictionary<int, ShaderDeclInfo> Uniforms => m_Uniforms;
-
-        public IReadOnlyDictionary<int, ShaderDeclInfo> Attributes    => m_Attributes;
-        public IReadOnlyDictionary<int, ShaderDeclInfo> InAttributes  => m_InAttributes;
-        public IReadOnlyDictionary<int, ShaderDeclInfo> OutAttributes => m_OutAttributes;
-
-        public IReadOnlyDictionary<int, ShaderDeclInfo> Gprs     => m_Gprs;
-        public IReadOnlyDictionary<int, ShaderDeclInfo> GprsHalf => m_GprsHalf;
-        public IReadOnlyDictionary<int, ShaderDeclInfo> Preds    => m_Preds;
-
-        public GalShaderType ShaderType { get; private set; }
-
-        private GlslDecl(GalShaderType shaderType)
-        {
-            ShaderType = shaderType;
-
-            m_CbTextures = new Dictionary<ShaderIrOp, ShaderDeclInfo>();
-
-            m_Textures = new Dictionary<int, ShaderDeclInfo>();
-            m_Uniforms = new Dictionary<int, ShaderDeclInfo>();
-
-            m_Attributes    = new Dictionary<int, ShaderDeclInfo>();
-            m_InAttributes  = new Dictionary<int, ShaderDeclInfo>();
-            m_OutAttributes = new Dictionary<int, ShaderDeclInfo>();
-
-            m_Gprs     = new Dictionary<int, ShaderDeclInfo>();
-            m_GprsHalf = new Dictionary<int, ShaderDeclInfo>();
-            m_Preds    = new Dictionary<int, ShaderDeclInfo>();
-        }
-
-        public GlslDecl(ShaderIrBlock[] blocks, GalShaderType shaderType, ShaderHeader header) : this(shaderType)
-        {
-            _stagePrefix = _stagePrefixes[(int)shaderType] + "_";
-
-            if (shaderType == GalShaderType.Fragment)
-            {
-                int index = 0;
-
-                for (int attachment = 0; attachment < 8; attachment++)
-                {
-                    for (int component = 0; component < 4; component++)
-                    {
-                        if (header.OmapTargets[attachment].ComponentEnabled(component))
-                        {
-                            m_Gprs.TryAdd(index, new ShaderDeclInfo(GetGprName(index), index));
-
-                            index++;
-                        }
-                    }
-                }
-
-                if (header.OmapDepth)
-                {
-                    index = header.DepthRegister;
-
-                    m_Gprs.TryAdd(index, new ShaderDeclInfo(GetGprName(index), index));
-                }
-            }
-
-            foreach (ShaderIrBlock block in blocks)
-            {
-                ShaderIrNode[] nodes = block.GetNodes();
-
-                foreach (ShaderIrNode node in nodes)
-                {
-                    Traverse(nodes, null, node);
-                }
-            }
-        }
-
-        public static GlslDecl Merge(GlslDecl vpA, GlslDecl vpB)
-        {
-            GlslDecl combined = new GlslDecl(GalShaderType.Vertex);
-
-            Merge(combined.m_Textures, vpA.m_Textures, vpB.m_Textures);
-            Merge(combined.m_Uniforms, vpA.m_Uniforms, vpB.m_Uniforms);
-
-            Merge(combined.m_Attributes,    vpA.m_Attributes,    vpB.m_Attributes);
-            Merge(combined.m_OutAttributes, vpA.m_OutAttributes, vpB.m_OutAttributes);
-
-            Merge(combined.m_Gprs,     vpA.m_Gprs,     vpB.m_Gprs);
-            Merge(combined.m_GprsHalf, vpA.m_GprsHalf, vpB.m_GprsHalf);
-            Merge(combined.m_Preds,    vpA.m_Preds,    vpB.m_Preds);
-
-            //Merge input attributes.
-            foreach (KeyValuePair<int, ShaderDeclInfo> kv in vpA.m_InAttributes)
-            {
-                combined.m_InAttributes.TryAdd(kv.Key, kv.Value);
-            }
-
-            foreach (KeyValuePair<int, ShaderDeclInfo> kv in vpB.m_InAttributes)
-            {
-                //If Vertex Program A already writes to this attribute,
-                //then we don't need to add it as an input attribute since
-                //Vertex Program A will already have written to it anyway,
-                //and there's no guarantee that there is an input attribute
-                //for this slot.
-                if (!vpA.m_OutAttributes.ContainsKey(kv.Key))
-                {
-                    combined.m_InAttributes.TryAdd(kv.Key, kv.Value);
-                }
-            }
-
-            return combined;
-        }
-
-        public static string GetGprName(int index)
-        {
-            return GprName + index;
-        }
-
-        private static void Merge(
-            Dictionary<int, ShaderDeclInfo> c,
-            Dictionary<int, ShaderDeclInfo> a,
-            Dictionary<int, ShaderDeclInfo> b)
-        {
-            foreach (KeyValuePair<int, ShaderDeclInfo> kv in a)
-            {
-                c.TryAdd(kv.Key, kv.Value);
-            }
-
-            foreach (KeyValuePair<int, ShaderDeclInfo> kv in b)
-            {
-                c.TryAdd(kv.Key, kv.Value);
-            }
-        }
-
-        private void Traverse(ShaderIrNode[] nodes, ShaderIrNode parent, ShaderIrNode node)
-        {
-            switch (node)
-            {
-                case ShaderIrAsg asg:
-                {
-                    Traverse(nodes, asg, asg.Dst);
-                    Traverse(nodes, asg, asg.Src);
-
-                    break;
-                }
-
-                case ShaderIrCond cond:
-                {
-                    Traverse(nodes, cond, cond.Pred);
-                    Traverse(nodes, cond, cond.Child);
-
-                    break;
-                }
-
-                case ShaderIrOp op:
-                {
-                    Traverse(nodes, op, op.OperandA);
-                    Traverse(nodes, op, op.OperandB);
-                    Traverse(nodes, op, op.OperandC);
-
-                    if (op.Inst == ShaderIrInst.Texq ||
-                        op.Inst == ShaderIrInst.Texs ||
-                        op.Inst == ShaderIrInst.Tld4 ||
-                        op.Inst == ShaderIrInst.Txlf)
-                    {
-                        int handle = ((ShaderIrOperImm)op.OperandC).Value;
-
-                        int index = handle - TexStartIndex;
-
-                        string name = _stagePrefix + TextureName + index;
-
-                        GalTextureTarget textureTarget;
-                        
-                        TextureInstructionSuffix textureInstructionSuffix;
-
-                        // TODO: Non 2D texture type for TEXQ?
-                        if (op.Inst == ShaderIrInst.Texq)
-                        {
-                            textureTarget            = GalTextureTarget.TwoD;
-                            textureInstructionSuffix = TextureInstructionSuffix.None;
-                        }
-                        else
-                        {
-                            ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData);
-
-                            textureTarget            = meta.TextureTarget;
-                            textureInstructionSuffix = meta.TextureInstructionSuffix;
-                        }
-
-                        m_Textures.TryAdd(handle, new ShaderDeclInfo(name, handle, false, 0, 1, textureTarget, textureInstructionSuffix));
-                    }
-                    else if (op.Inst == ShaderIrInst.Texb)
-                    {
-                        ShaderIrNode handleSrc = null;
-
-                        int index = Array.IndexOf(nodes, parent) - 1;
-
-                        for (; index >= 0; index--)
-                        {
-                            ShaderIrNode curr = nodes[index];
-
-                            if (curr is ShaderIrAsg asg && asg.Dst is ShaderIrOperGpr gpr)
-                            {
-                                if (gpr.Index == ((ShaderIrOperGpr)op.OperandC).Index)
-                                {
-                                    handleSrc = asg.Src;
-
-                                    break;
-                                }
-                            }
-                        }
-
-                        if (handleSrc != null && handleSrc is ShaderIrOperCbuf cbuf)
-                        {
-                            ShaderIrMetaTex meta = ((ShaderIrMetaTex)op.MetaData);
-                            string name = _stagePrefix + TextureName + "_cb" + cbuf.Index + "_" + cbuf.Pos;
-
-                            m_CbTextures.Add(op, new ShaderDeclInfo(name, cbuf.Pos, true, cbuf.Index, 1, meta.TextureTarget, meta.TextureInstructionSuffix));
-                        }
-                        else
-                        {
-                            throw new NotImplementedException("Shader TEX.B instruction is not fully supported!");
-                        }
-                    }
-                    break;
-                }
-
-                case ShaderIrOperCbuf cbuf:
-                {
-                    if (!m_Uniforms.ContainsKey(cbuf.Index))
-                    {
-                        string name = _stagePrefix + UniformName + cbuf.Index;
-
-                        ShaderDeclInfo declInfo = new ShaderDeclInfo(name, cbuf.Pos, true, cbuf.Index);
-
-                        m_Uniforms.Add(cbuf.Index, declInfo);
-                    }
-                    break;
-                }
-
-                case ShaderIrOperAbuf abuf:
-                {
-                    //This is a built-in variable.
-                    if (abuf.Offs == LayerAttr       ||
-                        abuf.Offs == PointSizeAttr   ||
-                        abuf.Offs == PointCoordAttrX ||
-                        abuf.Offs == PointCoordAttrY ||
-                        abuf.Offs == VertexIdAttr    ||
-                        abuf.Offs == InstanceIdAttr  ||
-                        abuf.Offs == FaceAttr)
-                    {
-                        break;
-                    }
-
-                    int index =  abuf.Offs >> 4;
-                    int elem  = (abuf.Offs >> 2) & 3;
-
-                    int glslIndex = index - AttrStartIndex;
-
-                    if (glslIndex < 0)
-                    {
-                        return;
-                    }
-
-                    ShaderDeclInfo declInfo;
-
-                    if (parent is ShaderIrAsg asg && asg.Dst == node)
-                    {
-                        if (!m_OutAttributes.TryGetValue(index, out declInfo))
-                        {
-                            declInfo = new ShaderDeclInfo(OutAttrName + glslIndex, glslIndex);
-
-                            m_OutAttributes.Add(index, declInfo);
-                        }
-                    }
-                    else
-                    {
-                        if (!m_InAttributes.TryGetValue(index, out declInfo))
-                        {
-                            declInfo = new ShaderDeclInfo(InAttrName + glslIndex, glslIndex);
-
-                            m_InAttributes.Add(index, declInfo);
-                        }
-                    }
-
-                    declInfo.Enlarge(elem + 1);
-
-                    if (!m_Attributes.ContainsKey(index))
-                    {
-                        declInfo = new ShaderDeclInfo(AttrName + glslIndex, glslIndex, false, 0, 4);
-
-                        m_Attributes.Add(index, declInfo);
-                    }
-
-                    Traverse(nodes, abuf, abuf.Vertex);
-
-                    break;
-                }
-
-                case ShaderIrOperGpr gpr:
-                {
-                    if (!gpr.IsConst)
-                    {
-                        string name = GetGprName(gpr.Index);
-
-                        if (gpr.RegisterSize == ShaderRegisterSize.Single)
-                        {
-                            m_Gprs.TryAdd(gpr.Index, new ShaderDeclInfo(name, gpr.Index));
-                        }
-                        else if (gpr.RegisterSize == ShaderRegisterSize.Half)
-                        {
-                            name += "_h" + gpr.HalfPart;
-
-                            m_GprsHalf.TryAdd((gpr.Index << 1) | gpr.HalfPart, new ShaderDeclInfo(name, gpr.Index));
-                        }
-                        else /* if (Gpr.RegisterSize == ShaderRegisterSize.Double) */
-                        {
-                            throw new NotImplementedException("Double types are not supported.");
-                        }
-                    }
-                    break;
-                }
-
-                case ShaderIrOperPred pred:
-                {
-                    if (!pred.IsConst && !HasName(m_Preds, pred.Index))
-                    {
-                        string name = PredName + pred.Index;
-
-                        m_Preds.TryAdd(pred.Index, new ShaderDeclInfo(name, pred.Index));
-                    }
-                    break;
-                }
-            }
-        }
-
-        private bool HasName(Dictionary<int, ShaderDeclInfo> decls, int index)
-        {
-            //This is used to check if the dictionary already contains
-            //a entry for a vector at a given index position.
-            //Used to enable turning gprs into vectors.
-            int vecIndex = index & ~3;
-
-            if (decls.TryGetValue(vecIndex, out ShaderDeclInfo declInfo))
-            {
-                if (declInfo.Size > 1 && index < vecIndex + declInfo.Size)
-                {
-                    return true;
-                }
-            }
-
-            return decls.ContainsKey(index);
-        }
-    }
-}

+ 0 - 1679
Ryujinx.Graphics/Gal/Shader/GlslDecompiler.cs

@@ -1,1679 +0,0 @@
-using OpenTK.Graphics.OpenGL;
-using Ryujinx.Graphics.Texture;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Text;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    public class GlslDecompiler
-    {
-        private delegate string GetInstExpr(ShaderIrOp op);
-
-        private Dictionary<ShaderIrInst, GetInstExpr> _instsExpr;
-
-        private enum OperType
-        {
-            Bool,
-            F32,
-            I32
-        }
-
-        private const string IdentationStr = "    ";
-
-        private const int MaxVertexInput = 3;
-
-        private GlslDecl _decl;
-
-        private ShaderHeader _header, _headerB;
-
-        private ShaderIrBlock[] _blocks, _blocksB;
-
-        private StringBuilder _sb;
-
-        public int MaxUboSize { get; }
-
-        private bool _isNvidiaDriver;
-
-        public GlslDecompiler(int maxUboSize, bool isNvidiaDriver)
-        {
-            _instsExpr = new Dictionary<ShaderIrInst, GetInstExpr>()
-            {
-                { ShaderIrInst.Abs,    GetAbsExpr    },
-                { ShaderIrInst.Add,    GetAddExpr    },
-                { ShaderIrInst.And,    GetAndExpr    },
-                { ShaderIrInst.Asr,    GetAsrExpr    },
-                { ShaderIrInst.Band,   GetBandExpr   },
-                { ShaderIrInst.Bnot,   GetBnotExpr   },
-                { ShaderIrInst.Bor,    GetBorExpr    },
-                { ShaderIrInst.Bxor,   GetBxorExpr   },
-                { ShaderIrInst.Ceil,   GetCeilExpr   },
-                { ShaderIrInst.Ceq,    GetCeqExpr    },
-                { ShaderIrInst.Cge,    GetCgeExpr    },
-                { ShaderIrInst.Cgt,    GetCgtExpr    },
-                { ShaderIrInst.Clamps, GetClampsExpr },
-                { ShaderIrInst.Clampu, GetClampuExpr },
-                { ShaderIrInst.Cle,    GetCleExpr    },
-                { ShaderIrInst.Clt,    GetCltExpr    },
-                { ShaderIrInst.Cne,    GetCneExpr    },
-                { ShaderIrInst.Cut,    GetCutExpr    },
-                { ShaderIrInst.Exit,   GetExitExpr   },
-                { ShaderIrInst.Fabs,   GetAbsExpr    },
-                { ShaderIrInst.Fadd,   GetAddExpr    },
-                { ShaderIrInst.Fceq,   GetCeqExpr    },
-                { ShaderIrInst.Fcequ,  GetCequExpr   },
-                { ShaderIrInst.Fcge,   GetCgeExpr    },
-                { ShaderIrInst.Fcgeu,  GetCgeuExpr   },
-                { ShaderIrInst.Fcgt,   GetCgtExpr    },
-                { ShaderIrInst.Fcgtu,  GetCgtuExpr   },
-                { ShaderIrInst.Fclamp, GetFclampExpr },
-                { ShaderIrInst.Fcle,   GetCleExpr    },
-                { ShaderIrInst.Fcleu,  GetCleuExpr   },
-                { ShaderIrInst.Fclt,   GetCltExpr    },
-                { ShaderIrInst.Fcltu,  GetCltuExpr   },
-                { ShaderIrInst.Fcnan,  GetCnanExpr   },
-                { ShaderIrInst.Fcne,   GetCneExpr    },
-                { ShaderIrInst.Fcneu,  GetCneuExpr   },
-                { ShaderIrInst.Fcnum,  GetCnumExpr   },
-                { ShaderIrInst.Fcos,   GetFcosExpr   },
-                { ShaderIrInst.Fex2,   GetFex2Expr   },
-                { ShaderIrInst.Ffma,   GetFfmaExpr   },
-                { ShaderIrInst.Flg2,   GetFlg2Expr   },
-                { ShaderIrInst.Floor,  GetFloorExpr  },
-                { ShaderIrInst.Fmax,   GetMaxExpr    },
-                { ShaderIrInst.Fmin,   GetMinExpr    },
-                { ShaderIrInst.Fmul,   GetMulExpr    },
-                { ShaderIrInst.Fneg,   GetNegExpr    },
-                { ShaderIrInst.Frcp,   GetFrcpExpr   },
-                { ShaderIrInst.Frsq,   GetFrsqExpr   },
-                { ShaderIrInst.Fsin,   GetFsinExpr   },
-                { ShaderIrInst.Fsqrt,  GetFsqrtExpr  },
-                { ShaderIrInst.Ftos,   GetFtosExpr   },
-                { ShaderIrInst.Ftou,   GetFtouExpr   },
-                { ShaderIrInst.Ipa,    GetIpaExpr    },
-                { ShaderIrInst.Kil,    GetKilExpr    },
-                { ShaderIrInst.Lsl,    GetLslExpr    },
-                { ShaderIrInst.Lsr,    GetLsrExpr    },
-                { ShaderIrInst.Max,    GetMaxExpr    },
-                { ShaderIrInst.Min,    GetMinExpr    },
-                { ShaderIrInst.Mul,    GetMulExpr    },
-                { ShaderIrInst.Neg,    GetNegExpr    },
-                { ShaderIrInst.Not,    GetNotExpr    },
-                { ShaderIrInst.Or,     GetOrExpr     },
-                { ShaderIrInst.Stof,   GetStofExpr   },
-                { ShaderIrInst.Sub,    GetSubExpr    },
-                { ShaderIrInst.Texb,   GetTexbExpr   },
-                { ShaderIrInst.Texq,   GetTexqExpr   },
-                { ShaderIrInst.Texs,   GetTexsExpr   },
-                { ShaderIrInst.Tld4,   GetTld4Expr   },
-                { ShaderIrInst.Trunc,  GetTruncExpr  },
-                { ShaderIrInst.Txlf,   GetTxlfExpr   },
-                { ShaderIrInst.Utof,   GetUtofExpr   },
-                { ShaderIrInst.Xor,    GetXorExpr    }
-            };
-
-            MaxUboSize = maxUboSize / 16;
-            _isNvidiaDriver = isNvidiaDriver;
-        }
-
-        public GlslProgram Decompile(
-            IGalMemory    memory,
-            long          vpAPosition,
-            long          vpBPosition,
-            GalShaderType shaderType)
-        {
-            _header  = new ShaderHeader(memory, vpAPosition);
-            _headerB = new ShaderHeader(memory, vpBPosition);
-
-            _blocks  = ShaderDecoder.Decode(memory, vpAPosition);
-            _blocksB = ShaderDecoder.Decode(memory, vpBPosition);
-
-            GlslDecl declVpA = new GlslDecl(_blocks,  shaderType, _header);
-            GlslDecl declVpB = new GlslDecl(_blocksB, shaderType, _headerB);
-
-            _decl = GlslDecl.Merge(declVpA, declVpB);
-
-            return Decompile();
-        }
-
-        public GlslProgram Decompile(IGalMemory memory, long position, GalShaderType shaderType)
-        {
-            _header  = new ShaderHeader(memory, position);
-            _headerB = null;
-
-            _blocks  = ShaderDecoder.Decode(memory, position);
-            _blocksB = null;
-
-            _decl = new GlslDecl(_blocks, shaderType, _header);
-
-            return Decompile();
-        }
-
-        private GlslProgram Decompile()
-        {
-            _sb = new StringBuilder();
-
-            _sb.AppendLine("#version 410 core");
-
-            PrintDeclHeader();
-            PrintDeclTextures();
-            PrintDeclUniforms();
-            PrintDeclAttributes();
-            PrintDeclInAttributes();
-            PrintDeclOutAttributes();
-            PrintDeclGprs();
-            PrintDeclPreds();
-            PrintDeclSsy();
-
-            if (_blocksB != null)
-            {
-                PrintBlockScope(_blocks, GlslDecl.BasicBlockAName);
-
-                _sb.AppendLine();
-
-                PrintBlockScope(_blocksB, GlslDecl.BasicBlockBName);
-            }
-            else
-            {
-                PrintBlockScope(_blocks, GlslDecl.BasicBlockName);
-            }
-
-            _sb.AppendLine();
-
-            PrintMain();
-
-            string glslCode = _sb.ToString();
-
-            List<ShaderDeclInfo> textureInfo = new List<ShaderDeclInfo>();
-
-            textureInfo.AddRange(_decl.Textures.Values);
-            textureInfo.AddRange(IterateCbTextures());
-
-            return new GlslProgram(glslCode, textureInfo, _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 string GetSamplerType(TextureTarget textureTarget, bool hasShadow)
-        {
-            string result;
-
-            switch (textureTarget)
-            {
-                case TextureTarget.Texture1D:
-                    result = "sampler1D";
-                    break;
-                case TextureTarget.Texture2D:
-                    result = "sampler2D";
-                    break;
-                case TextureTarget.Texture3D:
-                    result = "sampler3D";
-                    break;
-                case TextureTarget.TextureCubeMap:
-                    result = "samplerCube";
-                    break;
-                case TextureTarget.TextureRectangle:
-                    result = "sampler2DRect";
-                    break;
-                case TextureTarget.Texture1DArray:
-                    result = "sampler1DArray";
-                    break;
-                case TextureTarget.Texture2DArray:
-                    result = "sampler2DArray";
-                    break;
-                case TextureTarget.TextureCubeMapArray:
-                    result = "samplerCubeArray";
-                    break;
-                case TextureTarget.TextureBuffer:
-                    result = "samplerBuffer";
-                    break;
-                case TextureTarget.Texture2DMultisample:
-                    result = "sampler2DMS";
-                    break;
-                case TextureTarget.Texture2DMultisampleArray:
-                    result = "sampler2DMSArray";
-                    break;
-                default:
-                    throw new NotSupportedException();
-            }
-
-            if (hasShadow)
-                result += "Shadow";
-
-            return result;
-        }
-
-        private void PrintDeclTextures()
-        {
-            foreach (ShaderDeclInfo declInfo in IterateCbTextures())
-            {
-                TextureTarget target = ImageUtils.GetTextureTarget(declInfo.TextureTarget);
-                _sb.AppendLine($"// {declInfo.TextureSuffix}");
-                _sb.AppendLine("uniform " + GetSamplerType(target, (declInfo.TextureSuffix & TextureInstructionSuffix.Dc) != 0) + " " + declInfo.Name + ";");
-            }
-
-            foreach (ShaderDeclInfo declInfo in _decl.Textures.Values.OrderBy(DeclKeySelector))
-            {
-                TextureTarget target = ImageUtils.GetTextureTarget(declInfo.TextureTarget);
-                _sb.AppendLine($"// {declInfo.TextureSuffix}");
-                _sb.AppendLine("uniform " + GetSamplerType(target, (declInfo.TextureSuffix & TextureInstructionSuffix.Dc) != 0) + " " + declInfo.Name + ";");
-            }
-        }
-
-        private IEnumerable<ShaderDeclInfo> IterateCbTextures()
-        {
-            HashSet<string> names = new HashSet<string>();
-
-            foreach (ShaderDeclInfo declInfo in _decl.CbTextures.Values.OrderBy(DeclKeySelector))
-            {
-                if (names.Add(declInfo.Name))
-                {
-                    yield return declInfo;
-                }
-            }
-        }
-
-        private void PrintDeclUniforms()
-        {
-            if (_decl.ShaderType == GalShaderType.Vertex)
-            {
-                //Memory layout here is [flip_x, flip_y, instance, unused]
-                //It's using 4 bytes, not 8
-
-                _sb.AppendLine("layout (std140) uniform " + GlslDecl.ExtraUniformBlockName + " {");
-
-                _sb.AppendLine(IdentationStr + "vec2 " + GlslDecl.FlipUniformName + ";");
-
-                _sb.AppendLine(IdentationStr + "int " + GlslDecl.InstanceUniformName + ";");
-
-                _sb.AppendLine("};");
-                _sb.AppendLine();
-            }
-
-            foreach (ShaderDeclInfo declInfo in _decl.Uniforms.Values.OrderBy(DeclKeySelector))
-            {
-                _sb.AppendLine($"layout (std140) uniform {declInfo.Name} {{");
-
-                _sb.AppendLine($"{IdentationStr}vec4 {declInfo.Name}_data[{MaxUboSize}];");
-
-                _sb.AppendLine("};");
-            }
-
-            if (_decl.Uniforms.Count > 0)
-            {
-                _sb.AppendLine();
-            }
-        }
-
-        private void PrintDeclAttributes()
-        {
-            string geometryArray = (_decl.ShaderType == GalShaderType.Geometry) ? "[" + MaxVertexInput + "]" : "";
-
-            PrintDecls(_decl.Attributes, suffix: geometryArray);
-        }
-
-        private void PrintDeclInAttributes()
-        {
-            if (_decl.ShaderType == GalShaderType.Fragment)
-            {
-                _sb.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") in vec4 " + GlslDecl.PositionOutAttrName + ";");
-            }
-
-            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 + ") vec4 " + declInfo.Name + "; ");
-                        }
-                    }
-
-                    _sb.AppendLine("} block_in[];" + Environment.NewLine);
-                }
-            }
-            else
-            {
-                PrintDeclAttributes(_decl.InAttributes.Values, "in");
-            }
-        }
-
-        private void PrintDeclOutAttributes()
-        {
-            if (_decl.ShaderType == GalShaderType.Fragment)
-            {
-                int count = 0;
-
-                for (int attachment = 0; attachment < 8; attachment++)
-                {
-                    if (_header.OmapTargets[attachment].Enabled)
-                    {
-                        _sb.AppendLine("layout (location = " + attachment + ") out vec4 " + GlslDecl.FragmentOutputName + attachment + ";");
-
-                        count++;
-                    }
-                }
-
-                if (count > 0)
-                {
-                    _sb.AppendLine();
-                }
-            }
-            else
-            {
-                _sb.AppendLine("layout (location = " + GlslDecl.PositionOutAttrLocation + ") out vec4 " + GlslDecl.PositionOutAttrName + ";");
-                _sb.AppendLine();
-            }
-
-            PrintDeclAttributes(_decl.OutAttributes.Values, "out");
-        }
-
-        private void PrintDeclAttributes(IEnumerable<ShaderDeclInfo> decls, string inOut)
-        {
-            int count = 0;
-
-            foreach (ShaderDeclInfo declInfo in decls.OrderBy(DeclKeySelector))
-            {
-                if (declInfo.Index >= 0)
-                {
-                    _sb.AppendLine("layout (location = " + declInfo.Index + ") " + inOut + " vec4 " + declInfo.Name + ";");
-
-                    count++;
-                }
-            }
-
-            if (count > 0)
-            {
-                _sb.AppendLine();
-            }
-        }
-
-        private void PrintDeclGprs()
-        {
-            PrintDecls(_decl.Gprs);
-            PrintDecls(_decl.GprsHalf);
-        }
-
-        private void PrintDeclPreds()
-        {
-            PrintDecls(_decl.Preds, "bool");
-        }
-
-        private void PrintDeclSsy()
-        {
-            _sb.AppendLine("uint " + GlslDecl.SsyCursorName + " = 0;");
-
-            _sb.AppendLine("uint " + GlslDecl.SsyStackName + "[" + GlslDecl.SsyStackSize + "];" + Environment.NewLine);
-        }
-
-        private void PrintDecls(IReadOnlyDictionary<int, ShaderDeclInfo> dict, string customType = null, string suffix = "")
-        {
-            foreach (ShaderDeclInfo declInfo in dict.Values.OrderBy(DeclKeySelector))
-            {
-                string name;
-
-                if (customType != null)
-                {
-                    name = customType + " " + declInfo.Name + suffix + ";";
-                }
-                else if (declInfo.Name.Contains(GlslDecl.FragmentOutputName))
-                {
-                    name = "layout (location = " + declInfo.Index / 4 + ") out vec4 " + declInfo.Name + suffix + ";";
-                }
-                else
-                {
-                    name = GetDecl(declInfo) + suffix + ";";
-                }
-
-                _sb.AppendLine(name);
-            }
-
-            if (dict.Count > 0)
-            {
-                _sb.AppendLine();
-            }
-        }
-
-        private int DeclKeySelector(ShaderDeclInfo declInfo)
-        {
-            return declInfo.Cbuf << 24 | declInfo.Index;
-        }
-
-        private string GetDecl(ShaderDeclInfo declInfo)
-        {
-            if (declInfo.Size == 4)
-            {
-                return "vec4 " + declInfo.Name;
-            }
-            else
-            {
-                return "float " + declInfo.Name;
-            }
-        }
-
-        private void PrintMain()
-        {
-            _sb.AppendLine("void main() {");
-
-            foreach (KeyValuePair<int, ShaderDeclInfo> kv in _decl.InAttributes)
-            {
-                if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr))
-                {
-                    continue;
-                }
-
-                ShaderDeclInfo declInfo = kv.Value;
-
-                if (_decl.ShaderType == GalShaderType.Geometry)
-                {
-                    for (int vertex = 0; vertex < MaxVertexInput; vertex++)
-                    {
-                        string dst = attr.Name + "[" + vertex + "]";
-
-                        string src = "block_in[" + vertex + "]." + declInfo.Name;
-
-                        _sb.AppendLine(IdentationStr + dst + " = " + src + ";");
-                    }
-                }
-                else
-                {
-                    _sb.AppendLine(IdentationStr + attr.Name + " = " + declInfo.Name + ";");
-                }
-            }
-
-            _sb.AppendLine(IdentationStr + "uint pc;");
-
-            if (_blocksB != null)
-            {
-                PrintProgram(_blocks,  GlslDecl.BasicBlockAName);
-                PrintProgram(_blocksB, GlslDecl.BasicBlockBName);
-            }
-            else
-            {
-                PrintProgram(_blocks, GlslDecl.BasicBlockName);
-            }
-
-            if (_decl.ShaderType != GalShaderType.Geometry)
-            {
-                PrintAttrToOutput();
-            }
-
-            if (_decl.ShaderType == GalShaderType.Fragment)
-            {
-                if (_header.OmapDepth)
-                {
-                    _sb.AppendLine(IdentationStr + "gl_FragDepth = " + GlslDecl.GetGprName(_header.DepthRegister) + ";");
-                }
-
-                int gprIndex = 0;
-
-                for (int attachment = 0; attachment < 8; attachment++)
-                {
-                    string output = GlslDecl.FragmentOutputName + attachment;
-
-                    OmapTarget target = _header.OmapTargets[attachment];
-
-                    for (int component = 0; component < 4; component++)
-                    {
-                        if (target.ComponentEnabled(component))
-                        {
-                            _sb.AppendLine(IdentationStr + output + "[" + component + "] = " + GlslDecl.GetGprName(gprIndex) + ";");
-
-                            gprIndex++;
-                        }
-                    }
-                }
-            }
-
-            _sb.AppendLine("}");
-        }
-
-        private void PrintProgram(ShaderIrBlock[] blocks, string name)
-        {
-            const string ident1 = IdentationStr;
-            const string ident2 = ident1 + IdentationStr;
-            const string ident3 = ident2 + IdentationStr;
-            const string ident4 = ident3 + IdentationStr;
-
-            _sb.AppendLine(ident1 + "pc = " + GetBlockPosition(blocks[0]) + ";");
-            _sb.AppendLine(ident1 + "do {");
-            _sb.AppendLine(ident2 + "switch (pc) {");
-
-            foreach (ShaderIrBlock block in blocks)
-            {
-                string functionName = block.Position.ToString("x8");
-
-                _sb.AppendLine(ident3 + "case 0x" + functionName + ": pc = " + name + "_" + functionName + "(); break;");
-            }
-
-            _sb.AppendLine(ident3 + "default:");
-            _sb.AppendLine(ident4 + "pc = 0;");
-            _sb.AppendLine(ident4 + "break;");
-
-            _sb.AppendLine(ident2 + "}");
-            _sb.AppendLine(ident1 + "} while (pc != 0);");
-        }
-
-        private void PrintAttrToOutput(string identation = IdentationStr)
-        {
-            foreach (KeyValuePair<int, ShaderDeclInfo> kv in _decl.OutAttributes)
-            {
-                if (!_decl.Attributes.TryGetValue(kv.Key, out ShaderDeclInfo attr))
-                {
-                    continue;
-                }
-
-                ShaderDeclInfo declInfo = kv.Value;
-
-                string name = attr.Name;
-
-                if (_decl.ShaderType == GalShaderType.Geometry)
-                {
-                    name += "[0]";
-                }
-
-                _sb.AppendLine(identation + declInfo.Name + " = " + name + ";");
-            }
-
-            if (_decl.ShaderType == GalShaderType.Vertex)
-            {
-                _sb.AppendLine(identation + "gl_Position.xy *= " + GlslDecl.FlipUniformName + ";");
-            }
-
-            if (_decl.ShaderType != GalShaderType.Fragment)
-            {
-                _sb.AppendLine(identation + GlslDecl.PositionOutAttrName + " = gl_Position;");
-                _sb.AppendLine(identation + GlslDecl.PositionOutAttrName + ".w = 1;");
-            }
-        }
-
-        private void PrintBlockScope(ShaderIrBlock[] blocks, string name)
-        {
-            foreach (ShaderIrBlock block in blocks)
-            {
-                _sb.AppendLine("uint " + name + "_" + block.Position.ToString("x8") + "() {");
-
-                PrintNodes(block, block.GetNodes());
-
-                _sb.AppendLine("}" + Environment.NewLine);
-            }
-        }
-
-        private void PrintNodes(ShaderIrBlock block, ShaderIrNode[] nodes)
-        {
-            foreach (ShaderIrNode node in nodes)
-            {
-                PrintNode(block, node, IdentationStr);
-            }
-
-            if (nodes.Length == 0)
-            {
-                _sb.AppendLine(IdentationStr + "return 0u;");
-
-                return;
-            }
-
-            ShaderIrNode last = nodes[nodes.Length - 1];
-
-            bool unconditionalFlowChange = false;
-
-            if (last is ShaderIrOp op)
-            {
-                switch (op.Inst)
-                {
-                    case ShaderIrInst.Bra:
-                    case ShaderIrInst.Exit:
-                    case ShaderIrInst.Sync:
-                        unconditionalFlowChange = true;
-                        break;
-                }
-            }
-
-            if (!unconditionalFlowChange)
-            {
-                if (block.Next != null)
-                {
-                    _sb.AppendLine(IdentationStr + "return " + GetBlockPosition(block.Next) + ";");
-                }
-                else
-                {
-                    _sb.AppendLine(IdentationStr + "return 0u;");
-                }
-            }
-        }
-
-        private void PrintNode(ShaderIrBlock block, ShaderIrNode node, string identation)
-        {
-            if (node is ShaderIrCond cond)
-            {
-                string ifExpr = GetSrcExpr(cond.Pred, true);
-
-                if (cond.Not)
-                {
-                    ifExpr = "!(" + ifExpr + ")";
-                }
-
-                _sb.AppendLine(identation + "if (" + ifExpr + ") {");
-
-                PrintNode(block, cond.Child, identation + IdentationStr);
-
-                _sb.AppendLine(identation + "}");
-            }
-            else if (node is ShaderIrAsg asg)
-            {
-                if (IsValidOutOper(asg.Dst))
-                {
-                    string expr = GetSrcExpr(asg.Src, true);
-
-                    expr = GetExprWithCast(asg.Dst, asg.Src, expr);
-
-                    _sb.AppendLine(identation + GetDstOperName(asg.Dst) + " = " + expr + ";");
-                }
-            }
-            else if (node is ShaderIrOp op)
-            {
-                switch (op.Inst)
-                {
-                    case ShaderIrInst.Bra:
-                    {
-                        _sb.AppendLine(identation + "return " + GetBlockPosition(block.Branch) + ";");
-
-                        break;
-                    }
-
-                    case ShaderIrInst.Emit:
-                    {
-                        PrintAttrToOutput(identation);
-
-                        _sb.AppendLine(identation + "EmitVertex();");
-
-                        break;
-                    }
-
-                    case ShaderIrInst.Ssy:
-                    {
-                        string stackIndex = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]";
-
-                        int targetPosition = (op.OperandA as ShaderIrOperImm).Value;
-
-                        string target = "0x" + targetPosition.ToString("x8") + "u";
-
-                        _sb.AppendLine(identation + stackIndex + " = " + target + ";");
-
-                        _sb.AppendLine(identation + GlslDecl.SsyCursorName + "++;");
-
-                        break;
-                    }
-
-                    case ShaderIrInst.Sync:
-                    {
-                        _sb.AppendLine(identation + GlslDecl.SsyCursorName + "--;");
-
-                        string target = GlslDecl.SsyStackName + "[" + GlslDecl.SsyCursorName + "]";
-
-                        _sb.AppendLine(identation + "return " + target + ";");
-
-                        break;
-                    }
-
-                    default:
-                        _sb.AppendLine(identation + GetSrcExpr(op, true) + ";");
-
-                        break;
-                }
-            }
-            else if (node is ShaderIrCmnt cmnt)
-            {
-                _sb.AppendLine(identation + "// " + cmnt.Comment);
-            }
-            else
-            {
-                throw new InvalidOperationException();
-            }
-        }
-
-        private bool IsValidOutOper(ShaderIrNode node)
-        {
-            if (node is ShaderIrOperGpr gpr && gpr.IsConst)
-            {
-                return false;
-            }
-            else if (node is ShaderIrOperPred pred && pred.IsConst)
-            {
-                return false;
-            }
-
-            return true;
-        }
-
-        private string GetDstOperName(ShaderIrNode node)
-        {
-            if (node is ShaderIrOperAbuf abuf)
-            {
-                return GetOutAbufName(abuf);
-            }
-            else if (node is ShaderIrOperGpr gpr)
-            {
-                return GetName(gpr);
-            }
-            else if (node is ShaderIrOperPred pred)
-            {
-                return GetName(pred);
-            }
-
-            throw new ArgumentException(nameof(node));
-        }
-
-        private string GetSrcExpr(ShaderIrNode node, bool entry = false)
-        {
-            switch (node)
-            {
-                case ShaderIrOperAbuf abuf: return GetName (abuf);
-                case ShaderIrOperCbuf cbuf: return GetName (cbuf);
-                case ShaderIrOperGpr  gpr:  return GetName (gpr);
-                case ShaderIrOperImm  imm:  return GetValue(imm);
-                case ShaderIrOperImmf immf: return GetValue(immf);
-                case ShaderIrOperPred pred: return GetName (pred);
-
-                case ShaderIrOp op:
-                    string expr;
-
-                    if (_instsExpr.TryGetValue(op.Inst, out GetInstExpr getExpr))
-                    {
-                        expr = getExpr(op);
-                    }
-                    else
-                    {
-                        throw new NotImplementedException(op.Inst.ToString());
-                    }
-
-                    if (!entry && NeedsParentheses(op))
-                    {
-                        expr = "(" + expr + ")";
-                    }
-
-                    return expr;
-
-                default: throw new ArgumentException(nameof(node));
-            }
-        }
-
-        private static bool NeedsParentheses(ShaderIrOp op)
-        {
-            switch (op.Inst)
-            {
-                case ShaderIrInst.Ipa:
-                case ShaderIrInst.Texq:
-                case ShaderIrInst.Texs:
-                case ShaderIrInst.Tld4:
-                case ShaderIrInst.Txlf:
-                    return false;
-            }
-
-            return true;
-        }
-
-        private string GetName(ShaderIrOperCbuf cbuf)
-        {
-            if (!_decl.Uniforms.TryGetValue(cbuf.Index, out ShaderDeclInfo declInfo))
-            {
-                throw new InvalidOperationException();
-            }
-
-            if (cbuf.Offs != null)
-            {
-                string offset = "floatBitsToInt(" + GetSrcExpr(cbuf.Offs) + ")";
-
-                string index = "(" + cbuf.Pos * 4 + " + " + offset + ")";
-
-                return $"{declInfo.Name}_data[{index} / 16][({index} / 4) % 4]";
-            }
-            else
-            {
-                return $"{declInfo.Name}_data[{cbuf.Pos / 4}][{cbuf.Pos % 4}]";
-            }
-        }
-
-        private string GetOutAbufName(ShaderIrOperAbuf abuf)
-        {
-            if (_decl.ShaderType == GalShaderType.Geometry)
-            {
-                switch (abuf.Offs)
-                {
-                    case GlslDecl.LayerAttr: return "gl_Layer";
-                }
-            }
-
-            return GetAttrTempName(abuf);
-        }
-
-        private string GetName(ShaderIrOperAbuf abuf)
-        {
-            //Handle special scalar read-only attributes here.
-            if (_decl.ShaderType == GalShaderType.Vertex)
-            {
-                switch (abuf.Offs)
-                {
-                    case GlslDecl.VertexIdAttr:   return "gl_VertexID";
-                    case GlslDecl.InstanceIdAttr: return GlslDecl.InstanceUniformName;
-                }
-            }
-            else if (_decl.ShaderType == GalShaderType.TessEvaluation)
-            {
-                switch (abuf.Offs)
-                {
-                    case GlslDecl.TessCoordAttrX: return "gl_TessCoord.x";
-                    case GlslDecl.TessCoordAttrY: return "gl_TessCoord.y";
-                    case GlslDecl.TessCoordAttrZ: return "gl_TessCoord.z";
-                }
-            }
-            else if (_decl.ShaderType == GalShaderType.Fragment)
-            {
-                switch (abuf.Offs)
-                {
-                    case GlslDecl.PointCoordAttrX: return "gl_PointCoord.x";
-                    case GlslDecl.PointCoordAttrY: return "gl_PointCoord.y";
-                    case GlslDecl.FaceAttr:        return "(gl_FrontFacing ? -1 : 0)";
-                }
-            }
-
-            return GetAttrTempName(abuf);
-        }
-
-        private string GetAttrTempName(ShaderIrOperAbuf abuf)
-        {
-            int index =  abuf.Offs >> 4;
-            int elem  = (abuf.Offs >> 2) & 3;
-
-            string swizzle = "." + GetAttrSwizzle(elem);
-
-            if (!_decl.Attributes.TryGetValue(index, out ShaderDeclInfo declInfo))
-            {
-                //Handle special vec4 attributes here
-                //(for example, index 7 is always gl_Position).
-                if (index == GlslDecl.GlPositionVec4Index)
-                {
-                    string name =
-                        _decl.ShaderType != GalShaderType.Vertex &&
-                        _decl.ShaderType != GalShaderType.Geometry ? GlslDecl.PositionOutAttrName : "gl_Position";
-
-                    return name + swizzle;
-                }
-                else if (abuf.Offs == GlslDecl.PointSizeAttr)
-                {
-                    return "gl_PointSize";
-                }
-            }
-
-            if (declInfo.Index >= 32)
-            {
-                throw new InvalidOperationException($"Shader attribute offset {abuf.Offs} is invalid.");
-            }
-
-            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)
-        {
-            if (gpr.IsConst)
-            {
-                return "0";
-            }
-
-            if (gpr.RegisterSize == ShaderRegisterSize.Single)
-            {
-                return GetNameWithSwizzle(_decl.Gprs, gpr.Index);
-            }
-            else if (gpr.RegisterSize == ShaderRegisterSize.Half)
-            {
-                return GetNameWithSwizzle(_decl.GprsHalf, (gpr.Index << 1) | gpr.HalfPart);
-            }
-            else /* if (Gpr.RegisterSize == ShaderRegisterSize.Double) */
-            {
-                throw new NotImplementedException("Double types are not supported.");
-            }
-        }
-
-        private string GetValue(ShaderIrOperImm imm)
-        {
-            //Only use hex is the value is too big and would likely be hard to read as int.
-            if (imm.Value >  0xfff ||
-                imm.Value < -0xfff)
-            {
-                return "0x" + imm.Value.ToString("x8", CultureInfo.InvariantCulture);
-            }
-            else
-            {
-                return GetIntConst(imm.Value);
-            }
-        }
-
-        private string GetValue(ShaderIrOperImmf immf)
-        {
-            return GetFloatConst(immf.Value);
-        }
-
-        private string GetName(ShaderIrOperPred pred)
-        {
-            return pred.IsConst ? "true" : GetNameWithSwizzle(_decl.Preds, pred.Index);
-        }
-
-        private string GetNameWithSwizzle(IReadOnlyDictionary<int, ShaderDeclInfo> dict, int index)
-        {
-            int vecIndex = index & ~3;
-
-            if (dict.TryGetValue(vecIndex, out ShaderDeclInfo declInfo))
-            {
-                if (declInfo.Size > 1 && index < vecIndex + declInfo.Size)
-                {
-                    return declInfo.Name + "." + GetAttrSwizzle(index & 3);
-                }
-            }
-
-            if (!dict.TryGetValue(index, out declInfo))
-            {
-                throw new InvalidOperationException();
-            }
-
-            return declInfo.Name;
-        }
-
-        private string GetAttrSwizzle(int elem)
-        {
-            return "xyzw".Substring(elem, 1);
-        }
-
-        private string GetAbsExpr(ShaderIrOp op) => GetUnaryCall(op, "abs");
-
-        private string GetAddExpr(ShaderIrOp op) => GetBinaryExpr(op, "+");
-
-        private string GetAndExpr(ShaderIrOp op) => GetBinaryExpr(op, "&");
-
-        private string GetAsrExpr(ShaderIrOp op) => GetBinaryExpr(op, ">>");
-
-        private string GetBandExpr(ShaderIrOp op) => GetBinaryExpr(op, "&&");
-
-        private string GetBnotExpr(ShaderIrOp op) => GetUnaryExpr(op, "!");
-
-        private string GetBorExpr(ShaderIrOp op) => GetBinaryExpr(op, "||");
-
-        private string GetBxorExpr(ShaderIrOp op) => GetBinaryExpr(op, "^^");
-
-        private string GetCeilExpr(ShaderIrOp op) => GetUnaryCall(op, "ceil");
-
-        private string GetClampsExpr(ShaderIrOp op)
-        {
-            return "clamp(" + GetOperExpr(op, op.OperandA) + ", " +
-                              GetOperExpr(op, op.OperandB) + ", " +
-                              GetOperExpr(op, op.OperandC) + ")";
-        }
-
-        private string GetClampuExpr(ShaderIrOp op)
-        {
-            return "int(clamp(uint(" + GetOperExpr(op, op.OperandA) + "), " +
-                             "uint(" + GetOperExpr(op, op.OperandB) + "), " +
-                             "uint(" + GetOperExpr(op, op.OperandC) + ")))";
-        }
-
-        private string GetCeqExpr(ShaderIrOp op) => GetBinaryExpr(op, "==");
-
-        private string GetCequExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "==");
-
-        private string GetCgeExpr(ShaderIrOp op) => GetBinaryExpr(op, ">=");
-
-        private string GetCgeuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, ">=");
-
-        private string GetCgtExpr(ShaderIrOp op) => GetBinaryExpr(op, ">");
-
-        private string GetCgtuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, ">");
-
-        private string GetCleExpr(ShaderIrOp op) => GetBinaryExpr(op, "<=");
-
-        private string GetCleuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "<=");
-
-        private string GetCltExpr(ShaderIrOp op) => GetBinaryExpr(op, "<");
-
-        private string GetCltuExpr(ShaderIrOp op) => GetBinaryExprWithNaN(op, "<");
-
-        private string GetCnanExpr(ShaderIrOp op) => GetUnaryCall(op, "isnan");
-
-        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");
-
-        private string GetExitExpr(ShaderIrOp op) => "return 0u";
-
-        private string GetFcosExpr(ShaderIrOp op) => GetUnaryCall(op, "cos");
-
-        private string GetFex2Expr(ShaderIrOp op) => GetUnaryCall(op, "exp2");
-
-        private string GetFfmaExpr(ShaderIrOp op) => GetTernaryExpr(op, "*", "+");
-
-        private string GetFclampExpr(ShaderIrOp op) => GetTernaryCall(op, "clamp");
-
-        private string GetFlg2Expr(ShaderIrOp op) => GetUnaryCall(op, "log2");
-
-        private string GetFloorExpr(ShaderIrOp op) => GetUnaryCall(op, "floor");
-
-        private string GetFrcpExpr(ShaderIrOp op) => GetUnaryExpr(op, "1 / ");
-
-        private string GetFrsqExpr(ShaderIrOp op) => GetUnaryCall(op, "inversesqrt");
-
-        private string GetFsinExpr(ShaderIrOp op) => GetUnaryCall(op, "sin");
-
-        private string GetFsqrtExpr(ShaderIrOp op) => GetUnaryCall(op, "sqrt");
-
-        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)
-        {
-            ShaderIrMetaIpa meta = (ShaderIrMetaIpa)op.MetaData;
-
-            ShaderIrOperAbuf abuf = (ShaderIrOperAbuf)op.OperandA;
-
-            if (meta.Mode == ShaderIpaMode.Pass)
-            {
-                int index = abuf.Offs >> 4;
-                int elem = (abuf.Offs >> 2) & 3;
-
-                if (_decl.ShaderType == GalShaderType.Fragment && index == GlslDecl.GlPositionVec4Index)
-                {
-                    switch (elem)
-                    {
-                        case 0: return "gl_FragCoord.x";
-                        case 1: return "gl_FragCoord.y";
-                        case 2: return "gl_FragCoord.z";
-                        case 3: return "1";
-                    }
-                }
-            }
-
-            return GetSrcExpr(op.OperandA);
-        }
-
-        private string GetKilExpr(ShaderIrOp op) => "discard";
-
-        private string GetLslExpr(ShaderIrOp op) => GetBinaryExpr(op, "<<");
-        private string GetLsrExpr(ShaderIrOp op)
-        {
-            return "int(uint(" + GetOperExpr(op, op.OperandA) + ") >> " +
-                                 GetOperExpr(op, op.OperandB) + ")";
-        }
-
-        private string GetMaxExpr(ShaderIrOp op) => GetBinaryCall(op, "max");
-        private string GetMinExpr(ShaderIrOp op) => GetBinaryCall(op, "min");
-
-        private string GetMulExpr(ShaderIrOp op) => GetBinaryExpr(op, "*");
-
-        private string GetNegExpr(ShaderIrOp op) => GetUnaryExpr(op, "-");
-
-        private string GetNotExpr(ShaderIrOp op) => GetUnaryExpr(op, "~");
-
-        private string GetOrExpr(ShaderIrOp op) => GetBinaryExpr(op, "|");
-
-        private string GetStofExpr(ShaderIrOp op)
-        {
-            return "float(" + GetOperExpr(op, op.OperandA) + ")";
-        }
-
-        private string GetSubExpr(ShaderIrOp op) => GetBinaryExpr(op, "-");
-
-        private string GetTexbExpr(ShaderIrOp op)
-        {
-            ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
-
-            if (!_decl.CbTextures.TryGetValue(op, out ShaderDeclInfo declInfo))
-            {
-                throw new InvalidOperationException();
-            }
-
-            string coords = GetTexSamplerCoords(op);
-
-            string ch = "rgba".Substring(meta.Elem, 1);
-
-            return GetTextureOperation(op, declInfo.Name, coords, ch);
-        }
-
-        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 GetTextureOperation(op, sampler, coords, ch);
-        }
-
-        private string GetTld4Expr(ShaderIrOp op)
-        {
-            ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
-
-            string sampler = GetTexSamplerName(op);
-
-            string coords = GetTexSamplerCoords(op);
-
-            string ch = "rgba".Substring(meta.Elem, 1);
-
-            return GetTextureGatherOperation(op, sampler, coords, ch);
-        }
-
-        // TODO: support AOFFI on non nvidia drivers
-        private string GetTxlfExpr(ShaderIrOp op)
-        {
-            // TODO: Support all suffixes
-            ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
-
-            TextureInstructionSuffix suffix = meta.TextureInstructionSuffix;
-
-            string sampler = GetTexSamplerName(op);
-
-            string coords = GetITexSamplerCoords(op);
-
-            string ch = "rgba".Substring(meta.Elem, 1);
-
-            string lod = "0";
-
-            if (meta.LevelOfDetail != null)
-            {
-                lod = GetOperExpr(op, meta.LevelOfDetail);
-            }
-
-            if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
-            {
-                string offset = GetTextureOffset(meta, GetOperExpr(op, meta.Offset));
-                return "texelFetchOffset(" + sampler + ", " + coords + ", " + lod + ", " + offset + ")." + ch;
-            }
-
-            return "texelFetch(" + sampler + ", " + coords + ", " + lod + ")." + ch;
-        }
-
-        private string GetTruncExpr(ShaderIrOp op) => GetUnaryCall(op, "trunc");
-
-        private string GetUtofExpr(ShaderIrOp op)
-        {
-            return "float(uint(" + GetOperExpr(op, op.OperandA) + "))";
-        }
-
-        private string GetXorExpr(ShaderIrOp op) => GetBinaryExpr(op, "^");
-
-        private string GetUnaryCall(ShaderIrOp op, string funcName)
-        {
-            return funcName + "(" + GetOperExpr(op, op.OperandA) + ")";
-        }
-
-        private string GetBinaryCall(ShaderIrOp op, string funcName)
-        {
-            return funcName + "(" + GetOperExpr(op, op.OperandA) + ", " +
-                                    GetOperExpr(op, op.OperandB) + ")";
-        }
-
-        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);
-        }
-
-        private string GetBinaryExpr(ShaderIrOp op, string opr)
-        {
-            return GetOperExpr(op, op.OperandA) + " " + opr + " " +
-                   GetOperExpr(op, op.OperandB);
-        }
-
-        private string GetBinaryExprWithNaN(ShaderIrOp op, string opr)
-        {
-            string a = GetOperExpr(op, op.OperandA);
-            string b = GetOperExpr(op, op.OperandB);
-
-            string nanCheck =
-                " || isnan(" + a + ")" +
-                " || isnan(" + b + ")";
-
-            return a + " " + opr + " " + b + nanCheck;
-        }
-
-        private string GetTernaryExpr(ShaderIrOp op, string opr1, string opr2)
-        {
-            return GetOperExpr(op, op.OperandA) + " " + opr1 + " " +
-                   GetOperExpr(op, op.OperandB) + " " + opr2 + " " +
-                   GetOperExpr(op, op.OperandC);
-        }
-
-        private string GetTexSamplerName(ShaderIrOp op)
-        {
-            ShaderIrOperImm node = (ShaderIrOperImm)op.OperandC;
-
-            int handle = ((ShaderIrOperImm)op.OperandC).Value;
-
-            if (!_decl.Textures.TryGetValue(handle, out ShaderDeclInfo declInfo))
-            {
-                throw new InvalidOperationException();
-            }
-
-            return declInfo.Name;
-        }
-
-        private string GetTexSamplerCoords(ShaderIrOp op)
-        {
-            ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
-
-            bool hasDepth = (meta.TextureInstructionSuffix & TextureInstructionSuffix.Dc) != 0;
-
-            int coords = ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget);
-
-            bool isArray = ImageUtils.IsArray(meta.TextureTarget);
-
-
-            string GetLastArgument(ShaderIrNode node)
-            {
-                string result = GetOperExpr(op, node);
-
-                // array index is actually an integer so we need to pass it correctly
-                if (isArray)
-                {
-                    result = "float(floatBitsToInt(" + result + "))";
-                }
-
-                return result;
-            }
-
-            string lastArgument;
-            string depthArgument = "";
-
-            int vecSize = coords;
-            if (hasDepth && op.Inst != ShaderIrInst.Tld4)
-            {
-                vecSize++;
-                depthArgument = $", {GetOperExpr(op, meta.DepthCompare)}";
-            }
-
-            switch (coords)
-            {
-                case 1:
-                    if (hasDepth)
-                    {
-                        return $"vec3({GetOperExpr(op, meta.Coordinates[0])}, 0.0{depthArgument})";
-                    }
-
-                    return GetOperExpr(op, meta.Coordinates[0]);
-                case 2:
-                    lastArgument = GetLastArgument(meta.Coordinates[1]);
-
-                    return $"vec{vecSize}({GetOperExpr(op, meta.Coordinates[0])}, {lastArgument}{depthArgument})";
-                case 3:
-                    lastArgument = GetLastArgument(meta.Coordinates[2]);
-
-                    return $"vec{vecSize}({GetOperExpr(op, meta.Coordinates[0])}, {GetOperExpr(op, meta.Coordinates[1])}, {lastArgument}{depthArgument})";
-                case 4:
-                    lastArgument = GetLastArgument(meta.Coordinates[3]);
-
-                    return $"vec4({GetOperExpr(op, meta.Coordinates[0])}, {GetOperExpr(op, meta.Coordinates[1])}, {GetOperExpr(op, meta.Coordinates[2])}, {lastArgument}){depthArgument}";
-                default:
-                    throw new InvalidOperationException();
-            }
-
-        }
-
-        private string GetTextureOffset(ShaderIrMetaTex meta, string oper, int shift = 4, int mask = 0xF)
-        {
-            string GetOffset(string operation, int index)
-            {
-                return $"({operation} >> {index * shift}) & 0x{mask:x}";
-            }
-
-            int coords = ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget);
-
-            if (ImageUtils.IsArray(meta.TextureTarget))
-                coords -= 1;
-
-            switch (coords)
-            {
-                case 1:
-                    return GetOffset(oper, 0);
-                case 2:
-                    return "ivec2(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ")";
-                case 3:
-                    return "ivec3(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ", " + GetOffset(oper, 2) + ")";
-                case 4:
-                    return "ivec4(" + GetOffset(oper, 0) + ", " + GetOffset(oper, 1) + ", " + GetOffset(oper, 2) + ", " + GetOffset(oper, 3) + ")";
-                default:
-                    throw new InvalidOperationException();
-            }
-        }
-
-        // TODO: support AOFFI on non nvidia drivers
-        private string GetTextureGatherOperation(ShaderIrOp op, string sampler, string coords, string ch)
-        {
-            ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
-
-            TextureInstructionSuffix suffix = meta.TextureInstructionSuffix;
-
-            string chString = "." + ch;
-
-            string comp = meta.Component.ToString();
-
-            if ((suffix & TextureInstructionSuffix.Dc) != 0)
-            {
-                comp = GetOperExpr(op, meta.DepthCompare);
-            }
-
-            if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
-            {
-                string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))", 8, 0x3F);
-
-                if ((suffix & TextureInstructionSuffix.Dc) != 0)
-                {
-                    return "textureGatherOffset(" + sampler + ", " + coords + ", " + comp + ", " + offset + ")" + chString;
-                }
-
-                return "textureGatherOffset(" + sampler + ", " + coords + ", " + offset + ", " + comp + ")" + chString;
-            }
-            // TODO: Support PTP
-            else if ((suffix & TextureInstructionSuffix.Ptp) != 0)
-            {
-                throw new NotImplementedException();
-            }
-
-            return "textureGather(" + sampler + ", " + coords + ", " + comp + ")" + chString;
-        }
-
-        // TODO: support AOFFI on non nvidia drivers
-        private string GetTextureOperation(ShaderIrOp op, string sampler, string coords, string ch)
-        {
-            ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
-
-            TextureInstructionSuffix suffix = meta.TextureInstructionSuffix;
-
-            string chString = "." + ch;
-
-            if ((suffix & TextureInstructionSuffix.Dc) != 0)
-            {
-                chString = "";
-            }
-
-            // TODO: Support LBA and LLA
-            if ((suffix & TextureInstructionSuffix.Lz) != 0)
-            {
-                if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
-                {
-                    string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))");
-
-                    return "textureLodOffset(" + sampler + ", " + coords + ", 0.0, " + offset + ")" + chString;
-                }
-
-                return "textureLod(" + sampler + ", " + coords + ", 0.0)" + chString;
-            }
-            else if ((suffix & TextureInstructionSuffix.Lb) != 0)
-            {
-                if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
-                {
-                    string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))");
-
-                    return "textureOffset(" + sampler + ", " + coords + ", " + offset + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString;
-                }
-
-                return "texture(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString;
-            }
-            else if ((suffix & TextureInstructionSuffix.Ll) != 0)
-            {
-                if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
-                {
-                    string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))");
-
-                    return "textureLodOffset(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ", " + offset + ")" + chString;
-                }
-
-                return "textureLod(" + sampler + ", " + coords + ", " + GetOperExpr(op, meta.LevelOfDetail) + ")" + chString;
-            }
-            else if ((suffix & TextureInstructionSuffix.AOffI) != 0 && _isNvidiaDriver)
-            {
-                string offset = GetTextureOffset(meta, "floatBitsToInt((" + GetOperExpr(op, meta.Offset) + "))");
-
-                return "textureOffset(" + sampler + ", " + coords + ", " + offset + ")" + chString;
-            }
-            else
-            {
-                return "texture(" + sampler + ", " + coords + ")" + chString;
-            }
-            throw new NotImplementedException($"Texture Suffix {meta.TextureInstructionSuffix} is not implemented");
-
-        }
-
-        private string GetITexSamplerCoords(ShaderIrOp op)
-        {
-            ShaderIrMetaTex meta = (ShaderIrMetaTex)op.MetaData;
-
-            switch (ImageUtils.GetCoordsCountTextureTarget(meta.TextureTarget))
-            {
-                case 1:
-                    return GetOperExpr(op, meta.Coordinates[0]);
-                case 2:
-                    return "ivec2(" + GetOperExpr(op, meta.Coordinates[0]) + ", " + GetOperExpr(op, meta.Coordinates[1]) + ")";
-                case 3:
-                    return "ivec3(" + GetOperExpr(op, meta.Coordinates[0]) + ", " + GetOperExpr(op, meta.Coordinates[1]) + ", " + GetOperExpr(op, meta.Coordinates[2]) + ")";
-                default:
-                    throw new InvalidOperationException();
-            }
-        }
-
-        private string GetOperExpr(ShaderIrOp op, ShaderIrNode oper)
-        {
-            return GetExprWithCast(op, oper, GetSrcExpr(oper));
-        }
-
-        private static string GetExprWithCast(ShaderIrNode dst, ShaderIrNode src, string expr)
-        {
-            //Note: The "DstType" (of the cast) is the type that the operation
-            //uses on the source operands, while the "SrcType" is the destination
-            //type of the operand result (if it is a operation) or just the type
-            //of the variable for registers/uniforms/attributes.
-            OperType dstType = GetSrcNodeType(dst);
-            OperType srcType = GetDstNodeType(src);
-
-            if (dstType != srcType)
-            {
-                //Check for invalid casts
-                //(like bool to int/float and others).
-                if (srcType != OperType.F32 &&
-                    srcType != OperType.I32)
-                {
-                    throw new InvalidOperationException();
-                }
-
-                switch (src)
-                {
-                    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;
-                    }
-                }
-
-                switch (dstType)
-                {
-                    case OperType.F32: expr = "intBitsToFloat(" + expr + ")"; break;
-                    case OperType.I32: expr = "floatBitsToInt(" + expr + ")"; break;
-                }
-            }
-
-            return expr;
-        }
-
-        private static string GetIntConst(int value)
-        {
-            string expr = value.ToString(CultureInfo.InvariantCulture);
-
-            return value < 0 ? "(" + expr + ")" : expr;
-        }
-
-        private static string GetFloatConst(float value)
-        {
-            string expr = value.ToString(CultureInfo.InvariantCulture);
-
-            return value < 0 ? "(" + expr + ")" : expr;
-        }
-
-        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:
-                    case ShaderIrInst.Txlf:
-                    case ShaderIrInst.Utof:
-                        return OperType.F32;
-
-                    case ShaderIrInst.Ftos:
-                    case ShaderIrInst.Ftou:
-                        return OperType.I32;
-                }
-            }
-
-            return GetSrcNodeType(node);
-        }
-
-        private static OperType GetSrcNodeType(ShaderIrNode node)
-        {
-            switch (node)
-            {
-                case ShaderIrOperAbuf abuf:
-                    return abuf.Offs == GlslDecl.LayerAttr      ||
-                           abuf.Offs == GlslDecl.InstanceIdAttr ||
-                           abuf.Offs == GlslDecl.VertexIdAttr   ||
-                           abuf.Offs == GlslDecl.FaceAttr
-                        ? OperType.I32
-                        : OperType.F32;
-
-                case ShaderIrOperCbuf cbuf: return OperType.F32;
-                case ShaderIrOperGpr  gpr:  return OperType.F32;
-                case ShaderIrOperImm  imm:  return OperType.I32;
-                case ShaderIrOperImmf immf: return OperType.F32;
-                case ShaderIrOperPred pred: return OperType.Bool;
-
-                case ShaderIrOp op:
-                    if (op.Inst > ShaderIrInst.B_Start &&
-                        op.Inst < ShaderIrInst.B_End)
-                    {
-                        return OperType.Bool;
-                    }
-                    else if (op.Inst > ShaderIrInst.F_Start &&
-                             op.Inst < ShaderIrInst.F_End)
-                    {
-                        return OperType.F32;
-                    }
-                    else if (op.Inst > ShaderIrInst.I_Start &&
-                             op.Inst < ShaderIrInst.I_End)
-                    {
-                        return OperType.I32;
-                    }
-                    break;
-            }
-
-            throw new ArgumentException(nameof(node));
-        }
-
-        private static string GetBlockPosition(ShaderIrBlock block)
-        {
-            if (block != null)
-            {
-                return "0x" + block.Position.ToString("x8") + "u";
-            }
-            else
-            {
-                return "0u";
-            }
-        }
-    }
-}

+ 0 - 22
Ryujinx.Graphics/Gal/Shader/GlslProgram.cs

@@ -1,22 +0,0 @@
-using System.Collections.Generic;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    public struct GlslProgram
-    {
-        public string Code { get; private set; }
-
-        public IEnumerable<ShaderDeclInfo> Textures { get; private set; }
-        public IEnumerable<ShaderDeclInfo> Uniforms { get; private set; }
-
-        public GlslProgram(
-            string                      code,
-            IEnumerable<ShaderDeclInfo> textures,
-            IEnumerable<ShaderDeclInfo> uniforms)
-        {
-            Code     = code;
-            Textures = textures;
-            Uniforms = uniforms;
-        }
-    }
-}

+ 0 - 1299
Ryujinx.Graphics/Gal/Shader/ShaderDecodeAlu.cs

@@ -1,1299 +0,0 @@
-using System;
-
-using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    static partial class ShaderDecode
-    {
-        private enum HalfOutputType
-        {
-            PackedFp16,
-            Fp32,
-            MergeH0,
-            MergeH1
-        }
-
-        public static void Bfe_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitBfe(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Bfe_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitBfe(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void Bfe_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitBfe(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Fadd_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFadd(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Fadd_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFadd(block, opCode, ShaderOper.Immf);
-        }
-
-        public static void Fadd_I32(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrNode operA = opCode.Gpr8();
-            ShaderIrNode operB = opCode.Immf32_20();
-
-            bool negB = opCode.Read(53);
-            bool absA = opCode.Read(54);
-            bool negA = opCode.Read(56);
-            bool absB = opCode.Read(57);
-
-            operA = GetAluFabsFneg(operA, absA, negA);
-            operB = GetAluFabsFneg(operB, absB, negB);
-
-            ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Fadd, operA, operB);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        public static void Fadd_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFadd(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Ffma_CR(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFfma(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Ffma_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFfma(block, opCode, ShaderOper.Immf);
-        }
-
-        public static void Ffma_RC(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFfma(block, opCode, ShaderOper.Rc);
-        }
-
-        public static void Ffma_RR(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFfma(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Fmnmx_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFmnmx(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Fmnmx_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFmnmx(block, opCode, ShaderOper.Immf);
-        }
-
-        public static void Fmnmx_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFmnmx(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Fmul_I32(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrNode operA = opCode.Gpr8();
-            ShaderIrNode operB = opCode.Immf32_20();
-
-            ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Fmul, operA, operB);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        public static void Fmul_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFmul(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Fmul_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFmul(block, opCode, ShaderOper.Immf);
-        }
-
-        public static void Fmul_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFmul(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Fset_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFset(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Fset_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFset(block, opCode, ShaderOper.Immf);
-        }
-
-        public static void Fset_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFset(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Fsetp_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFsetp(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Fsetp_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFsetp(block, opCode, ShaderOper.Immf);
-        }
-
-        public static void Fsetp_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitFsetp(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Hadd2_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitBinaryHalfOp(block, opCode, ShaderIrInst.Fadd);
-        }
-
-        public static void Hmul2_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitBinaryHalfOp(block, opCode, ShaderIrInst.Fmul);
-        }
-
-        public static void Iadd_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIadd(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Iadd_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIadd(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void Iadd_I32(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrNode operA = opCode.Gpr8();
-            ShaderIrNode operB = opCode.Imm32_20();
-
-            bool negA = opCode.Read(56);
-
-            operA = GetAluIneg(operA, negA);
-
-            ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Add, operA, operB);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        public static void Iadd_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIadd(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Iadd3_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIadd3(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Iadd3_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIadd3(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void Iadd3_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIadd3(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Imnmx_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitImnmx(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Imnmx_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitImnmx(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void Imnmx_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitImnmx(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Ipa(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrNode operA = opCode.Abuf28();
-            ShaderIrNode operB = opCode.Gpr20();
-
-            ShaderIpaMode mode = (ShaderIpaMode)(opCode.Read(54, 3));
-
-            ShaderIrMetaIpa meta = new ShaderIrMetaIpa(mode);
-
-            ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Ipa, operA, operB, null, meta);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        public static void Iscadd_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIscadd(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Iscadd_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIscadd(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void Iscadd_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIscadd(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Iset_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIset(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Iset_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIset(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void Iset_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIset(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Isetp_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIsetp(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Isetp_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIsetp(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void Isetp_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitIsetp(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Lop_I32(ShaderIrBlock block, long opCode, int position)
-        {
-            int subOp = opCode.Read(53, 3);
-
-            bool invA = opCode.Read(55);
-            bool invB = opCode.Read(56);
-
-            ShaderIrInst inst = 0;
-
-            switch (subOp)
-            {
-                case 0: inst = ShaderIrInst.And; break;
-                case 1: inst = ShaderIrInst.Or;  break;
-                case 2: inst = ShaderIrInst.Xor; break;
-            }
-
-            ShaderIrNode operB = GetAluNot(opCode.Imm32_20(), invB);
-
-            //SubOp == 3 is pass, used by the not instruction
-            //which just moves the inverted register value.
-            if (subOp < 3)
-            {
-                ShaderIrNode operA = GetAluNot(opCode.Gpr8(), invA);
-
-                ShaderIrOp op = new ShaderIrOp(inst, operA, operB);
-
-                block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-            }
-            else
-            {
-                block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operB)));
-            }
-        }
-
-        public static void Lop_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitLop(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Lop_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitLop(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void Lop_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitLop(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Mufu(ShaderIrBlock block, long opCode, int position)
-        {
-            int subOp = opCode.Read(20, 0xf);
-
-            bool absA = opCode.Read(46);
-            bool negA = opCode.Read(48);
-
-            ShaderIrInst inst = 0;
-
-            switch (subOp)
-            {
-                case 0: inst = ShaderIrInst.Fcos;  break;
-                case 1: inst = ShaderIrInst.Fsin;  break;
-                case 2: inst = ShaderIrInst.Fex2;  break;
-                case 3: inst = ShaderIrInst.Flg2;  break;
-                case 4: inst = ShaderIrInst.Frcp;  break;
-                case 5: inst = ShaderIrInst.Frsq;  break;
-                case 8: inst = ShaderIrInst.Fsqrt; break;
-
-                default: throw new NotImplementedException(subOp.ToString());
-            }
-
-            ShaderIrNode operA = opCode.Gpr8();
-
-            ShaderIrOp op = new ShaderIrOp(inst, GetAluFabsFneg(operA, absA, negA));
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        public static void Psetp(ShaderIrBlock block, long opCode, int position)
-        {
-            bool negA = opCode.Read(15);
-            bool negB = opCode.Read(32);
-            bool negP = opCode.Read(42);
-
-            ShaderIrInst lopInst = opCode.BLop24();
-
-            ShaderIrNode operA = opCode.Pred12();
-            ShaderIrNode operB = opCode.Pred29();
-
-            if (negA)
-            {
-                operA = new ShaderIrOp(ShaderIrInst.Bnot, operA);
-            }
-
-            if (negB)
-            {
-                operB = new ShaderIrOp(ShaderIrInst.Bnot, operB);
-            }
-
-            ShaderIrOp op = new ShaderIrOp(lopInst, operA, operB);
-
-            ShaderIrOperPred p0Node = opCode.Pred3();
-            ShaderIrOperPred p1Node = opCode.Pred0();
-            ShaderIrOperPred p2Node = opCode.Pred39();
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op)));
-
-            lopInst = opCode.BLop45();
-
-            if (lopInst == ShaderIrInst.Band && p1Node.IsConst && p2Node.IsConst)
-            {
-                return;
-            }
-
-            ShaderIrNode p2NNode = p2Node;
-
-            if (negP)
-            {
-                p2NNode = new ShaderIrOp(ShaderIrInst.Bnot, p2NNode);
-            }
-
-            op = new ShaderIrOp(ShaderIrInst.Bnot, p0Node);
-
-            op = new ShaderIrOp(lopInst, op, p2NNode);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(p1Node, op)));
-
-            op = new ShaderIrOp(lopInst, p0Node, p2NNode);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op)));
-        }
-
-        public static void Rro_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitRro(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Rro_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitRro(block, opCode, ShaderOper.Immf);
-        }
-
-        public static void Rro_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitRro(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Shl_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitAluBinary(block, opCode, ShaderOper.Cr, ShaderIrInst.Lsl);
-        }
-
-        public static void Shl_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitAluBinary(block, opCode, ShaderOper.Imm, ShaderIrInst.Lsl);
-        }
-
-        public static void Shl_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitAluBinary(block, opCode, ShaderOper.Rr, ShaderIrInst.Lsl);
-        }
-
-        public static void Shr_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitAluBinary(block, opCode, ShaderOper.Cr, GetShrInst(opCode));
-        }
-
-        public static void Shr_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitAluBinary(block, opCode, ShaderOper.Imm, GetShrInst(opCode));
-        }
-
-        public static void Shr_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitAluBinary(block, opCode, ShaderOper.Rr, GetShrInst(opCode));
-        }
-
-        private static ShaderIrInst GetShrInst(long opCode)
-        {
-            bool signed = opCode.Read(48);
-
-            return signed ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
-        }
-
-        public static void Vmad(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrNode operA = opCode.Gpr8();
-
-            ShaderIrNode operB;
-
-            if (opCode.Read(50))
-            {
-                operB = opCode.Gpr20();
-            }
-            else
-            {
-                operB = opCode.Imm19_20();
-            }
-
-            ShaderIrOperGpr operC = opCode.Gpr39();
-
-            ShaderIrNode tmp = new ShaderIrOp(ShaderIrInst.Mul, operA, operB);
-
-            ShaderIrNode final = new ShaderIrOp(ShaderIrInst.Add, tmp, operC);
-
-            int shr = opCode.Read(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(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), final)));
-        }
-
-        public static void Xmad_CR(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitXmad(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Xmad_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitXmad(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void Xmad_RC(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitXmad(block, opCode, ShaderOper.Rc);
-        }
-
-        public static void Xmad_RR(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitXmad(block, opCode, ShaderOper.Rr);
-        }
-
-        private static void EmitAluBinary(
-            ShaderIrBlock block,
-            long          opCode,
-            ShaderOper    oper,
-            ShaderIrInst  inst)
-        {
-            ShaderIrNode operA = opCode.Gpr8(), operB;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:  operB = opCode.Cbuf34();   break;
-                case ShaderOper.Imm: operB = opCode.Imm19_20(); break;
-                case ShaderOper.Rr:  operB = opCode.Gpr20();    break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            ShaderIrNode op = new ShaderIrOp(inst, operA, operB);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        private static void EmitBfe(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            //TODO: Handle the case where position + length
-            //is greater than the word size, in this case the sign bit
-            //needs to be replicated to fill the remaining space.
-            bool negB = opCode.Read(48);
-            bool negA = opCode.Read(49);
-
-            ShaderIrNode operA = opCode.Gpr8(), operB;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:  operB = opCode.Cbuf34();   break;
-                case ShaderOper.Imm: operB = opCode.Imm19_20(); break;
-                case ShaderOper.Rr:  operB = opCode.Gpr20();    break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            ShaderIrNode op;
-
-            bool signed = opCode.Read(48); //?
-
-            if (operB is ShaderIrOperImm posLen)
-            {
-                int position = (posLen.Value >> 0) & 0xff;
-                int length   = (posLen.Value >> 8) & 0xff;
-
-                int lSh = 32 - (position + length);
-
-                ShaderIrInst rightShift = signed
-                    ? ShaderIrInst.Asr
-                    : ShaderIrInst.Lsr;
-
-                op = new ShaderIrOp(ShaderIrInst.Lsl, operA, new ShaderIrOperImm(lSh));
-                op = new ShaderIrOp(rightShift,       op,    new ShaderIrOperImm(lSh + position));
-            }
-            else
-            {
-                ShaderIrOperImm shift = new ShaderIrOperImm(8);
-                ShaderIrOperImm mask  = new ShaderIrOperImm(0xff);
-
-                ShaderIrNode opPos, opLen;
-
-                opPos = new ShaderIrOp(ShaderIrInst.And, operB, mask);
-                opLen = new ShaderIrOp(ShaderIrInst.Lsr, operB, shift);
-                opLen = new ShaderIrOp(ShaderIrInst.And, opLen, mask);
-
-                op = new ShaderIrOp(ShaderIrInst.Lsr, operA, opPos);
-
-                op = ExtendTo32(op, signed, opLen);
-            }
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        private static void EmitFadd(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            bool negB = opCode.Read(45);
-            bool absA = opCode.Read(46);
-            bool negA = opCode.Read(48);
-            bool absB = opCode.Read(49);
-            bool sat  = opCode.Read(50);
-
-            ShaderIrNode operA = opCode.Gpr8(), operB;
-
-            operA = GetAluFabsFneg(operA, absA, negA);
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:   operB = opCode.Cbuf34();    break;
-                case ShaderOper.Immf: operB = opCode.Immf19_20(); break;
-                case ShaderOper.Rr:   operB = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            operB = GetAluFabsFneg(operB, absB, negB);
-
-            ShaderIrNode op = new ShaderIrOp(ShaderIrInst.Fadd, operA, operB);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), GetAluFsat(op, sat))));
-        }
-
-        private static void EmitFmul(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            bool negB = opCode.Read(48);
-            bool sat  = opCode.Read(50);
-
-            ShaderIrNode operA = opCode.Gpr8(), operB;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:   operB = opCode.Cbuf34();    break;
-                case ShaderOper.Immf: operB = opCode.Immf19_20(); break;
-                case ShaderOper.Rr:   operB = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            operB = GetAluFneg(operB, negB);
-
-            ShaderIrNode op = new ShaderIrOp(ShaderIrInst.Fmul, operA, operB);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), GetAluFsat(op, sat))));
-        }
-
-        private static void EmitFfma(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            bool negB = opCode.Read(48);
-            bool negC = opCode.Read(49);
-            bool sat  = opCode.Read(50);
-
-            ShaderIrNode operA = opCode.Gpr8(), operB, operC;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:   operB = opCode.Cbuf34();    break;
-                case ShaderOper.Immf: operB = opCode.Immf19_20(); break;
-                case ShaderOper.Rc:   operB = opCode.Gpr39();     break;
-                case ShaderOper.Rr:   operB = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            operB = GetAluFneg(operB, negB);
-
-            if (oper == ShaderOper.Rc)
-            {
-                operC = GetAluFneg(opCode.Cbuf34(), negC);
-            }
-            else
-            {
-                operC = GetAluFneg(opCode.Gpr39(), negC);
-            }
-
-            ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Ffma, operA, operB, operC);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), GetAluFsat(op, sat))));
-        }
-
-        private static void EmitIadd(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            ShaderIrNode operA = opCode.Gpr8();
-            ShaderIrNode operB;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:  operB = opCode.Cbuf34();   break;
-                case ShaderOper.Imm: operB = opCode.Imm19_20(); break;
-                case ShaderOper.Rr:  operB = opCode.Gpr20();    break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            bool negA = opCode.Read(49);
-            bool negB = opCode.Read(48);
-
-            operA = GetAluIneg(operA, negA);
-            operB = GetAluIneg(operB, negB);
-
-            ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Add, operA, operB);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        private static void EmitIadd3(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            int mode = opCode.Read(37, 3);
-
-            bool neg1 = opCode.Read(51);
-            bool neg2 = opCode.Read(50);
-            bool neg3 = opCode.Read(49);
-
-            int height1 = opCode.Read(35, 3);
-            int height2 = opCode.Read(33, 3);
-            int height3 = opCode.Read(31, 3);
-
-            ShaderIrNode operB;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:  operB = opCode.Cbuf34();   break;
-                case ShaderOper.Imm: operB = opCode.Imm19_20(); break;
-                case ShaderOper.Rr:  operB = opCode.Gpr20();    break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            ShaderIrNode ApplyHeight(ShaderIrNode src, int height)
-            {
-                if (oper != ShaderOper.Rr)
-                {
-                    return src;
-                }
-
-                switch (height)
-                {
-                    case 0: return src;
-                    case 1: return new ShaderIrOp(ShaderIrInst.And, src, new ShaderIrOperImm(0xffff));
-                    case 2: return new ShaderIrOp(ShaderIrInst.Lsr, src, new ShaderIrOperImm(16));
-
-                    default: throw new InvalidOperationException();
-                }
-            }
-
-            ShaderIrNode src1 = GetAluIneg(ApplyHeight(opCode.Gpr8(),  height1), neg1);
-            ShaderIrNode src2 = GetAluIneg(ApplyHeight(operB,          height2), neg2);
-            ShaderIrNode src3 = GetAluIneg(ApplyHeight(opCode.Gpr39(), height3), neg3);
-
-            ShaderIrOp sum = new ShaderIrOp(ShaderIrInst.Add, src1, src2);
-
-            if (oper == ShaderOper.Rr)
-            {
-                switch (mode)
-                {
-                    case 1: sum = new ShaderIrOp(ShaderIrInst.Lsr, sum, new ShaderIrOperImm(16)); break;
-                    case 2: sum = new ShaderIrOp(ShaderIrInst.Lsl, sum, new ShaderIrOperImm(16)); break;
-                }
-            }
-
-            //Note: Here there should be a "+ 1" when carry flag is set
-            //but since carry is mostly ignored by other instructions, it's excluded for now
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), new ShaderIrOp(ShaderIrInst.Add, sum, src3))));
-        }
-
-        private static void EmitIscadd(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            bool negB = opCode.Read(48);
-            bool negA = opCode.Read(49);
-
-            ShaderIrNode operA = opCode.Gpr8(), operB;
-
-            ShaderIrOperImm scale = opCode.Imm5_39();
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:  operB = opCode.Cbuf34();   break;
-                case ShaderOper.Imm: operB = opCode.Imm19_20(); break;
-                case ShaderOper.Rr:  operB = opCode.Gpr20();    break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            operA = GetAluIneg(operA, negA);
-            operB = GetAluIneg(operB, negB);
-
-            ShaderIrOp scaleOp = new ShaderIrOp(ShaderIrInst.Lsl, operA, scale);
-            ShaderIrOp addOp   = new ShaderIrOp(ShaderIrInst.Add, operB, scaleOp);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), addOp)));
-        }
-
-        private static void EmitFmnmx(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            EmitMnmx(block, opCode, true, oper);
-        }
-
-        private static void EmitImnmx(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            EmitMnmx(block, opCode, false, oper);
-        }
-
-        private static void EmitMnmx(ShaderIrBlock block, long opCode, bool isFloat, ShaderOper oper)
-        {
-            bool negB = opCode.Read(45);
-            bool absA = opCode.Read(46);
-            bool negA = opCode.Read(48);
-            bool absB = opCode.Read(49);
-
-            ShaderIrNode operA = opCode.Gpr8(), operB;
-
-            if (isFloat)
-            {
-                operA = GetAluFabsFneg(operA, absA, negA);
-            }
-            else
-            {
-                operA = GetAluIabsIneg(operA, absA, negA);
-            }
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:   operB = opCode.Cbuf34();    break;
-                case ShaderOper.Imm:  operB = opCode.Imm19_20();  break;
-                case ShaderOper.Immf: operB = opCode.Immf19_20(); break;
-                case ShaderOper.Rr:   operB = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            if (isFloat)
-            {
-                operB = GetAluFabsFneg(operB, absB, negB);
-            }
-            else
-            {
-                operB = GetAluIabsIneg(operB, absB, negB);
-            }
-
-            ShaderIrOperPred pred = opCode.Pred39();
-
-            ShaderIrOp op;
-
-            ShaderIrInst maxInst = isFloat ? ShaderIrInst.Fmax : ShaderIrInst.Max;
-            ShaderIrInst minInst = isFloat ? ShaderIrInst.Fmin : ShaderIrInst.Min;
-
-            if (pred.IsConst)
-            {
-                bool isMax = opCode.Read(42);
-
-                op = new ShaderIrOp(isMax
-                    ? maxInst
-                    : minInst, operA, operB);
-
-                block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-            }
-            else
-            {
-                ShaderIrNode predN = opCode.Pred39N();
-
-                ShaderIrOp opMax = new ShaderIrOp(maxInst, operA, operB);
-                ShaderIrOp opMin = new ShaderIrOp(minInst, operA, operB);
-
-                ShaderIrAsg asgMax = new ShaderIrAsg(opCode.Gpr0(), opMax);
-                ShaderIrAsg asgMin = new ShaderIrAsg(opCode.Gpr0(), opMin);
-
-                block.AddNode(opCode.PredNode(new ShaderIrCond(predN, asgMax, not: true)));
-                block.AddNode(opCode.PredNode(new ShaderIrCond(predN, asgMin, not: false)));
-            }
-        }
-
-        private static void EmitRro(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            //Note: this is a range reduction instruction and is supposed to
-            //be used with Mufu, here it just moves the value and ignores the operation.
-            bool negA = opCode.Read(45);
-            bool absA = opCode.Read(49);
-
-            ShaderIrNode operA;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:   operA = opCode.Cbuf34();    break;
-                case ShaderOper.Immf: operA = opCode.Immf19_20(); break;
-                case ShaderOper.Rr:   operA = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            operA = GetAluFabsFneg(operA, absA, negA);
-
-            block.AddNode(new ShaderIrCmnt("Stubbed."));
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA)));
-        }
-
-        private static void EmitFset(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            EmitSet(block, opCode, true, oper);
-        }
-
-        private static void EmitIset(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            EmitSet(block, opCode, false, oper);
-        }
-
-        private static void EmitSet(ShaderIrBlock block, long opCode, bool isFloat, ShaderOper oper)
-        {
-            bool negA = opCode.Read(43);
-            bool absB = opCode.Read(44);
-            bool negB = opCode.Read(53);
-            bool absA = opCode.Read(54);
-
-            bool boolFloat = opCode.Read(isFloat ? 52 : 44);
-
-            ShaderIrNode operA = opCode.Gpr8(), operB;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:   operB = opCode.Cbuf34();    break;
-                case ShaderOper.Imm:  operB = opCode.Imm19_20();  break;
-                case ShaderOper.Immf: operB = opCode.Immf19_20(); break;
-                case ShaderOper.Rr:   operB = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            ShaderIrInst cmpInst;
-
-            if (isFloat)
-            {
-                operA = GetAluFabsFneg(operA, absA, negA);
-                operB = GetAluFabsFneg(operB, absB, negB);
-
-                cmpInst = opCode.CmpF();
-            }
-            else
-            {
-                cmpInst = opCode.Cmp();
-            }
-
-            ShaderIrOp op = new ShaderIrOp(cmpInst, operA, operB);
-
-            ShaderIrInst lopInst = opCode.BLop45();
-
-            ShaderIrOperPred pNode = opCode.Pred39();
-
-            ShaderIrNode imm0, imm1;
-
-            if (boolFloat)
-            {
-                imm0 = new ShaderIrOperImmf(0);
-                imm1 = new ShaderIrOperImmf(1);
-            }
-            else
-            {
-                imm0 = new ShaderIrOperImm(0);
-                imm1 = new ShaderIrOperImm(-1);
-            }
-
-            ShaderIrNode asg0 = new ShaderIrAsg(opCode.Gpr0(), imm0);
-            ShaderIrNode asg1 = new ShaderIrAsg(opCode.Gpr0(), imm1);
-
-            if (lopInst != ShaderIrInst.Band || !pNode.IsConst)
-            {
-                ShaderIrOp op2 = new ShaderIrOp(lopInst, op, pNode);
-
-                asg0 = new ShaderIrCond(op2, asg0, not: true);
-                asg1 = new ShaderIrCond(op2, asg1, not: false);
-            }
-            else
-            {
-                asg0 = new ShaderIrCond(op, asg0, not: true);
-                asg1 = new ShaderIrCond(op, asg1, not: false);
-            }
-
-            block.AddNode(opCode.PredNode(asg0));
-            block.AddNode(opCode.PredNode(asg1));
-        }
-
-        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 absA = opCode.Read(7);
-            bool negP = opCode.Read(42);
-            bool negA = opCode.Read(43);
-            bool absB = opCode.Read(44);
-
-            ShaderIrNode operA = opCode.Gpr8(), operB;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:   operB = opCode.Cbuf34();    break;
-                case ShaderOper.Imm:  operB = opCode.Imm19_20();  break;
-                case ShaderOper.Immf: operB = opCode.Immf19_20(); break;
-                case ShaderOper.Rr:   operB = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            ShaderIrInst cmpInst;
-
-            if (isFloat)
-            {
-                operA = GetAluFabsFneg(operA, absA, negA);
-                operB = GetAluFabs    (operB, absB);
-
-                cmpInst = opCode.CmpF();
-            }
-            else
-            {
-                cmpInst = opCode.Cmp();
-            }
-
-            ShaderIrOp op = new ShaderIrOp(cmpInst, operA, operB);
-
-            ShaderIrOperPred p0Node = opCode.Pred3();
-            ShaderIrOperPred p1Node = opCode.Pred0();
-            ShaderIrOperPred p2Node = opCode.Pred39();
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op)));
-
-            ShaderIrInst lopInst = opCode.BLop45();
-
-            if (lopInst == ShaderIrInst.Band && p1Node.IsConst && p2Node.IsConst)
-            {
-                return;
-            }
-
-            ShaderIrNode p2NNode = p2Node;
-
-            if (negP)
-            {
-                p2NNode = new ShaderIrOp(ShaderIrInst.Bnot, p2NNode);
-            }
-
-            op = new ShaderIrOp(ShaderIrInst.Bnot, p0Node);
-
-            op = new ShaderIrOp(lopInst, op, p2NNode);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(p1Node, op)));
-
-            op = new ShaderIrOp(lopInst, p0Node, p2NNode);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(p0Node, op)));
-        }
-
-        private static void EmitBinaryHalfOp(ShaderIrBlock block, long opCode, ShaderIrInst inst)
-        {
-            bool absB = opCode.Read(30);
-            bool negB = opCode.Read(31);
-            bool sat  = opCode.Read(32);
-            bool absA = opCode.Read(44);
-
-            ShaderIrOperGpr[] vecA = opCode.GprHalfVec8();
-            ShaderIrOperGpr[] vecB = opCode.GprHalfVec20();
-
-            HalfOutputType outputType = (HalfOutputType)opCode.Read(49, 3);
-
-            int elems = outputType == HalfOutputType.PackedFp16 ? 2 : 1;
-            int first = outputType == HalfOutputType.MergeH1    ? 1 : 0;
-
-            for (int index = first; index < elems; index++)
-            {
-                ShaderIrNode operA = GetAluFabs    (vecA[index], absA);
-                ShaderIrNode operB = GetAluFabsFneg(vecB[index], absB, negB);
-
-                ShaderIrNode op = new ShaderIrOp(inst, operA, operB);
-
-                ShaderIrOperGpr dst = GetHalfDst(opCode, outputType, index);
-
-                block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, GetAluFsat(op, sat))));
-            }
-        }
-
-        private static ShaderIrOperGpr GetHalfDst(long opCode, HalfOutputType outputType, int index)
-        {
-            switch (outputType)
-            {
-                case HalfOutputType.PackedFp16: return opCode.GprHalf0(index);
-                case HalfOutputType.Fp32:       return opCode.Gpr0();
-                case HalfOutputType.MergeH0:    return opCode.GprHalf0(0);
-                case HalfOutputType.MergeH1:    return opCode.GprHalf0(1);
-            }
-
-            throw new ArgumentException(nameof(outputType));
-        }
-
-        private static void EmitLop(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            int subOp = opCode.Read(41, 3);
-
-            bool invA = opCode.Read(39);
-            bool invB = opCode.Read(40);
-
-            ShaderIrInst inst = 0;
-
-            switch (subOp)
-            {
-                case 0: inst = ShaderIrInst.And; break;
-                case 1: inst = ShaderIrInst.Or;  break;
-                case 2: inst = ShaderIrInst.Xor; break;
-            }
-
-            ShaderIrNode operA = GetAluNot(opCode.Gpr8(), invA);
-            ShaderIrNode operB;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:  operB = opCode.Cbuf34();   break;
-                case ShaderOper.Imm: operB = opCode.Imm19_20(); break;
-                case ShaderOper.Rr:  operB = opCode.Gpr20();    break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            operB = GetAluNot(operB, invB);
-
-            ShaderIrNode op;
-
-            if (subOp < 3)
-            {
-                op = new ShaderIrOp(inst, operA, operB);
-            }
-            else
-            {
-                op = operB;
-            }
-
-            ShaderIrNode compare = new ShaderIrOp(ShaderIrInst.Cne, op, new ShaderIrOperImm(0));
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Pred48(), compare)));
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        private enum XmadMode
-        {
-            Cfull = 0,
-            Clo   = 1,
-            Chi   = 2,
-            Csfu  = 3,
-            Cbcc  = 4
-        }
-
-        private static void EmitXmad(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            bool signedA = opCode.Read(48);
-            bool signedB = opCode.Read(49);
-            bool highB   = opCode.Read(52);
-            bool highA   = opCode.Read(53);
-
-            int mode = opCode.Read(50, 7);
-
-            ShaderIrNode operA = opCode.Gpr8(), operB, operC;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:  operB = opCode.Cbuf34();    break;
-                case ShaderOper.Imm: operB = opCode.ImmU16_20(); break;
-                case ShaderOper.Rc:  operB = opCode.Gpr39();     break;
-                case ShaderOper.Rr:  operB = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            ShaderIrNode operB2 = operB;
-
-            if (oper == ShaderOper.Imm)
-            {
-                int imm = ((ShaderIrOperImm)operB2).Value;
-
-                if (!highB)
-                {
-                    imm <<= 16;
-                }
-
-                if (signedB)
-                {
-                    imm >>= 16;
-                }
-                else
-                {
-                    imm = (int)((uint)imm >> 16);
-                }
-
-                operB2 = new ShaderIrOperImm(imm);
-            }
-
-            ShaderIrOperImm imm16 = new ShaderIrOperImm(16);
-
-            //If we are working with the lower 16-bits of the A/B operands,
-            //we need to shift the lower 16-bits to the top 16-bits. Later,
-            //they will be right shifted. For U16 types, this will be a logical
-            //right shift, and for S16 types, a arithmetic right shift.
-            if (!highA)
-            {
-                operA = new ShaderIrOp(ShaderIrInst.Lsl, operA, imm16);
-            }
-
-            if (!highB && oper != ShaderOper.Imm)
-            {
-                operB2 = new ShaderIrOp(ShaderIrInst.Lsl, operB2, imm16);
-            }
-
-            ShaderIrInst shiftA = signedA ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
-            ShaderIrInst shiftB = signedB ? ShaderIrInst.Asr : ShaderIrInst.Lsr;
-
-            operA = new ShaderIrOp(shiftA, operA,  imm16);
-
-            if (oper != ShaderOper.Imm)
-            {
-                operB2 = new ShaderIrOp(shiftB, operB2, imm16);
-            }
-
-            bool productShiftLeft = false;
-            bool merge            = false;
-
-            if (oper == ShaderOper.Rc)
-            {
-                operC = opCode.Cbuf34();
-            }
-            else
-            {
-                operC = opCode.Gpr39();
-
-                productShiftLeft = opCode.Read(36);
-                merge            = opCode.Read(37);
-            }
-
-            ShaderIrOp mulOp = new ShaderIrOp(ShaderIrInst.Mul, operA, operB2);
-
-            if (productShiftLeft)
-            {
-                mulOp = new ShaderIrOp(ShaderIrInst.Lsl, mulOp, imm16);
-            }
-
-            switch ((XmadMode)mode)
-            {
-                case XmadMode.Clo: operC = ExtendTo32(operC, signed: false, size: 16); break;
-
-                case XmadMode.Chi: operC = new ShaderIrOp(ShaderIrInst.Lsr, operC, imm16); break;
-
-                case XmadMode.Cbcc:
-                {
-                    ShaderIrOp operBLsh16 = new ShaderIrOp(ShaderIrInst.Lsl, operB, imm16);
-
-                    operC = new ShaderIrOp(ShaderIrInst.Add, operC, operBLsh16);
-
-                    break;
-                }
-
-                case XmadMode.Csfu:
-                {
-                    ShaderIrOperImm imm31 = new ShaderIrOperImm(31);
-
-                    ShaderIrOp signAdjustA = new ShaderIrOp(ShaderIrInst.Lsr, operA,  imm31);
-                    ShaderIrOp signAdjustB = new ShaderIrOp(ShaderIrInst.Lsr, operB2, imm31);
-
-                    signAdjustA = new ShaderIrOp(ShaderIrInst.Lsl, signAdjustA, imm16);
-                    signAdjustB = new ShaderIrOp(ShaderIrInst.Lsl, signAdjustB, imm16);
-
-                    ShaderIrOp signAdjust = new ShaderIrOp(ShaderIrInst.Add, signAdjustA, signAdjustB);
-
-                    operC = new ShaderIrOp(ShaderIrInst.Sub, operC, signAdjust);
-
-                    break;
-                }
-            }
-
-            ShaderIrOp addOp = new ShaderIrOp(ShaderIrInst.Add, mulOp, operC);
-
-            if (merge)
-            {
-                ShaderIrOperImm imm16Mask = new ShaderIrOperImm(0xffff);
-
-                addOp = new ShaderIrOp(ShaderIrInst.And, addOp, imm16Mask);
-                operB = new ShaderIrOp(ShaderIrInst.Lsl, operB, imm16);
-                addOp = new ShaderIrOp(ShaderIrInst.Or,  addOp, operB);
-            }
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), addOp)));
-        }
-    }
-}

+ 0 - 57
Ryujinx.Graphics/Gal/Shader/ShaderDecodeFlow.cs

@@ -1,57 +0,0 @@
-using System;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    static partial class ShaderDecode
-    {
-        public static void Bra(ShaderIrBlock block, long opCode, int position)
-        {
-            if ((opCode & 0x20) != 0)
-            {
-                //This reads the target offset from the constant buffer.
-                //Almost impossible to support with GLSL.
-                throw new NotImplementedException();
-            }
-
-            ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch());
-
-            block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Bra, imm)));
-        }
-
-        public static void Exit(ShaderIrBlock block, long opCode, int position)
-        {
-            int cCode = (int)opCode & 0x1f;
-
-            //TODO: Figure out what the other condition codes mean...
-            if (cCode == 0xf)
-            {
-                block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Exit)));
-            }
-        }
-
-        public static void Kil(ShaderIrBlock block, long opCode, int position)
-        {
-            block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Kil)));
-        }
-
-        public static void Ssy(ShaderIrBlock block, long opCode, int position)
-        {
-            if ((opCode & 0x20) != 0)
-            {
-                //This reads the target offset from the constant buffer.
-                //Almost impossible to support with GLSL.
-                throw new NotImplementedException();
-            }
-
-            ShaderIrOperImm imm = new ShaderIrOperImm(position + opCode.Branch());
-
-            block.AddNode(new ShaderIrOp(ShaderIrInst.Ssy, imm));
-        }
-
-        public static void Sync(ShaderIrBlock block, long opCode, int position)
-        {
-            //TODO: Implement Sync condition codes
-            block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Sync)));
-        }
-    }
-}

+ 0 - 4
Ryujinx.Graphics/Gal/Shader/ShaderDecodeFunc.cs

@@ -1,4 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    delegate void ShaderDecodeFunc(ShaderIrBlock block, long opCode, int position);
-}

+ 0 - 78
Ryujinx.Graphics/Gal/Shader/ShaderDecodeHelper.cs

@@ -1,78 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    static class ShaderDecodeHelper
-    {
-        private static readonly ShaderIrOperImmf ImmfZero = new ShaderIrOperImmf(0);
-        private static readonly ShaderIrOperImmf ImmfOne  = new ShaderIrOperImmf(1);
-
-        public static ShaderIrNode GetAluFabsFneg(ShaderIrNode node, bool abs, bool neg)
-        {
-            return GetAluFneg(GetAluFabs(node, abs), neg);
-        }
-
-        public static ShaderIrNode GetAluFabs(ShaderIrNode node, bool abs)
-        {
-            return abs ? new ShaderIrOp(ShaderIrInst.Fabs, node) : node;
-        }
-
-        public static ShaderIrNode GetAluFneg(ShaderIrNode node, bool neg)
-        {
-            return neg ? new ShaderIrOp(ShaderIrInst.Fneg, node) : node;
-        }
-
-        public static ShaderIrNode GetAluFsat(ShaderIrNode node, bool sat)
-        {
-            return sat ? new ShaderIrOp(ShaderIrInst.Fclamp, node, ImmfZero, ImmfOne) : node;
-        }
-
-        public static ShaderIrNode GetAluIabsIneg(ShaderIrNode node, bool abs, bool neg)
-        {
-            return GetAluIneg(GetAluIabs(node, abs), neg);
-        }
-
-        public static ShaderIrNode GetAluIabs(ShaderIrNode node, bool abs)
-        {
-            return abs ? new ShaderIrOp(ShaderIrInst.Abs, node) : node;
-        }
-
-        public static ShaderIrNode GetAluIneg(ShaderIrNode node, bool neg)
-        {
-            return neg ? new ShaderIrOp(ShaderIrInst.Neg, node) : node;
-        }
-
-        public static ShaderIrNode GetAluNot(ShaderIrNode node, bool not)
-        {
-            return not ? new ShaderIrOp(ShaderIrInst.Not, node) : node;
-        }
-
-        public static ShaderIrNode ExtendTo32(ShaderIrNode node, bool signed, int size)
-        {
-            int shift = 32 - size;
-
-            ShaderIrInst rightShift = signed
-                ? ShaderIrInst.Asr
-                : ShaderIrInst.Lsr;
-
-            node = new ShaderIrOp(ShaderIrInst.Lsl, node, new ShaderIrOperImm(shift));
-            node = new ShaderIrOp(rightShift,       node, new ShaderIrOperImm(shift));
-
-            return node;
-        }
-
-        public static ShaderIrNode ExtendTo32(ShaderIrNode node, bool signed, ShaderIrNode size)
-        {
-            ShaderIrOperImm wordSize = new ShaderIrOperImm(32);
-
-            ShaderIrOp shift = new ShaderIrOp(ShaderIrInst.Sub, wordSize, size);
-
-            ShaderIrInst rightShift = signed
-                ? ShaderIrInst.Asr
-                : ShaderIrInst.Lsr;
-
-            node = new ShaderIrOp(ShaderIrInst.Lsl, node, shift);
-            node = new ShaderIrOp(rightShift,       node, shift);
-
-            return node;
-        }
-    }
-}

+ 0 - 878
Ryujinx.Graphics/Gal/Shader/ShaderDecodeMem.cs

@@ -1,878 +0,0 @@
-using Ryujinx.Graphics.Texture;
-using System;
-
-using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    static partial class ShaderDecode
-    {
-        // ReSharper disable InconsistentNaming
-        private const int ____ = 0x0;
-        private const int R___ = 0x1;
-        private const int _G__ = 0x2;
-        private const int RG__ = 0x3;
-        private const int __B_ = 0x4;
-        private const int RGB_ = 0x7;
-        private const int ___A = 0x8;
-        private const int R__A = 0x9;
-        private const int _G_A = 0xa;
-        private const int RG_A = 0xb;
-        private const int __BA = 0xc;
-        private const int R_BA = 0xd;
-        private const int _GBA = 0xe;
-        private const int RGBA = 0xf;
-        // ReSharper restore InconsistentNaming
-
-        private static int[,] _maskLut = new int[,]
-        {
-            { ____, ____, ____, ____, ____, ____, ____, ____ },
-            { R___, _G__, __B_, ___A, RG__, R__A, _G_A, __BA },
-            { R___, _G__, __B_, ___A, RG__, ____, ____, ____ },
-            { RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
-        };
-
-        private static GalTextureTarget TexToTextureTarget(int texType, bool isArray)
-        {
-            switch (texType)
-            {
-                case 0:
-                    return isArray ? GalTextureTarget.OneDArray : GalTextureTarget.OneD;
-                case 2:
-                    return isArray ? GalTextureTarget.TwoDArray : GalTextureTarget.TwoD;
-                case 4:
-                    if (isArray)
-                        throw new InvalidOperationException("ARRAY bit set on a TEX with 3D texture!");
-                    return GalTextureTarget.ThreeD;
-                case 6:
-                    return isArray ? GalTextureTarget.CubeArray : GalTextureTarget.CubeMap;
-                default:
-                    throw new InvalidOperationException();
-            }
-        }
-
-        private static GalTextureTarget TexsToTextureTarget(int texType)
-        {
-            switch (texType)
-            {
-                case 0:
-                    return GalTextureTarget.OneD;
-                case 2:
-                case 4:
-                case 6:
-                case 8:
-                case 0xa:
-                case 0xc:
-                    return GalTextureTarget.TwoD;
-                case 0xe:
-                case 0x10:
-                case 0x12:
-                    return GalTextureTarget.TwoDArray;
-                case 0x14:
-                case 0x16:
-                    return GalTextureTarget.ThreeD;
-                case 0x18:
-                case 0x1a:
-                    return GalTextureTarget.CubeMap;
-                default:
-                    throw new InvalidOperationException();
-            }
-        }
-
-        public static GalTextureTarget TldsToTextureTarget(int texType)
-        {
-            switch (texType)
-            {
-                case 0:
-                case 2:
-                    return GalTextureTarget.OneD;
-                case 4:
-                case 8:
-                case 0xa:
-                case 0xc:
-                case 0x18:
-                    return GalTextureTarget.TwoD;
-                case 0x10:
-                    return GalTextureTarget.TwoDArray;
-                case 0xe:
-                    return GalTextureTarget.ThreeD;
-                default:
-                    throw new InvalidOperationException();
-            }
-        }
-
-        public static void Ld_A(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrNode[] opers = opCode.Abuf20();
-
-            //Used by GS
-            ShaderIrOperGpr vertex = opCode.Gpr39();
-
-            int index = 0;
-
-            foreach (ShaderIrNode operA in opers)
-            {
-                ShaderIrOperGpr operD = opCode.Gpr0();
-
-                operD.Index += index++;
-
-                block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, operA)));
-            }
-        }
-
-        public static void Ld_C(ShaderIrBlock block, long opCode, int position)
-        {
-            int cbufPos   = opCode.Read(22, 0x3fff);
-            int cbufIndex = opCode.Read(36, 0x1f);
-            int type      = opCode.Read(48, 7);
-
-            if (type > 5)
-            {
-                throw new InvalidOperationException();
-            }
-
-            ShaderIrOperGpr temp = ShaderIrOperGpr.MakeTemporary();
-
-            block.AddNode(new ShaderIrAsg(temp, opCode.Gpr8()));
-
-            int count = type == 5 ? 2 : 1;
-
-            for (int index = 0; index < count; index++)
-            {
-                ShaderIrOperCbuf operA = new ShaderIrOperCbuf(cbufIndex, cbufPos, temp);
-
-                ShaderIrOperGpr operD = opCode.Gpr0();
-
-                operA.Pos   += index;
-                operD.Index += index;
-
-                if (!operD.IsValidRegister)
-                {
-                    break;
-                }
-
-                ShaderIrNode node = operA;
-
-                if (type < 4)
-                {
-                    //This is a 8 or 16 bits type.
-                    bool signed = (type & 1) != 0;
-
-                    int size = 8 << (type >> 1);
-
-                    node = ExtendTo32(node, signed, size);
-                }
-
-                block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, node)));
-            }
-        }
-
-        public static void St_A(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrNode[] opers = opCode.Abuf20();
-
-            int index = 0;
-
-            foreach (ShaderIrNode operA in opers)
-            {
-                ShaderIrOperGpr operD = opCode.Gpr0();
-
-                operD.Index += index++;
-
-                block.AddNode(opCode.PredNode(new ShaderIrAsg(operA, operD)));
-            }
-        }
-
-        public static void Texq(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrNode operD = opCode.Gpr0();
-            ShaderIrNode operA = opCode.Gpr8();
-
-            ShaderTexqInfo info = (ShaderTexqInfo)(opCode.Read(22, 0x1f));
-
-            ShaderIrMetaTexq meta0 = new ShaderIrMetaTexq(info, 0);
-            ShaderIrMetaTexq meta1 = new ShaderIrMetaTexq(info, 1);
-
-            ShaderIrNode operC = opCode.Imm13_36();
-
-            ShaderIrOp op0 = new ShaderIrOp(ShaderIrInst.Texq, operA, null, operC, meta0);
-            ShaderIrOp op1 = new ShaderIrOp(ShaderIrInst.Texq, operA, null, operC, meta1);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(operD, op0)));
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(operA, op1))); //Is this right?
-        }
-
-        public static void Tex(ShaderIrBlock block, long opCode, int position)
-        {
-            TextureInstructionSuffix suffix;
-
-            int rawSuffix = opCode.Read(0x34, 0x38);
-
-            switch (rawSuffix)
-            {
-                case 0:
-                    suffix = TextureInstructionSuffix.None;
-                    break;
-                case 0x8:
-                    suffix = TextureInstructionSuffix.Lz;
-                    break;
-                case 0x10:
-                    suffix = TextureInstructionSuffix.Lb;
-                    break;
-                case 0x18:
-                    suffix = TextureInstructionSuffix.Ll;
-                    break;
-                case 0x30:
-                    suffix = TextureInstructionSuffix.Lba;
-                    break;
-                case 0x38:
-                    suffix = TextureInstructionSuffix.Lla;
-                    break;
-                default:
-                    throw new InvalidOperationException($"Invalid Suffix for TEX instruction {rawSuffix}");
-            }
-
-            bool isOffset = opCode.Read(0x36);
-
-            if (isOffset)
-                suffix |= TextureInstructionSuffix.AOffI;
-
-            EmitTex(block, opCode, suffix, gprHandle: false);
-        }
-
-        public static void Tex_B(ShaderIrBlock block, long opCode, int position)
-        {
-            TextureInstructionSuffix suffix;
-
-            int rawSuffix = opCode.Read(0x24, 0xe);
-
-            switch (rawSuffix)
-            {
-                case 0:
-                    suffix = TextureInstructionSuffix.None;
-                    break;
-                case 0x2:
-                    suffix = TextureInstructionSuffix.Lz;
-                    break;
-                case 0x4:
-                    suffix = TextureInstructionSuffix.Lb;
-                    break;
-                case 0x6:
-                    suffix = TextureInstructionSuffix.Ll;
-                    break;
-                case 0xc:
-                    suffix = TextureInstructionSuffix.Lba;
-                    break;
-                case 0xe:
-                    suffix = TextureInstructionSuffix.Lla;
-                    break;
-                default:
-                    throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {rawSuffix}");
-            }
-
-            bool isOffset = opCode.Read(0x23);
-
-            if (isOffset)
-                suffix |= TextureInstructionSuffix.AOffI;
-
-            EmitTex(block, opCode, suffix, gprHandle: true);
-        }
-
-        private static void EmitTex(ShaderIrBlock block, long opCode, TextureInstructionSuffix textureInstructionSuffix, bool gprHandle)
-        {
-            bool isArray = opCode.HasArray();
-
-            GalTextureTarget textureTarget = TexToTextureTarget(opCode.Read(28, 6), isArray);
-
-            bool hasDepthCompare = opCode.Read(0x32);
-
-            if (hasDepthCompare)
-            {
-                textureInstructionSuffix |= TextureInstructionSuffix.Dc;
-            }
-
-            ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)];
-
-            int indexExtraCoord = 0;
-
-            if (isArray)
-            {
-                indexExtraCoord++;
-
-                coords[coords.Length - 1] = opCode.Gpr8();
-            }
-
-
-            for (int index = 0; index < coords.Length - indexExtraCoord; index++)
-            {
-                ShaderIrOperGpr coordReg = opCode.Gpr8();
-
-                coordReg.Index += index;
-
-                coordReg.Index += indexExtraCoord;
-
-                if (!coordReg.IsValidRegister)
-                {
-                    coordReg.Index = ShaderIrOperGpr.ZrIndex;
-                }
-
-                coords[index] = coordReg;
-            }
-
-            int chMask = opCode.Read(31, 0xf);
-
-            ShaderIrOperGpr levelOfDetail = null;
-            ShaderIrOperGpr offset        = null;
-            ShaderIrOperGpr depthCompare  = null;
-
-            // TODO: determine first argument when TEX.B is used
-            int operBIndex = gprHandle ? 1 : 0;
-
-            if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0 ||
-                (textureInstructionSuffix & TextureInstructionSuffix.Lb) != 0 ||
-                (textureInstructionSuffix & TextureInstructionSuffix.Lba) != 0 ||
-                (textureInstructionSuffix & TextureInstructionSuffix.Lla) != 0)
-            {
-                levelOfDetail        = opCode.Gpr20();
-                levelOfDetail.Index += operBIndex;
-
-                operBIndex++;
-            }
-
-            if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0)
-            {
-                offset        = opCode.Gpr20();
-                offset.Index += operBIndex;
-
-                operBIndex++;
-            }
-
-            if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0)
-            {
-                depthCompare        = opCode.Gpr20();
-                depthCompare.Index += operBIndex;
-
-                operBIndex++;
-            }
-
-            // ???
-            ShaderIrNode operC = gprHandle
-                ? (ShaderIrNode)opCode.Gpr20()
-                : (ShaderIrNode)opCode.Imm13_36();
-
-            ShaderIrInst inst = gprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs;
-
-            coords = CoordsRegistersToTempRegisters(block, coords);
-
-            int regInc = 0;
-
-            for (int ch = 0; ch < 4; ch++)
-            {
-                if (!IsChannelUsed(chMask, ch))
-                {
-                    continue;
-                }
-
-                ShaderIrOperGpr dst = opCode.Gpr0();
-
-                dst.Index += regInc++;
-
-                if (!dst.IsValidRegister || dst.IsConst)
-                {
-                    continue;
-                }
-
-                ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords)
-                {
-                    LevelOfDetail = levelOfDetail,
-                    Offset        = offset,
-                    DepthCompare  = depthCompare
-                };
-
-                ShaderIrOp op = new ShaderIrOp(inst, coords[0], coords.Length > 1 ? coords[1] : null, operC, meta);
-
-                block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op)));
-            }
-        }
-
-        public static void Texs(ShaderIrBlock block, long opCode, int position)
-        {
-            TextureInstructionSuffix suffix;
-
-            int rawSuffix = opCode.Read(0x34, 0x1e);
-
-            switch (rawSuffix)
-            {
-                case 0:
-                case 0x4:
-                case 0x10:
-                case 0x16:
-                    suffix = TextureInstructionSuffix.Lz;
-                    break;
-                case 0x6:
-                case 0x1a:
-                    suffix = TextureInstructionSuffix.Ll;
-                    break;
-                case 0x8:
-                    suffix = TextureInstructionSuffix.Dc;
-                    break;
-                case 0x2:
-                case 0xe:
-                case 0x14:
-                case 0x18:
-                    suffix = TextureInstructionSuffix.None;
-                    break;
-                case 0xa:
-                    suffix = TextureInstructionSuffix.Ll | TextureInstructionSuffix.Dc;
-                    break;
-                case 0xc:
-                case 0x12:
-                    suffix = TextureInstructionSuffix.Lz | TextureInstructionSuffix.Dc;
-                    break;
-                default:
-                    throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {rawSuffix}");
-            }
-
-            GalTextureTarget textureTarget = TexsToTextureTarget(opCode.Read(52, 0x1e));
-
-            EmitTexs(block, opCode, ShaderIrInst.Texs, textureTarget, suffix);
-        }
-
-        public static void Tlds(ShaderIrBlock block, long opCode, int position)
-        {
-            TextureInstructionSuffix suffix;
-
-            int rawSuffix = opCode.Read(0x34, 0x1e);
-
-            switch (rawSuffix)
-            {
-                case 0:
-                case 0x4:
-                case 0x8:
-                    suffix = TextureInstructionSuffix.Lz | TextureInstructionSuffix.AOffI;
-                    break;
-                case 0xc:
-                    suffix = TextureInstructionSuffix.Lz | TextureInstructionSuffix.Mz;
-                    break;
-                case 0xe:
-                case 0x10:
-                    suffix = TextureInstructionSuffix.Lz;
-                    break;
-                case 0x2:
-                case 0xa:
-                    suffix = TextureInstructionSuffix.Ll;
-                    break;
-                case 0x18:
-                    suffix = TextureInstructionSuffix.Ll | TextureInstructionSuffix.AOffI;
-                    break;
-                default:
-                    throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {rawSuffix}");
-            }
-
-            GalTextureTarget textureTarget = TldsToTextureTarget(opCode.Read(52, 0x1e));
-
-            EmitTexs(block, opCode, ShaderIrInst.Txlf, textureTarget, suffix);
-        }
-
-        public static void Tld4(ShaderIrBlock block, long opCode, int position)
-        {
-            TextureInstructionSuffix suffix;
-
-            int rawSuffix = opCode.Read(0x34, 0xc);
-
-            switch (rawSuffix)
-            {
-                case 0:
-                    suffix = TextureInstructionSuffix.None;
-                    break;
-                case 0x4:
-                    suffix = TextureInstructionSuffix.AOffI;
-                    break;
-                case 0x8:
-                    suffix = TextureInstructionSuffix.Ptp;
-                    break;
-                default:
-                    throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {rawSuffix}");
-            }
-
-            bool isShadow = opCode.Read(0x32);
-
-            bool isArray = opCode.HasArray();
-            int  chMask  = opCode.Read(31, 0xf);
-
-            GalTextureTarget textureTarget = TexToTextureTarget(opCode.Read(28, 6), isArray);
-
-            if (isShadow)
-            {
-                suffix |= TextureInstructionSuffix.Dc;
-            }
-
-            EmitTld4(block, opCode, textureTarget, suffix, chMask, opCode.Read(0x38, 0x3), false);
-        }
-
-        public static void Tld4S(ShaderIrBlock block, long opCode, int position)
-        {
-            TextureInstructionSuffix suffix = TextureInstructionSuffix.None;
-
-            bool isOffset = opCode.Read(0x33);
-            bool isShadow = opCode.Read(0x32);
-
-            if (isOffset)
-            {
-                suffix |= TextureInstructionSuffix.AOffI;
-            }
-
-            if (isShadow)
-            {
-                suffix |= TextureInstructionSuffix.Dc;
-            }
-
-            // TLD4S seems to only support 2D textures with RGBA mask?
-            EmitTld4(block, opCode, GalTextureTarget.TwoD, suffix, RGBA, opCode.Read(0x34, 0x3), true);
-        }
-
-        private static void EmitTexs(ShaderIrBlock            block,
-                                     long                     opCode,
-                                     ShaderIrInst             inst,
-                                     GalTextureTarget         textureTarget,
-                                     TextureInstructionSuffix textureInstructionSuffix)
-        {
-            if (inst == ShaderIrInst.Txlf && textureTarget == GalTextureTarget.CubeArray)
-            {
-                throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!");
-            }
-
-            bool isArray = ImageUtils.IsArray(textureTarget);
-
-            ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureTarget)];
-
-            ShaderIrOperGpr operA = opCode.Gpr8();
-            ShaderIrOperGpr operB = opCode.Gpr20();
-
-            ShaderIrOperGpr suffixExtra = opCode.Gpr20();
-            suffixExtra.Index += 1;
-
-            int coordStartIndex = 0;
-
-            if (isArray)
-            {
-                coordStartIndex++;
-                coords[coords.Length - 1] = opCode.Gpr8();
-            }
-
-            switch (coords.Length - coordStartIndex)
-            {
-                case 1:
-                    coords[0] = opCode.Gpr8();
-
-                    break;
-                case 2:
-                    coords[0] = opCode.Gpr8();
-                    coords[0].Index += coordStartIndex;
-
-                    break;
-                case 3:
-                    coords[0] = opCode.Gpr8();
-                    coords[0].Index += coordStartIndex;
-
-                    coords[1] = opCode.Gpr8();
-                    coords[1].Index += 1 + coordStartIndex;
-
-                    break;
-                default:
-                    throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TEXS");
-            }
-
-            int operBIndex = 0;
-
-            ShaderIrOperGpr levelOfDetail = null;
-            ShaderIrOperGpr offset        = null;
-            ShaderIrOperGpr depthCompare  = null;
-
-            // OperB is always the last value
-            // Not applicable to 1d textures
-            if (coords.Length - coordStartIndex != 1)
-            {
-                coords[coords.Length - coordStartIndex -  1] = operB;
-                operBIndex++;
-            }
-
-            // Encoding of TEXS/TLDS is a bit special and change for 2d textures
-            // NOTE: OperA seems to hold at best two args.
-            // On 2D textures, if no suffix need an additional values, Y is stored in OperB, otherwise coords are in OperA and the additional values is in OperB.
-            if (textureInstructionSuffix != TextureInstructionSuffix.None && textureInstructionSuffix != TextureInstructionSuffix.Lz && textureTarget == GalTextureTarget.TwoD)
-            {
-                coords[coords.Length - coordStartIndex - 1]        = opCode.Gpr8();
-                coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1;
-                operBIndex--;
-            }
-
-            // TODO: Find what MZ does and what changes about the encoding (Maybe Multisample?)
-            if ((textureInstructionSuffix & TextureInstructionSuffix.Ll) != 0)
-            {
-                levelOfDetail        = opCode.Gpr20();
-                levelOfDetail.Index += operBIndex;
-                operBIndex++;
-            }
-
-            if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0)
-            {
-                offset        = opCode.Gpr20();
-                offset.Index += operBIndex;
-                operBIndex++;
-            }
-
-            if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0)
-            {
-                depthCompare        = opCode.Gpr20();
-                depthCompare.Index += operBIndex;
-                operBIndex++;
-            }
-
-            int lutIndex;
-
-            lutIndex  = !opCode.Gpr0().IsConst  ? 1 : 0;
-            lutIndex |= !opCode.Gpr28().IsConst ? 2 : 0;
-
-            if (lutIndex == 0)
-            {
-                //Both destination registers are RZ, do nothing.
-                return;
-            }
-
-            bool fp16 = !opCode.Read(59);
-
-            int dstIncrement = 0;
-
-            ShaderIrOperGpr GetDst()
-            {
-                ShaderIrOperGpr dst;
-
-                if (fp16)
-                {
-                    //FP16 mode, two components are packed on the two
-                    //halfs of a 32-bits register, as two half-float values.
-                    int halfPart = dstIncrement & 1;
-
-                    switch (lutIndex)
-                    {
-                        case 1: dst = opCode.GprHalf0(halfPart);  break;
-                        case 2: dst = opCode.GprHalf28(halfPart); break;
-                        case 3: dst = (dstIncrement >> 1) != 0
-                            ? opCode.GprHalf28(halfPart)
-                            : opCode.GprHalf0(halfPart); break;
-
-                        default: throw new InvalidOperationException();
-                    }
-                }
-                else
-                {
-                    //32-bits mode, each component uses one register.
-                    //Two components uses two consecutive registers.
-                    switch (lutIndex)
-                    {
-                        case 1: dst = opCode.Gpr0();  break;
-                        case 2: dst = opCode.Gpr28(); break;
-                        case 3: dst = (dstIncrement >> 1) != 0
-                            ? opCode.Gpr28()
-                            : opCode.Gpr0(); break;
-
-                        default: throw new InvalidOperationException();
-                    }
-
-                    dst.Index += dstIncrement & 1;
-                }
-
-                dstIncrement++;
-
-                return dst;
-            }
-
-            int chMask = _maskLut[lutIndex, opCode.Read(50, 7)];
-
-            if (chMask == 0)
-            {
-                //All channels are disabled, do nothing.
-                return;
-            }
-
-            ShaderIrNode operC = opCode.Imm13_36();
-            coords = CoordsRegistersToTempRegisters(block, coords);
-
-            for (int ch = 0; ch < 4; ch++)
-            {
-                if (!IsChannelUsed(chMask, ch))
-                {
-                    continue;
-                }
-
-                ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureTarget, textureInstructionSuffix, coords)
-                {
-                    LevelOfDetail = levelOfDetail,
-                    Offset        = offset,
-                    DepthCompare  = depthCompare
-                };
-                ShaderIrOp op = new ShaderIrOp(inst, operA, operB, operC, meta);
-
-                ShaderIrOperGpr dst = GetDst();
-
-                if (dst.IsValidRegister && !dst.IsConst)
-                {
-                    block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op)));
-                }
-            }
-        }
-
-        private static void EmitTld4(ShaderIrBlock block, long opCode, GalTextureTarget textureType, TextureInstructionSuffix textureInstructionSuffix, int chMask, int component, bool scalar)
-        {
-            ShaderIrOperGpr operA = opCode.Gpr8();
-            ShaderIrOperGpr operB = opCode.Gpr20();
-            ShaderIrOperImm operC = opCode.Imm13_36();
-
-            ShaderIrOperGpr[] coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(textureType)];
-
-            ShaderIrOperGpr offset       = null;
-            ShaderIrOperGpr depthCompare = null;
-
-            bool isArray = ImageUtils.IsArray(textureType);
-
-            int operBIndex = 0;
-
-            if (scalar)
-            {
-                int coordStartIndex = 0;
-
-                if (isArray)
-                {
-                    coordStartIndex++;
-                    coords[coords.Length - 1] = operB;
-                }
-
-                switch (coords.Length - coordStartIndex)
-                {
-                    case 1:
-                        coords[0] = opCode.Gpr8();
-
-                        break;
-                    case 2:
-                        coords[0] = opCode.Gpr8();
-                        coords[0].Index += coordStartIndex;
-
-                        break;
-                    case 3:
-                        coords[0] = opCode.Gpr8();
-                        coords[0].Index += coordStartIndex;
-
-                        coords[1] = opCode.Gpr8();
-                        coords[1].Index += 1 + coordStartIndex;
-
-                        break;
-                    default:
-                        throw new NotSupportedException($"{coords.Length - coordStartIndex} coords textures aren't supported in TLD4S");
-                }
-
-                if (coords.Length - coordStartIndex != 1)
-                {
-                    coords[coords.Length - coordStartIndex - 1] = operB;
-                    operBIndex++;
-                }
-
-                if (textureInstructionSuffix != TextureInstructionSuffix.None && textureType == GalTextureTarget.TwoD)
-                {
-                    coords[coords.Length - coordStartIndex - 1] = opCode.Gpr8();
-                    coords[coords.Length - coordStartIndex - 1].Index += coords.Length - coordStartIndex - 1;
-                    operBIndex--;
-                }
-            }
-            else
-            {
-                int indexExtraCoord = 0;
-
-                if (isArray)
-                {
-                    indexExtraCoord++;
-
-                    coords[coords.Length - 1] = opCode.Gpr8();
-                }
-
-                for (int index = 0; index < coords.Length - indexExtraCoord; index++)
-                {
-                    coords[index] = opCode.Gpr8();
-
-                    coords[index].Index += index;
-
-                    coords[index].Index += indexExtraCoord;
-
-                    if (coords[index].Index > ShaderIrOperGpr.ZrIndex)
-                    {
-                        coords[index].Index = ShaderIrOperGpr.ZrIndex;
-                    }
-                }
-            }
-
-            if ((textureInstructionSuffix & TextureInstructionSuffix.AOffI) != 0)
-            {
-                offset = opCode.Gpr20();
-                offset.Index += operBIndex;
-                operBIndex++;
-            }
-
-            if ((textureInstructionSuffix & TextureInstructionSuffix.Dc) != 0)
-            {
-                depthCompare = opCode.Gpr20();
-                depthCompare.Index += operBIndex;
-                operBIndex++;
-            }
-
-            coords = CoordsRegistersToTempRegisters(block, coords);
-
-            int regInc = 0;
-
-            for (int ch = 0; ch < 4; ch++)
-            {
-                if (!IsChannelUsed(chMask, ch))
-                {
-                    continue;
-                }
-
-                ShaderIrOperGpr dst = opCode.Gpr0();
-
-                dst.Index += regInc++;
-
-                if (!dst.IsValidRegister || dst.IsConst)
-                {
-                    continue;
-                }
-
-                ShaderIrMetaTex meta = new ShaderIrMetaTex(ch, textureType, textureInstructionSuffix, coords)
-                {
-                    Component = component,
-                    Offset = offset,
-                    DepthCompare = depthCompare
-                };
-
-                ShaderIrOp op = new ShaderIrOp(ShaderIrInst.Tld4, operA, operB, operC, meta);
-
-                block.AddNode(opCode.PredNode(new ShaderIrAsg(dst, op)));
-            }
-        }
-
-        private static bool IsChannelUsed(int chMask, int ch)
-        {
-            return (chMask & (1 << ch)) != 0;
-        }
-
-        private static ShaderIrOperGpr[] CoordsRegistersToTempRegisters(ShaderIrBlock block, params ShaderIrOperGpr[] registers)
-        {
-            ShaderIrOperGpr[] res = new ShaderIrOperGpr[registers.Length];
-
-            for (int index = 0; index < res.Length; index++)
-            {
-                res[index] = ShaderIrOperGpr.MakeTemporary(index);
-                block.AddNode(new ShaderIrAsg(res[index], registers[index]));
-            }
-
-            return res;
-        }
-    }
-}

+ 0 - 431
Ryujinx.Graphics/Gal/Shader/ShaderDecodeMove.cs

@@ -1,431 +0,0 @@
-using System;
-
-using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    static partial class ShaderDecode
-    {
-        private enum IntType
-        {
-            U8  = 0,
-            U16 = 1,
-            U32 = 2,
-            U64 = 3,
-            S8  = 4,
-            S16 = 5,
-            S32 = 6,
-            S64 = 7
-        }
-
-        private enum FloatType
-        {
-            F16 = 1,
-            F32 = 2,
-            F64 = 3
-        }
-
-        public static void F2f_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitF2F(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void F2f_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitF2F(block, opCode, ShaderOper.Immf);
-        }
-
-        public static void F2f_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitF2F(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void F2i_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitF2I(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void F2i_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitF2I(block, opCode, ShaderOper.Immf);
-        }
-
-        public static void F2i_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitF2I(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void I2f_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitI2F(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void I2f_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitI2F(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void I2f_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitI2F(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void I2i_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitI2I(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void I2i_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitI2I(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void I2i_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitI2I(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Isberd(ShaderIrBlock block, long opCode, int position)
-        {
-            //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(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), opCode.Gpr8())));
-        }
-
-        public static void Mov_C(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrOperCbuf cbuf = opCode.Cbuf34();
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), cbuf)));
-        }
-
-        public static void Mov_I(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrOperImm imm = opCode.Imm19_20();
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), imm)));
-        }
-
-        public static void Mov_I32(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrOperImm imm = opCode.Imm32_20();
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), imm)));
-        }
-
-        public static void Mov_R(ShaderIrBlock block, long opCode, int position)
-        {
-            ShaderIrOperGpr gpr = opCode.Gpr20();
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), gpr)));
-        }
-
-        public static void Sel_C(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitSel(block, opCode, ShaderOper.Cr);
-        }
-
-        public static void Sel_I(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitSel(block, opCode, ShaderOper.Imm);
-        }
-
-        public static void Sel_R(ShaderIrBlock block, long opCode, int position)
-        {
-            EmitSel(block, opCode, ShaderOper.Rr);
-        }
-
-        public static void Mov_S(ShaderIrBlock block, long opCode, int position)
-        {
-            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(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), source)));
-        }
-
-        private static void EmitF2F(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            bool negA = opCode.Read(45);
-            bool absA = opCode.Read(49);
-
-            ShaderIrNode operA;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:   operA = opCode.Cbuf34();    break;
-                case ShaderOper.Immf: operA = opCode.Immf19_20(); break;
-                case ShaderOper.Rr:   operA = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            operA = GetAluFabsFneg(operA, absA, negA);
-
-            ShaderIrInst roundInst = GetRoundInst(opCode);
-
-            if (roundInst != ShaderIrInst.Invalid)
-            {
-                operA = new ShaderIrOp(roundInst, operA);
-            }
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA)));
-        }
-
-        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 negA = opCode.Read(45);
-            bool absA = opCode.Read(49);
-
-            ShaderIrNode operA;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:   operA = opCode.Cbuf34();    break;
-                case ShaderOper.Immf: operA = opCode.Immf19_20(); break;
-                case ShaderOper.Rr:   operA = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            operA = GetAluFabsFneg(operA, absA, negA);
-
-            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 min = new ShaderIrOperImmf(cMin);
-                ShaderIrOperImmf max = new ShaderIrOperImmf(cMax);
-
-                operA = new ShaderIrOp(ShaderIrInst.Fclamp, operA, min, max);
-            }
-
-            ShaderIrInst inst = signed
-                ? ShaderIrInst.Ftos
-                : ShaderIrInst.Ftou;
-
-            ShaderIrNode op = new ShaderIrOp(inst, operA);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        private static void EmitI2F(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();
-            }
-
-            int sel = opCode.Read(41, 3);
-
-            bool negA = opCode.Read(45);
-            bool absA = opCode.Read(49);
-
-            ShaderIrNode operA;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:  operA = opCode.Cbuf34();   break;
-                case ShaderOper.Imm: operA = opCode.Imm19_20(); break;
-                case ShaderOper.Rr:  operA = opCode.Gpr20();    break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            operA = GetAluIabsIneg(operA, absA, negA);
-
-            bool signed = type >= IntType.S8;
-
-            int shift = sel * 8;
-
-            int size = 8 << ((int)type & 3);
-
-            if (shift != 0)
-            {
-                operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift));
-            }
-
-            if (size < 32)
-            {
-                operA = ExtendTo32(operA, signed, size);
-            }
-
-            ShaderIrInst inst = signed
-                ? ShaderIrInst.Stof
-                : ShaderIrInst.Utof;
-
-            ShaderIrNode op = new ShaderIrOp(inst, operA);
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), op)));
-        }
-
-        private static void EmitI2I(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();
-            }
-
-            int sel = opCode.Read(41, 3);
-
-            bool negA = opCode.Read(45);
-            bool absA = opCode.Read(49);
-            bool satA = opCode.Read(50);
-
-            ShaderIrNode operA;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:   operA = opCode.Cbuf34();    break;
-                case ShaderOper.Immf: operA = opCode.Immf19_20(); break;
-                case ShaderOper.Rr:   operA = opCode.Gpr20();     break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            operA = GetAluIabsIneg(operA, absA, negA);
-
-            bool signed = type >= IntType.S8;
-
-            int shift = sel * 8;
-
-            int size = 8 << ((int)type & 3);
-
-            if (shift != 0)
-            {
-                operA = new ShaderIrOp(ShaderIrInst.Asr, operA, new ShaderIrOperImm(shift));
-            }
-
-            if (size < 32)
-            {
-                uint mask = uint.MaxValue >> (32 - size);
-
-                if (satA)
-                {
-                    uint cMin = 0;
-                    uint cMax = mask;
-
-                    if (signed)
-                    {
-                        uint halfMask = mask >> 1;
-
-                        cMin -= halfMask + 1;
-                        cMax  = halfMask;
-                    }
-
-                    ShaderIrOperImm min = new ShaderIrOperImm((int)cMin);
-                    ShaderIrOperImm max = new ShaderIrOperImm((int)cMax);
-
-                    operA = new ShaderIrOp(signed
-                        ? ShaderIrInst.Clamps
-                        : ShaderIrInst.Clampu, operA, min, max);
-                }
-                else
-                {
-                    operA = ExtendTo32(operA, signed, size);
-                }
-            }
-
-            block.AddNode(opCode.PredNode(new ShaderIrAsg(opCode.Gpr0(), operA)));
-        }
-
-        private static void EmitSel(ShaderIrBlock block, long opCode, ShaderOper oper)
-        {
-            ShaderIrOperGpr dst  = opCode.Gpr0();
-            ShaderIrNode    pred = opCode.Pred39N();
-
-            ShaderIrNode resultA = opCode.Gpr8();
-            ShaderIrNode resultB;
-
-            switch (oper)
-            {
-                case ShaderOper.Cr:  resultB = opCode.Cbuf34();   break;
-                case ShaderOper.Imm: resultB = opCode.Imm19_20(); break;
-                case ShaderOper.Rr:  resultB = opCode.Gpr20();    break;
-
-                default: throw new ArgumentException(nameof(oper));
-            }
-
-            block.AddNode(opCode.PredNode(new ShaderIrCond(pred, new ShaderIrAsg(dst, resultA), false)));
-
-            block.AddNode(opCode.PredNode(new ShaderIrCond(pred, new ShaderIrAsg(dst, resultB), true)));
-        }
-
-        private static IntType GetIntType(long opCode)
-        {
-            bool signed = opCode.Read(13);
-
-            IntType type = (IntType)(opCode.Read(10, 3));
-
-            if (signed)
-            {
-                type += (int)IntType.S8;
-            }
-
-            return type;
-        }
-
-        private static FloatType GetFloatType(long opCode)
-        {
-            return (FloatType)(opCode.Read(8, 3));
-        }
-
-        private static ShaderIrInst GetRoundInst(long opCode)
-        {
-            switch (opCode.Read(39, 3))
-            {
-                case 1: return ShaderIrInst.Floor;
-                case 2: return ShaderIrInst.Ceil;
-                case 3: return ShaderIrInst.Trunc;
-            }
-
-            return ShaderIrInst.Invalid;
-        }
-    }
-}

+ 0 - 313
Ryujinx.Graphics/Gal/Shader/ShaderDecodeOpCode.cs

@@ -1,313 +0,0 @@
-using System;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    static partial class ShaderDecode
-    {
-        private static int Read(this long opCode, int position, int mask)
-        {
-            return (int)(opCode >> position) & mask;
-        }
-
-        private static bool Read(this long opCode, int position)
-        {
-            return ((opCode >> position) & 1) != 0;
-        }
-
-        private static int Branch(this long opCode)
-        {
-            return ((int)(opCode >> 20) << 8) >> 8;
-        }
-
-        private static bool HasArray(this long opCode)
-        {
-            return opCode.Read(0x1c);
-        }
-
-        private static ShaderIrOperAbuf[] Abuf20(this long opCode)
-        {
-            int abuf = opCode.Read(20, 0x3ff);
-            int size = opCode.Read(47, 3);
-
-            ShaderIrOperGpr vertex = opCode.Gpr39();
-
-            ShaderIrOperAbuf[] opers = new ShaderIrOperAbuf[size + 1];
-
-            for (int index = 0; index <= size; index++)
-            {
-                opers[index] = new ShaderIrOperAbuf(abuf + index * 4, vertex);
-            }
-
-            return opers;
-        }
-
-        private static ShaderIrOperAbuf Abuf28(this long opCode)
-        {
-            int abuf = opCode.Read(28, 0x3ff);
-
-            return new ShaderIrOperAbuf(abuf, opCode.Gpr39());
-        }
-
-        private static ShaderIrOperCbuf Cbuf34(this long opCode)
-        {
-            return new ShaderIrOperCbuf(
-                opCode.Read(34, 0x1f),
-                opCode.Read(20, 0x3fff));
-        }
-
-        private static ShaderIrOperGpr Gpr8(this long opCode)
-        {
-            return new ShaderIrOperGpr(opCode.Read(8, 0xff));
-        }
-
-        private static ShaderIrOperGpr Gpr20(this long opCode)
-        {
-            return new ShaderIrOperGpr(opCode.Read(20, 0xff));
-        }
-
-        private static ShaderIrOperGpr Gpr39(this long opCode)
-        {
-            return new ShaderIrOperGpr(opCode.Read(39, 0xff));
-        }
-
-        private static ShaderIrOperGpr Gpr0(this long opCode)
-        {
-            return new ShaderIrOperGpr(opCode.Read(0, 0xff));
-        }
-
-        private static ShaderIrOperGpr Gpr28(this long opCode)
-        {
-            return new ShaderIrOperGpr(opCode.Read(28, 0xff));
-        }
-
-        private static ShaderIrOperGpr[] GprHalfVec8(this long opCode)
-        {
-            return GetGprHalfVec2(opCode.Read(8, 0xff), opCode.Read(47, 3));
-        }
-
-        private static ShaderIrOperGpr[] GprHalfVec20(this long opCode)
-        {
-            return GetGprHalfVec2(opCode.Read(20, 0xff), opCode.Read(28, 3));
-        }
-
-        private static ShaderIrOperGpr[] GetGprHalfVec2(int gpr, int mask)
-        {
-            if (mask == 1)
-            {
-                //This value is used for FP32, the whole 32-bits register
-                //is used as each element on the vector.
-                return new ShaderIrOperGpr[]
-                {
-                    new ShaderIrOperGpr(gpr),
-                    new ShaderIrOperGpr(gpr)
-                };
-            }
-
-            ShaderIrOperGpr low  = new ShaderIrOperGpr(gpr, 0);
-            ShaderIrOperGpr high = new ShaderIrOperGpr(gpr, 1);
-
-            return new ShaderIrOperGpr[]
-            {
-                (mask & 1) != 0 ? high : low,
-                (mask & 2) != 0 ? high : low
-            };
-        }
-
-        private static ShaderIrOperGpr GprHalf0(this long opCode, int halfPart)
-        {
-            return new ShaderIrOperGpr(opCode.Read(0, 0xff), halfPart);
-        }
-
-        private static ShaderIrOperGpr GprHalf28(this long opCode, int halfPart)
-        {
-            return new ShaderIrOperGpr(opCode.Read(28, 0xff), halfPart);
-        }
-
-        private static ShaderIrOperImm Imm5_39(this long opCode)
-        {
-            return new ShaderIrOperImm(opCode.Read(39, 0x1f));
-        }
-
-        private static ShaderIrOperImm Imm13_36(this long opCode)
-        {
-            return new ShaderIrOperImm(opCode.Read(36, 0x1fff));
-        }
-
-        private static ShaderIrOperImm Imm32_20(this long opCode)
-        {
-            return new ShaderIrOperImm((int)(opCode >> 20));
-        }
-
-        private static ShaderIrOperImmf Immf32_20(this long opCode)
-        {
-            return new ShaderIrOperImmf(BitConverter.Int32BitsToSingle((int)(opCode >> 20)));
-        }
-
-        private static ShaderIrOperImm ImmU16_20(this long opCode)
-        {
-            return new ShaderIrOperImm(opCode.Read(20, 0xffff));
-        }
-
-        private static ShaderIrOperImm Imm19_20(this long opCode)
-        {
-            int value = opCode.Read(20, 0x7ffff);
-
-            bool neg = opCode.Read(56);
-
-            if (neg)
-            {
-                value = -value;
-            }
-
-            return new ShaderIrOperImm(value);
-        }
-
-        private static ShaderIrOperImmf Immf19_20(this long opCode)
-        {
-            uint imm = (uint)(opCode >> 20) & 0x7ffff;
-
-            bool neg = opCode.Read(56);
-
-            imm <<= 12;
-
-            if (neg)
-            {
-                imm |= 0x80000000;
-            }
-
-            float value = BitConverter.Int32BitsToSingle((int)imm);
-
-            return new ShaderIrOperImmf(value);
-        }
-
-        private static ShaderIrOperPred Pred0(this long opCode)
-        {
-            return new ShaderIrOperPred(opCode.Read(0, 7));
-        }
-
-        private static ShaderIrOperPred Pred3(this long opCode)
-        {
-            return new ShaderIrOperPred(opCode.Read(3, 7));
-        }
-
-        private static ShaderIrOperPred Pred12(this long opCode)
-        {
-            return new ShaderIrOperPred(opCode.Read(12, 7));
-        }
-
-        private static ShaderIrOperPred Pred29(this long opCode)
-        {
-            return new ShaderIrOperPred(opCode.Read(29, 7));
-        }
-
-        private static ShaderIrNode Pred39N(this long opCode)
-        {
-            ShaderIrNode node = opCode.Pred39();
-
-            if (opCode.Read(42))
-            {
-                node = new ShaderIrOp(ShaderIrInst.Bnot, node);
-            }
-
-            return node;
-        }
-
-        private static ShaderIrOperPred Pred39(this long opCode)
-        {
-            return new ShaderIrOperPred(opCode.Read(39, 7));
-        }
-
-        private static ShaderIrOperPred Pred48(this long opCode)
-        {
-            return new ShaderIrOperPred(opCode.Read(48, 7));
-        }
-
-        private static ShaderIrInst Cmp(this long opCode)
-        {
-            switch (opCode.Read(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));
-        }
-
-        private static ShaderIrInst CmpF(this long opCode)
-        {
-            switch (opCode.Read(48, 0xf))
-            {
-                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));
-        }
-
-        private static ShaderIrInst BLop45(this long opCode)
-        {
-            switch (opCode.Read(45, 3))
-            {
-                case 0: return ShaderIrInst.Band;
-                case 1: return ShaderIrInst.Bor;
-                case 2: return ShaderIrInst.Bxor;
-            }
-
-            throw new ArgumentException(nameof(opCode));
-        }
-
-        private static ShaderIrInst BLop24(this long opCode)
-        {
-            switch (opCode.Read(24, 3))
-            {
-                case 0: return ShaderIrInst.Band;
-                case 1: return ShaderIrInst.Bor;
-                case 2: return ShaderIrInst.Bxor;
-            }
-
-            throw new ArgumentException(nameof(opCode));
-        }
-
-        private static ShaderIrNode PredNode(this long opCode, ShaderIrNode node)
-        {
-            ShaderIrOperPred pred = opCode.PredNode();
-
-            if (pred.Index != ShaderIrOperPred.UnusedIndex)
-            {
-                bool inv = opCode.Read(19);
-
-                node = new ShaderIrCond(pred, node, inv);
-            }
-
-            return node;
-        }
-
-        private static ShaderIrOperPred PredNode(this long opCode)
-        {
-            int pred = opCode.Read(16, 0xf);
-
-            if (pred != 0xf)
-            {
-                pred &= 7;
-            }
-
-            return new ShaderIrOperPred(pred);
-        }
-    }
-}

+ 0 - 25
Ryujinx.Graphics/Gal/Shader/ShaderDecodeSpecial.cs

@@ -1,25 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    static partial class ShaderDecode
-    {
-        public static void Out_R(ShaderIrBlock block, long opCode, int position)
-        {
-            //TODO: Those registers have to be used for something
-            ShaderIrOperGpr gpr0  = opCode.Gpr0();
-            ShaderIrOperGpr gpr8  = opCode.Gpr8();
-            ShaderIrOperGpr gpr20 = opCode.Gpr20();
-
-            int type = opCode.Read(39, 3);
-
-            if ((type & 1) != 0)
-            {
-                block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Emit)));
-            }
-
-            if ((type & 2) != 0)
-            {
-                block.AddNode(opCode.PredNode(new ShaderIrOp(ShaderIrInst.Cut)));
-            }
-        }
-    }
-}

+ 0 - 218
Ryujinx.Graphics/Gal/Shader/ShaderDecoder.cs

@@ -1,218 +0,0 @@
-using System.Collections.Generic;
-
-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)
-        {
-            Dictionary<int, ShaderIrBlock> visited    = new Dictionary<int, ShaderIrBlock>();
-            Dictionary<int, ShaderIrBlock> visitedEnd = new Dictionary<int, ShaderIrBlock>();
-
-            Queue<ShaderIrBlock> blocks = new Queue<ShaderIrBlock>();
-
-            long beginning = start + HeaderSize;
-
-            ShaderIrBlock Enqueue(int position, ShaderIrBlock source = null)
-            {
-                if (!visited.TryGetValue(position, out ShaderIrBlock output))
-                {
-                    output = new ShaderIrBlock(position);
-
-                    blocks.Enqueue(output);
-
-                    visited.Add(position, output);
-                }
-
-                if (source != null)
-                {
-                    output.Sources.Add(source);
-                }
-
-                return output;
-            }
-
-            ShaderIrBlock entry = Enqueue(0);
-
-            while (blocks.Count > 0)
-            {
-                ShaderIrBlock current = blocks.Dequeue();
-
-                FillBlock(memory, current, beginning);
-
-                //Set child blocks. "Branch" is the block the branch instruction
-                //points to (when taken), "Next" is the block at the next address,
-                //executed when the branch is not taken. For Unconditional Branches
-                //or end of shader, Next is null.
-                if (current.Nodes.Count > 0)
-                {
-                    ShaderIrNode lastNode = current.GetLastNode();
-
-                    ShaderIrOp innerOp = GetInnermostOp(lastNode);
-
-                    if (innerOp?.Inst == ShaderIrInst.Bra)
-                    {
-                        int target = ((ShaderIrOperImm)innerOp.OperandA).Value;
-
-                        current.Branch = Enqueue(target, current);
-                    }
-
-                    foreach (ShaderIrNode node in current.Nodes)
-                    {
-                        innerOp = GetInnermostOp(node);
-
-                        if (innerOp is ShaderIrOp currOp && currOp.Inst == ShaderIrInst.Ssy)
-                        {
-                            int target = ((ShaderIrOperImm)currOp.OperandA).Value;
-
-                            Enqueue(target, current);
-                        }
-                    }
-
-                    if (NodeHasNext(lastNode))
-                    {
-                        current.Next = Enqueue(current.EndPosition);
-                    }
-                }
-
-                //If we have on the graph two blocks with the same end position,
-                //then we need to split the bigger block and have two small blocks,
-                //the end position of the bigger "Current" block should then be == to
-                //the position of the "Smaller" block.
-                while (visitedEnd.TryGetValue(current.EndPosition, out ShaderIrBlock smaller))
-                {
-                    if (current.Position > smaller.Position)
-                    {
-                        ShaderIrBlock temp = smaller;
-
-                        smaller = current;
-                        current = temp;
-                    }
-
-                    current.EndPosition = smaller.Position;
-                    current.Next        = smaller;
-                    current.Branch      = null;
-
-                    current.Nodes.RemoveRange(
-                        current.Nodes.Count - smaller.Nodes.Count,
-                        smaller.Nodes.Count);
-
-                    visitedEnd[smaller.EndPosition] = smaller;
-                }
-
-                visitedEnd.Add(current.EndPosition, current);
-            }
-
-            //Make and sort Graph blocks array by position.
-            ShaderIrBlock[] graph = new ShaderIrBlock[visited.Count];
-
-            while (visited.Count > 0)
-            {
-                uint firstPos = uint.MaxValue;
-
-                foreach (ShaderIrBlock block in visited.Values)
-                {
-                    if (firstPos > (uint)block.Position)
-                        firstPos = (uint)block.Position;
-                }
-
-                ShaderIrBlock current = visited[(int)firstPos];
-
-                do
-                {
-                    graph[graph.Length - visited.Count] = current;
-
-                    visited.Remove(current.Position);
-
-                    current = current.Next;
-                }
-                while (current != null);
-            }
-
-            return graph;
-        }
-
-        private static void FillBlock(IGalMemory memory, ShaderIrBlock block, long beginning)
-        {
-            int position = block.Position;
-
-            do
-            {
-                //Ignore scheduling instructions, which are written every 32 bytes.
-                if ((position & 0x1f) == 0)
-                {
-                    position += 8;
-
-                    continue;
-                }
-
-                uint word0 = (uint)memory.ReadInt32(position + beginning + 0);
-                uint word1 = (uint)memory.ReadInt32(position + beginning + 4);
-
-                position += 8;
-
-                long opCode = word0 | (long)word1 << 32;
-
-                ShaderDecodeFunc decode = ShaderOpCodeTable.GetDecoder(opCode);
-
-                if (AddDbgComments)
-                {
-                    string dbgOpCode = $"0x{(position - 8):x16}: 0x{opCode:x16} ";
-
-                    dbgOpCode += (decode?.Method.Name ?? "???");
-
-                    if (decode == ShaderDecode.Bra || decode == ShaderDecode.Ssy)
-                    {
-                        int offset = ((int)(opCode >> 20) << 8) >> 8;
-
-                        long target = position + offset;
-
-                        dbgOpCode += " (0x" + target.ToString("x16") + ")";
-                    }
-
-                    block.AddNode(new ShaderIrCmnt(dbgOpCode));
-                }
-
-                if (decode == null)
-                {
-                    continue;
-                }
-
-                decode(block, opCode, position);
-            }
-            while (!IsFlowChange(block.GetLastNode()));
-
-            block.EndPosition = position;
-        }
-
-        private static bool IsFlowChange(ShaderIrNode node)
-        {
-            return !NodeHasNext(GetInnermostOp(node));
-        }
-
-        private static ShaderIrOp GetInnermostOp(ShaderIrNode node)
-        {
-            if (node is ShaderIrCond cond)
-            {
-                node = cond.Child;
-            }
-
-            return node is ShaderIrOp op ? op : null;
-        }
-
-        private static bool NodeHasNext(ShaderIrNode node)
-        {
-            if (!(node is ShaderIrOp op))
-            {
-                return true;
-            }
-
-            return op.Inst != ShaderIrInst.Exit &&
-                   op.Inst != ShaderIrInst.Bra;
-        }
-    }
-}

+ 0 - 146
Ryujinx.Graphics/Gal/Shader/ShaderHeader.cs

@@ -1,146 +0,0 @@
-using System;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    struct OmapTarget
-    {
-        public bool Red;
-        public bool Green;
-        public bool Blue;
-        public bool Alpha;
-
-        public bool Enabled => Red || Green || Blue || Alpha;
-
-        public bool ComponentEnabled(int component)
-        {
-            switch (component)
-            {
-                case 0: return Red;
-                case 1: return Green;
-                case 2: return Blue;
-                case 3: return Alpha;
-            }
-
-            throw new ArgumentException(nameof(component));
-        }
-    }
-
-    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 OmapTarget[] OmapTargets    { get; private set; }
-        public bool         OmapSampleMask { get; private set; }
-        public bool         OmapDepth      { 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);
-
-            //Type 2 (fragment?) reading
-            uint type2OmapTarget = (uint)memory.ReadInt32(position + 72);
-            uint type2Omap       = (uint)memory.ReadInt32(position + 76);
-
-            OmapTargets = new OmapTarget[8];
-
-            for (int i = 0; i < OmapTargets.Length; i++)
-            {
-                int offset = i * 4;
-
-                OmapTargets[i] = new OmapTarget
-                {
-                    Red   = ReadBits(type2OmapTarget, offset + 0, 1) != 0,
-                    Green = ReadBits(type2OmapTarget, offset + 1, 1) != 0,
-                    Blue  = ReadBits(type2OmapTarget, offset + 2, 1) != 0,
-                    Alpha = ReadBits(type2OmapTarget, offset + 3, 1) != 0
-                };
-            }
-
-            OmapSampleMask = ReadBits(type2Omap, 0, 1) != 0;
-            OmapDepth      = ReadBits(type2Omap, 1, 1) != 0;
-        }
-
-        public int DepthRegister
-        {
-            get
-            {
-                int count = 0;
-
-                for (int index = 0; index < OmapTargets.Length; index++)
-                {
-                    for (int component = 0; component < 4; component++)
-                    {
-                        if (OmapTargets[index].ComponentEnabled(component))
-                        {
-                            count++;
-                        }
-                    }
-                }
-
-                // Depth register is always two registers after the last color output
-                return count + 1;
-            }
-        }
-
-        private static int ReadBits(uint word, int offset, int bitWidth)
-        {
-            uint mask = (1u << bitWidth) - 1u;
-
-            return (int)((word >> offset) & mask);
-        }
-    }
-}

+ 0 - 10
Ryujinx.Graphics/Gal/Shader/ShaderIpaMode.cs

@@ -1,10 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    enum ShaderIpaMode
-    {
-        Pass     = 0,
-        None     = 1,
-        Constant = 2,
-        Sc       = 3
-    }
-}

+ 0 - 14
Ryujinx.Graphics/Gal/Shader/ShaderIrAsg.cs

@@ -1,14 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrAsg : ShaderIrNode
-    {
-        public ShaderIrNode Dst { get; set; }
-        public ShaderIrNode Src { get; set; }
-
-        public ShaderIrAsg(ShaderIrNode dst, ShaderIrNode src)
-        {
-            Dst = dst;
-            Src = src;
-        }
-    }
-}

+ 0 - 46
Ryujinx.Graphics/Gal/Shader/ShaderIrBlock.cs

@@ -1,46 +0,0 @@
-using System.Collections.Generic;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrBlock
-    {
-        public int Position    { get; set; }
-        public int EndPosition { get; set; }
-
-        public ShaderIrBlock Next   { get; set; }
-        public ShaderIrBlock Branch { get; set; }
-
-        public List<ShaderIrBlock> Sources { get; private set; }
-
-        public List<ShaderIrNode> Nodes { get; private set; }
-
-        public ShaderIrBlock(int position)
-        {
-            Position = position;
-
-            Sources = new List<ShaderIrBlock>();
-
-            Nodes = new List<ShaderIrNode>();
-        }
-
-        public void AddNode(ShaderIrNode node)
-        {
-            Nodes.Add(node);
-        }
-
-        public ShaderIrNode[] GetNodes()
-        {
-            return Nodes.ToArray();
-        }
-
-        public ShaderIrNode GetLastNode()
-        {
-            if (Nodes.Count > 0)
-            {
-                return Nodes[Nodes.Count - 1];
-            }
-
-            return null;
-        }
-    }
-}

+ 0 - 12
Ryujinx.Graphics/Gal/Shader/ShaderIrCmnt.cs

@@ -1,12 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrCmnt : ShaderIrNode
-    {
-        public string Comment { get; private set; }
-
-        public ShaderIrCmnt(string comment)
-        {
-            Comment = comment;
-        }
-    }
-}

+ 0 - 17
Ryujinx.Graphics/Gal/Shader/ShaderIrCond.cs

@@ -1,17 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrCond : ShaderIrNode
-    {
-        public ShaderIrNode Pred  { get; set; }
-        public ShaderIrNode Child { get; set; }
-
-        public bool Not { get; private set; }
-
-        public ShaderIrCond(ShaderIrNode pred, ShaderIrNode child, bool not)
-        {
-            Pred  = pred;
-            Child = child;
-            Not   = not;
-        }
-    }
-}

+ 0 - 94
Ryujinx.Graphics/Gal/Shader/ShaderIrInst.cs

@@ -1,94 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    enum ShaderIrInst
-    {
-        Invalid,
-
-        B_Start,
-        Band,
-        Bnot,
-        Bor,
-        Bxor,
-        B_End,
-
-        F_Start,
-        Ceil,
-
-        Fabs,
-        Fadd,
-        Fceq,
-        Fcequ,
-        Fcge,
-        Fcgeu,
-        Fcgt,
-        Fcgtu,
-        Fclamp,
-        Fcle,
-        Fcleu,
-        Fclt,
-        Fcltu,
-        Fcnan,
-        Fcne,
-        Fcneu,
-        Fcnum,
-        Fcos,
-        Fex2,
-        Ffma,
-        Flg2,
-        Floor,
-        Fmax,
-        Fmin,
-        Fmul,
-        Fneg,
-        Frcp,
-        Frsq,
-        Fsin,
-        Fsqrt,
-        Ftos,
-        Ftou,
-        Ipa,
-        Texb,
-        Texs,
-        Tld4,
-        Trunc,
-        F_End,
-
-        I_Start,
-        Abs,
-        Add,
-        And,
-        Asr,
-        Ceq,
-        Cge,
-        Cgt,
-        Clamps,
-        Clampu,
-        Cle,
-        Clt,
-        Cne,
-        Lsl,
-        Lsr,
-        Max,
-        Min,
-        Mul,
-        Neg,
-        Not,
-        Or,
-        Stof,
-        Sub,
-        Texq,
-        Txlf,
-        Utof,
-        Xor,
-        I_End,
-
-        Bra,
-        Exit,
-        Kil,
-        Ssy,
-        Sync,
-
-        Emit,
-        Cut
-    }
-}

+ 0 - 4
Ryujinx.Graphics/Gal/Shader/ShaderIrMeta.cs

@@ -1,4 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrMeta { }
-}

+ 0 - 12
Ryujinx.Graphics/Gal/Shader/ShaderIrMetaIpa.cs

@@ -1,12 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrMetaIpa : ShaderIrMeta
-    {
-        public ShaderIpaMode Mode { get; private set; }
-
-        public ShaderIrMetaIpa(ShaderIpaMode mode)
-        {
-            Mode = mode;
-        }
-    }
-}

+ 0 - 24
Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTex.cs

@@ -1,24 +0,0 @@
-using Ryujinx.Graphics.Texture;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrMetaTex : ShaderIrMeta
-    {
-        public int                      Elem { get; private set; }
-        public GalTextureTarget         TextureTarget { get; private set; }
-        public ShaderIrNode[]           Coordinates { get; private set; }
-        public TextureInstructionSuffix TextureInstructionSuffix { get; private set; }
-        public ShaderIrOperGpr          LevelOfDetail;
-        public ShaderIrOperGpr          Offset;
-        public ShaderIrOperGpr          DepthCompare;
-        public int                      Component; // for TLD4(S)
-
-        public ShaderIrMetaTex(int elem, GalTextureTarget textureTarget, TextureInstructionSuffix textureInstructionSuffix, params ShaderIrNode[] coordinates)
-        {
-            Elem                     = elem;
-            TextureTarget            = textureTarget;
-            TextureInstructionSuffix = textureInstructionSuffix;
-            Coordinates              = coordinates;
-        }
-    }
-}

+ 0 - 15
Ryujinx.Graphics/Gal/Shader/ShaderIrMetaTexq.cs

@@ -1,15 +0,0 @@
-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)
-        {
-            Info = info;
-            Elem = elem;
-        }
-    }
-}

+ 0 - 4
Ryujinx.Graphics/Gal/Shader/ShaderIrNode.cs

@@ -1,4 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrNode { }
-}

+ 0 - 25
Ryujinx.Graphics/Gal/Shader/ShaderIrOp.cs

@@ -1,25 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrOp : ShaderIrNode
-    {
-        public ShaderIrInst Inst     { get; private set; }
-        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,
-            ShaderIrMeta metaData = null)
-        {
-            Inst     = inst;
-            OperandA = operandA;
-            OperandB = operandB;
-            OperandC = operandC;
-            MetaData = metaData;
-        }
-    }
-}

+ 0 - 15
Ryujinx.Graphics/Gal/Shader/ShaderIrOperAbuf.cs

@@ -1,15 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrOperAbuf : ShaderIrNode
-    {
-        public int Offs { get; private set; }
-
-        public ShaderIrNode Vertex { get; private set; }
-
-        public ShaderIrOperAbuf(int offs, ShaderIrNode vertex)
-        {
-            Offs   = offs;
-            Vertex = vertex;
-        }
-    }
-}

+ 0 - 17
Ryujinx.Graphics/Gal/Shader/ShaderIrOperCbuf.cs

@@ -1,17 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrOperCbuf : ShaderIrNode
-    {
-        public int Index { get; private set; }
-        public int Pos   { get; set; }
-
-        public ShaderIrNode Offs { get; private set; }
-
-        public ShaderIrOperCbuf(int index, int pos, ShaderIrNode offs = null)
-        {
-            Index = index;
-            Pos   = pos;
-            Offs  = offs;
-        }
-    }
-}

+ 0 - 36
Ryujinx.Graphics/Gal/Shader/ShaderIrOperGpr.cs

@@ -1,36 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrOperGpr : ShaderIrNode
-    {
-        public const int ZrIndex = 0xff;
-
-        public bool IsConst => Index == ZrIndex;
-
-        public bool IsValidRegister => (uint)Index <= ZrIndex;
-
-        public int Index    { get; set; }
-        public int HalfPart { get; set; }
-
-        public ShaderRegisterSize RegisterSize { get; private set; }
-
-        public ShaderIrOperGpr(int index)
-        {
-            Index = index;
-
-            RegisterSize = ShaderRegisterSize.Single;
-        }
-
-        public ShaderIrOperGpr(int index, int halfPart)
-        {
-            Index    = index;
-            HalfPart = halfPart;
-
-            RegisterSize = ShaderRegisterSize.Half;
-        }
-
-        public static ShaderIrOperGpr MakeTemporary(int index = 0)
-        {
-            return new ShaderIrOperGpr(0x100 + index);
-        }
-    }
-}

+ 0 - 12
Ryujinx.Graphics/Gal/Shader/ShaderIrOperImm.cs

@@ -1,12 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrOperImm : ShaderIrNode
-    {
-        public int Value { get; private set; }
-
-        public ShaderIrOperImm(int value)
-        {
-            Value = value;
-        }
-    }
-}

+ 0 - 12
Ryujinx.Graphics/Gal/Shader/ShaderIrOperImmf.cs

@@ -1,12 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrOperImmf : ShaderIrNode
-    {
-        public float Value { get; private set; }
-
-        public ShaderIrOperImmf(float value)
-        {
-            Value = value;
-        }
-    }
-}

+ 0 - 17
Ryujinx.Graphics/Gal/Shader/ShaderIrOperPred.cs

@@ -1,17 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    class ShaderIrOperPred : ShaderIrNode
-    {
-        public const int UnusedIndex  = 0x7;
-        public const int NeverExecute = 0xf;
-
-        public bool IsConst => Index >= UnusedIndex;
-
-        public int Index { get; set; }
-
-        public ShaderIrOperPred(int index)
-        {
-            Index = index;
-        }
-    }
-}

+ 0 - 190
Ryujinx.Graphics/Gal/Shader/ShaderOpCodeTable.cs

@@ -1,190 +0,0 @@
-using System;
-
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    static class ShaderOpCodeTable
-    {
-        private const int EncodingBits = 14;
-
-        private class ShaderDecodeEntry
-        {
-            public ShaderDecodeFunc Func;
-
-            public int XBits;
-
-            public ShaderDecodeEntry(ShaderDecodeFunc func, int xBits)
-            {
-                Func  = func;
-                XBits = xBits;
-            }
-        }
-
-        private static ShaderDecodeEntry[] _opCodes;
-
-        static ShaderOpCodeTable()
-        {
-            _opCodes = new ShaderDecodeEntry[1 << EncodingBits];
-
-#region Instructions
-            Set("0100110000000x", ShaderDecode.Bfe_C);
-            Set("0011100x00000x", ShaderDecode.Bfe_I);
-            Set("0101110000000x", ShaderDecode.Bfe_R);
-            Set("111000100100xx", ShaderDecode.Bra);
-            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("000010xxxxxxxx", ShaderDecode.Fadd_I32);
-            Set("0101110001011x", ShaderDecode.Fadd_R);
-            Set("010010011xxxxx", ShaderDecode.Ffma_CR);
-            Set("0011001x1xxxxx", ShaderDecode.Ffma_I);
-            Set("010100011xxxxx", ShaderDecode.Ffma_RC);
-            Set("010110011xxxxx", ShaderDecode.Ffma_RR);
-            Set("0100110001101x", ShaderDecode.Fmul_C);
-            Set("0011100x01101x", ShaderDecode.Fmul_I);
-            Set("00011110xxxxxx", ShaderDecode.Fmul_I32);
-            Set("0101110001101x", ShaderDecode.Fmul_R);
-            Set("0100110001100x", ShaderDecode.Fmnmx_C);
-            Set("0011100x01100x", ShaderDecode.Fmnmx_I);
-            Set("0101110001100x", ShaderDecode.Fmnmx_R);
-            Set("0100100xxxxxxx", ShaderDecode.Fset_C);
-            Set("0011000xxxxxxx", ShaderDecode.Fset_I);
-            Set("01011000xxxxxx", ShaderDecode.Fset_R);
-            Set("010010111011xx", ShaderDecode.Fsetp_C);
-            Set("0011011x1011xx", ShaderDecode.Fsetp_I);
-            Set("010110111011xx", ShaderDecode.Fsetp_R);
-            Set("0101110100010x", ShaderDecode.Hadd2_R);
-            Set("0101110100001x", ShaderDecode.Hmul2_R);
-            Set("0100110010111x", ShaderDecode.I2f_C);
-            Set("0011100x10111x", ShaderDecode.I2f_I);
-            Set("0101110010111x", ShaderDecode.I2f_R);
-            Set("0100110011100x", ShaderDecode.I2i_C);
-            Set("0011100x11100x", ShaderDecode.I2i_I);
-            Set("0101110011100x", ShaderDecode.I2i_R);
-            Set("0100110000010x", ShaderDecode.Iadd_C);
-            Set("0011100000010x", ShaderDecode.Iadd_I);
-            Set("0001110x0xxxxx", ShaderDecode.Iadd_I32);
-            Set("0101110000010x", ShaderDecode.Iadd_R);
-            Set("010011001100xx", ShaderDecode.Iadd3_C);
-            Set("001110001100xx", ShaderDecode.Iadd3_I);
-            Set("010111001100xx", ShaderDecode.Iadd3_R);
-            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);
-            Set("0101110000011x", ShaderDecode.Iscadd_R);
-            Set("010010110101xx", ShaderDecode.Iset_C);
-            Set("001101100101xx", ShaderDecode.Iset_I);
-            Set("010110110101xx", ShaderDecode.Iset_R);
-            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("1110111110010x", ShaderDecode.Ld_C);
-            Set("0100110001000x", ShaderDecode.Lop_C);
-            Set("0011100001000x", ShaderDecode.Lop_I);
-            Set("000001xxxxxxxx", ShaderDecode.Lop_I32);
-            Set("0101110001000x", ShaderDecode.Lop_R);
-            Set("0100110010011x", ShaderDecode.Mov_C);
-            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);
-            Set("0101110010010x", ShaderDecode.Rro_R);
-            Set("0100110010100x", ShaderDecode.Sel_C);
-            Set("0011100010100x", ShaderDecode.Sel_I);
-            Set("0101110010100x", ShaderDecode.Sel_R);
-            Set("0100110001001x", ShaderDecode.Shl_C);
-            Set("0011100x01001x", ShaderDecode.Shl_I);
-            Set("0101110001001x", ShaderDecode.Shl_R);
-            Set("0100110000101x", ShaderDecode.Shr_C);
-            Set("0011100x00101x", ShaderDecode.Shr_I);
-            Set("0101110000101x", ShaderDecode.Shr_R);
-            Set("111000101001xx", ShaderDecode.Ssy);
-            Set("1110111111110x", ShaderDecode.St_A);
-            Set("1111000011111x", ShaderDecode.Sync);
-            Set("110000xxxx111x", ShaderDecode.Tex);
-            Set("1101111010111x", ShaderDecode.Tex_B);
-            Set("1101111101001x", ShaderDecode.Texq);
-            Set("1101x00xxxxxxx", ShaderDecode.Texs);
-            Set("1101101xxxxxxx", ShaderDecode.Tlds);
-            Set("110010xxxx111x", ShaderDecode.Tld4);
-            Set("1101111100xxxx", ShaderDecode.Tld4S);
-            Set("01011111xxxxxx", ShaderDecode.Vmad);
-            Set("0100111xxxxxxx", ShaderDecode.Xmad_CR);
-            Set("0011011x00xxxx", ShaderDecode.Xmad_I);
-            Set("010100010xxxxx", ShaderDecode.Xmad_RC);
-            Set("0101101100xxxx", ShaderDecode.Xmad_RR);
-#endregion
-        }
-
-        private static void Set(string encoding, ShaderDecodeFunc func)
-        {
-            if (encoding.Length != EncodingBits)
-            {
-                throw new ArgumentException(nameof(encoding));
-            }
-
-            int bit   = encoding.Length - 1;
-            int value = 0;
-            int xMask = 0;
-            int xBits = 0;
-
-            int[] xPos = new int[encoding.Length];
-
-            for (int index = 0; index < encoding.Length; index++, bit--)
-            {
-                char chr = encoding[index];
-
-                if (chr == '1')
-                {
-                    value |= 1 << bit;
-                }
-                else if (chr == 'x')
-                {
-                    xMask |= 1 << bit;
-
-                    xPos[xBits++] = bit;
-                }
-            }
-
-            xMask = ~xMask;
-
-            ShaderDecodeEntry entry = new ShaderDecodeEntry(func, xBits);
-
-            for (int index = 0; index < (1 << xBits); index++)
-            {
-                value &= xMask;
-
-                for (int x = 0; x < xBits; x++)
-                {
-                    value |= ((index >> x) & 1) << xPos[x];
-                }
-
-                if (_opCodes[value] == null || _opCodes[value].XBits > xBits)
-                {
-                    _opCodes[value] = entry;
-                }
-            }
-        }
-
-        public static ShaderDecodeFunc GetDecoder(long opCode)
-        {
-            return _opCodes[(ulong)opCode >> (64 - EncodingBits)]?.Func;
-        }
-    }
-}

+ 0 - 11
Ryujinx.Graphics/Gal/Shader/ShaderOper.cs

@@ -1,11 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    enum ShaderOper
-    {
-        Cr,
-        Imm,
-        Immf,
-        Rc,
-        Rr
-    }
-}

+ 0 - 9
Ryujinx.Graphics/Gal/Shader/ShaderRegisterSize.cs

@@ -1,9 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    enum ShaderRegisterSize
-    {
-        Half,
-        Single,
-        Double
-    }
-}

+ 0 - 13
Ryujinx.Graphics/Gal/Shader/ShaderTexqInfo.cs

@@ -1,13 +0,0 @@
-namespace Ryujinx.Graphics.Gal.Shader
-{
-    enum ShaderTexqInfo
-    {
-        Dimension   = 1,
-        TextureType = 2,
-        SamplePos   = 5,
-        Filter      = 16,
-        Lod         = 18,
-        Wrap        = 20,
-        BorderColor = 22
-    }
-}

+ 0 - 45
Ryujinx.Graphics/Gal/ShaderDeclInfo.cs

@@ -1,45 +0,0 @@
-using Ryujinx.Graphics.Texture;
-
-namespace Ryujinx.Graphics.Gal
-{
-    public class ShaderDeclInfo
-    {
-        public string Name { get; private set; }
-
-        public int  Index { get; private set; }
-        public bool IsCb  { get; private set; }
-        public int  Cbuf  { get; private set; }
-        public int  Size  { get; private set; }
-
-        public GalTextureTarget TextureTarget { get; private set; }
-
-        public TextureInstructionSuffix TextureSuffix { get; private set; }
-
-        public ShaderDeclInfo(
-            string name,
-            int    index,
-            bool   isCb = false,
-            int    cbuf = 0,
-            int    size = 1,
-            GalTextureTarget         textureTarget = GalTextureTarget.TwoD,
-            TextureInstructionSuffix textureSuffix = TextureInstructionSuffix.None)
-        {
-            Name        = name;
-            Index       = index;
-            IsCb        = isCb;
-            Cbuf        = cbuf;
-            Size        = size;
-
-            TextureTarget = textureTarget;
-            TextureSuffix = textureSuffix;
-        }
-
-        internal void Enlarge(int newSize)
-        {
-            if (Size < newSize)
-            {
-                Size = newSize;
-            }
-        }
-    }
-}

+ 14 - 11
Ryujinx.Graphics/Graphics3d/NvGpuEngine3d.cs

@@ -1,6 +1,7 @@
 using Ryujinx.Common;
 using Ryujinx.Graphics.Gal;
 using Ryujinx.Graphics.Memory;
+using Ryujinx.Graphics.Shader;
 using Ryujinx.Graphics.Texture;
 using System;
 using System.Collections.Generic;
@@ -464,7 +465,7 @@ namespace Ryujinx.Graphics.Graphics3d
                         left  = _viewportX1 - (left  - _viewportX0);
                         right = _viewportX1 - (right - _viewportX0);
                     }
-                    
+
                     // Ensure X is in the right order
                     if (left > right)
                     {
@@ -626,20 +627,22 @@ namespace Ryujinx.Graphics.Graphics3d
 
             for (int index = 0; index < keys.Length; index++)
             {
-                foreach (ShaderDeclInfo declInfo in _gpu.Renderer.Shader.GetTextureUsage(keys[index]))
+                foreach (TextureDescriptor desc in _gpu.Renderer.Shader.GetTextureUsage(keys[index]))
                 {
-                    long position;
+                    int textureHandle;
 
-                    if (declInfo.IsCb)
+                    if (desc.IsBindless)
                     {
-                        position = _constBuffers[index][declInfo.Cbuf].Position;
+                        long position = _constBuffers[index][desc.CbufSlot].Position;
+
+                        textureHandle = vmm.ReadInt32(position + desc.CbufOffset * 4);
                     }
                     else
                     {
-                        position = _constBuffers[index][textureCbIndex].Position;
-                    }
+                        long position = _constBuffers[index][textureCbIndex].Position;
 
-                    int textureHandle = vmm.ReadInt32(position + declInfo.Index * 4);
+                        textureHandle = vmm.ReadInt32(position + desc.HandleIndex * 4);
+                    }
 
                     unboundTextures.Add(UploadTexture(vmm, textureHandle));
                 }
@@ -712,9 +715,9 @@ namespace Ryujinx.Graphics.Graphics3d
         {
             for (int stage = 0; stage < keys.Length; stage++)
             {
-                foreach (ShaderDeclInfo declInfo in _gpu.Renderer.Shader.GetConstBufferUsage(keys[stage]))
+                foreach (CBufferDescriptor desc in _gpu.Renderer.Shader.GetConstBufferUsage(keys[stage]))
                 {
-                    ConstBuffer cb = _constBuffers[stage][declInfo.Cbuf];
+                    ConstBuffer cb = _constBuffers[stage][desc.Slot];
 
                     if (!cb.Enabled)
                     {
@@ -735,7 +738,7 @@ namespace Ryujinx.Graphics.Graphics3d
                         }
                     }
 
-                    state.ConstBufferKeys[stage][declInfo.Cbuf] = key;
+                    state.ConstBufferKeys[stage][desc.Slot] = key;
                 }
             }
         }

+ 15 - 0
Ryujinx.Graphics/Shader/CBufferDescriptor.cs

@@ -0,0 +1,15 @@
+namespace Ryujinx.Graphics.Shader
+{
+    public struct CBufferDescriptor
+    {
+        public string Name { get; }
+
+        public int Slot { get; }
+
+        public CBufferDescriptor(string name, int slot)
+        {
+            Name = name;
+            Slot = slot;
+        }
+    }
+}

+ 90 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/CodeGenContext.cs

@@ -0,0 +1,90 @@
+using System.Collections.Generic;
+using System.Text;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
+{
+    class CodeGenContext
+    {
+        private const string Tab = "    ";
+
+        public ShaderConfig Config { get; }
+
+        public List<CBufferDescriptor> CBufferDescriptors { get; }
+        public List<TextureDescriptor> TextureDescriptors { get; }
+
+        public OperandManager OperandManager { get; }
+
+        private StringBuilder _sb;
+
+        private int _level;
+
+        private string _identation;
+
+        public CodeGenContext(ShaderConfig config)
+        {
+            Config = config;
+
+            CBufferDescriptors = new List<CBufferDescriptor>();
+            TextureDescriptors = new List<TextureDescriptor>();
+
+            OperandManager = new OperandManager();
+
+            _sb = new StringBuilder();
+        }
+
+        public void AppendLine()
+        {
+            _sb.AppendLine();
+        }
+
+        public void AppendLine(string str)
+        {
+            _sb.AppendLine(_identation + str);
+        }
+
+        public string GetCode()
+        {
+            return _sb.ToString();
+        }
+
+        public void EnterScope()
+        {
+            AppendLine("{");
+
+            _level++;
+
+            UpdateIdentation();
+        }
+
+        public void LeaveScope(string suffix = "")
+        {
+            if (_level == 0)
+            {
+                return;
+            }
+
+            _level--;
+
+            UpdateIdentation();
+
+            AppendLine("}" + suffix);
+        }
+
+        private void UpdateIdentation()
+        {
+            _identation = GetIdentation(_level);
+        }
+
+        private static string GetIdentation(int level)
+        {
+            string identation = string.Empty;
+
+            for (int index = 0; index < level; index++)
+            {
+                identation += Tab;
+            }
+
+            return identation;
+        }
+    }
+}

+ 206 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/Declarations.cs

@@ -0,0 +1,206 @@
+using Ryujinx.Graphics.Gal;
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.StructuredIr;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
+{
+    static class Declarations
+    {
+        public static void Declare(CodeGenContext context, StructuredProgramInfo info)
+        {
+            context.AppendLine("#version 420 core");
+
+            context.AppendLine();
+
+            context.AppendLine($"const int {DefaultNames.UndefinedName} = 0;");
+
+            context.AppendLine();
+
+            if (context.Config.Type == GalShaderType.Geometry)
+            {
+                context.AppendLine("layout (points) in;");
+                context.AppendLine("layout (triangle_strip, max_vertices = 4) out;");
+
+                context.AppendLine();
+            }
+
+            context.AppendLine("layout (std140) uniform Extra");
+
+            context.EnterScope();
+
+            context.AppendLine("vec2 flip;");
+            context.AppendLine("int instance;");
+
+            context.LeaveScope(";");
+
+            context.AppendLine();
+
+            if (info.CBuffers.Count != 0)
+            {
+                DeclareUniforms(context, info);
+
+                context.AppendLine();
+            }
+
+            if (info.Samplers.Count != 0)
+            {
+                DeclareSamplers(context, info);
+
+                context.AppendLine();
+            }
+
+            if (info.IAttributes.Count != 0)
+            {
+                DeclareInputAttributes(context, info);
+
+                context.AppendLine();
+            }
+
+            if (info.OAttributes.Count != 0)
+            {
+                DeclareOutputAttributes(context, info);
+
+                context.AppendLine();
+            }
+        }
+
+        public static void DeclareLocals(CodeGenContext context, StructuredProgramInfo info)
+        {
+            foreach (AstOperand decl in info.Locals)
+            {
+                string name = context.OperandManager.DeclareLocal(decl);
+
+                context.AppendLine(GetVarTypeName(decl.VarType) + " " + name + ";");
+            }
+        }
+
+        private static string GetVarTypeName(VariableType type)
+        {
+            switch (type)
+            {
+                case VariableType.Bool: return "bool";
+                case VariableType.F32:  return "float";
+                case VariableType.S32:  return "int";
+                case VariableType.U32:  return "uint";
+            }
+
+            throw new ArgumentException($"Invalid variable type \"{type}\".");
+        }
+
+        private static void DeclareUniforms(CodeGenContext context, StructuredProgramInfo info)
+        {
+            foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
+            {
+                string ubName = OperandManager.GetShaderStagePrefix(context.Config.Type);
+
+                ubName += "_" + DefaultNames.UniformNamePrefix + cbufSlot;
+
+                context.CBufferDescriptors.Add(new CBufferDescriptor(ubName, cbufSlot));
+
+                context.AppendLine("layout (std140) uniform " + ubName);
+
+                context.EnterScope();
+
+                string ubSize = "[" + NumberFormatter.FormatInt(context.Config.MaxCBufferSize / 16) + "]";
+
+                context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Type, cbufSlot) + ubSize + ";");
+
+                context.LeaveScope(";");
+            }
+        }
+
+        private static void DeclareSamplers(CodeGenContext context, StructuredProgramInfo info)
+        {
+            Dictionary<string, AstTextureOperation> samplers = new Dictionary<string, AstTextureOperation>();
+
+            foreach (AstTextureOperation texOp in info.Samplers.OrderBy(x => x.Handle))
+            {
+                string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp);
+
+                if (!samplers.TryAdd(samplerName, texOp))
+                {
+                    continue;
+                }
+
+                string samplerTypeName = GetSamplerTypeName(texOp.Type);
+
+                context.AppendLine("uniform " + samplerTypeName + " " + samplerName + ";");
+            }
+
+            foreach (KeyValuePair<string, AstTextureOperation> kv in samplers)
+            {
+                string samplerName = kv.Key;
+
+                AstTextureOperation texOp = kv.Value;
+
+                TextureDescriptor desc;
+
+                if ((texOp.Flags & TextureFlags.Bindless) != 0)
+                {
+                    AstOperand operand = texOp.GetSource(0) as AstOperand;
+
+                    desc = new TextureDescriptor(samplerName, operand.CbufSlot, operand.CbufOffset);
+                }
+                else
+                {
+                    desc = new TextureDescriptor(samplerName, texOp.Handle);
+                }
+
+                context.TextureDescriptors.Add(desc);
+            }
+        }
+
+        private static void DeclareInputAttributes(CodeGenContext context, StructuredProgramInfo info)
+        {
+            string suffix = context.Config.Type == GalShaderType.Geometry ? "[]" : string.Empty;
+
+            foreach (int attr in info.IAttributes.OrderBy(x => x))
+            {
+                context.AppendLine($"layout (location = {attr}) in vec4 {DefaultNames.IAttributePrefix}{attr}{suffix};");
+            }
+        }
+
+        private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info)
+        {
+            foreach (int attr in info.OAttributes.OrderBy(x => x))
+            {
+                context.AppendLine($"layout (location = {attr}) out vec4 {DefaultNames.OAttributePrefix}{attr};");
+            }
+        }
+
+        private static string GetSamplerTypeName(TextureType type)
+        {
+            string typeName;
+
+            switch (type & TextureType.Mask)
+            {
+                case TextureType.Texture1D:   typeName = "sampler1D";   break;
+                case TextureType.Texture2D:   typeName = "sampler2D";   break;
+                case TextureType.Texture3D:   typeName = "sampler3D";   break;
+                case TextureType.TextureCube: typeName = "samplerCube"; break;
+
+                default: throw new ArgumentException($"Invalid sampler type \"{type}\".");
+            }
+
+            if ((type & TextureType.Multisample) != 0)
+            {
+                typeName += "MS";
+            }
+
+            if ((type & TextureType.Array) != 0)
+            {
+                typeName += "Array";
+            }
+
+            if ((type & TextureType.Shadow) != 0)
+            {
+                typeName += "Shadow";
+            }
+
+            return typeName;
+        }
+    }
+}

+ 17 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/DefaultNames.cs

@@ -0,0 +1,17 @@
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
+{
+    static class DefaultNames
+    {
+        public const string LocalNamePrefix = "temp";
+
+        public const string SamplerNamePrefix = "tex";
+
+        public const string IAttributePrefix = "in_attr";
+        public const string OAttributePrefix = "out_attr";
+
+        public const string UniformNamePrefix = "c";
+        public const string UniformNameSuffix = "data";
+
+        public const string UndefinedName = "undef";
+    }
+}

+ 133 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslGenerator.cs

@@ -0,0 +1,133 @@
+using Ryujinx.Graphics.Gal;
+using Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions;
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.StructuredIr;
+using System;
+
+using static Ryujinx.Graphics.Shader.CodeGen.Glsl.TypeConversion;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
+{
+    static class GlslGenerator
+    {
+        public static GlslProgram Generate(StructuredProgramInfo info, ShaderConfig config)
+        {
+            CodeGenContext context = new CodeGenContext(config);
+
+            Declarations.Declare(context, info);
+
+            PrintMainBlock(context, info);
+
+            return new GlslProgram(
+                context.CBufferDescriptors.ToArray(),
+                context.TextureDescriptors.ToArray(),
+                context.GetCode());
+        }
+
+        private static void PrintMainBlock(CodeGenContext context, StructuredProgramInfo info)
+        {
+            context.AppendLine("void main()");
+
+            context.EnterScope();
+
+            Declarations.DeclareLocals(context, info);
+
+            PrintBlock(context, info.MainBlock);
+
+            context.LeaveScope();
+        }
+
+        private static void PrintBlock(CodeGenContext context, AstBlock block)
+        {
+            AstBlockVisitor visitor = new AstBlockVisitor(block);
+
+            visitor.BlockEntered += (sender, e) =>
+            {
+                switch (e.Block.Type)
+                {
+                    case AstBlockType.DoWhile:
+                        context.AppendLine("do");
+                        break;
+
+                    case AstBlockType.Else:
+                        context.AppendLine("else");
+                        break;
+
+                    case AstBlockType.ElseIf:
+                        context.AppendLine($"else if ({GetCondExpr(context, e.Block.Condition)})");
+                        break;
+
+                    case AstBlockType.If:
+                        context.AppendLine($"if ({GetCondExpr(context, e.Block.Condition)})");
+                        break;
+
+                    default: throw new InvalidOperationException($"Found unexpected block type \"{e.Block.Type}\".");
+                }
+
+                context.EnterScope();
+            };
+
+            visitor.BlockLeft += (sender, e) =>
+            {
+                context.LeaveScope();
+
+                if (e.Block.Type == AstBlockType.DoWhile)
+                {
+                    context.AppendLine($"while ({GetCondExpr(context, e.Block.Condition)});");
+                }
+            };
+
+            foreach (IAstNode node in visitor.Visit())
+            {
+                if (node is AstOperation operation)
+                {
+                    if (operation.Inst == Instruction.Return)
+                    {
+                        PrepareForReturn(context);
+                    }
+
+                    context.AppendLine(InstGen.GetExpression(context, operation) + ";");
+                }
+                else if (node is AstAssignment assignment)
+                {
+                    VariableType srcType = OperandManager.GetNodeDestType(assignment.Source);
+                    VariableType dstType = OperandManager.GetNodeDestType(assignment.Destination);
+
+                    string dest;
+
+                    if (assignment.Destination is AstOperand operand && operand.Type == OperandType.Attribute)
+                    {
+                        dest = OperandManager.GetOutAttributeName(operand, context.Config.Type);
+                    }
+                    else
+                    {
+                        dest = InstGen.GetExpression(context, assignment.Destination);
+                    }
+
+                    string src = ReinterpretCast(context, assignment.Source, srcType, dstType);
+
+                    context.AppendLine(dest + " = " + src + ";");
+                }
+                else
+                {
+                    throw new InvalidOperationException($"Found unexpected node type \"{node?.GetType().Name ?? "null"}\".");
+                }
+            }
+        }
+
+        private static string GetCondExpr(CodeGenContext context, IAstNode cond)
+        {
+            VariableType srcType = OperandManager.GetNodeDestType(cond);
+
+            return ReinterpretCast(context, cond, srcType, VariableType.Bool);
+        }
+
+        private static void PrepareForReturn(CodeGenContext context)
+        {
+            if (context.Config.Type == GalShaderType.Vertex)
+            {
+                context.AppendLine("gl_Position.xy *= flip;");
+            }
+        }
+    }
+}

+ 20 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/GlslProgram.cs

@@ -0,0 +1,20 @@
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
+{
+    class GlslProgram
+    {
+        public CBufferDescriptor[] CBufferDescriptors { get; }
+        public TextureDescriptor[] TextureDescriptors { get; }
+
+        public string Code { get; }
+
+        public GlslProgram(
+            CBufferDescriptor[] cBufferDescs,
+            TextureDescriptor[] textureDescs,
+            string              code)
+        {
+            CBufferDescriptors = cBufferDescs;
+            TextureDescriptors = textureDescs;
+            Code               = code;
+        }
+    }
+}

+ 110 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGen.cs

@@ -0,0 +1,110 @@
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.StructuredIr;
+using System;
+
+using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
+using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
+{
+    static class InstGen
+    {
+        public static string GetExpression(CodeGenContext context, IAstNode node)
+        {
+            if (node is AstOperation operation)
+            {
+                return GetExpression(context, operation);
+            }
+            else if (node is AstOperand operand)
+            {
+                return context.OperandManager.GetExpression(operand, context.Config.Type);
+            }
+
+            throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\".");
+        }
+
+        private static string GetExpression(CodeGenContext context, AstOperation operation)
+        {
+            Instruction inst = operation.Inst;
+
+            InstInfo info = GetInstructionInfo(inst);
+
+            if ((info.Type & InstType.Call) != 0)
+            {
+                int arity = (int)(info.Type & InstType.ArityMask);
+
+                string args = string.Empty;
+
+                for (int argIndex = 0; argIndex < arity; argIndex++)
+                {
+                    if (argIndex != 0)
+                    {
+                        args += ", ";
+                    }
+
+                    VariableType dstType = GetSrcVarType(inst, argIndex);
+
+                    args += GetSoureExpr(context, operation.GetSource(argIndex), dstType);
+                }
+
+                return info.OpName + "(" + args + ")";
+            }
+            else if ((info.Type & InstType.Op) != 0)
+            {
+                string op = info.OpName;
+
+                int arity = (int)(info.Type & InstType.ArityMask);
+
+                string[] expr = new string[arity];
+
+                for (int index = 0; index < arity; index++)
+                {
+                    IAstNode src = operation.GetSource(index);
+
+                    string srcExpr = GetSoureExpr(context, src, GetSrcVarType(inst, index));
+
+                    bool isLhs = arity == 2 && index == 0;
+
+                    expr[index] = Enclose(srcExpr, src, inst, info, isLhs);
+                }
+
+                switch (arity)
+                {
+                    case 0:
+                        return op;
+
+                    case 1:
+                        return op + expr[0];
+
+                    case 2:
+                        return $"{expr[0]} {op} {expr[1]}";
+
+                    case 3:
+                        return $"{expr[0]} {op[0]} {expr[1]} {op[1]} {expr[2]}";
+                }
+            }
+            else if ((info.Type & InstType.Special) != 0)
+            {
+                switch (inst)
+                {
+                    case Instruction.LoadConstant:
+                        return InstGenMemory.LoadConstant(context, operation);
+
+                    case Instruction.PackHalf2x16:
+                        return InstGenPacking.PackHalf2x16(context, operation);
+
+                    case Instruction.TextureSample:
+                        return InstGenMemory.TextureSample(context, operation);
+
+                    case Instruction.TextureSize:
+                        return InstGenMemory.TextureSize(context, operation);
+
+                    case Instruction.UnpackHalf2x16:
+                        return InstGenPacking.UnpackHalf2x16(context, operation);
+                }
+            }
+
+            throw new InvalidOperationException($"Unexpected instruction type \"{info.Type}\".");
+        }
+    }
+}

+ 170 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenHelper.cs

@@ -0,0 +1,170 @@
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.StructuredIr;
+
+using static Ryujinx.Graphics.Shader.CodeGen.Glsl.TypeConversion;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
+{
+    static class InstGenHelper
+    {
+        private static InstInfo[] _infoTbl;
+
+        static InstGenHelper()
+        {
+            _infoTbl = new InstInfo[(int)Instruction.Count];
+
+            Add(Instruction.Absolute,                 InstType.CallUnary,      "abs");
+            Add(Instruction.Add,                      InstType.OpBinaryCom,    "+",               2);
+            Add(Instruction.BitfieldExtractS32,       InstType.CallTernary,    "bitfieldExtract");
+            Add(Instruction.BitfieldExtractU32,       InstType.CallTernary,    "bitfieldExtract");
+            Add(Instruction.BitfieldInsert,           InstType.CallQuaternary, "bitfieldInsert");
+            Add(Instruction.BitfieldReverse,          InstType.CallUnary,      "bitfieldReverse");
+            Add(Instruction.BitwiseAnd,               InstType.OpBinaryCom,    "&",               6);
+            Add(Instruction.BitwiseExclusiveOr,       InstType.OpBinaryCom,    "^",               7);
+            Add(Instruction.BitwiseNot,               InstType.OpUnary,        "~",               0);
+            Add(Instruction.BitwiseOr,                InstType.OpBinaryCom,    "|",               8);
+            Add(Instruction.Ceiling,                  InstType.CallUnary,      "ceil");
+            Add(Instruction.Clamp,                    InstType.CallTernary,    "clamp");
+            Add(Instruction.ClampU32,                 InstType.CallTernary,    "clamp");
+            Add(Instruction.CompareEqual,             InstType.OpBinaryCom,    "==",              5);
+            Add(Instruction.CompareGreater,           InstType.OpBinary,       ">",               4);
+            Add(Instruction.CompareGreaterOrEqual,    InstType.OpBinary,       ">=",              4);
+            Add(Instruction.CompareGreaterOrEqualU32, InstType.OpBinary,       ">=",              4);
+            Add(Instruction.CompareGreaterU32,        InstType.OpBinary,       ">",               4);
+            Add(Instruction.CompareLess,              InstType.OpBinary,       "<",               4);
+            Add(Instruction.CompareLessOrEqual,       InstType.OpBinary,       "<=",              4);
+            Add(Instruction.CompareLessOrEqualU32,    InstType.OpBinary,       "<=",              4);
+            Add(Instruction.CompareLessU32,           InstType.OpBinary,       "<",               4);
+            Add(Instruction.CompareNotEqual,          InstType.OpBinaryCom,    "!=",              5);
+            Add(Instruction.ConditionalSelect,        InstType.OpTernary,      "?:",              12);
+            Add(Instruction.ConvertFPToS32,           InstType.CallUnary,      "int");
+            Add(Instruction.ConvertS32ToFP,           InstType.CallUnary,      "float");
+            Add(Instruction.ConvertU32ToFP,           InstType.CallUnary,      "float");
+            Add(Instruction.Cosine,                   InstType.CallUnary,      "cos");
+            Add(Instruction.Discard,                  InstType.OpNullary,      "discard");
+            Add(Instruction.Divide,                   InstType.OpBinary,       "/",               1);
+            Add(Instruction.EmitVertex,               InstType.CallNullary,    "EmitVertex");
+            Add(Instruction.EndPrimitive,             InstType.CallNullary,    "EndPrimitive");
+            Add(Instruction.ExponentB2,               InstType.CallUnary,      "exp2");
+            Add(Instruction.Floor,                    InstType.CallUnary,      "floor");
+            Add(Instruction.FusedMultiplyAdd,         InstType.CallTernary,    "fma");
+            Add(Instruction.IsNan,                    InstType.CallUnary,      "isnan");
+            Add(Instruction.LoadConstant,             InstType.Special);
+            Add(Instruction.LogarithmB2,              InstType.CallUnary,      "log2");
+            Add(Instruction.LogicalAnd,               InstType.OpBinaryCom,    "&&",              9);
+            Add(Instruction.LogicalExclusiveOr,       InstType.OpBinaryCom,    "^^",              10);
+            Add(Instruction.LogicalNot,               InstType.OpUnary,        "!",               0);
+            Add(Instruction.LogicalOr,                InstType.OpBinaryCom,    "||",              11);
+            Add(Instruction.LoopBreak,                InstType.OpNullary,      "break");
+            Add(Instruction.LoopContinue,             InstType.OpNullary,      "continue");
+            Add(Instruction.PackHalf2x16,             InstType.Special);
+            Add(Instruction.ShiftLeft,                InstType.OpBinary,       "<<",              3);
+            Add(Instruction.ShiftRightS32,            InstType.OpBinary,       ">>",              3);
+            Add(Instruction.ShiftRightU32,            InstType.OpBinary,       ">>",              3);
+            Add(Instruction.Maximum,                  InstType.CallBinary,     "max");
+            Add(Instruction.MaximumU32,               InstType.CallBinary,     "max");
+            Add(Instruction.Minimum,                  InstType.CallBinary,     "min");
+            Add(Instruction.MinimumU32,               InstType.CallBinary,     "min");
+            Add(Instruction.Multiply,                 InstType.OpBinaryCom,    "*",               1);
+            Add(Instruction.Negate,                   InstType.OpUnary,        "-",               0);
+            Add(Instruction.ReciprocalSquareRoot,     InstType.CallUnary,      "inversesqrt");
+            Add(Instruction.Return,                   InstType.OpNullary,      "return");
+            Add(Instruction.Sine,                     InstType.CallUnary,      "sin");
+            Add(Instruction.SquareRoot,               InstType.CallUnary,      "sqrt");
+            Add(Instruction.Subtract,                 InstType.OpBinary,       "-",               2);
+            Add(Instruction.TextureSample,            InstType.Special);
+            Add(Instruction.TextureSize,              InstType.Special);
+            Add(Instruction.Truncate,                 InstType.CallUnary,      "trunc");
+            Add(Instruction.UnpackHalf2x16,           InstType.Special);
+        }
+
+        private static void Add(Instruction inst, InstType flags, string opName = null, int precedence = 0)
+        {
+            _infoTbl[(int)inst] = new InstInfo(flags, opName, precedence);
+        }
+
+        public static InstInfo GetInstructionInfo(Instruction inst)
+        {
+            return _infoTbl[(int)(inst & Instruction.Mask)];
+        }
+
+        public static string GetSoureExpr(CodeGenContext context, IAstNode node, VariableType dstType)
+        {
+            return ReinterpretCast(context, node, OperandManager.GetNodeDestType(node), dstType);
+        }
+
+        public static string Enclose(string expr, IAstNode node, Instruction pInst, bool isLhs)
+        {
+            InstInfo pInfo = GetInstructionInfo(pInst);
+
+            return Enclose(expr, node, pInst, pInfo, isLhs);
+        }
+
+        public static string Enclose(string expr, IAstNode node, Instruction pInst, InstInfo pInfo, bool isLhs = false)
+        {
+            if (NeedsParenthesis(node, pInst, pInfo, isLhs))
+            {
+                expr = "(" + expr + ")";
+            }
+
+            return expr;
+        }
+
+        public static bool NeedsParenthesis(IAstNode node, Instruction pInst, InstInfo pInfo, bool isLhs)
+        {
+            //If the node isn't a operation, then it can only be a operand,
+            //and those never needs to be surrounded in parenthesis.
+            if (!(node is AstOperation operation))
+            {
+                //This is sort of a special case, if this is a negative constant,
+                //and it is consumed by a unary operation, we need to put on the parenthesis,
+                //as in GLSL a sequence like --2 or ~-1 is not valid.
+                if (IsNegativeConst(node) && pInfo.Type == InstType.OpUnary)
+                {
+                    return true;
+                }
+
+                return false;
+            }
+
+            if ((pInfo.Type & (InstType.Call | InstType.Special)) != 0)
+            {
+                return false;
+            }
+
+            InstInfo info = _infoTbl[(int)(operation.Inst & Instruction.Mask)];
+
+            if ((info.Type & (InstType.Call | InstType.Special)) != 0)
+            {
+                return false;
+            }
+
+            if (info.Precedence < pInfo.Precedence)
+            {
+                return false;
+            }
+
+            if (info.Precedence == pInfo.Precedence && isLhs)
+            {
+                return false;
+            }
+
+            if (pInst == operation.Inst && info.Type == InstType.OpBinaryCom)
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        private static bool IsNegativeConst(IAstNode node)
+        {
+            if (!(node is AstOperand operand))
+            {
+                return false;
+            }
+
+            return operand.Type == OperandType.Constant && operand.Value < 0;
+        }
+    }
+}

+ 244 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs

@@ -0,0 +1,244 @@
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.StructuredIr;
+
+using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
+using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
+{
+    static class InstGenMemory
+    {
+        public static string LoadConstant(CodeGenContext context, AstOperation operation)
+        {
+            IAstNode src1 = operation.GetSource(1);
+
+            string offsetExpr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 1));
+
+            offsetExpr = Enclose(offsetExpr, src1, Instruction.ShiftRightS32, isLhs: true);
+
+            return OperandManager.GetConstantBufferName(operation.GetSource(0), offsetExpr, context.Config.Type);
+        }
+
+        public static string TextureSample(CodeGenContext context, AstOperation operation)
+        {
+            AstTextureOperation texOp = (AstTextureOperation)operation;
+
+            bool isBindless    = (texOp.Flags & TextureFlags.Bindless)   != 0;
+            bool isGather      = (texOp.Flags & TextureFlags.Gather)     != 0;
+            bool intCoords     = (texOp.Flags & TextureFlags.IntCoords)  != 0;
+            bool hasLodBias    = (texOp.Flags & TextureFlags.LodBias)    != 0;
+            bool hasLodLevel   = (texOp.Flags & TextureFlags.LodLevel)   != 0;
+            bool hasOffset     = (texOp.Flags & TextureFlags.Offset)     != 0;
+            bool hasOffsets    = (texOp.Flags & TextureFlags.Offsets)    != 0;
+            bool isArray       = (texOp.Type  & TextureType.Array)       != 0;
+            bool isMultisample = (texOp.Type  & TextureType.Multisample) != 0;
+            bool isShadow      = (texOp.Type  & TextureType.Shadow)      != 0;
+
+            string texCall = intCoords ? "texelFetch" : "texture";
+
+            if (isGather)
+            {
+                texCall += "Gather";
+            }
+            else if (hasLodLevel && !intCoords)
+            {
+                texCall += "Lod";
+            }
+
+            if (hasOffset)
+            {
+                texCall += "Offset";
+            }
+            else if (hasOffsets)
+            {
+                texCall += "Offsets";
+            }
+
+            string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp);
+
+            texCall += "(" + samplerName;
+
+            int coordsCount = texOp.Type.GetCoordsCount();
+
+            int pCount = coordsCount;
+
+            int arrayIndexElem = -1;
+
+            if (isArray)
+            {
+                arrayIndexElem = pCount++;
+            }
+
+            //The sampler 1D shadow overload expects a
+            //dummy value on the middle of the vector, who knows why...
+            bool hasDummy1DShadowElem = texOp.Type == (TextureType.Texture1D | TextureType.Shadow);
+
+            if (hasDummy1DShadowElem)
+            {
+                pCount++;
+            }
+
+            if (isShadow && !isGather)
+            {
+                pCount++;
+            }
+
+            //On textureGather*, the comparison value is
+            //always specified as an extra argument.
+            bool hasExtraCompareArg = isShadow && isGather;
+
+            if (pCount == 5)
+            {
+                pCount = 4;
+
+                hasExtraCompareArg = true;
+            }
+
+            int srcIndex = isBindless ? 1 : 0;
+
+            string Src(VariableType type)
+            {
+                return GetSoureExpr(context, texOp.GetSource(srcIndex++), type);
+            }
+
+            void Append(string str)
+            {
+                texCall += ", " + str;
+            }
+
+            VariableType coordType = intCoords ? VariableType.S32 : VariableType.F32;
+
+            string AssemblePVector(int count)
+            {
+                if (count > 1)
+                {
+                    string[] elems = new string[count];
+
+                    for (int index = 0; index < count; index++)
+                    {
+                        if (arrayIndexElem == index)
+                        {
+                            elems[index] = Src(VariableType.S32);
+
+                            if (!intCoords)
+                            {
+                                elems[index] = "float(" + elems[index] + ")";
+                            }
+                        }
+                        else if (index == 1 && hasDummy1DShadowElem)
+                        {
+                            elems[index] = NumberFormatter.FormatFloat(0);
+                        }
+                        else
+                        {
+                            elems[index] = Src(coordType);
+                        }
+                    }
+
+                    string prefix = intCoords ? "i" : string.Empty;
+
+                    return prefix + "vec" + count + "(" + string.Join(", ", elems) + ")";
+                }
+                else
+                {
+                    return Src(coordType);
+                }
+            }
+
+            Append(AssemblePVector(pCount));
+
+            if (hasExtraCompareArg)
+            {
+                Append(Src(VariableType.F32));
+            }
+
+            if (isMultisample)
+            {
+                Append(Src(VariableType.S32));
+            }
+            else if (hasLodLevel)
+            {
+                Append(Src(coordType));
+            }
+
+            string AssembleOffsetVector(int count)
+            {
+                if (count > 1)
+                {
+                    string[] elems = new string[count];
+
+                    for (int index = 0; index < count; index++)
+                    {
+                        elems[index] = Src(VariableType.S32);
+                    }
+
+                    return "ivec" + count + "(" + string.Join(", ", elems) + ")";
+                }
+                else
+                {
+                    return Src(VariableType.S32);
+                }
+            }
+
+            if (hasOffset)
+            {
+                Append(AssembleOffsetVector(coordsCount));
+            }
+            else if (hasOffsets)
+            {
+                texCall += $", ivec{coordsCount}[4](";
+
+                texCall += AssembleOffsetVector(coordsCount) + ", ";
+                texCall += AssembleOffsetVector(coordsCount) + ", ";
+                texCall += AssembleOffsetVector(coordsCount) + ", ";
+                texCall += AssembleOffsetVector(coordsCount) + ")";
+            }
+
+            if (hasLodBias)
+            {
+               Append(Src(VariableType.F32));
+            }
+
+            //textureGather* optional extra component index,
+            //not needed for shadow samplers.
+            if (isGather && !isShadow)
+            {
+               Append(Src(VariableType.S32));
+            }
+
+            texCall += ")" + (isGather || !isShadow ? GetMask(texOp.ComponentMask) : "");
+
+            return texCall;
+        }
+
+        public static string TextureSize(CodeGenContext context, AstOperation operation)
+        {
+            AstTextureOperation texOp = (AstTextureOperation)operation;
+
+            bool isBindless  = (texOp.Flags & TextureFlags.Bindless) != 0;
+
+            string samplerName = OperandManager.GetSamplerName(context.Config.Type, texOp);
+
+            IAstNode src0 = operation.GetSource(isBindless ? 1 : 0);
+
+            string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0));
+
+            return $"textureSize({samplerName}, {src0Expr}){GetMask(texOp.ComponentMask)}";
+        }
+
+        private static string GetMask(int compMask)
+        {
+            string mask = ".";
+
+            for (int index = 0; index < 4; index++)
+            {
+                if ((compMask & (1 << index)) != 0)
+                {
+                    mask += "rgba".Substring(index, 1);
+                }
+            }
+
+            return mask;
+        }
+    }
+}

+ 45 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstGenPacking.cs

@@ -0,0 +1,45 @@
+using Ryujinx.Graphics.Shader.StructuredIr;
+
+using static Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions.InstGenHelper;
+using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
+{
+    static class InstGenPacking
+    {
+        public static string PackHalf2x16(CodeGenContext context, AstOperation operation)
+        {
+            IAstNode src0 = operation.GetSource(0);
+            IAstNode src1 = operation.GetSource(1);
+
+            string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0));
+            string src1Expr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 1));
+
+            return $"packHalf2x16(vec2({src0Expr}, {src1Expr}))";
+        }
+
+        public static string UnpackHalf2x16(CodeGenContext context, AstOperation operation)
+        {
+            IAstNode src = operation.GetSource(0);
+
+            string srcExpr = GetSoureExpr(context, src, GetSrcVarType(operation.Inst, 0));
+
+            return $"unpackHalf2x16({srcExpr}){GetMask(operation.ComponentMask)}";
+        }
+
+        private static string GetMask(int compMask)
+        {
+            string mask = ".";
+
+            for (int index = 0; index < 2; index++)
+            {
+                if ((compMask & (1 << index)) != 0)
+                {
+                    mask += "xy".Substring(index, 1);
+                }
+            }
+
+            return mask;
+        }
+    }
+}

+ 18 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstInfo.cs

@@ -0,0 +1,18 @@
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
+{
+    struct InstInfo
+    {
+        public InstType Type { get; }
+
+        public string OpName { get; }
+
+        public int Precedence { get; }
+
+        public InstInfo(InstType type, string opName, int precedence)
+        {
+            Type       = type;
+            OpName     = opName;
+            Precedence = precedence;
+        }
+    }
+}

+ 27 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/Instructions/InstType.cs

@@ -0,0 +1,27 @@
+using System;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
+{
+    [Flags]
+    enum InstType
+    {
+        OpNullary   = Op | 0,
+        OpUnary     = Op | 1,
+        OpBinary    = Op | 2,
+        OpTernary   = Op | 3,
+        OpBinaryCom = OpBinary | Comutative,
+
+        CallNullary    = Call | 0,
+        CallUnary      = Call | 1,
+        CallBinary     = Call | 2,
+        CallTernary    = Call | 3,
+        CallQuaternary = Call | 4,
+
+        Comutative = 1 << 8,
+        Op         = 1 << 9,
+        Call       = 1 << 10,
+        Special    = 1 << 11,
+
+        ArityMask = 0xff
+    }
+}

+ 104 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/NumberFormatter.cs

@@ -0,0 +1,104 @@
+using Ryujinx.Graphics.Shader.StructuredIr;
+using System;
+using System.Globalization;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
+{
+    static class NumberFormatter
+    {
+        private const int MaxDecimal = 256;
+
+        public static bool TryFormat(int value, VariableType dstType, out string formatted)
+        {
+            if (dstType == VariableType.F32)
+            {
+                return TryFormatFloat(BitConverter.Int32BitsToSingle(value), out formatted);
+            }
+            else if (dstType == VariableType.S32)
+            {
+                formatted = FormatInt(value);
+            }
+            else if (dstType == VariableType.U32)
+            {
+                formatted = FormatUint((uint)value);
+            }
+            else if (dstType == VariableType.Bool)
+            {
+                formatted = value != 0 ? "true" : "false";
+            }
+            else
+            {
+                throw new ArgumentException($"Invalid variable type \"{dstType}\".");
+            }
+
+            return true;
+        }
+
+        public static string FormatFloat(float value)
+        {
+            if (!TryFormatFloat(value, out string formatted))
+            {
+                throw new ArgumentException("Failed to convert float value to string.");
+            }
+
+            return formatted;
+        }
+
+        public static bool TryFormatFloat(float value, out string formatted)
+        {
+            if (float.IsNaN(value) || float.IsInfinity(value))
+            {
+                formatted = null;
+
+                return false;
+            }
+
+            formatted = value.ToString("G9", CultureInfo.InvariantCulture);
+
+            if (!(formatted.Contains('.') ||
+                  formatted.Contains('e') ||
+                  formatted.Contains('E')))
+            {
+                formatted += ".0";
+            }
+
+            return true;
+        }
+
+        public static string FormatInt(int value, VariableType dstType)
+        {
+            if (dstType == VariableType.S32)
+            {
+                return FormatInt(value);
+            }
+            else if (dstType == VariableType.U32)
+            {
+                return FormatUint((uint)value);
+            }
+            else
+            {
+                throw new ArgumentException($"Invalid variable type \"{dstType}\".");
+            }
+        }
+
+        public static string FormatInt(int value)
+        {
+            if (value <= MaxDecimal && value >= -MaxDecimal)
+            {
+                return value.ToString(CultureInfo.InvariantCulture);
+            }
+
+            return "0x" + value.ToString("X", CultureInfo.InvariantCulture);
+        }
+
+        public static string FormatUint(uint value)
+        {
+            if (value <= MaxDecimal && value >= 0)
+            {
+                return value.ToString(CultureInfo.InvariantCulture) + "u";
+            }
+
+            return "0x" + value.ToString("X", CultureInfo.InvariantCulture) + "u";
+        }
+    }
+}

+ 239 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/OperandManager.cs

@@ -0,0 +1,239 @@
+using Ryujinx.Graphics.Gal;
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.StructuredIr;
+using System;
+using System.Collections.Generic;
+
+using static Ryujinx.Graphics.Shader.StructuredIr.InstructionInfo;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
+{
+    class OperandManager
+    {
+        private static string[] _stagePrefixes = new string[] { "vp", "tcp", "tep", "gp", "fp" };
+
+        private struct BuiltInAttribute
+        {
+            public string Name { get; }
+
+            public VariableType Type { get; }
+
+            public BuiltInAttribute(string name, VariableType type)
+            {
+                Name = name;
+                Type = type;
+            }
+        }
+
+        private static Dictionary<int, BuiltInAttribute> _builtInAttributes =
+                   new Dictionary<int, BuiltInAttribute>()
+        {
+            { AttributeConsts.Layer,               new BuiltInAttribute("gl_Layer",        VariableType.S32)  },
+            { AttributeConsts.PointSize,           new BuiltInAttribute("gl_PointSize",    VariableType.F32)  },
+            { AttributeConsts.PositionX,           new BuiltInAttribute("gl_Position.x",   VariableType.F32)  },
+            { AttributeConsts.PositionY,           new BuiltInAttribute("gl_Position.y",   VariableType.F32)  },
+            { AttributeConsts.PositionZ,           new BuiltInAttribute("gl_Position.z",   VariableType.F32)  },
+            { AttributeConsts.PositionW,           new BuiltInAttribute("gl_Position.w",   VariableType.F32)  },
+            { AttributeConsts.PointCoordX,         new BuiltInAttribute("gl_PointCoord.x", VariableType.F32)  },
+            { AttributeConsts.PointCoordY,         new BuiltInAttribute("gl_PointCoord.y", VariableType.F32)  },
+            { AttributeConsts.TessCoordX,          new BuiltInAttribute("gl_TessCoord.x",  VariableType.F32)  },
+            { AttributeConsts.TessCoordY,          new BuiltInAttribute("gl_TessCoord.y",  VariableType.F32)  },
+            { AttributeConsts.InstanceId,          new BuiltInAttribute("instance",        VariableType.S32)  },
+            { AttributeConsts.VertexId,            new BuiltInAttribute("gl_VertexID",     VariableType.S32)  },
+            { AttributeConsts.FrontFacing,         new BuiltInAttribute("gl_FrontFacing",  VariableType.Bool) },
+            { AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth",    VariableType.F32)  }
+        };
+
+        private Dictionary<AstOperand, string> _locals;
+
+        public OperandManager()
+        {
+            _locals = new Dictionary<AstOperand, string>();
+        }
+
+        public string DeclareLocal(AstOperand operand)
+        {
+            string name = $"{DefaultNames.LocalNamePrefix}_{_locals.Count}";
+
+            _locals.Add(operand, name);
+
+            return name;
+        }
+
+        public string GetExpression(AstOperand operand, GalShaderType shaderType)
+        {
+            switch (operand.Type)
+            {
+                case OperandType.Attribute:
+                    return GetAttributeName(operand, shaderType);
+
+                case OperandType.Constant:
+                    return NumberFormatter.FormatInt(operand.Value);
+
+                case OperandType.ConstantBuffer:
+                    return GetConstantBufferName(operand, shaderType);
+
+                case OperandType.LocalVariable:
+                    return _locals[operand];
+
+                case OperandType.Undefined:
+                    return DefaultNames.UndefinedName;
+            }
+
+            throw new ArgumentException($"Invalid operand type \"{operand.Type}\".");
+        }
+
+        public static string GetConstantBufferName(AstOperand cbuf, GalShaderType shaderType)
+        {
+            string ubName = GetUbName(shaderType, cbuf.CbufSlot);
+
+            ubName += "[" + (cbuf.CbufOffset >> 2) + "]";
+
+            return ubName + "." + GetSwizzleMask(cbuf.CbufOffset & 3);
+        }
+
+        public static string GetConstantBufferName(IAstNode slot, string offsetExpr, GalShaderType shaderType)
+        {
+            //Non-constant slots are not supported.
+            //It is expected that upstream stages are never going to generate non-constant
+            //slot access.
+            AstOperand operand = (AstOperand)slot;
+
+            string ubName = GetUbName(shaderType, operand.Value);
+
+            string index0 = "[" + offsetExpr + " >> 4]";
+            string index1 = "[" + offsetExpr + " >> 2 & 3]";
+
+            return ubName + index0 + index1;
+        }
+
+        public static string GetOutAttributeName(AstOperand attr, GalShaderType shaderType)
+        {
+            return GetAttributeName(attr, shaderType, isOutAttr: true);
+        }
+
+        private static string GetAttributeName(AstOperand attr, GalShaderType shaderType, bool isOutAttr = false)
+        {
+            int value = attr.Value;
+
+            string swzMask = GetSwizzleMask((value >> 2) & 3);
+
+            if (value >= AttributeConsts.UserAttributeBase &&
+                value <  AttributeConsts.UserAttributeEnd)
+            {
+                value -= AttributeConsts.UserAttributeBase;
+
+                string prefix = isOutAttr
+                    ? DefaultNames.OAttributePrefix
+                    : DefaultNames.IAttributePrefix;
+
+                string name = $"{prefix}{(value >> 4)}";
+
+                if (shaderType == GalShaderType.Geometry && !isOutAttr)
+                {
+                    name += "[0]";
+                }
+
+                name += "." + swzMask;
+
+                return name;
+            }
+            else
+            {
+                if (value >= AttributeConsts.FragmentOutputColorBase &&
+                    value <  AttributeConsts.FragmentOutputColorEnd)
+                {
+                    value -= AttributeConsts.FragmentOutputColorBase;
+
+                    return $"{DefaultNames.OAttributePrefix}{(value >> 4)}.{swzMask}";
+                }
+                else if (_builtInAttributes.TryGetValue(value & ~3, out BuiltInAttribute builtInAttr))
+                {
+                    //TODO: There must be a better way to handle this...
+                    if (shaderType == GalShaderType.Fragment)
+                    {
+                        switch (value & ~3)
+                        {
+                            case AttributeConsts.PositionX: return "gl_FragCoord.x";
+                            case AttributeConsts.PositionY: return "gl_FragCoord.y";
+                            case AttributeConsts.PositionZ: return "gl_FragCoord.z";
+                            case AttributeConsts.PositionW: return "1.0";
+                        }
+                    }
+
+                    string name = builtInAttr.Name;
+
+                    if (shaderType == GalShaderType.Geometry && !isOutAttr)
+                    {
+                        name = "gl_in[0]." + name;
+                    }
+
+                    return name;
+                }
+            }
+
+            return DefaultNames.UndefinedName;
+        }
+
+        public static string GetUbName(GalShaderType shaderType, int slot)
+        {
+            string ubName = OperandManager.GetShaderStagePrefix(shaderType);
+
+            ubName += "_" + DefaultNames.UniformNamePrefix + slot;
+
+            return ubName + "_" + DefaultNames.UniformNameSuffix;
+        }
+
+        public static string GetSamplerName(GalShaderType shaderType, AstTextureOperation texOp)
+        {
+            string suffix;
+
+            if ((texOp.Flags & TextureFlags.Bindless) != 0)
+            {
+                AstOperand operand = texOp.GetSource(0) as AstOperand;
+
+                suffix = "_cb" + operand.CbufSlot + "_" + operand.CbufOffset;
+            }
+            else
+            {
+                suffix = (texOp.Handle - 8).ToString();
+            }
+
+            return GetShaderStagePrefix(shaderType) + "_" + DefaultNames.SamplerNamePrefix + suffix;
+        }
+
+        public static string GetShaderStagePrefix(GalShaderType shaderType)
+        {
+            return _stagePrefixes[(int)shaderType];
+        }
+
+        private static string GetSwizzleMask(int value)
+        {
+            return "xyzw".Substring(value, 1);
+        }
+
+        public static VariableType GetNodeDestType(IAstNode node)
+        {
+            if (node is AstOperation operation)
+            {
+                return GetDestVarType(operation.Inst);
+            }
+            else if (node is AstOperand operand)
+            {
+                if (operand.Type == OperandType.Attribute)
+                {
+                    if (_builtInAttributes.TryGetValue(operand.Value & ~3, out BuiltInAttribute builtInAttr))
+                    {
+                        return builtInAttr.Type;
+                    }
+                }
+
+                return OperandInfo.GetVarType(operand);
+            }
+            else
+            {
+                throw new ArgumentException($"Invalid node type \"{node?.GetType().Name ?? "null"}\".");
+            }
+        }
+    }
+}

+ 85 - 0
Ryujinx.Graphics/Shader/CodeGen/Glsl/TypeConversion.cs

@@ -0,0 +1,85 @@
+using Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions;
+using Ryujinx.Graphics.Shader.IntermediateRepresentation;
+using Ryujinx.Graphics.Shader.StructuredIr;
+using System;
+
+namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
+{
+    static class TypeConversion
+    {
+        public static string ReinterpretCast(
+            CodeGenContext context,
+            IAstNode       node,
+            VariableType   srcType,
+            VariableType   dstType)
+        {
+            if (node is AstOperand operand && operand.Type == OperandType.Constant)
+            {
+                if (NumberFormatter.TryFormat(operand.Value, dstType, out string formatted))
+                {
+                    return formatted;
+                }
+            }
+
+            string expr = InstGen.GetExpression(context, node);
+
+            return ReinterpretCast(expr, node, srcType, dstType);
+        }
+
+        private static string ReinterpretCast(string expr, IAstNode node, VariableType srcType, VariableType dstType)
+        {
+            if (srcType == dstType)
+            {
+                return expr;
+            }
+
+            if (srcType == VariableType.F32)
+            {
+                switch (dstType)
+                {
+                    case VariableType.S32: return $"floatBitsToInt({expr})";
+                    case VariableType.U32: return $"floatBitsToUint({expr})";
+                }
+            }
+            else if (dstType == VariableType.F32)
+            {
+                switch (srcType)
+                {
+                    case VariableType.Bool: return $"intBitsToFloat({ReinterpretBoolToInt(expr, node, VariableType.S32)})";
+                    case VariableType.S32:  return $"intBitsToFloat({expr})";
+                    case VariableType.U32:  return $"uintBitsToFloat({expr})";
+                }
+            }
+            else if (srcType == VariableType.Bool)
+            {
+                return ReinterpretBoolToInt(expr, node, dstType);
+            }
+            else if (dstType == VariableType.Bool)
+            {
+                expr = InstGenHelper.Enclose(expr, node, Instruction.CompareNotEqual, isLhs: true);
+
+                return $"({expr} != 0)";
+            }
+            else if (dstType == VariableType.S32)
+            {
+                return $"int({expr})";
+            }
+            else if (dstType == VariableType.U32)
+            {
+                return $"uint({expr})";
+            }
+
+            throw new ArgumentException($"Invalid reinterpret cast from \"{srcType}\" to \"{dstType}\".");
+        }
+
+        private static string ReinterpretBoolToInt(string expr, IAstNode node, VariableType dstType)
+        {
+            string trueExpr  = NumberFormatter.FormatInt(IrConsts.True,  dstType);
+            string falseExpr = NumberFormatter.FormatInt(IrConsts.False, dstType);
+
+            expr = InstGenHelper.Enclose(expr, node, Instruction.ConditionalSelect, isLhs: false);
+
+            return $"({expr} ? {trueExpr} : {falseExpr})";
+        }
+    }
+}

+ 25 - 0
Ryujinx.Graphics/Shader/Decoders/BitfieldExtensions.cs

@@ -0,0 +1,25 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    static class BitfieldExtensions
+    {
+        public static bool Extract(this int value, int lsb)
+        {
+            return ((int)(value >> lsb) & 1) != 0;
+        }
+
+        public static int Extract(this int value, int lsb, int length)
+        {
+            return (int)(value >> lsb) & (int)(uint.MaxValue >> (32 - length));
+        }
+
+        public static bool Extract(this long value, int lsb)
+        {
+            return ((int)(value >> lsb) & 1) != 0;
+        }
+
+        public static int Extract(this long value, int lsb, int length)
+        {
+            return (int)(value >> lsb) & (int)(uint.MaxValue >> (32 - length));
+        }
+    }
+}

+ 117 - 0
Ryujinx.Graphics/Shader/Decoders/Block.cs

@@ -0,0 +1,117 @@
+using System;
+using System.Collections.Generic;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class Block
+    {
+        public ulong Address    { get; set; }
+        public ulong EndAddress { get; set; }
+
+        public Block Next   { get; set; }
+        public Block Branch { get; set; }
+
+        public List<OpCode>    OpCodes    { get; }
+        public List<OpCodeSsy> SsyOpCodes { get; }
+
+        public Block(ulong address)
+        {
+            Address = address;
+
+            OpCodes    = new List<OpCode>();
+            SsyOpCodes = new List<OpCodeSsy>();
+        }
+
+        public void Split(Block rightBlock)
+        {
+            int splitIndex = BinarySearch(OpCodes, rightBlock.Address);
+
+            if (OpCodes[splitIndex].Address < rightBlock.Address)
+            {
+                splitIndex++;
+            }
+
+            int splitCount = OpCodes.Count - splitIndex;
+
+            if (splitCount <= 0)
+            {
+                throw new ArgumentException("Can't split at right block address.");
+            }
+
+            rightBlock.EndAddress = EndAddress;
+
+            rightBlock.Next   = Next;
+            rightBlock.Branch = Branch;
+
+            rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount));
+
+            rightBlock.UpdateSsyOpCodes();
+
+            EndAddress = rightBlock.Address;
+
+            Next   = rightBlock;
+            Branch = null;
+
+            OpCodes.RemoveRange(splitIndex, splitCount);
+
+            UpdateSsyOpCodes();
+        }
+
+        private static int BinarySearch(List<OpCode> opCodes, ulong address)
+        {
+            int left   = 0;
+            int middle = 0;
+            int right  = opCodes.Count - 1;
+
+            while (left <= right)
+            {
+                int size = right - left;
+
+                middle = left + (size >> 1);
+
+                OpCode opCode = opCodes[middle];
+
+                if (address == opCode.Address)
+                {
+                    break;
+                }
+
+                if (address < opCode.Address)
+                {
+                    right = middle - 1;
+                }
+                else
+                {
+                    left = middle + 1;
+                }
+            }
+
+            return middle;
+        }
+
+        public OpCode GetLastOp()
+        {
+            if (OpCodes.Count != 0)
+            {
+                return OpCodes[OpCodes.Count - 1];
+            }
+
+            return null;
+        }
+
+        public void UpdateSsyOpCodes()
+        {
+            SsyOpCodes.Clear();
+
+            for (int index = 0; index < OpCodes.Count; index++)
+            {
+                if (!(OpCodes[index] is OpCodeSsy op))
+                {
+                    continue;
+                }
+
+                SsyOpCodes.Add(op);
+            }
+        }
+    }
+}

+ 45 - 0
Ryujinx.Graphics/Shader/Decoders/Condition.cs

@@ -0,0 +1,45 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum Condition
+    {
+        Less     = 1 << 0,
+        Equal    = 1 << 1,
+        Greater  = 1 << 2,
+        Nan      = 1 << 3,
+        Unsigned = 1 << 4,
+
+        Never = 0,
+
+        LessOrEqual    = Less    | Equal,
+        NotEqual       = Less    | Greater,
+        GreaterOrEqual = Greater | Equal,
+        Number         = Greater | Equal | Less,
+
+        LessUnordered           = Less           | Nan,
+        EqualUnordered          = Equal          | Nan,
+        LessOrEqualUnordered    = LessOrEqual    | Nan,
+        GreaterUnordered        = Greater        | Nan,
+        NotEqualUnordered       = NotEqual       | Nan,
+        GreaterOrEqualUnordered = GreaterOrEqual | Nan,
+
+        Always = 0xf,
+
+        Off          = Unsigned | Never,
+        Lower        = Unsigned | Less,
+        Sff          = Unsigned | Equal,
+        LowerOrSame  = Unsigned | LessOrEqual,
+        Higher       = Unsigned | Greater,
+        Sft          = Unsigned | NotEqual,
+        HigherOrSame = Unsigned | GreaterOrEqual,
+        Oft          = Unsigned | Always,
+
+        CsmTa  = 0x18,
+        CsmTr  = 0x19,
+        CsmMx  = 0x1a,
+        FcsmTa = 0x1b,
+        FcsmTr = 0x1c,
+        FcsmMx = 0x1d,
+        Rle    = 0x1e,
+        Rgt    = 0x1f
+    }
+}

+ 10 - 0
Ryujinx.Graphics/Shader/Decoders/ConditionalOperation.cs

@@ -0,0 +1,10 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum ConditionalOperation
+    {
+        False   = 0,
+        True    = 1,
+        Zero    = 2,
+        NotZero = 3
+    }
+}

+ 406 - 0
Ryujinx.Graphics/Shader/Decoders/Decoder.cs

@@ -0,0 +1,406 @@
+using Ryujinx.Graphics.Gal;
+using Ryujinx.Graphics.Shader.Instructions;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection.Emit;
+
+using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    static class Decoder
+    {
+        private const long HeaderSize = 0x50;
+
+        private delegate object OpActivator(InstEmitter emitter, ulong address, long opCode);
+
+        private static ConcurrentDictionary<Type, OpActivator> _opActivators;
+
+        static Decoder()
+        {
+            _opActivators = new ConcurrentDictionary<Type, OpActivator>();
+        }
+
+        public static Block[] Decode(IGalMemory memory, ulong address)
+        {
+            List<Block> blocks = new List<Block>();
+
+            Queue<Block> workQueue = new Queue<Block>();
+
+            Dictionary<ulong, Block> visited = new Dictionary<ulong, Block>();
+
+            Block GetBlock(ulong blkAddress)
+            {
+                if (!visited.TryGetValue(blkAddress, out Block block))
+                {
+                    block = new Block(blkAddress);
+
+                    workQueue.Enqueue(block);
+
+                    visited.Add(blkAddress, block);
+                }
+
+                return block;
+            }
+
+            ulong startAddress = address + HeaderSize;
+
+            GetBlock(startAddress);
+
+            while (workQueue.TryDequeue(out Block currBlock))
+            {
+                //Check if the current block is inside another block.
+                if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex))
+                {
+                    Block nBlock = blocks[nBlkIndex];
+
+                    if (nBlock.Address == currBlock.Address)
+                    {
+                        throw new InvalidOperationException("Found duplicate block address on the list.");
+                    }
+
+                    nBlock.Split(currBlock);
+
+                    blocks.Insert(nBlkIndex + 1, currBlock);
+
+                    continue;
+                }
+
+                //If we have a block after the current one, set the limit address.
+                ulong limitAddress = ulong.MaxValue;
+
+                if (nBlkIndex != blocks.Count)
+                {
+                    Block nBlock = blocks[nBlkIndex];
+
+                    int nextIndex = nBlkIndex + 1;
+
+                    if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count)
+                    {
+                        limitAddress = blocks[nextIndex].Address;
+                    }
+                    else if (nBlock.Address > currBlock.Address)
+                    {
+                        limitAddress = blocks[nBlkIndex].Address;
+                    }
+                }
+
+                FillBlock(memory, currBlock, limitAddress, startAddress);
+
+                if (currBlock.OpCodes.Count != 0)
+                {
+                    foreach (OpCodeSsy ssyOp in currBlock.SsyOpCodes)
+                    {
+                        GetBlock(ssyOp.GetAbsoluteAddress());
+                    }
+
+                    //Set child blocks. "Branch" is the block the branch instruction
+                    //points to (when taken), "Next" is the block at the next address,
+                    //executed when the branch is not taken. For Unconditional Branches
+                    //or end of program, Next is null.
+                    OpCode lastOp = currBlock.GetLastOp();
+
+                    if (lastOp is OpCodeBranch op)
+                    {
+                        currBlock.Branch = GetBlock(op.GetAbsoluteAddress());
+                    }
+
+                    if (!IsUnconditionalBranch(lastOp))
+                    {
+                        currBlock.Next = GetBlock(currBlock.EndAddress);
+                    }
+                }
+
+                //Insert the new block on the list (sorted by address).
+                if (blocks.Count != 0)
+                {
+                    Block nBlock = blocks[nBlkIndex];
+
+                    blocks.Insert(nBlkIndex + (nBlock.Address < currBlock.Address ? 1 : 0), currBlock);
+                }
+                else
+                {
+                    blocks.Add(currBlock);
+                }
+            }
+
+            foreach (Block ssyBlock in blocks.Where(x => x.SsyOpCodes.Count != 0))
+            {
+                for (int ssyIndex = 0; ssyIndex < ssyBlock.SsyOpCodes.Count; ssyIndex++)
+                {
+                    PropagateSsy(visited, ssyBlock, ssyIndex);
+                }
+            }
+
+            return blocks.ToArray();
+        }
+
+        private static bool BinarySearch(List<Block> blocks, ulong address, out int index)
+        {
+            index = 0;
+
+            int left  = 0;
+            int right = blocks.Count - 1;
+
+            while (left <= right)
+            {
+                int size = right - left;
+
+                int middle = left + (size >> 1);
+
+                Block block = blocks[middle];
+
+                index = middle;
+
+                if (address >= block.Address && address < block.EndAddress)
+                {
+                    return true;
+                }
+
+                if (address < block.Address)
+                {
+                    right = middle - 1;
+                }
+                else
+                {
+                    left = middle + 1;
+                }
+            }
+
+            return false;
+        }
+
+        private static void FillBlock(
+            IGalMemory memory,
+            Block      block,
+            ulong      limitAddress,
+            ulong      startAddress)
+        {
+            ulong address = block.Address;
+
+            do
+            {
+                if (address >= limitAddress)
+                {
+                    break;
+                }
+
+                //Ignore scheduling instructions, which are written every 32 bytes.
+                if (((address - startAddress) & 0x1f) == 0)
+                {
+                    address += 8;
+
+                    continue;
+                }
+
+                uint word0 = (uint)memory.ReadInt32((long)(address + 0));
+                uint word1 = (uint)memory.ReadInt32((long)(address + 4));
+
+                ulong opAddress = address;
+
+                address += 8;
+
+                long opCode = word0 | (long)word1 << 32;
+
+                (InstEmitter emitter, Type opCodeType) = OpCodeTable.GetEmitter(opCode);
+
+                if (emitter == null)
+                {
+                    //TODO: Warning, illegal encoding.
+                    continue;
+                }
+
+                OpCode op = MakeOpCode(opCodeType, emitter, opAddress, opCode);
+
+                block.OpCodes.Add(op);
+            }
+            while (!IsBranch(block.GetLastOp()));
+
+            block.EndAddress = address;
+
+            block.UpdateSsyOpCodes();
+        }
+
+        private static bool IsUnconditionalBranch(OpCode opCode)
+        {
+            return IsUnconditional(opCode) && IsBranch(opCode);
+        }
+
+        private static bool IsUnconditional(OpCode opCode)
+        {
+            if (opCode is OpCodeExit op && op.Condition != Condition.Always)
+            {
+                return false;
+            }
+
+            return opCode.Predicate.Index == RegisterConsts.PredicateTrueIndex && !opCode.InvertPredicate;
+        }
+
+        private static bool IsBranch(OpCode opCode)
+        {
+            return (opCode is OpCodeBranch && opCode.Emitter != InstEmit.Ssy) ||
+                    opCode is OpCodeSync ||
+                    opCode is OpCodeExit;
+        }
+
+        private static OpCode MakeOpCode(Type type, InstEmitter emitter, ulong address, long opCode)
+        {
+            if (type == null)
+            {
+                throw new ArgumentNullException(nameof(type));
+            }
+
+            OpActivator createInstance = _opActivators.GetOrAdd(type, CacheOpActivator);
+
+            return (OpCode)createInstance(emitter, address, opCode);
+        }
+
+        private static OpActivator CacheOpActivator(Type type)
+        {
+            Type[] argTypes = new Type[] { typeof(InstEmitter), typeof(ulong), typeof(long) };
+
+            DynamicMethod mthd = new DynamicMethod($"Make{type.Name}", type, argTypes);
+
+            ILGenerator generator = mthd.GetILGenerator();
+
+            generator.Emit(OpCodes.Ldarg_0);
+            generator.Emit(OpCodes.Ldarg_1);
+            generator.Emit(OpCodes.Ldarg_2);
+            generator.Emit(OpCodes.Newobj, type.GetConstructor(argTypes));
+            generator.Emit(OpCodes.Ret);
+
+            return (OpActivator)mthd.CreateDelegate(typeof(OpActivator));
+        }
+
+        private struct PathBlockState
+        {
+            public Block Block { get; }
+
+            private enum RestoreType
+            {
+                None,
+                PopSsy,
+                PushSync
+            }
+
+            private RestoreType _restoreType;
+
+            private ulong _restoreValue;
+
+            public bool ReturningFromVisit => _restoreType != RestoreType.None;
+
+            public PathBlockState(Block block)
+            {
+                Block         = block;
+                _restoreType  = RestoreType.None;
+                _restoreValue = 0;
+            }
+
+            public PathBlockState(int oldSsyStackSize)
+            {
+                Block         = null;
+                _restoreType  = RestoreType.PopSsy;
+                _restoreValue = (ulong)oldSsyStackSize;
+            }
+
+            public PathBlockState(ulong syncAddress)
+            {
+                Block         = null;
+                _restoreType  = RestoreType.PushSync;
+                _restoreValue = syncAddress;
+            }
+
+            public void RestoreStackState(Stack<ulong> ssyStack)
+            {
+                if (_restoreType == RestoreType.PushSync)
+                {
+                    ssyStack.Push(_restoreValue);
+                }
+                else if (_restoreType == RestoreType.PopSsy)
+                {
+                    while (ssyStack.Count > (uint)_restoreValue)
+                    {
+                        ssyStack.Pop();
+                    }
+                }
+            }
+        }
+
+        private static void PropagateSsy(Dictionary<ulong, Block> blocks, Block ssyBlock, int ssyIndex)
+        {
+            OpCodeSsy ssyOp = ssyBlock.SsyOpCodes[ssyIndex];
+
+            Stack<PathBlockState> workQueue = new Stack<PathBlockState>();
+
+            HashSet<Block> visited = new HashSet<Block>();
+
+            Stack<ulong> ssyStack = new Stack<ulong>();
+
+            void Push(PathBlockState pbs)
+            {
+                if (pbs.Block == null || visited.Add(pbs.Block))
+                {
+                    workQueue.Push(pbs);
+                }
+            }
+
+            Push(new PathBlockState(ssyBlock));
+
+            while (workQueue.TryPop(out PathBlockState pbs))
+            {
+                if (pbs.ReturningFromVisit)
+                {
+                    pbs.RestoreStackState(ssyStack);
+
+                    continue;
+                }
+
+                Block current = pbs.Block;
+
+                int ssyOpCodesCount = current.SsyOpCodes.Count;
+
+                if (ssyOpCodesCount != 0)
+                {
+                    Push(new PathBlockState(ssyStack.Count));
+
+                    for (int index = ssyIndex; index < ssyOpCodesCount; index++)
+                    {
+                        ssyStack.Push(current.SsyOpCodes[index].GetAbsoluteAddress());
+                    }
+                }
+
+                ssyIndex = 0;
+
+                if (current.Next != null)
+                {
+                    Push(new PathBlockState(current.Next));
+                }
+
+                if (current.Branch != null)
+                {
+                    Push(new PathBlockState(current.Branch));
+                }
+                else if (current.GetLastOp() is OpCodeSync op)
+                {
+                    ulong syncAddress = ssyStack.Pop();
+
+                    if (ssyStack.Count == 0)
+                    {
+                        ssyStack.Push(syncAddress);
+
+                        op.Targets.Add(ssyOp, op.Targets.Count);
+
+                        ssyOp.Syncs.TryAdd(op, Local());
+                    }
+                    else
+                    {
+                        Push(new PathBlockState(syncAddress));
+                        Push(new PathBlockState(blocks[syncAddress]));
+                    }
+                }
+            }
+        }
+    }
+}

+ 58 - 0
Ryujinx.Graphics/Shader/Decoders/DecoderHelper.cs

@@ -0,0 +1,58 @@
+using System;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    static class DecoderHelper
+    {
+        public static int DecodeS20Immediate(long opCode)
+        {
+            int imm = opCode.Extract(20, 19);
+
+            bool negate = opCode.Extract(56);
+
+            if (negate)
+            {
+                imm = -imm;
+            }
+
+            return imm;
+        }
+
+        public static int Decode2xF10Immediate(long opCode)
+        {
+            int immH0 = opCode.Extract(20, 9);
+            int immH1 = opCode.Extract(30, 9);
+
+            bool negateH0 = opCode.Extract(29);
+            bool negateH1 = opCode.Extract(56);
+
+            if (negateH0)
+            {
+                immH0 |= 1 << 9;
+            }
+
+            if (negateH1)
+            {
+                immH1 |= 1 << 9;
+            }
+
+            return immH1 << 22 | immH0 << 6;
+        }
+
+        public static float DecodeF20Immediate(long opCode)
+        {
+            int imm = opCode.Extract(20, 19);
+
+            bool negate = opCode.Extract(56);
+
+            imm <<= 12;
+
+            if (negate)
+            {
+                imm |= 1 << 31;
+            }
+
+            return BitConverter.Int32BitsToSingle(imm);
+        }
+    }
+}

+ 10 - 0
Ryujinx.Graphics/Shader/Decoders/FPHalfSwizzle.cs

@@ -0,0 +1,10 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum FPHalfSwizzle
+    {
+        FP16  = 0,
+        FP32  = 1,
+        DupH0 = 2,
+        DupH1 = 3
+    }
+}

+ 9 - 0
Ryujinx.Graphics/Shader/Decoders/FPType.cs

@@ -0,0 +1,9 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum FPType
+    {
+        FP16 = 1,
+        FP32 = 2,
+        FP64 = 3
+    }
+}

+ 13 - 0
Ryujinx.Graphics/Shader/Decoders/FmulScale.cs

@@ -0,0 +1,13 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum FmulScale
+    {
+        None      = 0,
+        Divide2   = 1,
+        Divide4   = 2,
+        Divide8   = 3,
+        Multiply8 = 4,
+        Multiply4 = 5,
+        Multiply2 = 6
+    }
+}

+ 16 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCode.cs

@@ -0,0 +1,16 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCode
+    {
+        InstEmitter Emitter { get; }
+
+        ulong Address   { get; }
+        long  RawOpCode { get; }
+
+        Register Predicate { get; }
+
+        bool InvertPredicate { get; }
+    }
+}

+ 12 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeAlu.cs

@@ -0,0 +1,12 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeAlu : IOpCodeRd, IOpCodeRa
+    {
+        Register Predicate39 { get; }
+
+        bool InvertP     { get; }
+        bool Extended    { get; }
+        bool SetCondCode { get; }
+        bool Saturate    { get; }
+    }
+}

+ 8 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeCbuf.cs

@@ -0,0 +1,8 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeCbuf : IOpCode
+    {
+        int Offset { get; }
+        int Slot   { get; }
+    }
+}

+ 12 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeFArith.cs

@@ -0,0 +1,12 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeFArith : IOpCodeAlu
+    {
+        RoundingMode RoundingMode { get; }
+
+        FmulScale Scale { get; }
+
+        bool FlushToZero { get; }
+        bool AbsoluteA   { get; }
+    }
+}

+ 13 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeHfma.cs

@@ -0,0 +1,13 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeHfma : IOpCode
+    {
+        bool NegateB  { get; }
+        bool NegateC  { get; }
+        bool Saturate { get; }
+
+        FPHalfSwizzle SwizzleA { get; }
+        FPHalfSwizzle SwizzleB { get; }
+        FPHalfSwizzle SwizzleC { get; }
+    }
+}

+ 7 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeImm.cs

@@ -0,0 +1,7 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeImm : IOpCode
+    {
+        int Immediate { get; }
+    }
+}

+ 7 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeImmF.cs

@@ -0,0 +1,7 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeImmF : IOpCode
+    {
+        float Immediate { get; }
+    }
+}

+ 10 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeLop.cs

@@ -0,0 +1,10 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeLop : IOpCodeAlu
+    {
+        LogicalOperation LogicalOp { get; }
+
+        bool InvertA { get; }
+        bool InvertB { get; }
+    }
+}

+ 7 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeRa.cs

@@ -0,0 +1,7 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeRa : IOpCode
+    {
+        Register Ra { get; }
+    }
+}

+ 7 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeRc.cs

@@ -0,0 +1,7 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeRc : IOpCode
+    {
+        Register Rc { get; }
+    }
+}

+ 7 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeRd.cs

@@ -0,0 +1,7 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeRd : IOpCode
+    {
+        Register Rd { get; }
+    }
+}

+ 7 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeReg.cs

@@ -0,0 +1,7 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeReg : IOpCode
+    {
+        Register Rb { get; }
+    }
+}

+ 8 - 0
Ryujinx.Graphics/Shader/Decoders/IOpCodeRegCbuf.cs

@@ -0,0 +1,8 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    interface IOpCodeRegCbuf : IOpCodeRc
+    {
+        int Offset { get; }
+        int Slot   { get; }
+    }
+}

+ 18 - 0
Ryujinx.Graphics/Shader/Decoders/IntegerCondition.cs

@@ -0,0 +1,18 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum IntegerCondition
+    {
+        Less    = 1 << 0,
+        Equal   = 1 << 1,
+        Greater = 1 << 2,
+
+        Never = 0,
+
+        LessOrEqual    = Less    | Equal,
+        NotEqual       = Less    | Greater,
+        GreaterOrEqual = Greater | Equal,
+        Number         = Greater | Equal | Less,
+
+        Always = 7
+    }
+}

+ 9 - 0
Ryujinx.Graphics/Shader/Decoders/IntegerHalfPart.cs

@@ -0,0 +1,9 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum IntegerHalfPart
+    {
+        B32 = 0,
+        H0  = 1,
+        H1  = 2
+    }
+}

+ 9 - 0
Ryujinx.Graphics/Shader/Decoders/IntegerShift.cs

@@ -0,0 +1,9 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum IntegerShift
+    {
+        NoShift    = 0,
+        ShiftRight = 1,
+        ShiftLeft  = 2
+    }
+}

+ 12 - 0
Ryujinx.Graphics/Shader/Decoders/IntegerSize.cs

@@ -0,0 +1,12 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum IntegerSize
+    {
+        U8  = 0,
+        S8  = 1,
+        U16 = 2,
+        S16 = 3,
+        B32 = 4,
+        B64 = 5
+    }
+}

+ 14 - 0
Ryujinx.Graphics/Shader/Decoders/IntegerType.cs

@@ -0,0 +1,14 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum IntegerType
+    {
+        U8  = 0,
+        U16 = 1,
+        U32 = 2,
+        U64 = 3,
+        S8  = 4,
+        S16 = 5,
+        S32 = 6,
+        S64 = 7
+    }
+}

+ 10 - 0
Ryujinx.Graphics/Shader/Decoders/LogicalOperation.cs

@@ -0,0 +1,10 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum LogicalOperation
+    {
+        And         = 0,
+        Or          = 1,
+        ExclusiveOr = 2,
+        Passthrough = 3
+    }
+}

+ 15 - 0
Ryujinx.Graphics/Shader/Decoders/MufuOperation.cs

@@ -0,0 +1,15 @@
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    enum MufuOperation
+    {
+        Cosine                  = 0,
+        Sine                    = 1,
+        ExponentB2              = 2,
+        LogarithmB2             = 3,
+        Reciprocal              = 4,
+        ReciprocalSquareRoot    = 5,
+        Reciprocal64H           = 6,
+        ReciprocalSquareRoot64H = 7,
+        SquareRoot              = 8
+    }
+}

+ 30 - 0
Ryujinx.Graphics/Shader/Decoders/OpCode.cs

@@ -0,0 +1,30 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCode
+    {
+        public InstEmitter Emitter { get; }
+
+        public ulong Address   { get; }
+        public long  RawOpCode { get; }
+
+        public Register Predicate { get; protected set; }
+
+        public bool InvertPredicate { get; protected set; }
+
+        //When inverted, the always true predicate == always false.
+        public bool NeverExecute => Predicate.Index == RegisterConsts.PredicateTrueIndex && InvertPredicate;
+
+        public OpCode(InstEmitter emitter, ulong address, long opCode)
+        {
+            Emitter   = emitter;
+            Address   = address;
+            RawOpCode = opCode;
+
+            Predicate = new Register(opCode.Extract(16, 3), RegisterType.Predicate);
+
+            InvertPredicate = opCode.Extract(19);
+        }
+    }
+}

+ 34 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeAlu.cs

@@ -0,0 +1,34 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeAlu : OpCode, IOpCodeAlu, IOpCodeRc
+    {
+        public Register Rd          { get; }
+        public Register Ra          { get; }
+        public Register Rc          { get; }
+        public Register Predicate39 { get; }
+
+        public int ByteSelection { get; }
+
+        public bool InvertP     { get; }
+        public bool Extended    { get; protected set; }
+        public bool SetCondCode { get; protected set; }
+        public bool Saturate    { get; protected set; }
+
+        public OpCodeAlu(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Rd          = new Register(opCode.Extract(0,  8), RegisterType.Gpr);
+            Ra          = new Register(opCode.Extract(8,  8), RegisterType.Gpr);
+            Rc          = new Register(opCode.Extract(39, 8), RegisterType.Gpr);
+            Predicate39 = new Register(opCode.Extract(39, 3), RegisterType.Predicate);
+
+            ByteSelection = opCode.Extract(41, 2);
+
+            InvertP     = opCode.Extract(42);
+            Extended    = opCode.Extract(43);
+            SetCondCode = opCode.Extract(47);
+            Saturate    = opCode.Extract(50);
+        }
+    }
+}

+ 16 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeAluCbuf.cs

@@ -0,0 +1,16 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeAluCbuf : OpCodeAlu, IOpCodeCbuf
+    {
+        public int Offset { get; }
+        public int Slot   { get; }
+
+        public OpCodeAluCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Offset = opCode.Extract(20, 14);
+            Slot   = opCode.Extract(34, 5);
+        }
+    }
+}

+ 14 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm.cs

@@ -0,0 +1,14 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeAluImm : OpCodeAlu, IOpCodeImm
+    {
+        public int Immediate { get; }
+
+        public OpCodeAluImm(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Immediate = DecoderHelper.DecodeS20Immediate(opCode);
+        }
+    }
+}

+ 14 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm2x10.cs

@@ -0,0 +1,14 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeAluImm2x10 : OpCodeAlu, IOpCodeImm
+    {
+        public int Immediate { get; }
+
+        public OpCodeAluImm2x10(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Immediate = DecoderHelper.Decode2xF10Immediate(opCode);
+        }
+    }
+}

+ 18 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm32.cs

@@ -0,0 +1,18 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeAluImm32 : OpCodeAlu, IOpCodeImm
+    {
+        public int Immediate { get; }
+
+        public OpCodeAluImm32(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Immediate = opCode.Extract(20, 32);
+
+            SetCondCode = opCode.Extract(52);
+            Extended    = opCode.Extract(53);
+            Saturate    = opCode.Extract(54);
+        }
+    }
+}

+ 14 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeAluReg.cs

@@ -0,0 +1,14 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeAluReg : OpCodeAlu, IOpCodeReg
+    {
+        public Register Rb { get; protected set; }
+
+        public OpCodeAluReg(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Rb = new Register(opCode.Extract(20, 8), RegisterType.Gpr);
+        }
+    }
+}

+ 18 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeAluRegCbuf.cs

@@ -0,0 +1,18 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeAluRegCbuf : OpCodeAluReg, IOpCodeRegCbuf
+    {
+        public int Offset { get; }
+        public int Slot   { get; }
+
+        public OpCodeAluRegCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Offset = opCode.Extract(20, 14);
+            Slot   = opCode.Extract(34, 5);
+
+            Rb = new Register(opCode.Extract(39, 8), RegisterType.Gpr);
+        }
+    }
+}

+ 16 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeAttribute.cs

@@ -0,0 +1,16 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeAttribute : OpCodeAluReg
+    {
+        public int AttributeOffset { get; }
+        public int Count           { get; }
+
+        public OpCodeAttribute(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            AttributeOffset = opCode.Extract(20, 10);
+            Count           = opCode.Extract(47, 2) + 1;
+        }
+    }
+}

+ 19 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeBranch.cs

@@ -0,0 +1,19 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeBranch : OpCode
+    {
+        public int Offset { get; }
+
+        public OpCodeBranch(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Offset = ((int)(opCode >> 20) << 8) >> 8;
+        }
+
+        public ulong GetAbsoluteAddress()
+        {
+            return (ulong)((long)Address + (long)Offset + 8);
+        }
+    }
+}

+ 14 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeExit.cs

@@ -0,0 +1,14 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeExit : OpCode
+    {
+        public Condition Condition { get; }
+
+        public OpCodeExit(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Condition = (Condition)opCode.Extract(0, 5);
+        }
+    }
+}

+ 24 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeFArith.cs

@@ -0,0 +1,24 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeFArith : OpCodeAlu, IOpCodeFArith
+    {
+        public RoundingMode RoundingMode { get; }
+
+        public FmulScale Scale { get; }
+
+        public bool FlushToZero { get; }
+        public bool AbsoluteA   { get; }
+
+        public OpCodeFArith(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            RoundingMode = (RoundingMode)opCode.Extract(39, 2);
+
+            Scale = (FmulScale)opCode.Extract(41, 3);
+
+            FlushToZero = opCode.Extract(44);
+            AbsoluteA   = opCode.Extract(46);
+        }
+    }
+}

+ 16 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeFArithCbuf.cs

@@ -0,0 +1,16 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeFArithCbuf : OpCodeFArith, IOpCodeCbuf
+    {
+        public int Offset { get; }
+        public int Slot   { get; }
+
+        public OpCodeFArithCbuf(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Offset = opCode.Extract(20, 14);
+            Slot   = opCode.Extract(34, 5);
+        }
+    }
+}

+ 14 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm.cs

@@ -0,0 +1,14 @@
+using Ryujinx.Graphics.Shader.Instructions;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeFArithImm : OpCodeFArith, IOpCodeImmF
+    {
+        public float Immediate { get; }
+
+        public OpCodeFArithImm(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            Immediate = DecoderHelper.DecodeF20Immediate(opCode);
+        }
+    }
+}

+ 30 - 0
Ryujinx.Graphics/Shader/Decoders/OpCodeFArithImm32.cs

@@ -0,0 +1,30 @@
+using Ryujinx.Graphics.Shader.Instructions;
+using System;
+
+namespace Ryujinx.Graphics.Shader.Decoders
+{
+    class OpCodeFArithImm32 : OpCodeAlu, IOpCodeFArith, IOpCodeImmF
+    {
+        public RoundingMode RoundingMode => RoundingMode.ToNearest;
+
+        public FmulScale Scale => FmulScale.None;
+
+        public bool FlushToZero { get; }
+        public bool AbsoluteA   { get; }
+
+        public float Immediate { get; }
+
+        public OpCodeFArithImm32(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
+        {
+            int imm = opCode.Extract(20, 32);
+
+            Immediate = BitConverter.Int32BitsToSingle(imm);
+
+            SetCondCode = opCode.Extract(52);
+            AbsoluteA   = opCode.Extract(54);
+            FlushToZero = opCode.Extract(55);
+
+            Saturate = false;
+        }
+    }
+}

Some files were not shown because too many files changed in this diff