diff --git a/Ryujinx.Graphics.GAL/IRenderer.cs b/Ryujinx.Graphics.GAL/IRenderer.cs
index a119320822..a36d999d60 100644
--- a/Ryujinx.Graphics.GAL/IRenderer.cs
+++ b/Ryujinx.Graphics.GAL/IRenderer.cs
@@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.GAL
 
         BufferHandle CreateBuffer(int size);
 
-        IProgram CreateProgram(IShader[] shaders);
+        IProgram CreateProgram(IShader[] shaders, ShaderInfo info);
 
         ISampler CreateSampler(SamplerCreateInfo info);
         ITexture CreateTexture(TextureCreateInfo info, float scale);
@@ -33,7 +33,7 @@ namespace Ryujinx.Graphics.GAL
 
         Capabilities GetCapabilities();
 
-        IProgram LoadProgramBinary(byte[] programBinary);
+        IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info);
 
         void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan<byte> data);
 
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/BinaryProgramRequest.cs b/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/BinaryProgramRequest.cs
index 96bfedf8dd..b4c6853f25 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/BinaryProgramRequest.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/BinaryProgramRequest.cs
@@ -5,17 +5,21 @@
         public ThreadedProgram Threaded { get; set; }
 
         private byte[] _data;
+        private bool _hasFragmentShader;
+        private ShaderInfo _info;
 
-        public BinaryProgramRequest(ThreadedProgram program, byte[] data)
+        public BinaryProgramRequest(ThreadedProgram program, byte[] data, bool hasFragmentShader, ShaderInfo info)
         {
             Threaded = program;
 
             _data = data;
+            _hasFragmentShader = hasFragmentShader;
+            _info = info;
         }
 
         public IProgram Create(IRenderer renderer)
         {
-            return renderer.LoadProgramBinary(_data);
+            return renderer.LoadProgramBinary(_data, _hasFragmentShader, _info);
         }
     }
 }
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs b/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs
index 8e4cd1d49c..d808fe2216 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Resources/Programs/SourceProgramRequest.cs
@@ -7,12 +7,14 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
         public ThreadedProgram Threaded { get; set; }
 
         private IShader[] _shaders;
+        private ShaderInfo _info;
 
-        public SourceProgramRequest(ThreadedProgram program, IShader[] shaders)
+        public SourceProgramRequest(ThreadedProgram program, IShader[] shaders, ShaderInfo info)
         {
             Threaded = program;
 
             _shaders = shaders;
+            _info = info;
         }
 
         public IProgram Create(IRenderer renderer)
@@ -24,7 +26,7 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources.Programs
                 return threaded?.Base;
             }).ToArray();
 
-            return renderer.CreateProgram(shaders);
+            return renderer.CreateProgram(shaders, _info);
         }
     }
 }
diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs
index df46b42897..5030fee623 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedRenderer.cs
@@ -268,10 +268,10 @@ namespace Ryujinx.Graphics.GAL.Multithreading
             return handle;
         }
 
-        public IProgram CreateProgram(IShader[] shaders)
+        public IProgram CreateProgram(IShader[] shaders, ShaderInfo info)
         {
             var program = new ThreadedProgram(this);
-            SourceProgramRequest request = new SourceProgramRequest(program, shaders);
+            SourceProgramRequest request = new SourceProgramRequest(program, shaders, info);
             Programs.Add(request);
 
             New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
@@ -355,11 +355,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading
             _baseRenderer.Initialize(logLevel);
         }
 
