diff --git a/Ryujinx.Graphics.GAL/Format.cs b/Ryujinx.Graphics.GAL/Format.cs
index a66673614..a4e434b1f 100644
--- a/Ryujinx.Graphics.GAL/Format.cs
+++ b/Ryujinx.Graphics.GAL/Format.cs
@@ -341,38 +341,5 @@ namespace Ryujinx.Graphics.GAL
         {
             return format.IsUint() || format.IsSint();
         }
-
-        /// <summary>
-        /// Checks if the texture format only has one component.
-        /// </summary>
-        /// <param name="format">Texture format</param>
-        /// <returns>True if the texture format only has one component, false otherwise</returns>
-        public static bool HasOneComponent(this Format format)
-        {
-            switch (format)
-            {
-                case Format.R8Unorm:
-                case Format.R8Snorm:
-                case Format.R8Uint:
-                case Format.R8Sint:
-                case Format.R16Float:
-                case Format.R16Unorm:
-                case Format.R16Snorm:
-                case Format.R16Uint:
-                case Format.R16Sint:
-                case Format.R32Float:
-                case Format.R32Uint:
-                case Format.R32Sint:
-                case Format.R8Uscaled:
-                case Format.R8Sscaled:
-                case Format.R16Uscaled:
-                case Format.R16Sscaled:
-                case Format.R32Uscaled:
-                case Format.R32Sscaled:
-                    return true;
-            }
-
-            return false;
-        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs b/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs
index 12f3aecbb..62f41cbb0 100644
--- a/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs
+++ b/Ryujinx.Graphics.Gpu/Image/FormatInfo.cs
@@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <summary>
         /// A default, generic RGBA8 texture format.
         /// </summary>
-        public static FormatInfo Default { get; } = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4);
+        public static FormatInfo Default { get; } = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
 
         /// <summary>
         /// The format of the texture data.
@@ -38,6 +38,11 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// </summary>
         public int BytesPerPixel { get; }
 
+        /// <summary>
+        /// The maximum number of components this format has defined (in RGBA order).
+        /// </summary>
+        public int Components { get; }
+
         /// <summary>
         /// Whenever or not the texture format is a compressed format. Determined from block size.
         /// </summary>
@@ -54,12 +59,14 @@ namespace Ryujinx.Graphics.Gpu.Image
             Format format,
             int    blockWidth,
             int    blockHeight,
