diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index fb58f84a6c..b1291906cd 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -365,11 +365,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
             foreach (int attr in info.IAttributes.OrderBy(x => x))
             {
-                string iq = info.InterpolationQualifiers[attr].ToGlslQualifier();
+                string iq = string.Empty;
 
-                if (iq != string.Empty)
+                if (context.Config.Stage == ShaderStage.Fragment)
                 {
-                    iq += " ";
+                    iq = context.Config.ImapTypes[attr].GetFirstUsedType() switch
+                    {
+                        PixelImap.Constant => "flat ",
+                        PixelImap.ScreenLinear => "noperspective ",
+                        _ => string.Empty
+                    };
                 }
 
                 context.AppendLine($"layout (location = {attr}) {iq}in vec4 {DefaultNames.IAttributePrefix}{attr}{suffix};");
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
index 2de55b2ddd..8d092d4e7c 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
@@ -188,7 +188,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
                             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";
+                            case AttributeConsts.PositionW: return "gl_FragCoord.w";
                         }
                     }
 
diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
index 1fddcc8cac..7eb8888316 100644
--- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
+++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs
@@ -96,17 +96,27 @@ namespace Ryujinx.Graphics.Shader.Instructions
         {
             OpCodeIpa op = (OpCodeIpa)context.CurrOp;
 
-            InterpolationQualifier iq = InterpolationQualifier.None;
+            Operand res = Attribute(op.AttributeOffset);
 
-            switch (op.Mode)
+            if (op.AttributeOffset >= AttributeConsts.UserAttributeBase &&
+                op.AttributeOffset <  AttributeConsts.UserAttributeEnd)
             {
-                case InterpolationMode.Constant: iq = InterpolationQualifier.Flat;          break;
-                case InterpolationMode.Pass:     iq = InterpolationQualifier.NoPerspective; break;
+                int index = (op.AttributeOffset - AttributeConsts.UserAttributeBase) >> 4;
+
+                if (context.Config.ImapTypes[index].GetFirstUsedType() == PixelImap.Perspective)
+                {
+                    res = context.FPMultiply(res, Attribute(AttributeConsts.PositionW));
+                }
+            }
+ 
+            if (op.Mode == InterpolationMode.Default)
+            {
+                Operand srcB = GetSrcB(context);
+
+                res = context.FPMultiply(res, srcB);
             }
 
-            Operand srcA = Attribute(op.AttributeOffset, iq);
-
-            Operand res = context.FPSaturate(srcA, op.Saturate);
+            res = context.FPSaturate(res, op.Saturate);
 
             context.Copy(GetDest(context), res);
         }
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs
index 567277a75b..1df88a3d9b 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs
@@ -14,8 +14,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
 
         public int Value { get; }
 
-        public InterpolationQualifier Interpolation { get; }
-
         public INode AsgOp { get; set; }
 
         public HashSet<INode> UseOps { get; }
@@ -30,11 +28,10 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
             Type = type;
         }
 
-        public Operand(OperandType type, int value, InterpolationQualifier iq = InterpolationQualifier.None) : this()
+        public Operand(OperandType type, int value) : this()
         {
-            Type          = type;
-            Value         = value;
-            Interpolation = iq;
+            Type  = type;
+            Value = value;
         }
 
         public Operand(Register reg) : this()
diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs
index 45c9ba1e55..6765f8a44f 100644
--- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs
+++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs
@@ -5,9 +5,9 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
 {
     static class OperandHelper
     {
-        public static Operand Attribute(int value, InterpolationQualifier iq = InterpolationQualifier.None)
+        public static Operand Attribute(int value)
         {
-            return new Operand(OperandType.Attribute, value, iq);
+            return new Operand(OperandType.Attribute, value);
         }
 
         public static Operand Cbuf(int slot, int offset)
diff --git a/Ryujinx.Graphics.Shader/InterpolationQualifier.cs b/Ryujinx.Graphics.Shader/InterpolationQualifier.cs
deleted file mode 100644
index b7a0c1c9a8..0000000000
--- a/Ryujinx.Graphics.Shader/InterpolationQualifier.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-using System;
-
-namespace Ryujinx.Graphics.Shader
-{
-    [Flags]
-    enum InterpolationQualifier
-    {
-        None = 0,
-
-        Flat          = 1,
-        NoPerspective = 2,
-        Smooth        = 3,
-
-        Centroid = 1 << 16,
-        Sample   = 1 << 17,
-
-        FlagsMask = Centroid | Sample
-    }
-
-    static class InterpolationQualifierExtensions
-    {
-        public static string ToGlslQualifier(this InterpolationQualifier iq)
-        {
-            string output = (iq & ~InterpolationQualifier.FlagsMask) switch
-            {
-                InterpolationQualifier.Flat => "flat",
-                InterpolationQualifier.NoPerspective => "noperspective",
-                InterpolationQualifier.Smooth => "smooth",
-                _ => string.Empty
-            };
-
-            if ((iq & InterpolationQualifier.Centroid) != 0)
-            {
-                output = "centroid " + output;
-            }
-            else if ((iq & InterpolationQualifier.Sample) != 0)
-            {
-                output = "sample " + output;
-            }
-
-            return output;
-        }
-    }
-}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/ShaderProgram.cs b/Ryujinx.Graphics.Shader/ShaderProgram.cs
index 4d0c6e5bd6..7a800d8c73 100644
--- a/Ryujinx.Graphics.Shader/ShaderProgram.cs
+++ b/Ryujinx.Graphics.Shader/ShaderProgram.cs
@@ -24,10 +24,5 @@ namespace Ryujinx.Graphics.Shader
         {
             Code = line + Environment.NewLine + Code;
         }
-
-        public void Replace(string name, string value)
-        {
-            Code = Code.Replace(name, value);
-        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/AstOperand.cs b/Ryujinx.Graphics.Shader/StructuredIr/AstOperand.cs
index 25b09636fe..97ff3ca97c 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/AstOperand.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/AstOperand.cs
@@ -12,8 +12,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 
         public VariableType VarType { get; set; }
 
-        public InterpolationQualifier Interpolation { get; }
-
         public int Value { get; }
 
         public int CbufSlot   { get; }
@@ -29,8 +27,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 
         public AstOperand(Operand operand) : this()
         {
-            Type          = operand.Type;
-            Interpolation = operand.Interpolation;
+            Type = operand.Type;
 
             if (Type == OperandType.ConstantBuffer)
             {
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs
index f2af84f3b5..b7d5efbe54 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs
@@ -273,8 +273,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
             if (TryGetUserAttributeIndex(operand, out int attrIndex))
             {
                 Info.IAttributes.Add(attrIndex);
-
-                Info.InterpolationQualifiers[attrIndex] = operand.Interpolation;
             }
             else if (operand.Type == OperandType.Attribute && operand.Value == AttributeConsts.InstanceId)
             {
diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs
index 0ef4bde340..be79f00e2a 100644
--- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs
+++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs
@@ -14,8 +14,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
         public HashSet<int> IAttributes { get; }
         public HashSet<int> OAttributes { get; }
 
-        public InterpolationQualifier[] InterpolationQualifiers { get; }
-
         public bool UsesInstanceId { get; set; }
 
         public HelperFunctionsMask HelperFunctionsMask { get; set; }
@@ -35,8 +33,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
             IAttributes = new HashSet<int>();
             OAttributes = new HashSet<int>();
 
-            InterpolationQualifiers = new InterpolationQualifier[32];
-
             Samplers = new HashSet<AstTextureOperation>();
             Images   = new HashSet<AstTextureOperation>();
         }
diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
index 7111196b79..8044f074a7 100644
--- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
+++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs
@@ -76,7 +76,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 
                 for (int attachment = 0; attachment < 8; attachment++)
                 {
-                    OutputMapTarget target = _config.OmapTargets[attachment];
+                    OmapTarget target = _config.OmapTargets[attachment];
 
                     for (int component = 0; component < 4; component++)
                     {
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index e3708b41d6..60660847b1 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -12,9 +12,11 @@ namespace Ryujinx.Graphics.Shader.Translation
 
         public int LocalMemorySize { get; }
 
-        public OutputMapTarget[] OmapTargets    { get; }
-        public bool              OmapSampleMask { get; }
-        public bool              OmapDepth      { get; }
+        public ImapPixelType[] ImapTypes { get; }
+
+        public OmapTarget[] OmapTargets    { get; }
+        public bool         OmapSampleMask { get; }
+        public bool         OmapDepth      { get; }
 
         public TranslationFlags Flags { get; }
 
@@ -26,6 +28,7 @@ namespace Ryujinx.Graphics.Shader.Translation
             OutputTopology    = OutputTopology.PointList;
             MaxOutputVertices = 0;
             LocalMemorySize   = 0;
+            ImapTypes         = null;
             OmapTargets       = null;
             OmapSampleMask    = false;
             OmapDepth         = false;
@@ -39,6 +42,7 @@ namespace Ryujinx.Graphics.Shader.Translation
             OutputTopology    = header.OutputTopology;
             MaxOutputVertices = header.MaxOutputVertexCount;
             LocalMemorySize   = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize;
+            ImapTypes         = header.ImapTypes;
             OmapTargets       = header.OmapTargets;
             OmapSampleMask    = header.OmapSampleMask;
             OmapDepth         = header.OmapDepth;
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
index 42701fbdca..a3b861c979 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs
@@ -4,7 +4,39 @@ using System.Runtime.InteropServices;
 
 namespace Ryujinx.Graphics.Shader.Translation
 {
-    struct OutputMapTarget
+    enum PixelImap
+    {
+        Unused = 0,
+        Constant = 1,
+        Perspective = 2,
+        ScreenLinear = 3
+    }
+
+    struct ImapPixelType
+    {
+        public PixelImap X { get; }
+        public PixelImap Y { get; }
+        public PixelImap Z { get; }
+        public PixelImap W { get; }
+
+        public ImapPixelType(PixelImap x, PixelImap y, PixelImap z, PixelImap w)
+        {
+            X = x;
+            Y = y;
+            Z = z;
+            W = w;
+        }
+
+        public PixelImap GetFirstUsedType()
+        {
+            if (X != PixelImap.Unused) return X;
+            if (Y != PixelImap.Unused) return Y;
+            if (Z != PixelImap.Unused) return Z;
+            return W;
+        }
+    }
+
+    struct OmapTarget
     {
         public bool Red   { get; }
         public bool Green { get; }
@@ -13,7 +45,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 
         public bool Enabled => Red || Green || Blue || Alpha;
 
-        public OutputMapTarget(bool red, bool green, bool blue, bool alpha)
+        public OmapTarget(bool red, bool green, bool blue, bool alpha)
         {
             Red   = red;
             Green = green;
@@ -72,9 +104,11 @@ namespace Ryujinx.Graphics.Shader.Translation
         public int StoreReqStart { get; }
         public int StoreReqEnd   { get; }
 
-        public OutputMapTarget[] OmapTargets    { get; }
-        public bool              OmapSampleMask { get; }
-        public bool              OmapDepth      { get; }
+        public ImapPixelType[] ImapTypes { get; }
+
+        public OmapTarget[] OmapTargets    { get; }
+        public bool         OmapSampleMask { get; }
+        public bool         OmapDepth      { get; }
 
         public ShaderHeader(ReadOnlySpan<byte> code)
         {
@@ -127,14 +161,30 @@ namespace Ryujinx.Graphics.Shader.Translation
             StoreReqStart = commonWord4.Extract(12, 8);
             StoreReqEnd   = commonWord4.Extract(24, 8);
 
+            ImapTypes = new ImapPixelType[32];
+
+            for (int i = 0; i < 8; i++)
+            {
+                for (int j = 0; j < 4; j++)
+                {
+                    byte imap = (byte)(header[6 + i] >> (j * 8));
+
+                    ImapTypes[i * 4 + j] = new ImapPixelType(
+                        (PixelImap)((imap >> 0) & 3),
+                        (PixelImap)((imap >> 2) & 3),
+                        (PixelImap)((imap >> 4) & 3),
+                        (PixelImap)((imap >> 6) & 3));
+                }
+            }
+
             int type2OmapTarget = header[18];
             int type2Omap       = header[19];
 
-            OmapTargets = new OutputMapTarget[8];
+            OmapTargets = new OmapTarget[8];
 
             for (int offset = 0; offset < OmapTargets.Length * 4; offset += 4)
             {
-                OmapTargets[offset >> 2] = new OutputMapTarget(
+                OmapTargets[offset >> 2] = new OmapTarget(
                     type2OmapTarget.Extract(offset + 0),
                     type2OmapTarget.Extract(offset + 1),
                     type2OmapTarget.Extract(offset + 2),