diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index e4a91058c9..30c8b78164 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -226,7 +226,8 @@ struct Regs {
             Texture1               = 0x4,
             Texture2               = 0x5,
             Texture3               = 0x6,
-            // 0x7-0xc = primary color??
+
+            PreviousBuffer         = 0xd,
             Constant               = 0xe,
             Previous               = 0xf,
         };
@@ -309,11 +310,36 @@ struct Regs {
     TevStageConfig tev_stage2;
     INSERT_PADDING_WORDS(0x3);
     TevStageConfig tev_stage3;
-    INSERT_PADDING_WORDS(0x13);
+    INSERT_PADDING_WORDS(0x3);
+
+    union {
+        // Tev stages 0-3 write their output to the combiner buffer if the corresponding bit in
+        // these masks are set
+        BitField< 8, 4, u32> update_mask_rgb;
+        BitField<12, 4, u32> update_mask_a;
+
+        bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
+            return (stage_index < 4) && (update_mask_rgb & (1 << stage_index));
+        }
+
+        bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
+            return (stage_index < 4) && (update_mask_a & (1 << stage_index));
+        }
+    } tev_combiner_buffer_input;
+    
+    INSERT_PADDING_WORDS(0xf);
     TevStageConfig tev_stage4;
     INSERT_PADDING_WORDS(0x3);
     TevStageConfig tev_stage5;
-    INSERT_PADDING_WORDS(0x3);
+
+    union {
+        BitField< 0, 8, u32> r;
+        BitField< 8, 8, u32> g;
+        BitField<16, 8, u32> b;
+        BitField<24, 8, u32> a;
+    } tev_combiner_buffer_color;
+
+    INSERT_PADDING_WORDS(0x2);
 
     const std::array<Regs::TevStageConfig,6> GetTevStages() const {
         return { tev_stage0, tev_stage1,
@@ -784,8 +810,10 @@ struct Regs {
         ADD_FIELD(tev_stage1);
         ADD_FIELD(tev_stage2);
         ADD_FIELD(tev_stage3);
+        ADD_FIELD(tev_combiner_buffer_input);
         ADD_FIELD(tev_stage4);
         ADD_FIELD(tev_stage5);
+        ADD_FIELD(tev_combiner_buffer_color);
         ADD_FIELD(output_merger);
         ADD_FIELD(framebuffer);
         ADD_FIELD(vertex_attributes);
@@ -859,8 +887,10 @@ ASSERT_REG_POSITION(tev_stage0, 0xc0);
 ASSERT_REG_POSITION(tev_stage1, 0xc8);
 ASSERT_REG_POSITION(tev_stage2, 0xd0);
 ASSERT_REG_POSITION(tev_stage3, 0xd8);
+ASSERT_REG_POSITION(tev_combiner_buffer_input, 0xe0);
 ASSERT_REG_POSITION(tev_stage4, 0xf0);
 ASSERT_REG_POSITION(tev_stage5, 0xf8);
+ASSERT_REG_POSITION(tev_combiner_buffer_color, 0xfd);
 ASSERT_REG_POSITION(output_merger, 0x100);
 ASSERT_REG_POSITION(framebuffer, 0x110);
 ASSERT_REG_POSITION(vertex_attributes, 0x200);
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 3b36afad95..7bdb503c89 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -376,7 +376,13 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
             // with some basic arithmetic. Alpha combiners can be configured separately but work
             // analogously.
             Math::Vec4<u8> combiner_output;
-            for (const auto& tev_stage : tev_stages) {
+            Math::Vec4<u8> combiner_buffer = {
+                registers.tev_combiner_buffer_color.r, registers.tev_combiner_buffer_color.g,
+                registers.tev_combiner_buffer_color.b, registers.tev_combiner_buffer_color.a
+            };
+
+            for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
+                const auto& tev_stage = tev_stages[tev_stage_index];
                 using Source = Regs::TevStageConfig::Source;
                 using ColorModifier = Regs::TevStageConfig::ColorModifier;
                 using AlphaModifier = Regs::TevStageConfig::AlphaModifier;
@@ -398,6 +404,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
                     case Source::Texture2:
                         return texture_color[2];
 
+                    case Source::PreviousBuffer:
+                        return combiner_buffer;
+
                     case Source::Constant:
                         return {tev_stage.const_r, tev_stage.const_g, tev_stage.const_b, tev_stage.const_a};
 
@@ -579,6 +588,16 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
                 auto alpha_output = AlphaCombine(tev_stage.alpha_op, alpha_result);
 
                 combiner_output = Math::MakeVec(color_output, alpha_output);
+
+                if (registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index)) {
+                    combiner_buffer.r() = combiner_output.r();
+                    combiner_buffer.g() = combiner_output.g();
+                    combiner_buffer.b() = combiner_output.b();
+                }
+
+                if (registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) {
+                    combiner_buffer.a() = combiner_output.a();
+                }
             }
 
             if (registers.output_merger.alpha_test.enable) {