-            int    bytesPerPixel)
+            int    bytesPerPixel,
+            int    components)
         {
             Format        = format;
             BlockWidth    = blockWidth;
             BlockHeight   = blockHeight;
             BytesPerPixel = bytesPerPixel;
+            Components    = components;
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/FormatTable.cs b/Ryujinx.Graphics.Gpu/Image/FormatTable.cs
index 9f8b0fa06..d8f2a9d45 100644
--- a/Ryujinx.Graphics.Gpu/Image/FormatTable.cs
+++ b/Ryujinx.Graphics.Gpu/Image/FormatTable.cs
@@ -10,102 +10,102 @@ namespace Ryujinx.Graphics.Gpu.Image
     {
         private static Dictionary<uint, FormatInfo> _textureFormats = new Dictionary<uint, FormatInfo>()
         {
-            { 0x2491d, new FormatInfo(Format.R8Unorm,           1,  1,  1)  },
-            { 0x1249d, new FormatInfo(Format.R8Snorm,           1,  1,  1)  },
-            { 0x4921d, new FormatInfo(Format.R8Uint,            1,  1,  1)  },
-            { 0x36d9d, new FormatInfo(Format.R8Sint,            1,  1,  1)  },
-            { 0x7ff9b, new FormatInfo(Format.R16Float,          1,  1,  2)  },
-            { 0x2491b, new FormatInfo(Format.R16Unorm,          1,  1,  2)  },
-            { 0x1249b, new FormatInfo(Format.R16Snorm,          1,  1,  2)  },
-            { 0x4921b, new FormatInfo(Format.R16Uint,           1,  1,  2)  },
-            { 0x36d9b, new FormatInfo(Format.R16Sint,           1,  1,  2)  },
-            { 0x7ff8f, new FormatInfo(Format.R32Float,          1,  1,  4)  },
-            { 0x4920f, new FormatInfo(Format.R32Uint,           1,  1,  4)  },
-            { 0x36d8f, new FormatInfo(Format.R32Sint,           1,  1,  4)  },
-            { 0x24918, new FormatInfo(Format.R8G8Unorm,         1,  1,  2)  },
-            { 0x12498, new FormatInfo(Format.R8G8Snorm,         1,  1,  2)  },
-            { 0x49218, new FormatInfo(Format.R8G8Uint,          1,  1,  2)  },
-            { 0x36d98, new FormatInfo(Format.R8G8Sint,          1,  1,  2)  },
-            { 0x7ff8c, new FormatInfo(Format.R16G16Float,       1,  1,  4)  },
-            { 0x2490c, new FormatInfo(Format.R16G16Unorm,       1,  1,  4)  },
-            { 0x1248c, new FormatInfo(Format.R16G16Snorm,       1,  1,  4)  },
-            { 0x4920c, new FormatInfo(Format.R16G16Uint,        1,  1,  4)  },
-            { 0x36d8c, new FormatInfo(Format.R16G16Sint,        1,  1,  4)  },
-            { 0x7ff84, new FormatInfo(Format.R32G32Float,       1,  1,  8)  },
-            { 0x49204, new FormatInfo(Format.R32G32Uint,        1,  1,  8)  },
-            { 0x36d84, new FormatInfo(Format.R32G32Sint,        1,  1,  8)  },
-            { 0x7ff82, new FormatInfo(Format.R32G32B32Float,    1,  1,  12) },
-            { 0x49202, new FormatInfo(Format.R32G32B32Uint,     1,  1,  12) },
-            { 0x36d82, new FormatInfo(Format.R32G32B32Sint,     1,  1,  12) },
-            { 0x24908, new FormatInfo(Format.R8G8B8A8Unorm,     1,  1,  4)  },
-            { 0x12488, new FormatInfo(Format.R8G8B8A8Snorm,     1,  1,  4)  },
-            { 0x49208, new FormatInfo(Format.R8G8B8A8Uint,      1,  1,  4)  },
-            { 0x36d88, new FormatInfo(Format.R8G8B8A8Sint,      1,  1,  4)  },
-            { 0x7ff83, new FormatInfo(Format.R16G16B16A16Float, 1,  1,  8)  },
-            { 0x24903, new FormatInfo(Format.R16G16B16A16Unorm, 1,  1,  8)  },
-            { 0x12483, new FormatInfo(Format.R16G16B16A16Snorm, 1,  1,  8)  },
-            { 0x49203, new FormatInfo(Format.R16G16B16A16Uint,  1,  1,  8)  },
-            { 0x36d83, new FormatInfo(Format.R16G16B16A16Sint,  1,  1,  8)  },
-            { 0x7ff81, new FormatInfo(Format.R32G32B32A32Float, 1,  1,  16) },
-            { 0x49201, new FormatInfo(Format.R32G32B32A32Uint,  1,  1,  16) },
-            { 0x36d81, new FormatInfo(Format.R32G32B32A32Sint,  1,  1,  16) },
-            { 0x2493a, new FormatInfo(Format.D16Unorm,          1,  1,  2)  },
-            { 0x7ffaf, new FormatInfo(Format.D32Float,          1,  1,  4)  },
-            { 0x24a0e, new FormatInfo(Format.D24UnormS8Uint,    1,  1,  4)  },
-            { 0x24a29, new FormatInfo(Format.D24UnormS8Uint,    1,  1,  4)  },
-            { 0x25385, new FormatInfo(Format.D32FloatS8Uint,    1,  1,  8)  },
-            { 0x253b0, new FormatInfo(Format.D32FloatS8Uint,    1,  1,  8)  },
-            { 0xa4908, new FormatInfo(Format.R8G8B8A8Srgb,      1,  1,  4)  },
-            { 0x24912, new FormatInfo(Format.R4G4B4A4Unorm,     1,  1,  2)  },
-            { 0x24914, new FormatInfo(Format.R5G5B5A1Unorm,     1,  1,  2)  },
-            { 0x24915, new FormatInfo(Format.R5G6B5Unorm,       1,  1,  2)  },
-            { 0x24909, new FormatInfo(Format.R10G10B10A2Unorm,  1,  1,  4)  },
-            { 0x49209, new FormatInfo(Format.R10G10B10A2Uint,   1,  1,  4)  },
-            { 0x7ffa1, new FormatInfo(Format.R11G11B10Float,    1,  1,  4)  },
-            { 0x7ffa0, new FormatInfo(Format.R9G9B9E5Float,     1,  1,  4)  },
-            { 0x24924, new FormatInfo(Format.Bc1RgbaUnorm,      4,  4,  8)  },
-            { 0x24925, new FormatInfo(Format.Bc2Unorm,          4,  4,  16) },
-            { 0x24926, new FormatInfo(Format.Bc3Unorm,          4,  4,  16) },
-            { 0xa4924, new FormatInfo(Format.Bc1RgbaSrgb,       4,  4,  8)  },
-            { 0xa4925, new FormatInfo(Format.Bc2Srgb,           4,  4,  16) },
-            { 0xa4926, new FormatInfo(Format.Bc3Srgb,           4,  4,  16) },
-            { 0x24927, new FormatInfo(Format.Bc4Unorm,          4,  4,  8)  },
-            { 0x124a7, new FormatInfo(Format.Bc4Snorm,          4,  4,  8)  },
-            { 0x24928, new FormatInfo(Format.Bc5Unorm,          4,  4,  16) },
-            { 0x124a8, new FormatInfo(Format.Bc5Snorm,          4,  4,  16) },
-            { 0x24917, new FormatInfo(Format.Bc7Unorm,          4,  4,  16) },
-            { 0xa4917, new FormatInfo(Format.Bc7Srgb,           4,  4,  16) },
-            { 0x7ff90, new FormatInfo(Format.Bc6HSfloat,        4,  4,  16) },
-            { 0x7ff91, new FormatInfo(Format.Bc6HUfloat,        4,  4,  16) },
-            { 0x24940, new FormatInfo(Format.Astc4x4Unorm,      4,  4,  16) },
-            { 0x24950, new FormatInfo(Format.Astc5x4Unorm,      5,  4,  16) },
-            { 0x24941, new FormatInfo(Format.Astc5x5Unorm,      5,  5,  16) },
-            { 0x24951, new FormatInfo(Format.Astc6x5Unorm,      6,  5,  16) },
-            { 0x24942, new FormatInfo(Format.Astc6x6Unorm,      6,  6,  16) },
-            { 0x24955, new FormatInfo(Format.Astc8x5Unorm,      8,  5,  16) },
-            { 0x24952, new FormatInfo(Format.Astc8x6Unorm,      8,  6,  16) },
-            { 0x24944, new FormatInfo(Format.Astc8x8Unorm,      8,  8,  16) },
-            { 0x24956, new FormatInfo(Format.Astc10x5Unorm,     10, 5,  16) },
-            { 0x24957, new FormatInfo(Format.Astc10x6Unorm,     10, 6,  16) },
-            { 0x24953, new FormatInfo(Format.Astc10x8Unorm,     10, 8,  16) },
-            { 0x24945, new FormatInfo(Format.Astc10x10Unorm,    10, 10, 16) },
-            { 0x24954, new FormatInfo(Format.Astc12x10Unorm,    12, 10, 16) },
-            { 0x24946, new FormatInfo(Format.Astc12x12Unorm,    12, 12, 16) },
-            { 0xa4940, new FormatInfo(Format.Astc4x4Srgb,       4,  4,  16) },
-            { 0xa4950, new FormatInfo(Format.Astc5x4Srgb,       5,  4,  16) },
-            { 0xa4941, new FormatInfo(Format.Astc5x5Srgb,       5,  5,  16) },
-            { 0xa4951, new FormatInfo(Format.Astc6x5Srgb,       6,  5,  16) },
-            { 0xa4942, new FormatInfo(Format.Astc6x6Srgb,       6,  6,  16) },
-            { 0xa4955, new FormatInfo(Format.Astc8x5Srgb,       8,  5,  16) },
-            { 0xa4952, new FormatInfo(Format.Astc8x6Srgb,       8,  6,  16) },
-            { 0xa4944, new FormatInfo(Format.Astc8x8Srgb,       8,  8,  16) },
-            { 0xa4956, new FormatInfo(Format.Astc10x5Srgb,      10, 5,  16) },
-            { 0xa4957, new FormatInfo(Format.Astc10x6Srgb,      10, 6,  16) },
-            { 0xa4953, new FormatInfo(Format.Astc10x8Srgb,      10, 8,  16) },
-            { 0xa4945, new FormatInfo(Format.Astc10x10Srgb,     10, 10, 16) },
-            { 0xa4954, new FormatInfo(Format.Astc12x10Srgb,     12, 10, 16) },
-            { 0xa4946, new FormatInfo(Format.Astc12x12Srgb,     12, 12, 16) },
-            { 0x24913, new FormatInfo(Format.A1B5G5R5Unorm,     1,  1,  2)  }
+            { 0x2491d, new FormatInfo(Format.R8Unorm,           1,  1,  1,  1) },
+            { 0x1249d, new FormatInfo(Format.R8Snorm,           1,  1,  1,  1) },
+            { 0x4921d, new FormatInfo(Format.R8Uint,            1,  1,  1,  1) },
+            { 0x36d9d, new FormatInfo(Format.R8Sint,            1,  1,  1,  1) },
+            { 0x7ff9b, new FormatInfo(Format.R16Float,          1,  1,  2,  1) },
+            { 0x2491b, new FormatInfo(Format.R16Unorm,          1,  1,  2,  1) },
+            { 0x1249b, new FormatInfo(Format.R16Snorm,          1,  1,  2,  1) },
+            { 0x4921b, new FormatInfo(Format.R16Uint,           1,  1,  2,  1) },
+            { 0x36d9b, new FormatInfo(Format.R16Sint,           1,  1,  2,  1) },
+            { 0x7ff8f, new FormatInfo(Format.R32Float,          1,  1,  4,  1) },
+            { 0x4920f, new FormatInfo(Format.R32Uint,           1,  1,  4,  1) },
+            { 0x36d8f, new FormatInfo(Format.R32Sint,           1,  1,  4,  1) },
+            { 0x24918, new FormatInfo(Format.R8G8Unorm,         1,  1,  2,  2) },
+            { 0x12498, new FormatInfo(Format.R8G8Snorm,         1,  1,  2,  2) },
+            { 0x49218, new FormatInfo(Format.R8G8Uint,          1,  1,  2,  2) },
+            { 0x36d98, new FormatInfo(Format.R8G8Sint,          1,  1,  2,  2) },
+            { 0x7ff8c, new FormatInfo(Format.R16G16Float,       1,  1,  4,  2) },
+            { 0x2490c, new FormatInfo(Format.R16G16Unorm,       1,  1,  4,  2) },
+            { 0x1248c, new FormatInfo(Format.R16G16Snorm,       1,  1,  4,  2) },
+            { 0x4920c, new FormatInfo(Format.R16G16Uint,        1,  1,  4,  2) },
+            { 0x36d8c, new FormatInfo(Format.R16G16Sint,        1,  1,  4,  2) },
+            { 0x7ff84, new FormatInfo(Format.R32G32Float,       1,  1,  8,  2) },
+            { 0x49204, new FormatInfo(Format.R32G32Uint,        1,  1,  8,  2) },
+            { 0x36d84, new FormatInfo(Format.R32G32Sint,        1,  1,  8,  2) },
+            { 0x7ff82, new FormatInfo(Format.R32G32B32Float,    1,  1,  12, 3) },
+            { 0x49202, new FormatInfo(Format.R32G32B32Uint,     1,  1,  12, 3) },
+            { 0x36d82, new FormatInfo(Format.R32G32B32Sint,     1,  1,  12, 3) },
+            { 0x24908, new FormatInfo(Format.R8G8B8A8Unorm,     1,  1,  4,  4) },
+            { 0x12488, new FormatInfo(Format.R8G8B8A8Snorm,     1,  1,  4,  4) },
+            { 0x49208, new FormatInfo(Format.R8G8B8A8Uint,      1,  1,  4,  4) },
+            { 0x36d88, new FormatInfo(Format.R8G8B8A8Sint,      1,  1,  4,  4) },
+            { 0x7ff83, new FormatInfo(Format.R16G16B16A16Float, 1,  1,  8,  4) },
+            { 0x24903, new FormatInfo(Format.R16G16B16A16Unorm, 1,  1,  8,  4) },
+            { 0x12483, new FormatInfo(Format.R16G16B16A16Snorm, 1,  1,  8,  4) },
+            { 0x49203, new FormatInfo(Format.R16G16B16A16Uint,  1,  1,  8,  4) },
+            { 0x36d83, new FormatInfo(Format.R16G16B16A16Sint,  1,  1,  8,  4) },
+            { 0x7ff81, new FormatInfo(Format.R32G32B32A32Float, 1,  1,  16, 4) },
+            { 0x49201, new FormatInfo(Format.R32G32B32A32Uint,  1,  1,  16, 4) },
+            { 0x36d81, new FormatInfo(Format.R32G32B32A32Sint,  1,  1,  16, 4) },
+            { 0x2493a, new FormatInfo(Format.D16Unorm,          1,  1,  2,  1) },
+            { 0x7ffaf, new FormatInfo(Format.D32Float,          1,  1,  4,  1) },
+            { 0x24a0e, new FormatInfo(Format.D24UnormS8Uint,    1,  1,  4,  2) },
+            { 0x24a29, new FormatInfo(Format.D24UnormS8Uint,    1,  1,  4,  2) },
+            { 0x25385, new FormatInfo(Format.D32FloatS8Uint,    1,  1,  8,  2) },
+            { 0x253b0, new FormatInfo(Format.D32FloatS8Uint,    1,  1,  8,  2) },
+            { 0xa4908, new FormatInfo(Format.R8G8B8A8Srgb,      1,  1,  4,  4) },
+            { 0x24912, new FormatInfo(Format.R4G4B4A4Unorm,     1,  1,  2,  4) },
+            { 0x24914, new FormatInfo(Format.R5G5B5A1Unorm,     1,  1,  2,  4) },
+            { 0x24915, new FormatInfo(Format.R5G6B5Unorm,       1,  1,  2,  3) },
+            { 0x24909, new FormatInfo(Format.R10G10B10A2Unorm,  1,  1,  4,  4) },
+            { 0x49209, new FormatInfo(Format.R10G10B10A2Uint,   1,  1,  4,  4) },
+            { 0x7ffa1, new FormatInfo(Format.R11G11B10Float,    1,  1,  4,  3) },
+            { 0x7ffa0, new FormatInfo(Format.R9G9B9E5Float,     1,  1,  4,  4) },
+            { 0x24924, new FormatInfo(Format.Bc1RgbaUnorm,      4,  4,  8,  4) },
+            { 0x24925, new FormatInfo(Format.Bc2Unorm,          4,  4,  16, 4) },
+            { 0x24926, new FormatInfo(Format.Bc3Unorm,          4,  4,  16, 4) },
+            { 0xa4924, new FormatInfo(Format.Bc1RgbaSrgb,       4,  4,  8,  4) },
+            { 0xa4925, new FormatInfo(Format.Bc2Srgb,           4,  4,  16, 4) },
+            { 0xa4926, new FormatInfo(Format.Bc3Srgb,           4,  4,  16, 4) },
+            { 0x24927, new FormatInfo(Format.Bc4Unorm,          4,  4,  8,  1) },
+            { 0x124a7, new FormatInfo(Format.Bc4Snorm,          4,  4,  8,  1) },
+            { 0x24928, new FormatInfo(Format.Bc5Unorm,          4,  4,  16, 2) },
+            { 0x124a8, new FormatInfo(Format.Bc5Snorm,          4,  4,  16, 2) },
+            { 0x24917, new FormatInfo(Format.Bc7Unorm,          4,  4,  16, 4) },
+            { 0xa4917, new FormatInfo(Format.Bc7Srgb,           4,  4,  16, 4) },
+            { 0x7ff90, new FormatInfo(Format.Bc6HSfloat,        4,  4,  16, 4) },
+            { 0x7ff91, new FormatInfo(Format.Bc6HUfloat,        4,  4,  16, 4) },
+            { 0x24940, new FormatInfo(Format.Astc4x4Unorm,      4,  4,  16, 4) },
+            { 0x24950, new FormatInfo(Format.Astc5x4Unorm,      5,  4,  16, 4) },
+            { 0x24941, new FormatInfo(Format.Astc5x5Unorm,      5,  5,  16, 4) },
+            { 0x24951, new FormatInfo(Format.Astc6x5Unorm,      6,  5,  16, 4) },
+            { 0x24942, new FormatInfo(Format.Astc6x6Unorm,      6,  6,  16, 4) },
+            { 0x24955, new FormatInfo(Format.Astc8x5Unorm,      8,  5,  16, 4) },
+            { 0x24952, new FormatInfo(Format.Astc8x6Unorm,      8,  6,  16, 4) },
+            { 0x24944, new FormatInfo(Format.Astc8x8Unorm,      8,  8,  16, 4) },
+            { 0x24956, new FormatInfo(Format.Astc10x5Unorm,     10, 5,  16, 4) },
+            { 0x24957, new FormatInfo(Format.Astc10x6Unorm,     10, 6,  16, 4) },
+            { 0x24953, new FormatInfo(Format.Astc10x8Unorm,     10, 8,  16, 4) },
+            { 0x24945, new FormatInfo(Format.Astc10x10Unorm,    10, 10, 16, 4) },
+            { 0x24954, new FormatInfo(Format.Astc12x10Unorm,    12, 10, 16, 4) },
+            { 0x24946, new FormatInfo(Format.Astc12x12Unorm,    12, 12, 16, 4) },
+            { 0xa4940, new FormatInfo(Format.Astc4x4Srgb,       4,  4,  16, 4) },
+            { 0xa4950, new FormatInfo(Format.Astc5x4Srgb,       5,  4,  16, 4) },
+            { 0xa4941, new FormatInfo(Format.Astc5x5Srgb,       5,  5,  16, 4) },
+            { 0xa4951, new FormatInfo(Format.Astc6x5Srgb,       6,  5,  16, 4) },
+            { 0xa4942, new FormatInfo(Format.Astc6x6Srgb,       6,  6,  16, 4) },
+            { 0xa4955, new FormatInfo(Format.Astc8x5Srgb,       8,  5,  16, 4) },
+            { 0xa4952, new FormatInfo(Format.Astc8x6Srgb,       8,  6,  16, 4) },
+            { 0xa4944, new FormatInfo(Format.Astc8x8Srgb,       8,  8,  16, 4) },
+            { 0xa4956, new FormatInfo(Format.Astc10x5Srgb,      10, 5,  16, 4) },
+            { 0xa4957, new FormatInfo(Format.Astc10x6Srgb,      10, 6,  16, 4) },
+            { 0xa4953, new FormatInfo(Format.Astc10x8Srgb,      10, 8,  16, 4) },
+            { 0xa4945, new FormatInfo(Format.Astc10x10Srgb,     10, 10, 16, 4) },
+            { 0xa4954, new FormatInfo(Format.Astc12x10Srgb,     12, 10, 16, 4) },
+            { 0xa4946, new FormatInfo(Format.Astc12x12Srgb,     12, 12, 16, 4) },
+            { 0x24913, new FormatInfo(Format.A1B5G5R5Unorm,     1,  1,  2,  4) }
         };
 
         private static Dictionary<ulong, Format> _attribFormats = new Dictionary<ulong, Format>()
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
index e8e3c2c24..22473a1b1 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
@@ -397,6 +397,49 @@ namespace Ryujinx.Graphics.Gpu.Image
             return result ? TextureViewCompatibility.Full : TextureViewCompatibility.Incompatible;
         }
 
+        /// <summary>
+        /// Checks if a swizzle component in two textures functionally match, taking into account if the components are defined.
+        /// </summary>
+        /// <param name="lhs">Texture information to compare</param>
+        /// <param name="rhs">Texture information to compare with</param>
+        /// <param name="swizzleLhs">Swizzle component for the first texture</param>
+        /// <param name="swizzleRhs">Swizzle component for the second texture</param>
+        /// <param name="component">Component index, starting at 0 for red</param>
+        /// <returns>True if the swizzle components functionally match, false othersize</returns>
+        private static bool SwizzleComponentMatches(TextureInfo lhs, TextureInfo rhs, SwizzleComponent swizzleLhs, SwizzleComponent swizzleRhs, int component)
+        {
+            int lhsComponents = lhs.FormatInfo.Components;
+            int rhsComponents = rhs.FormatInfo.Components;
+
+            if (lhsComponents == 4 && rhsComponents == 4)
+            {
+                return swizzleLhs == swizzleRhs;
+            }
+
+            // Swizzles after the number of components a format defines are "undefined".
+            // We allow these to not be equal under certain circumstances.
+            // This can only happen when there are less than 4 components in a format.
+            // It tends to happen when float depth textures are sampled.
+
+            bool lhsDefined = (swizzleLhs - SwizzleComponent.Red) < lhsComponents;
+            bool rhsDefined = (swizzleRhs - SwizzleComponent.Red) < rhsComponents;
+
+            if (lhsDefined == rhsDefined)
+            {
+                // If both are undefined, return true. Otherwise just check if they're equal.
+                return lhsDefined ? swizzleLhs == swizzleRhs : true;
+            }
+            else
+            {
+                SwizzleComponent defined = lhsDefined ? swizzleLhs : swizzleRhs;
+                SwizzleComponent undefined = lhsDefined ? swizzleRhs : swizzleLhs;
+
+                // Undefined swizzle can be matched by a forced value (0, 1), exact equality, or expected value.
+                // For example, R___ matches R001, RGBA but not RBGA.
+                return defined == undefined || defined < SwizzleComponent.Red || defined == SwizzleComponent.Red + component;
+            }
+        }
+
         /// <summary>
         /// Checks if the texture shader sampling parameters of two texture informations match.
         /// </summary>
@@ -406,10 +449,10 @@ namespace Ryujinx.Graphics.Gpu.Image
         public static bool SamplerParamsMatches(TextureInfo lhs, TextureInfo rhs)
         {
             return lhs.DepthStencilMode == rhs.DepthStencilMode &&
-                   lhs.SwizzleR         == rhs.SwizzleR &&
-                   lhs.SwizzleG         == rhs.SwizzleG &&
-                   lhs.SwizzleB         == rhs.SwizzleB &&
-                   lhs.SwizzleA         == rhs.SwizzleA;
+                   SwizzleComponentMatches(lhs, rhs, lhs.SwizzleR, rhs.SwizzleR, 0) &&
+                   SwizzleComponentMatches(lhs, rhs, lhs.SwizzleG, rhs.SwizzleG, 1) &&
+                   SwizzleComponentMatches(lhs, rhs, lhs.SwizzleB, rhs.SwizzleB, 2) &&
+                   SwizzleComponentMatches(lhs, rhs, lhs.SwizzleA, rhs.SwizzleA, 3);
         }
 
         /// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
index 0b1d38d10..f8720695d 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
@@ -398,7 +398,7 @@ namespace Ryujinx.Graphics.Gpu.Image
             // While upscaling works for all targets defined by IsUpscaleCompatible, we additionally blacklist targets here that
             // may have undesirable results (upscaling blur textures) or simply waste GPU resources (upscaling texture atlas).
 
-            if (!(info.FormatInfo.Format.IsDepthOrStencil() || info.FormatInfo.Format.HasOneComponent()))
+            if (!(info.FormatInfo.Format.IsDepthOrStencil() || info.FormatInfo.Components == 1))
             {
                 // Discount square textures that aren't depth-stencil like. (excludes game textures, cubemap faces, most 3D texture LUT, texture atlas)
                 // Detect if the texture is possibly square. Widths may be aligned, so to remove the uncertainty we align both the width and height.
@@ -1037,11 +1037,11 @@ namespace Ryujinx.Graphics.Gpu.Image
             {
                 if (formatInfo.Format.IsAstcUnorm())
                 {
-                    formatInfo = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4);
+                    formatInfo = new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4);
                 }
                 else if (formatInfo.Format.IsAstcSrgb())
                 {
-                    formatInfo = new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4);
+                    formatInfo = new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4);
                 }
             }
 
