Support for independentBlend feature

A few blend related context members were changed from scalars to
arrays in order to support independent blend.

Bug b/140193782

Change-Id: I5ca1153e952fe0d3899f68dc6cd7cc5d8a244b72
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/34113
Tested-by: Alexis Hétu <sugoi@google.com>
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Device/Context.cpp b/src/Device/Context.cpp
index c0f8ec1..af55417 100644
--- a/src/Device/Context.cpp
+++ b/src/Device/Context.cpp
@@ -24,6 +24,19 @@
 
 namespace sw
 {
+	void BlendState::init()
+	{
+		alphaBlendEnable = false;
+
+		sourceBlendFactor = VK_BLEND_FACTOR_ONE;
+		destBlendFactor = VK_BLEND_FACTOR_ZERO;
+		blendOperation = VK_BLEND_OP_ADD;
+
+		sourceBlendFactorAlpha = VK_BLEND_FACTOR_ONE;
+		destBlendFactorAlpha = VK_BLEND_FACTOR_ZERO;
+		blendOperationAlpha = VK_BLEND_OP_ADD;
+	}
+
 	Context::Context()
 	{
 		init();
@@ -88,6 +101,8 @@
 		for(int i = 0; i < RENDERTARGETS; ++i)
 		{
 			renderTarget[i] = nullptr;
+
+			blendState[i].init();
 		}
 		depthBuffer = nullptr;
 		stencilBuffer = nullptr;
@@ -103,15 +118,6 @@
 		depthBufferEnable = false;
 		depthWriteEnable = false;
 
-		alphaBlendEnable = false;
-		sourceBlendFactorState = VK_BLEND_FACTOR_ONE;
-		destBlendFactorState = VK_BLEND_FACTOR_ZERO;
-		blendOperationState = VK_BLEND_OP_ADD;
-
-		sourceBlendFactorStateAlpha = VK_BLEND_FACTOR_ONE;
-		destBlendFactorStateAlpha = VK_BLEND_FACTOR_ZERO;
-		blendOperationStateAlpha = VK_BLEND_OP_ADD;
-
 		cullMode = VK_CULL_MODE_FRONT_BIT;
 		frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
 
@@ -153,9 +159,33 @@
 		return stencilBuffer && stencilEnable;
 	}
 
-	bool Context::alphaBlendActive() const
+	void Context::setBlendState(int index, BlendState state)
 	{
-		if(!alphaBlendEnable)
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
+
+		blendState[index] = state;
+	}
+
+	BlendState Context::getBlendState(int index) const
+	{
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
+
+		BlendState activeBlendState;
+		activeBlendState.alphaBlendEnable = alphaBlendActive(index);
+		activeBlendState.sourceBlendFactor = sourceBlendFactor(index);
+		activeBlendState.destBlendFactor = destBlendFactor(index);
+		activeBlendState.blendOperation = blendOperation(index);
+		activeBlendState.sourceBlendFactorAlpha = sourceBlendFactorAlpha(index);
+		activeBlendState.destBlendFactorAlpha = destBlendFactorAlpha(index);
+		activeBlendState.blendOperationAlpha = blendOperationAlpha(index);
+		return activeBlendState;
+	}
+
+	bool Context::alphaBlendActive(int index) const
+	{
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
+
+		if(!blendState[index].alphaBlendEnable)
 		{
 			return false;
 		}
@@ -165,22 +195,24 @@
 			return false;
 		}
 
-		bool colorBlend = !(blendOperation() == VK_BLEND_OP_SRC_EXT && sourceBlendFactor() == VK_BLEND_FACTOR_ONE);
-		bool alphaBlend = !(blendOperationAlpha() == VK_BLEND_OP_SRC_EXT && sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ONE);
+		bool colorBlend = !(blendOperation(index) == VK_BLEND_OP_SRC_EXT && sourceBlendFactor(index) == VK_BLEND_FACTOR_ONE);
+		bool alphaBlend = !(blendOperationAlpha(index) == VK_BLEND_OP_SRC_EXT && sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE);
 
 		return colorBlend || alphaBlend;
 	}
 