-        public IProgram LoadProgramBinary(byte[] programBinary)
+        public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
         {
             var program = new ThreadedProgram(this);
 
-            BinaryProgramRequest request = new BinaryProgramRequest(program, programBinary);
+            BinaryProgramRequest request = new BinaryProgramRequest(program, programBinary, hasFragmentShader, info);
             Programs.Add(request);
 
             New<CreateProgramCommand>().Set(Ref((IProgramRequest)request));
diff --git a/Ryujinx.Graphics.GAL/ShaderInfo.cs b/Ryujinx.Graphics.GAL/ShaderInfo.cs
new file mode 100644
index 0000000000..0c187e0666
--- /dev/null
+++ b/Ryujinx.Graphics.GAL/ShaderInfo.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Graphics.GAL
+{
+    public struct ShaderInfo
+    {
+        public int FragmentOutputMap { get; }
+
+        public ShaderInfo(int fragmentOutputMap)
+        {
+            FragmentOutputMap = fragmentOutputMap;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs
index 68f6b3c1d9..819c6bcc90 100644
--- a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntry.cs
@@ -77,7 +77,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
                                                     programInfo.Images.Count,
                                                     programInfo.UsesInstanceId,
                                                     programInfo.UsesRtLayer,
-                                                    programInfo.ClipDistancesWritten);
+                                                    programInfo.ClipDistancesWritten,
+                                                    programInfo.FragmentOutputMap);
             CBuffers = programInfo.CBuffers.ToArray();
             SBuffers = programInfo.SBuffers.ToArray();
             Textures = programInfo.Textures.ToArray();
@@ -97,7 +98,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
                 Images,
                 Header.UseFlags.HasFlag(UseFlags.InstanceId),
                 Header.UseFlags.HasFlag(UseFlags.RtLayer),
-                Header.ClipDistancesWritten);
+                Header.ClipDistancesWritten,
+                Header.FragmentOutputMap);
         }
 
         /// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs
index 4b8b15bc21..c3c0de22f7 100644
--- a/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/Cache/Definition/HostShaderCacheEntryHeader.cs
@@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
     /// <summary>
     /// Host shader entry header used for binding information.
     /// </summary>
-    [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x14)]
+    [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 0x18)]
     struct HostShaderCacheEntryHeader
     {
         /// <summary>
@@ -70,6 +70,11 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
         /// </summary>
         public byte Reserved;
 
+        /// <summary>
+        /// Mask of components written by the fragment shader stage.
+        /// </summary>
+        public int FragmentOutputMap;
+
         /// <summary>
         /// Create a new host shader cache entry header.
         /// </summary>
@@ -78,6 +83,8 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
         /// <param name="texturesCount">Count of texture descriptors</param>
         /// <param name="imagesCount">Count of image descriptors</param>
         /// <param name="usesInstanceId">Set to true if the shader uses instance id</param>
+        /// <param name="clipDistancesWritten">Mask of clip distances that are written to on the shader</param>
+        /// <param name="fragmentOutputMap">Mask of components written by the fragment shader stage</param>
         public HostShaderCacheEntryHeader(
             int cBuffersCount,
             int sBuffersCount,
@@ -85,13 +92,15 @@ namespace Ryujinx.Graphics.Gpu.Shader.Cache.Definition
             int imagesCount,
             bool usesInstanceId,
             bool usesRtLayer,
-            byte clipDistancesWritten) : this()
+            byte clipDistancesWritten,
+            int fragmentOutputMap) : this()
         {
             CBuffersCount        = cBuffersCount;
             SBuffersCount        = sBuffersCount;
             TexturesCount        = texturesCount;
             ImagesCount          = imagesCount;
             ClipDistancesWritten = clipDistancesWritten;
+            FragmentOutputMap    = fragmentOutputMap;
             InUse                = true;
 
             UseFlags = usesInstanceId ? UseFlags.InstanceId : UseFlags.None;
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index f1e9f383db..bf76d592f9 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
         /// <summary>
         /// Version of the codegen (to be changed when codegen or guest format change).
         /// </summary>
-        private const ulong ShaderCodeGenVersion = 3106;
+        private const ulong ShaderCodeGenVersion = 3063;
 
         // Progress reporting helpers
         private volatile int _shaderCount;
@@ -188,7 +188,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
                             {
                                 hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
                                 hostProgramBinary = hostProgramBinarySpan.ToArray();
-                                hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
+                                hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary, false, new ShaderInfo(-1));
                             }
 
                             ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