@@ -1052,12 +1052,12 @@ namespace Ryujinx.Graphics.Gpu.Image
                 // The shader will need the appropriate conversion code to compensate.
                 switch (formatInfo.Format)
                 {
-                    case Format.R8Snorm:           formatInfo = new FormatInfo(Format.R8Sint,           1, 1, 1); break;
-                    case Format.R16Snorm:          formatInfo = new FormatInfo(Format.R16Sint,          1, 1, 2); break;
-                    case Format.R8G8Snorm:         formatInfo = new FormatInfo(Format.R8G8Sint,         1, 1, 2); break;
-                    case Format.R16G16Snorm:       formatInfo = new FormatInfo(Format.R16G16Sint,       1, 1, 4); break;
-                    case Format.R8G8B8A8Snorm:     formatInfo = new FormatInfo(Format.R8G8B8A8Sint,     1, 1, 4); break;
-                    case Format.R16G16B16A16Snorm: formatInfo = new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8); break;
+                    case Format.R8Snorm:           formatInfo = new FormatInfo(Format.R8Sint,           1, 1, 1, 1); break;
+                    case Format.R16Snorm:          formatInfo = new FormatInfo(Format.R16Sint,          1, 1, 2, 1); break;
+                    case Format.R8G8Snorm:         formatInfo = new FormatInfo(Format.R8G8Sint,         1, 1, 2, 2); break;
+                    case Format.R16G16Snorm:       formatInfo = new FormatInfo(Format.R16G16Sint,       1, 1, 4, 2); break;
+                    case Format.R8G8B8A8Snorm:     formatInfo = new FormatInfo(Format.R8G8B8A8Sint,     1, 1, 4, 4); break;
+                    case Format.R16G16B16A16Snorm: formatInfo = new FormatInfo(Format.R16G16B16A16Sint, 1, 1, 8, 4); break;
                 }
             }
 