-	VkBlendFactor Context::sourceBlendFactor() const
+	VkBlendFactor Context::sourceBlendFactor(int index) const
 	{
-		if(!alphaBlendEnable) return VK_BLEND_FACTOR_ONE;
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
 
-		switch(blendOperationState)
+		if(!blendState[index].alphaBlendEnable) return VK_BLEND_FACTOR_ONE;
+
+		switch(blendState[index].blendOperation)
 		{
 		case VK_BLEND_OP_ADD:
 		case VK_BLEND_OP_SUBTRACT:
 		case VK_BLEND_OP_REVERSE_SUBTRACT:
-			return sourceBlendFactorState;
+			return blendState[index].sourceBlendFactor;
 		case VK_BLEND_OP_MIN:
 			return VK_BLEND_FACTOR_ONE;
 		case VK_BLEND_OP_MAX:
@@ -189,19 +221,21 @@
 			ASSERT(false);
 		}
 
-		return sourceBlendFactorState;
+		return blendState[index].sourceBlendFactor;
 	}
 
-	VkBlendFactor Context::destBlendFactor() const
+	VkBlendFactor Context::destBlendFactor(int index) const
 	{
-		if(!alphaBlendEnable) return VK_BLEND_FACTOR_ONE;
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
 
-		switch(blendOperationState)
+		if(!blendState[index].alphaBlendEnable) return VK_BLEND_FACTOR_ONE;
+
+		switch(blendState[index].blendOperation)
 		{
 		case VK_BLEND_OP_ADD:
 		case VK_BLEND_OP_SUBTRACT:
 		case VK_BLEND_OP_REVERSE_SUBTRACT:
-			return destBlendFactorState;
+			return blendState[index].destBlendFactor;
 		case VK_BLEND_OP_MIN:
 			return VK_BLEND_FACTOR_ONE;
 		case VK_BLEND_OP_MAX:
@@ -210,7 +244,7 @@
 			ASSERT(false);
 		}
 
-		return destBlendFactorState;
+		return blendState[index].destBlendFactor;
 	}
 
 	bool Context::allTargetsColorClamp() const
@@ -227,16 +261,18 @@
 		return true;
 	}
 
-	VkBlendOp Context::blendOperation() const
+	VkBlendOp Context::blendOperation(int index) const
 	{
-		if(!alphaBlendEnable) return VK_BLEND_OP_SRC_EXT;
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
 
-		switch(blendOperationState)
+		if(!blendState[index].alphaBlendEnable) return VK_BLEND_OP_SRC_EXT;
+
+		switch(blendState[index].blendOperation)
 		{
 		case VK_BLEND_OP_ADD:
-			if(sourceBlendFactor() == VK_BLEND_FACTOR_ZERO)
+			if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ZERO)
 			{
-				if(destBlendFactor() == VK_BLEND_FACTOR_ZERO)
+				if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_ZERO_EXT;
 				}
@@ -245,9 +281,9 @@
 					return VK_BLEND_OP_DST_EXT;
 				}
 			}
-			else if(sourceBlendFactor() == VK_BLEND_FACTOR_ONE)
+			else if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ONE)
 			{
-				if(destBlendFactor() == VK_BLEND_FACTOR_ZERO)
+				if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_SRC_EXT;
 				}
@@ -258,7 +294,7 @@
 			}
 			else
 			{
-				if(destBlendFactor() == VK_BLEND_FACTOR_ZERO)
+				if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_SRC_EXT;
 				}
@@ -268,13 +304,13 @@
 				}
 			}
 		case VK_BLEND_OP_SUBTRACT:
-			if(sourceBlendFactor() == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
+			if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
 			{
 				return VK_BLEND_OP_ZERO_EXT;   // Negative, clamped to zero
 			}
-			else if(sourceBlendFactor() == VK_BLEND_FACTOR_ONE)
+			else if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ONE)
 			{
-				if(destBlendFactor() == VK_BLEND_FACTOR_ZERO)
+				if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_SRC_EXT;
 				}
@@ -285,7 +321,7 @@
 			}
 			else
 			{
-				if(destBlendFactor() == VK_BLEND_FACTOR_ZERO)
+				if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_SRC_EXT;
 				}
@@ -295,9 +331,9 @@
 				}
 			}
 		case VK_BLEND_OP_REVERSE_SUBTRACT:
-			if(sourceBlendFactor() == VK_BLEND_FACTOR_ZERO)
+			if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ZERO)
 			{
-				if(destBlendFactor() == VK_BLEND_FACTOR_ZERO)
+				if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_ZERO_EXT;
 				}