@@ -252,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
 
                                         // Compile shader and create program as the shader program binary got invalidated.
                                         shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, program.Code);
-                                        hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader });
+                                        hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, new ShaderInfo(-1));
 
                                         task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
                                         {
@@ -303,7 +303,18 @@ namespace Ryujinx.Graphics.Gpu.Shader
                             {
                                 hostShaderEntries = HostShaderCacheEntry.Parse(hostProgramBinary, out ReadOnlySpan<byte> hostProgramBinarySpan);
                                 hostProgramBinary = hostProgramBinarySpan.ToArray();
-                                hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary);
+
+                                bool hasFragmentShader = false;
+                                int fragmentOutputMap = -1;
+                                int fragmentIndex = (int)ShaderStage.Fragment - 1;
+
+                                if (hostShaderEntries[fragmentIndex] != null && hostShaderEntries[fragmentIndex].Header.InUse)
+                                {
+                                    hasFragmentShader = true;
+                                    fragmentOutputMap = hostShaderEntries[fragmentIndex].Header.FragmentOutputMap;
+                                }
+
+                                hostProgram = _context.Renderer.LoadProgramBinary(hostProgramBinary, hasFragmentShader, new ShaderInfo(fragmentOutputMap));
                             }
 
                             ShaderCompileTask task = new ShaderCompileTask(taskDoneEvent);
@@ -426,7 +437,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
                                             hostShaders.Add(hostShader);
                                         }
 
-                                        hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray());
+                                        int fragmentIndex = (int)ShaderStage.Fragment - 1;
+                                        int fragmentOutputMap = -1;
+
+                                        if (shaders[fragmentIndex] != null)
+                                        {
+                                            fragmentOutputMap = shaders[fragmentIndex].Info.FragmentOutputMap;
+                                        }
+
+                                        hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), new ShaderInfo(fragmentOutputMap));
 
                                         task.OnCompiled(hostProgram, (bool isNewProgramValid, ShaderCompileTask task) =>
                                         {
@@ -617,7 +636,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
 
                 shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code);
 
-                IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader });
+                IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, new ShaderInfo(-1));
 
                 cpShader = new ShaderBundle(hostProgram, shader);
 
@@ -755,7 +774,15 @@ namespace Ryujinx.Graphics.Gpu.Shader
                     hostShaders.Add(hostShader);
                 }
 
-                IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray());
+                int fragmentIndex = (int)ShaderStage.Fragment - 1;
+                int fragmentOutputMap = -1;
+
+                if (shaders[fragmentIndex] != null)
+                {
+                    fragmentOutputMap = shaders[fragmentIndex].Info.FragmentOutputMap;
+                }
+
+                IProgram hostProgram = _context.Renderer.CreateProgram(hostShaders.ToArray(), new ShaderInfo(fragmentOutputMap));
 
                 gpShaders = new ShaderBundle(hostProgram, shaders);
 
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index ff5af42d13..c20ce8a328 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -53,7 +53,9 @@ namespace Ryujinx.Graphics.OpenGL
         private ClipOrigin _clipOrigin;
         private ClipDepthMode _clipDepthMode;
 
-        private readonly uint[] _componentMasks;
+        private uint _fragmentOutputMap;
+        private uint _componentMasks;
+        private uint _currentComponentMasks;
 
         private uint _scissorEnables;
 
@@ -73,12 +75,8 @@ namespace Ryujinx.Graphics.OpenGL
             _clipOrigin = ClipOrigin.LowerLeft;
             _clipDepthMode = ClipDepthMode.NegativeOneToOne;
 