diff --git a/Ryujinx.Graphics.Gpu/State/RtFormat.cs b/Ryujinx.Graphics.Gpu/State/RtFormat.cs
index ffd2492b6..f20ad2cda 100644
--- a/Ryujinx.Graphics.Gpu/State/RtFormat.cs
+++ b/Ryujinx.Graphics.Gpu/State/RtFormat.cs
@@ -81,66 +81,66 @@ namespace Ryujinx.Graphics.Gpu.State
         {
             return format switch
             {
-                RtFormat.D32Float          => new FormatInfo(Format.D32Float,          1, 1, 4),
-                RtFormat.D16Unorm          => new FormatInfo(Format.D16Unorm,          1, 1, 2),
-                RtFormat.D24UnormS8Uint    => new FormatInfo(Format.D24UnormS8Uint,    1, 1, 4),
-                RtFormat.D24Unorm          => new FormatInfo(Format.D24UnormS8Uint,    1, 1, 4),
-                RtFormat.S8UintD24Unorm    => new FormatInfo(Format.D24UnormS8Uint,    1, 1, 4),
-                RtFormat.S8Uint            => new FormatInfo(Format.S8Uint,            1, 1, 1),
-                RtFormat.D32FloatS8Uint    => new FormatInfo(Format.D32FloatS8Uint,    1, 1, 8),
-                RtFormat.R32G32B32A32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16),
-                RtFormat.R32G32B32A32Sint  => new FormatInfo(Format.R32G32B32A32Sint,  1, 1, 16),
-                RtFormat.R32G32B32A32Uint  => new FormatInfo(Format.R32G32B32A32Uint,  1, 1, 16),
-                RtFormat.R32G32B32X32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16),
-                RtFormat.R32G32B32X32Sint  => new FormatInfo(Format.R32G32B32A32Sint,  1, 1, 16),
-                RtFormat.R32G32B32X32Uint  => new FormatInfo(Format.R32G32B32A32Uint,  1, 1, 16),
-                RtFormat.R16G16B16X16Unorm => new FormatInfo(Format.R16G16B16A16Unorm, 1, 1, 8),
-                RtFormat.R16G16B16X16Snorm => new FormatInfo(Format.R16G16B16A16Snorm, 1, 1, 8),
-                RtFormat.R16G16B16X16Sint  => new FormatInfo(Format.R16G16B16A16Sint,  1, 1, 8),
-                RtFormat.R16G16B16X16Uint  => new FormatInfo(Format.R16G16B16A16Uint,  1, 1, 8),
-                RtFormat.R16G16B16A16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8),
-                RtFormat.R32G32Float       => new FormatInfo(Format.R32G32Float,       1, 1, 8),
-                RtFormat.R32G32Sint        => new FormatInfo(Format.R32G32Sint,        1, 1, 8),
-                RtFormat.R32G32Uint        => new FormatInfo(Format.R32G32Uint,        1, 1, 8),
-                RtFormat.R16G16B16X16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8),
-                RtFormat.B8G8R8A8Unorm     => new FormatInfo(Format.B8G8R8A8Unorm,     1, 1, 4),
-                RtFormat.B8G8R8A8Srgb      => new FormatInfo(Format.B8G8R8A8Srgb,      1, 1, 4),
-                RtFormat.R10G10B10A2Unorm  => new FormatInfo(Format.R10G10B10A2Unorm,  1, 1, 4),
-                RtFormat.R10G10B10A2Uint   => new FormatInfo(Format.R10G10B10A2Uint,   1, 1, 4),
-                RtFormat.R8G8B8A8Unorm     => new FormatInfo(Format.R8G8B8A8Unorm,     1, 1, 4),
-                RtFormat.R8G8B8A8Srgb      => new FormatInfo(Format.R8G8B8A8Srgb,      1, 1, 4),
-                RtFormat.R8G8B8X8Snorm     => new FormatInfo(Format.R8G8B8A8Snorm,     1, 1, 4),
-                RtFormat.R8G8B8X8Sint      => new FormatInfo(Format.R8G8B8A8Sint,      1, 1, 4),
-                RtFormat.R8G8B8X8Uint      => new FormatInfo(Format.R8G8B8A8Uint,      1, 1, 4),
-                RtFormat.R16G16Unorm       => new FormatInfo(Format.R16G16Unorm,       1, 1, 4),
-                RtFormat.R16G16Snorm       => new FormatInfo(Format.R16G16Snorm,       1, 1, 4),
-                RtFormat.R16G16Sint        => new FormatInfo(Format.R16G16Sint,        1, 1, 4),
-                RtFormat.R16G16Uint        => new FormatInfo(Format.R16G16Uint,        1, 1, 4),
-                RtFormat.R16G16Float       => new FormatInfo(Format.R16G16Float,       1, 1, 4),
-                RtFormat.R11G11B10Float    => new FormatInfo(Format.R11G11B10Float,    1, 1, 4),
-                RtFormat.R32Sint           => new FormatInfo(Format.R32Sint,           1, 1, 4),
-                RtFormat.R32Uint           => new FormatInfo(Format.R32Uint,           1, 1, 4),
-                RtFormat.R32Float          => new FormatInfo(Format.R32Float,          1, 1, 4),
-                RtFormat.B8G8R8X8Unorm     => new FormatInfo(Format.B8G8R8A8Unorm,     1, 1, 4),
-                RtFormat.B8G8R8X8Srgb      => new FormatInfo(Format.B8G8R8A8Srgb,      1, 1, 4),
-                RtFormat.B5G6R5Unorm       => new FormatInfo(Format.B5G6R5Unorm,       1, 1, 2),
-                RtFormat.B5G5R5A1Unorm     => new FormatInfo(Format.B5G5R5A1Unorm,     1, 1, 2),
-                RtFormat.R8G8Unorm         => new FormatInfo(Format.R8G8Unorm,         1, 1, 2),
-                RtFormat.R8G8Snorm         => new FormatInfo(Format.R8G8Snorm,         1, 1, 2),
-                RtFormat.R8G8Sint          => new FormatInfo(Format.R8G8Sint,          1, 1, 2),
-                RtFormat.R8G8Uint          => new FormatInfo(Format.R8G8Uint,          1, 1, 2),
-                RtFormat.R16Unorm          => new FormatInfo(Format.R16Unorm,          1, 1, 2),
-                RtFormat.R16Snorm          => new FormatInfo(Format.R16Snorm,          1, 1, 2),
-                RtFormat.R16Sint           => new FormatInfo(Format.R16Sint,           1, 1, 2),
-                RtFormat.R16Uint           => new FormatInfo(Format.R16Uint,           1, 1, 2),
-                RtFormat.R16Float          => new FormatInfo(Format.R16Float,          1, 1, 2),
-                RtFormat.R8Unorm           => new FormatInfo(Format.R8Unorm,           1, 1, 1),
-                RtFormat.R8Snorm           => new FormatInfo(Format.R8Snorm,           1, 1, 1),
-                RtFormat.R8Sint            => new FormatInfo(Format.R8Sint,            1, 1, 1),
-                RtFormat.R8Uint            => new FormatInfo(Format.R8Uint,            1, 1, 1),
-                RtFormat.B5G5R5X1Unorm     => new FormatInfo(Format.B5G5R5X1Unorm,     1, 1, 2),
-                RtFormat.R8G8B8X8Unorm     => new FormatInfo(Format.R8G8B8A8Unorm,     1, 1, 4),
-                RtFormat.R8G8B8X8Srgb      => new FormatInfo(Format.R8G8B8A8Srgb,      1, 1, 4),
+                RtFormat.D32Float          => new FormatInfo(Format.D32Float,          1, 1, 4,  1),
+                RtFormat.D16Unorm          => new FormatInfo(Format.D16Unorm,          1, 1, 2,  1),
+                RtFormat.D24UnormS8Uint    => new FormatInfo(Format.D24UnormS8Uint,    1, 1, 4,  2),
+                RtFormat.D24Unorm          => new FormatInfo(Format.D24UnormS8Uint,    1, 1, 4,  1),
+                RtFormat.S8UintD24Unorm    => new FormatInfo(Format.D24UnormS8Uint,    1, 1, 4,  2),
+                RtFormat.S8Uint            => new FormatInfo(Format.S8Uint,            1, 1, 1,  1),
+                RtFormat.D32FloatS8Uint    => new FormatInfo(Format.D32FloatS8Uint,    1, 1, 8,  2),
+                RtFormat.R32G32B32A32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16, 4),
+                RtFormat.R32G32B32A32Sint  => new FormatInfo(Format.R32G32B32A32Sint,  1, 1, 16, 4),
+                RtFormat.R32G32B32A32Uint  => new FormatInfo(Format.R32G32B32A32Uint,  1, 1, 16, 4),
+                RtFormat.R32G32B32X32Float => new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16, 4),
+                RtFormat.R32G32B32X32Sint  => new FormatInfo(Format.R32G32B32A32Sint,  1, 1, 16, 4),
+                RtFormat.R32G32B32X32Uint  => new FormatInfo(Format.R32G32B32A32Uint,  1, 1, 16, 4),
+                RtFormat.R16G16B16X16Unorm => new FormatInfo(Format.R16G16B16A16Unorm, 1, 1, 8,  4),
+                RtFormat.R16G16B16X16Snorm => new FormatInfo(Format.R16G16B16A16Snorm, 1, 1, 8,  4),
+                RtFormat.R16G16B16X16Sint  => new FormatInfo(Format.R16G16B16A16Sint,  1, 1, 8,  4),
+                RtFormat.R16G16B16X16Uint  => new FormatInfo(Format.R16G16B16A16Uint,  1, 1, 8,  4),
+                RtFormat.R16G16B16A16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8,  4),
+                RtFormat.R32G32Float       => new FormatInfo(Format.R32G32Float,       1, 1, 8,  2),
+                RtFormat.R32G32Sint        => new FormatInfo(Format.R32G32Sint,        1, 1, 8,  2),
+                RtFormat.R32G32Uint        => new FormatInfo(Format.R32G32Uint,        1, 1, 8,  2),
+                RtFormat.R16G16B16X16Float => new FormatInfo(Format.R16G16B16A16Float, 1, 1, 8,  4),
+                RtFormat.B8G8R8A8Unorm     => new FormatInfo(Format.B8G8R8A8Unorm,     1, 1, 4,  4),
+                RtFormat.B8G8R8A8Srgb      => new FormatInfo(Format.B8G8R8A8Srgb,      1, 1, 4,  4),
+                RtFormat.R10G10B10A2Unorm  => new FormatInfo(Format.R10G10B10A2Unorm,  1, 1, 4,  4),
+                RtFormat.R10G10B10A2Uint   => new FormatInfo(Format.R10G10B10A2Uint,   1, 1, 4,  4),
+                RtFormat.R8G8B8A8Unorm     => new FormatInfo(Format.R8G8B8A8Unorm,     1, 1, 4,  4),
+                RtFormat.R8G8B8A8Srgb      => new FormatInfo(Format.R8G8B8A8Srgb,      1, 1, 4,  4),
+                RtFormat.R8G8B8X8Snorm     => new FormatInfo(Format.R8G8B8A8Snorm,     1, 1, 4,  4),
+                RtFormat.R8G8B8X8Sint      => new FormatInfo(Format.R8G8B8A8Sint,      1, 1, 4,  4),
+                RtFormat.R8G8B8X8Uint      => new FormatInfo(Format.R8G8B8A8Uint,      1, 1, 4,  4),
+                RtFormat.R16G16Unorm       => new FormatInfo(Format.R16G16Unorm,       1, 1, 4,  2),
+                RtFormat.R16G16Snorm       => new FormatInfo(Format.R16G16Snorm,       1, 1, 4,  2),
+                RtFormat.R16G16Sint        => new FormatInfo(Format.R16G16Sint,        1, 1, 4,  2),
+                RtFormat.R16G16Uint        => new FormatInfo(Format.R16G16Uint,        1, 1, 4,  2),
+                RtFormat.R16G16Float       => new FormatInfo(Format.R16G16Float,       1, 1, 4,  2),
+                RtFormat.R11G11B10Float    => new FormatInfo(Format.R11G11B10Float,    1, 1, 4,  3),
+                RtFormat.R32Sint           => new FormatInfo(Format.R32Sint,           1, 1, 4,  1),
+                RtFormat.R32Uint           => new FormatInfo(Format.R32Uint,           1, 1, 4,  1),
+                RtFormat.R32Float          => new FormatInfo(Format.R32Float,          1, 1, 4,  1),
+                RtFormat.B8G8R8X8Unorm     => new FormatInfo(Format.B8G8R8A8Unorm,     1, 1, 4,  4),
+                RtFormat.B8G8R8X8Srgb      => new FormatInfo(Format.B8G8R8A8Srgb,      1, 1, 4,  4),
+                RtFormat.B5G6R5Unorm       => new FormatInfo(Format.B5G6R5Unorm,       1, 1, 2,  3),
+                RtFormat.B5G5R5A1Unorm     => new FormatInfo(Format.B5G5R5A1Unorm,     1, 1, 2,  4),
+                RtFormat.R8G8Unorm         => new FormatInfo(Format.R8G8Unorm,         1, 1, 2,  2),
+                RtFormat.R8G8Snorm         => new FormatInfo(Format.R8G8Snorm,         1, 1, 2,  2),
+                RtFormat.R8G8Sint          => new FormatInfo(Format.R8G8Sint,          1, 1, 2,  2),
+                RtFormat.R8G8Uint          => new FormatInfo(Format.R8G8Uint,          1, 1, 2,  2),
+                RtFormat.R16Unorm          => new FormatInfo(Format.R16Unorm,          1, 1, 2,  1),
+                RtFormat.R16Snorm          => new FormatInfo(Format.R16Snorm,          1, 1, 2,  1),
+                RtFormat.R16Sint           => new FormatInfo(Format.R16Sint,           1, 1, 2,  1),
+                RtFormat.R16Uint           => new FormatInfo(Format.R16Uint,           1, 1, 2,  1),
+                RtFormat.R16Float          => new FormatInfo(Format.R16Float,          1, 1, 2,  1),
+                RtFormat.R8Unorm           => new FormatInfo(Format.R8Unorm,           1, 1, 1,  1),
+                RtFormat.R8Snorm           => new FormatInfo(Format.R8Snorm,           1, 1, 1,  1),
+                RtFormat.R8Sint            => new FormatInfo(Format.R8Sint,            1, 1, 1,  1),
+                RtFormat.R8Uint            => new FormatInfo(Format.R8Uint,            1, 1, 1,  1),
+                RtFormat.B5G5R5X1Unorm     => new FormatInfo(Format.B5G5R5X1Unorm,     1, 1, 2,  4),
+                RtFormat.R8G8B8X8Unorm     => new FormatInfo(Format.R8G8B8A8Unorm,     1, 1, 4,  4),
+                RtFormat.R8G8B8X8Srgb      => new FormatInfo(Format.R8G8B8A8Srgb,      1, 1, 4,  4),
                 _                          => FormatInfo.Default
             };
         }
diff --git a/Ryujinx.Graphics.Gpu/Window.cs b/Ryujinx.Graphics.Gpu/Window.cs
index 10ee74bec..cf5c01efc 100644
--- a/Ryujinx.Graphics.Gpu/Window.cs
+++ b/Ryujinx.Graphics.Gpu/Window.cs
@@ -112,7 +112,7 @@ namespace Ryujinx.Graphics.Gpu
             Action<object>             releaseCallback,
             object                     userObj)
         {
-            FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel);
+            FormatInfo formatInfo = new FormatInfo(format, 1, 1, bytesPerPixel, 4);
 
             TextureInfo info = new TextureInfo(
                 address,