@@ -306,9 +342,9 @@
 					return VK_BLEND_OP_DST_EXT;
 				}
 			}
-			else if(sourceBlendFactor() == VK_BLEND_FACTOR_ONE)
+			else if(sourceBlendFactor(index) == VK_BLEND_FACTOR_ONE)
 			{
-				if(destBlendFactor() == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
+				if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
 				{
 					return VK_BLEND_OP_ZERO_EXT;   // Negative, clamped to zero
 				}
@@ -319,7 +355,7 @@
 			}
 			else
 			{
-				if(destBlendFactor() == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
+				if(destBlendFactor(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
 				{
 					return VK_BLEND_OP_ZERO_EXT;   // Negative, clamped to zero
 				}
@@ -336,17 +372,19 @@
 			ASSERT(false);
 		}
 
-		return blendOperationState;
+		return blendState[index].blendOperation;
 	}
 
-	VkBlendFactor Context::sourceBlendFactorAlpha() const
+	VkBlendFactor Context::sourceBlendFactorAlpha(int index) const
 	{
-		switch (blendOperationStateAlpha)
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
+
+		switch (blendState[index].blendOperationAlpha)
 		{
 		case VK_BLEND_OP_ADD:
 		case VK_BLEND_OP_SUBTRACT:
 		case VK_BLEND_OP_REVERSE_SUBTRACT:
-			return sourceBlendFactorStateAlpha;
+			return blendState[index].sourceBlendFactorAlpha;
 		case VK_BLEND_OP_MIN:
 			return VK_BLEND_FACTOR_ONE;
 		case VK_BLEND_OP_MAX:
@@ -355,17 +393,19 @@
 			ASSERT(false);
 		}
 
-		return sourceBlendFactorStateAlpha;
+		return blendState[index].sourceBlendFactorAlpha;
 	}
 
-	VkBlendFactor Context::destBlendFactorAlpha() const
+	VkBlendFactor Context::destBlendFactorAlpha(int index) const
 	{
-		switch (blendOperationStateAlpha)
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
+
+		switch (blendState[index].blendOperationAlpha)
 		{
 		case VK_BLEND_OP_ADD:
 		case VK_BLEND_OP_SUBTRACT:
 		case VK_BLEND_OP_REVERSE_SUBTRACT:
-			return destBlendFactorStateAlpha;
+			return blendState[index].destBlendFactorAlpha;
 		case VK_BLEND_OP_MIN:
 			return VK_BLEND_FACTOR_ONE;
 		case VK_BLEND_OP_MAX:
@@ -374,17 +414,19 @@
 			ASSERT(false);
 		}
 
-		return destBlendFactorStateAlpha;
+		return blendState[index].destBlendFactorAlpha;
 	}
 
-	VkBlendOp Context::blendOperationAlpha() const
+	VkBlendOp Context::blendOperationAlpha(int index) const
 	{
-		switch (blendOperationStateAlpha)
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
+
+		switch (blendState[index].blendOperationAlpha)
 		{
 		case VK_BLEND_OP_ADD:
-			if (sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO)
+			if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO)
 			{
-				if (destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO)
+				if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_ZERO_EXT;
 				}
@@ -393,9 +435,9 @@
 					return VK_BLEND_OP_DST_EXT;
 				}
 			}
-			else if (sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ONE)
+			else if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE)
 			{
-				if (destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO)
+				if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_SRC_EXT;
 				}
@@ -406,7 +448,7 @@
 			}
 			else
 			{
-				if (destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO)
+				if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_SRC_EXT;
 				}
@@ -416,13 +458,13 @@
 				}
 			}
 		case VK_BLEND_OP_SUBTRACT:
-			if (sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
+			if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
 			{
 				return VK_BLEND_OP_ZERO_EXT;   // Negative, clamped to zero
 			}
-			else if (sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ONE)
+			else if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE)
 			{
-				if (destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO)
+				if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_SRC_EXT;
 				}
@@ -433,7 +475,7 @@
 			}
 			else
 			{
-				if (destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO)
+				if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_SRC_EXT;
 				}
@@ -443,9 +485,9 @@
 				}
 			}
 		case VK_BLEND_OP_REVERSE_SUBTRACT:
-			if (sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO)
+			if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO)
 			{
-				if (destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO)
+				if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO)
 				{
 					return VK_BLEND_OP_ZERO_EXT;
 				}