-            _componentMasks = new uint[Constants.MaxRenderTargets];
-
-            for (int index = 0; index < Constants.MaxRenderTargets; index++)
-            {
-                _componentMasks[index] = 0xf;
-            }
+            _fragmentOutputMap = uint.MaxValue;
+            _componentMasks = uint.MaxValue;
 
             var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f };
             new Span<Vector4<float>>(_renderScale).Fill(defaultScale);
@@ -1001,18 +999,30 @@ namespace Ryujinx.Graphics.OpenGL
 
         public void SetProgram(IProgram program)
         {
-            _program = (Program)program;
+            Program prg = (Program)program;
 
             if (_tfEnabled)
             {
                 GL.EndTransformFeedback();
-                _program.Bind();
+                prg.Bind();
                 GL.BeginTransformFeedback(_tfTopology);
             }
             else
             {
-                _program.Bind();
+                prg.Bind();
             }
+
+            if (prg.HasFragmentShader && _fragmentOutputMap != (uint)prg.FragmentOutputMap)
+            {
+                _fragmentOutputMap = (uint)prg.FragmentOutputMap;
+
+                for (int index = 0; index < Constants.MaxRenderTargets; index++)
+                {
+                    RestoreComponentMask(index, force: false);
+                }
+            }
+
+            _program = prg;
         }
 
         public void SetRasterizerDiscard(bool discard)
@@ -1037,11 +1047,13 @@ namespace Ryujinx.Graphics.OpenGL
 
         public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMasks)
         {
+            _componentMasks = 0;
+
             for (int index = 0; index < componentMasks.Length; index++)
             {
-                _componentMasks[index] = componentMasks[index];
+                _componentMasks |= componentMasks[index] << (index * 4);
 
-                RestoreComponentMask(index);
+                RestoreComponentMask(index, force: false);
             }
         }
 
@@ -1436,18 +1448,34 @@ namespace Ryujinx.Graphics.OpenGL
             }
         }
 
-        public void RestoreComponentMask(int index)
+        public void RestoreComponentMask(int index, bool force = true)
         {
             // If the bound render target is bgra, swap the red and blue masks.
             uint redMask = _fpIsBgra[index].X == 0 ? 1u : 4u;
             uint blueMask = _fpIsBgra[index].X == 0 ? 4u : 1u;
 
+            int shift = index * 4;
+            uint componentMask = _componentMasks & _fragmentOutputMap;
+            uint checkMask = 0xfu << shift;
+            uint componentMaskAtIndex = componentMask & checkMask;
+
+            if (!force && componentMaskAtIndex == (_currentComponentMasks & checkMask))
+            {
+                return;
+            }
+
+            componentMask >>= shift;
+            componentMask &= 0xfu;
+
             GL.ColorMask(
                 index,
-                (_componentMasks[index] & redMask) != 0,
-                (_componentMasks[index] & 2u) != 0,
-                (_componentMasks[index] & blueMask) != 0,
-                (_componentMasks[index] & 8u) != 0);
+                (componentMask & redMask) != 0,
+                (componentMask & 2u) != 0,
+                (componentMask & blueMask) != 0,
+                (componentMask & 8u) != 0);
+
+            _currentComponentMasks &= ~checkMask;
+            _currentComponentMasks |= componentMaskAtIndex;
         }
 
         public void RestoreScissor0Enable()
diff --git a/Ryujinx.Graphics.OpenGL/Program.cs b/Ryujinx.Graphics.OpenGL/Program.cs
index 959029903d..838162ccdc 100644
--- a/Ryujinx.Graphics.OpenGL/Program.cs
+++ b/Ryujinx.Graphics.OpenGL/Program.cs
@@ -1,11 +1,8 @@
 using OpenTK.Graphics.OpenGL;
 using Ryujinx.Common.Logging;
 using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Shader.CodeGen.Glsl;
 using System;
 using System.Buffers.Binary;
