diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
index 46841d48a..84de8bd6e 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/CodeGenContext.cs
@@ -57,6 +57,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 
         private readonly Dictionary<AstBlock, BlockState> _labels = new Dictionary<AstBlock, BlockState>();
 
+        public Dictionary<AstBlock, (Instruction, Instruction)> LoopTargets { get; set; }
+
         public AstBlock CurrentBlock { get; private set; }
 
         public CodeGenContext(ShaderConfig config) : base(0x00010300)
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
index f5d9e70db..3375e8d64 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/Instructions.cs
@@ -95,6 +95,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
             Add(Instruction.LogicalNot,               GenerateLogicalNot);
             Add(Instruction.LogicalOr,                GenerateLogicalOr);
             Add(Instruction.LoopBreak,                GenerateLoopBreak);
+            Add(Instruction.LoopContinue,             GenerateLoopContinue);
             Add(Instruction.Maximum,                  GenerateMaximum);
             Add(Instruction.MaximumU32,               GenerateMaximumU32);
             Add(Instruction.MemoryBarrier,            GenerateMemoryBarrier);
@@ -963,6 +964,21 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
             return OperationResult.Invalid;
         }
 
+        private static OperationResult GenerateLoopContinue(CodeGenContext context, AstOperation operation)
+        {
+            AstBlock loopBlock = context.CurrentBlock;
+            while (loopBlock.Type != AstBlockType.DoWhile)
+            {
+                loopBlock = loopBlock.Parent;
+            }
+
+            (var loopTarget, var continueTarget) = context.LoopTargets[loopBlock];
+
+            context.Branch(continueTarget);
+
+            return OperationResult.Invalid;
+        }
+
         private static OperationResult GenerateMaximum(CodeGenContext context, AstOperation operation)
         {
             return GenerateBinary(context, operation, context.GlslFMax, context.GlslSMax);
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs b/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs
index 1a2157f24..67caa18e9 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Spirv/SpirvGenerator.cs
@@ -130,6 +130,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
 
             var loopTargets = new Dictionary<AstBlock, (SpvInstruction, SpvInstruction)>();
 
+            context.LoopTargets = loopTargets;
+
             visitor.BlockEntered += (sender, e) =>
             {
                 AstBlock mergeBlock = e.Block.Parent;
@@ -192,6 +194,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
                         bool lastIsCf = e.Block.Last is AstOperation lastOp &&
                             (lastOp.Inst == Instruction.Discard ||
                              lastOp.Inst == Instruction.LoopBreak ||
+                             lastOp.Inst == Instruction.LoopContinue ||
                              lastOp.Inst == Instruction.Return);
 
                         if (!lastIsCf)