@@ -454,9 +496,9 @@
 					return VK_BLEND_OP_DST_EXT;
 				}
 			}
-			else if (sourceBlendFactorAlpha() == VK_BLEND_FACTOR_ONE)
+			else if (sourceBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE)
 			{
-				if (destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
+				if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
 				{
 					return VK_BLEND_OP_ZERO_EXT;   // Negative, clamped to zero
 				}
@@ -467,7 +509,7 @@
 			}
 			else
 			{
-				if (destBlendFactorAlpha() == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
+				if (destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ZERO && allTargetsColorClamp())
 				{
 					return VK_BLEND_OP_ZERO_EXT;   // Negative, clamped to zero
 				}
@@ -484,11 +526,13 @@
 			ASSERT(false);
 		}
 
-		return blendOperationStateAlpha;
+		return blendState[index].blendOperationAlpha;
 	}
 
 	VkFormat Context::renderTargetInternalFormat(int index) const
 	{
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
+
 		if(renderTarget[index])
 		{
 			return renderTarget[index]->getFormat();
@@ -514,13 +558,15 @@
 
 	int Context::colorWriteActive(int index) const
 	{
+		ASSERT((index >= 0) && (index < RENDERTARGETS));
+
 		if(!renderTarget[index] || renderTarget[index]->getFormat() == VK_FORMAT_UNDEFINED)
 		{
 			return 0;
 		}
 
-		if(blendOperation() == VK_BLEND_OP_DST_EXT && destBlendFactor() == VK_BLEND_FACTOR_ONE &&
-		   (blendOperationAlpha() == VK_BLEND_OP_DST_EXT && destBlendFactorAlpha() == VK_BLEND_FACTOR_ONE))
+		if(blendOperation(index) == VK_BLEND_OP_DST_EXT && destBlendFactor(index) == VK_BLEND_FACTOR_ONE &&
+		   (blendOperationAlpha(index) == VK_BLEND_OP_DST_EXT && destBlendFactorAlpha(index) == VK_BLEND_FACTOR_ONE))
 		{
 			return 0;
 		}
diff --git a/src/Device/Context.hpp b/src/Device/Context.hpp
index fa79416..502eacf 100644
--- a/src/Device/Context.hpp
+++ b/src/Device/Context.hpp
@@ -36,6 +36,19 @@
 		unsigned char data[vk::MAX_PUSH_CONSTANT_SIZE];
 	};
 
+	struct BlendState
+	{
+		void init();
+
+		bool alphaBlendEnable;
+		VkBlendFactor sourceBlendFactor;
+		VkBlendFactor destBlendFactor;
+		VkBlendOp blendOperation;
+		VkBlendFactor sourceBlendFactorAlpha;
+		VkBlendFactor destBlendFactorAlpha;
+		VkBlendOp blendOperationAlpha;
+	};
+
 	class Context
 	{
 	public:
@@ -52,14 +65,9 @@
 		bool stencilActive() const;
 
 		bool allTargetsColorClamp() const;
-		bool alphaBlendActive() const;
-		VkBlendFactor sourceBlendFactor() const;
-		VkBlendFactor destBlendFactor() const;
-		VkBlendOp blendOperation() const;
 
-		VkBlendFactor sourceBlendFactorAlpha() const;
-		VkBlendFactor destBlendFactorAlpha() const;
-		VkBlendOp blendOperationAlpha() const;
+		void setBlendState(int index, BlendState state);
+		BlendState getBlendState(int index) const;
 
 		VkPrimitiveTopology topology;
 
@@ -75,9 +83,7 @@
 		float slopeDepthBias;
 
 		VkFormat renderTargetInternalFormat(int index) const;
-		bool colorWriteActive() const;
 		int colorWriteActive(int index) const;
-		bool colorUsed() const;
 
 		vk::DescriptorSet::Bindings descriptorSets = {};
 		vk::DescriptorSet::DynamicOffsets descriptorDynamicOffsets = {};
@@ -102,15 +108,6 @@
 		VkCompareOp depthCompareMode;
 		bool depthWriteEnable;
 
-		bool alphaBlendEnable;
-		VkBlendFactor sourceBlendFactorState;
-		VkBlendFactor destBlendFactorState;
-		VkBlendOp blendOperationState;
-
-		VkBlendFactor sourceBlendFactorStateAlpha;
-		VkBlendFactor destBlendFactorStateAlpha;
-		VkBlendOp blendOperationStateAlpha;
-
 		float lineWidth;
 
 		int colorWriteMask[RENDERTARGETS];   // RGBA
@@ -118,6 +115,21 @@
 		unsigned int multiSampleMask;
 		int sampleCount;
 		bool alphaToCoverage;
+
+	private:
+		bool colorWriteActive() const;
+		bool colorUsed() const;
+
+		bool alphaBlendActive(int index) const;
+		VkBlendFactor sourceBlendFactor(int index) const;
+		VkBlendFactor destBlendFactor(int index) const;
+		VkBlendOp blendOperation(int index) const;
+
+		VkBlendFactor sourceBlendFactorAlpha(int index) const;
+		VkBlendFactor destBlendFactorAlpha(int index) const;
+		VkBlendOp blendOperationAlpha(int index) const;
+
+		BlendState blendState[RENDERTARGETS];
 	};
 }
 
diff --git a/src/Device/PixelProcessor.cpp b/src/Device/PixelProcessor.cpp
index d6593b2..6976cce 100644
--- a/src/Device/PixelProcessor.cpp
+++ b/src/Device/PixelProcessor.cpp
@@ -195,21 +195,11 @@
 		state.occlusionEnabled = context->occlusionEnabled;
 		state.depthClamp = (context->depthBias != 0.0f) || (context->slopeDepthBias != 0.0f);
 
-		if(context->alphaBlendActive())
-		{
-			state.alphaBlendActive = true;
-			state.sourceBlendFactor = context->sourceBlendFactor();
-			state.destBlendFactor = context->destBlendFactor();
-			state.blendOperation = context->blendOperation();
-			state.sourceBlendFactorAlpha = context->sourceBlendFactorAlpha();
-			state.destBlendFactorAlpha = context->destBlendFactorAlpha();
-			state.blendOperationAlpha = context->blendOperationAlpha();
-		}
-
 		for(int i = 0; i < RENDERTARGETS; i++)
 		{
 			state.colorWriteMask |= context->colorWriteActive(i) << (4 * i);
 			state.targetFormat[i] = context->renderTargetInternalFormat(i);
+			state.blendState[i] = context->getBlendState(i);
 		}
 
 		state.multiSample = static_cast<unsigned int>(context->sampleCount);
diff --git a/src/Device/PixelProcessor.hpp b/src/Device/PixelProcessor.hpp
index c076a54..2b7ddca 100644
--- a/src/Device/PixelProcessor.hpp
+++ b/src/Device/PixelProcessor.hpp
@@ -52,13 +52,7 @@
 			bool perspective;
 			bool depthClamp;
 
-			bool alphaBlendActive;
-			VkBlendFactor sourceBlendFactor;
-			VkBlendFactor destBlendFactor;
-			VkBlendOp blendOperation;
-			VkBlendFactor sourceBlendFactorAlpha;
-			VkBlendFactor destBlendFactorAlpha;
-			VkBlendOp blendOperationAlpha;
+			BlendState blendState[RENDERTARGETS];
 
 			unsigned int colorWriteMask;
 			VkFormat targetFormat[RENDERTARGETS];
diff --git a/src/Pipeline/PixelRoutine.cpp b/src/Pipeline/PixelRoutine.cpp
index a231b62..188ac73 100644
--- a/src/Pipeline/PixelRoutine.cpp
+++ b/src/Pipeline/PixelRoutine.cpp
@@ -1064,7 +1064,7 @@
 
 	void PixelRoutine::alphaBlend(int index, Pointer<Byte> &cBuffer, Vector4s &current, Int &x)
 	{
-		if(!state.alphaBlendActive)
+		if(!state.blendState[index].alphaBlendEnable)
 		{
 			return;
 		}
@@ -1076,24 +1076,24 @@
 		Vector4s sourceFactor;
 		Vector4s destFactor;
 
-		blendFactor(sourceFactor, current, pixel, state.sourceBlendFactor);
-		blendFactor(destFactor, current, pixel, state.destBlendFactor);
+		blendFactor(sourceFactor, current, pixel, state.blendState[index].sourceBlendFactor);
+		blendFactor(destFactor, current, pixel, state.blendState[index].destBlendFactor);
 
-		if(state.sourceBlendFactor != VK_BLEND_FACTOR_ONE && state.sourceBlendFactor != VK_BLEND_FACTOR_ZERO)
+		if(state.blendState[index].sourceBlendFactor != VK_BLEND_FACTOR_ONE && state.blendState[index].sourceBlendFactor != VK_BLEND_FACTOR_ZERO)
 		{
 			current.x = MulHigh(As<UShort4>(current.x), As<UShort4>(sourceFactor.x));
 			current.y = MulHigh(As<UShort4>(current.y), As<UShort4>(sourceFactor.y));
 			current.z = MulHigh(As<UShort4>(current.z), As<UShort4>(sourceFactor.z));
 		}
 
-		if(state.destBlendFactor != VK_BLEND_FACTOR_ONE && state.destBlendFactor != VK_BLEND_FACTOR_ZERO)
+		if(state.blendState[index].destBlendFactor != VK_BLEND_FACTOR_ONE && state.blendState[index].destBlendFactor != VK_BLEND_FACTOR_ZERO)
 		{
 			pixel.x = MulHigh(As<UShort4>(pixel.x), As<UShort4>(destFactor.x));
 			pixel.y = MulHigh(As<UShort4>(pixel.y), As<UShort4>(destFactor.y));
 			pixel.z = MulHigh(As<UShort4>(pixel.z), As<UShort4>(destFactor.z));
 		}
 
-		switch(state.blendOperation)
+		switch(state.blendState[index].blendOperation)
 		{
 		case VK_BLEND_OP_ADD:
 			current.x = AddSat(As<UShort4>(current.x), As<UShort4>(pixel.x));
@@ -1134,23 +1134,23 @@
 			current.z = Short4(0x0000);
 			break;
 		default:
-			UNIMPLEMENTED("VkBlendOp: %d", int(state.blendOperation));
+			UNIMPLEMENTED("VkBlendOp: %d", int(state.blendState[index].blendOperation));
 		}
 
-		blendFactorAlpha(sourceFactor, current, pixel, state.sourceBlendFactorAlpha);
-		blendFactorAlpha(destFactor, current, pixel, state.destBlendFactorAlpha);
+		blendFactorAlpha(sourceFactor, current, pixel, state.blendState[index].sourceBlendFactorAlpha);
+		blendFactorAlpha(destFactor, current, pixel, state.blendState[index].destBlendFactorAlpha);
 
-		if(state.sourceBlendFactorAlpha != VK_BLEND_FACTOR_ONE && state.sourceBlendFactorAlpha != VK_BLEND_FACTOR_ZERO)
+		if(state.blendState[index].sourceBlendFactorAlpha != VK_BLEND_FACTOR_ONE && state.blendState[index].sourceBlendFactorAlpha != VK_BLEND_FACTOR_ZERO)
 		{
 			current.w = MulHigh(As<UShort4>(current.w), As<UShort4>(sourceFactor.w));
 		}
 
-		if(state.destBlendFactorAlpha != VK_BLEND_FACTOR_ONE && state.destBlendFactorAlpha != VK_BLEND_FACTOR_ZERO)
+		if(state.blendState[index].destBlendFactorAlpha != VK_BLEND_FACTOR_ONE && state.blendState[index].destBlendFactorAlpha != VK_BLEND_FACTOR_ZERO)
 		{
 			pixel.w = MulHigh(As<UShort4>(pixel.w), As<UShort4>(destFactor.w));
 		}
 
-		switch(state.blendOperationAlpha)
+		switch(state.blendState[index].blendOperationAlpha)
 		{
 		case VK_BLEND_OP_ADD:
 			current.w = AddSat(As<UShort4>(current.w), As<UShort4>(pixel.w));
@@ -1177,7 +1177,7 @@
 			current.w = Short4(0x0000);
 			break;
 		default:
-			UNIMPLEMENTED("VkBlendOp: %d", int(state.blendOperationAlpha));
+			UNIMPLEMENTED("VkBlendOp: %d", int(state.blendState[index].blendOperationAlpha));
 		}
 	}
 
@@ -1794,7 +1794,7 @@
 
 	void PixelRoutine::alphaBlend(int index, Pointer<Byte> &cBuffer, Vector4f &oC, Int &x)
 	{
-		if(!state.alphaBlendActive)
+		if(!state.blendState[index].alphaBlendEnable)
 		{
 			return;
 		}
@@ -1911,8 +1911,8 @@
 		Vector4f sourceFactor;
 		Vector4f destFactor;
 
-		blendFactor(sourceFactor, oC, pixel, state.sourceBlendFactor);
-		blendFactor(destFactor, oC, pixel, state.destBlendFactor);
+		blendFactor(sourceFactor, oC, pixel, state.blendState[index].sourceBlendFactor);
+		blendFactor(destFactor, oC, pixel, state.blendState[index].destBlendFactor);
 
 		oC.x *= sourceFactor.x;
 		oC.y *= sourceFactor.y;
@@ -1922,7 +1922,7 @@
 		pixel.y *= destFactor.y;
 		pixel.z *= destFactor.z;
 
-		switch(state.blendOperation)
+		switch(state.blendState[index].blendOperation)
 		{
 		case VK_BLEND_OP_ADD:
 			oC.x += pixel.x;
@@ -1963,16 +1963,16 @@
 			oC.z = Float4(0.0f);
 			break;
 		default:
-			UNIMPLEMENTED("VkBlendOp: %d", int(state.blendOperation));
+			UNIMPLEMENTED("VkBlendOp: %d", int(state.blendState[index].blendOperation));
 		}
 
-		blendFactorAlpha(sourceFactor, oC, pixel, state.sourceBlendFactorAlpha);
-		blendFactorAlpha(destFactor, oC, pixel, state.destBlendFactorAlpha);
+		blendFactorAlpha(sourceFactor, oC, pixel, state.blendState[index].sourceBlendFactorAlpha);
+		blendFactorAlpha(destFactor, oC, pixel, state.blendState[index].destBlendFactorAlpha);
 
 		oC.w *= sourceFactor.w;
 		pixel.w *= destFactor.w;
 
-		switch(state.blendOperationAlpha)
+		switch(state.blendState[index].blendOperationAlpha)
 		{
 		case VK_BLEND_OP_ADD:
 			oC.w += pixel.w;
@@ -2000,7 +2000,7 @@
 			oC.w = Float4(0.0f);
 			break;
 		default:
-			UNIMPLEMENTED("VkBlendOp: %d", int(state.blendOperationAlpha));
+			UNIMPLEMENTED("VkBlendOp: %d", int(state.blendState[index].blendOperationAlpha));
 		}
 	}
 
diff --git a/src/Vulkan/VkPhysicalDevice.cpp b/src/Vulkan/VkPhysicalDevice.cpp
index 5e5b74c..c86221c 100644
--- a/src/Vulkan/VkPhysicalDevice.cpp
+++ b/src/Vulkan/VkPhysicalDevice.cpp
@@ -34,7 +34,7 @@
 		VK_TRUE,   // robustBufferAccess
 		VK_FALSE,  // fullDrawIndexUint32
 		VK_FALSE,  // imageCubeArray
-		VK_FALSE,  // independentBlend
+		VK_TRUE,   // independentBlend
 		VK_FALSE,  // geometryShader
 		VK_FALSE,  // tessellationShader
 		VK_FALSE,  // sampleRateShading
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index 0efde4c..89e835d 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -468,18 +468,10 @@
 		{
 			const VkPipelineColorBlendAttachmentState& attachment = colorBlendState->pAttachments[i];
 			context.colorWriteMask[i] = attachment.colorWriteMask;
-		}
 
-		if(colorBlendState->attachmentCount > 0)
-		{
-			const VkPipelineColorBlendAttachmentState& attachment = colorBlendState->pAttachments[0];
-			context.alphaBlendEnable = (attachment.blendEnable == VK_TRUE);
-			context.blendOperationStateAlpha = attachment.alphaBlendOp;
-			context.blendOperationState = attachment.colorBlendOp;
-			context.destBlendFactorStateAlpha = attachment.dstAlphaBlendFactor;
-			context.destBlendFactorState = attachment.dstColorBlendFactor;
-			context.sourceBlendFactorStateAlpha = attachment.srcAlphaBlendFactor;
-			context.sourceBlendFactorState = attachment.srcColorBlendFactor;
+			context.setBlendState(i, { (attachment.blendEnable == VK_TRUE),
+				attachment.srcColorBlendFactor, attachment.dstColorBlendFactor, attachment.colorBlendOp,
+				attachment.srcAlphaBlendFactor, attachment.dstAlphaBlendFactor, attachment.alphaBlendOp });
 		}
 	}