-using System.Collections.Generic;
-using System.Linq;
 
 namespace Ryujinx.Graphics.OpenGL
 {
@@ -29,7 +26,10 @@ namespace Ryujinx.Graphics.OpenGL
         private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
         private IShader[] _shaders;
 
-        public Program(IShader[] shaders)
+        public bool HasFragmentShader;
+        public int FragmentOutputMap { get; }
+
+        public Program(IShader[] shaders, int fragmentOutputMap)
         {
             Handle = GL.CreateProgram();
 
@@ -37,17 +37,23 @@ namespace Ryujinx.Graphics.OpenGL
 
             for (int index = 0; index < shaders.Length; index++)
             {
-                int shaderHandle = ((Shader)shaders[index]).Handle;
+                Shader shader = (Shader)shaders[index];
 
-                GL.AttachShader(Handle, shaderHandle);
+                if (shader.IsFragment)
+                {
+                    HasFragmentShader = true;
+                }
+
+                GL.AttachShader(Handle, shader.Handle);
             }
 
             GL.LinkProgram(Handle);
 
             _shaders = shaders;
+            FragmentOutputMap = fragmentOutputMap;
         }
 
-        public Program(ReadOnlySpan<byte> code)
+        public Program(ReadOnlySpan<byte> code, bool hasFragmentShader, int fragmentOutputMap)
         {
             BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4));
 
@@ -60,6 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
                     GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
                 }
             }
+
+            HasFragmentShader = hasFragmentShader;
+            FragmentOutputMap = fragmentOutputMap;
         }
 
         public void Bind()
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index 8d44f2e447..a99ecfcc2b 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -66,9 +66,9 @@ namespace Ryujinx.Graphics.OpenGL
             return Buffer.Create(size);
         }
 
-        public IProgram CreateProgram(IShader[] shaders)
+        public IProgram CreateProgram(IShader[] shaders, ShaderInfo info)
         {
-            return new Program(shaders);
+            return new Program(shaders, info.FragmentOutputMap);
         }
 
         public ISampler CreateSampler(SamplerCreateInfo info)
@@ -202,9 +202,9 @@ namespace Ryujinx.Graphics.OpenGL
             _sync.Dispose();
         }
 
-        public IProgram LoadProgramBinary(byte[] programBinary)
+        public IProgram LoadProgramBinary(byte[] programBinary, bool hasFragmentShader, ShaderInfo info)
         {
-            return new Program(programBinary);
+            return new Program(programBinary, hasFragmentShader, info.FragmentOutputMap);
         }
 
         public void CreateSync(ulong id)
diff --git a/Ryujinx.Graphics.OpenGL/Shader.cs b/Ryujinx.Graphics.OpenGL/Shader.cs
index 1df07ee42d..8374fa6269 100644
--- a/Ryujinx.Graphics.OpenGL/Shader.cs
+++ b/Ryujinx.Graphics.OpenGL/Shader.cs
@@ -7,6 +7,7 @@ namespace Ryujinx.Graphics.OpenGL
     class Shader : IShader
     {
         public int Handle { get; private set; }
+        public bool IsFragment { get; }
 
         public Shader(ShaderStage stage, string code)
         {
@@ -22,6 +23,7 @@ namespace Ryujinx.Graphics.OpenGL
             };
 
             Handle = GL.CreateShader(type);
+            IsFragment = stage == ShaderStage.Fragment;
 
             GL.ShaderSource(Handle, code);
             GL.CompileShader(Handle);
diff --git a/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs b/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs
index a9ce486b69..d1c1b94571 100644
--- a/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs
+++ b/Ryujinx.Graphics.Shader/ShaderProgramInfo.cs
@@ -5,32 +5,35 @@ namespace Ryujinx.Graphics.Shader
 {
     public class ShaderProgramInfo
     {
-        public ReadOnlyCollection<BufferDescriptor>  CBuffers { get; }
-        public ReadOnlyCollection<BufferDescriptor>  SBuffers { get; }
+        public ReadOnlyCollection<BufferDescriptor> CBuffers { get; }
+        public ReadOnlyCollection<BufferDescriptor> SBuffers { get; }
         public ReadOnlyCollection<TextureDescriptor> Textures { get; }
-        public ReadOnlyCollection<TextureDescriptor> Images   { get; }
+        public ReadOnlyCollection<TextureDescriptor> Images { get; }
 
         public bool UsesInstanceId { get; }
         public bool UsesRtLayer { get; }
         public byte ClipDistancesWritten { get; }
+        public int FragmentOutputMap { get; }
 
         public ShaderProgramInfo(
-            BufferDescriptor[]  cBuffers,
-            BufferDescriptor[]  sBuffers,
+            BufferDescriptor[] cBuffers,
+            BufferDescriptor[] sBuffers,
             TextureDescriptor[] textures,
             TextureDescriptor[] images,
-            bool                usesInstanceId,
-            bool                usesRtLayer,
-            byte                clipDistancesWritten)
+            bool usesInstanceId,
+            bool usesRtLayer,
+            byte clipDistancesWritten,
+            int fragmentOutputMap)
         {
             CBuffers = Array.AsReadOnly(cBuffers);
             SBuffers = Array.AsReadOnly(sBuffers);
             Textures = Array.AsReadOnly(textures);
-            Images   = Array.AsReadOnly(images);
+            Images = Array.AsReadOnly(images);
 
             UsesInstanceId = usesInstanceId;
             UsesRtLayer = usesRtLayer;
             ClipDistancesWritten = clipDistancesWritten;
+            FragmentOutputMap = fragmentOutputMap;
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 3dcb04ade9..775f121794 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -172,11 +172,10 @@ namespace Ryujinx.Graphics.Shader.Translation
 
                 for (int rtIndex = 0; rtIndex < 8; rtIndex++)
                 {
-                    OmapTarget target = Config.OmapTargets[rtIndex];
-
                     for (int component = 0; component < 4; component++)
                     {
-                        if (!target.ComponentEnabled(component))
+                        bool componentEnabled = (Config.OmapTargets & (1 << (rtIndex * 4 + component))) != 0;
+                        if (!componentEnabled)
                         {
                             continue;
                         }
@@ -210,7 +209,8 @@ namespace Ryujinx.Graphics.Shader.Translation
                         }
                     }
 
-                    if (target.Enabled)
+                    bool targetEnabled = (Config.OmapTargets & (0xf << (rtIndex * 4))) != 0;
+                    if (targetEnabled)
                     {
                         Config.SetOutputUserAttribute(rtIndex, perPatch: false);
                         regIndexBase += 4;
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 21f170414c..996c2814b5 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -25,9 +25,9 @@ namespace Ryujinx.Graphics.Shader.Translation
 
         public ImapPixelType[] ImapTypes { get; }
 
-        public OmapTarget[] OmapTargets    { get; }
-        public bool         OmapSampleMask { get; }
-        public bool         OmapDepth      { get; }
+        public int OmapTargets { get; }
+        public bool OmapSampleMask { get; }
+        public bool OmapDepth { get; }
 
         public IGpuAccessor GpuAccessor { get; }
 
@@ -135,21 +135,8 @@ namespace Ryujinx.Graphics.Shader.Translation
 
         public int GetDepthRegister()
         {
-            int count = 0;
-
-            for (int index = 0; index < OmapTargets.Length; index++)
-            {
-                for (int component = 0; component < 4; component++)
-                {
-                    if (OmapTargets[index].ComponentEnabled(component))
-                    {
-                        count++;
-                    }
-                }
-            }
-
             // The depth register is always two registers after the last color output.
-            return count + 1;
+            return BitOperations.PopCount((uint)OmapTargets) + 1;
         }
 
         public TextureFormat GetTextureFormat(int handle, int cbufSlot = -1)
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
index 0ad172da88..e53c77af0e 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
@@ -36,37 +36,6 @@ namespace Ryujinx.Graphics.Shader.Translation
         }
     }
 
-    struct OmapTarget
-    {
-        public bool Red   { get; }
-        public bool Green { get; }
-        public bool Blue  { get; }
-        public bool Alpha { get; }
-
-        public bool Enabled => Red || Green || Blue || Alpha;
-
-        public OmapTarget(bool red, bool green, bool blue, bool alpha)
-        {
-            Red   = red;
-            Green = green;
-            Blue  = blue;
-            Alpha = 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 ArgumentOutOfRangeException(nameof(component));
-        }
-    }
-
     class ShaderHeader
     {
         public int SphType { get; }
@@ -85,7 +54,7 @@ namespace Ryujinx.Graphics.Shader.Translation
         public bool GpPassthrough { get; }
 
         public bool DoesLoadOrStore { get; }
-        public bool DoesFp64        { get; }
+        public bool DoesFp64 { get; }
 
         public int StreamOutMask { get; }
 
@@ -104,13 +73,13 @@ namespace Ryujinx.Graphics.Shader.Translation
         public int MaxOutputVertexCount { get; }
 
         public int StoreReqStart { get; }
-        public int StoreReqEnd   { get; }
+        public int StoreReqEnd { get; }
 
         public ImapPixelType[] ImapTypes { get; }
 
-        public OmapTarget[] OmapTargets    { get; }
-        public bool         OmapSampleMask { get; }
-        public bool         OmapDepth      { get; }
+        public int OmapTargets { get; }
+        public bool OmapSampleMask { get; }
+        public bool OmapDepth { get; }
 
         public ShaderHeader(IGpuAccessor gpuAccessor, ulong address)
         {
@@ -144,7 +113,7 @@ namespace Ryujinx.Graphics.Shader.Translation
             GpPassthrough = commonWord0.Extract(24);
 
             DoesLoadOrStore = commonWord0.Extract(26);
-            DoesFp64        = commonWord0.Extract(27);
+            DoesFp64 = commonWord0.Extract(27);
 
             StreamOutMask = commonWord0.Extract(28, 4);
 
@@ -163,7 +132,7 @@ namespace Ryujinx.Graphics.Shader.Translation
             MaxOutputVertexCount = commonWord4.Extract(0, 12);
 
             StoreReqStart = commonWord4.Extract(12, 8);
-            StoreReqEnd   = commonWord4.Extract(24, 8);
+            StoreReqEnd = commonWord4.Extract(24, 8);
 
             ImapTypes = new ImapPixelType[32];
 
@@ -179,21 +148,11 @@ namespace Ryujinx.Graphics.Shader.Translation
             }
 
             int type2OmapTarget = header[18];
-            int type2Omap       = header[19];
-
-            OmapTargets = new OmapTarget[8];
-
-            for (int offset = 0; offset < OmapTargets.Length * 4; offset += 4)
-            {
-                OmapTargets[offset >> 2] = new OmapTarget(
-                    type2OmapTarget.Extract(offset + 0),
-                    type2OmapTarget.Extract(offset + 1),
-                    type2OmapTarget.Extract(offset + 2),
-                    type2OmapTarget.Extract(offset + 3));
-            }
+            int type2Omap = header[19];
 
+            OmapTargets = type2OmapTarget;
             OmapSampleMask = type2Omap.Extract(0);
-            OmapDepth      = type2Omap.Extract(1);
+            OmapDepth = type2Omap.Extract(1);
         }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index 709b16db44..603b20d649 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -105,7 +105,8 @@ namespace Ryujinx.Graphics.Shader.Translation
                 config.GetImageDescriptors(),
                 config.UsedFeatures.HasFlag(FeatureFlags.InstanceId),
                 config.UsedFeatures.HasFlag(FeatureFlags.RtLayer),
-                config.ClipDistancesWritten);
+                config.ClipDistancesWritten,
+                config.OmapTargets);
 
             return program;
         }