Tidy stencil state handling

Bug: b/128715612
Change-Id: I1e9859d2cf001bfb341a49ad4f8fc9ef52c9fa5b
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/27508
Tested-by: Chris Forbes <chrisforbes@google.com>
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Device/Context.cpp b/src/Device/Context.cpp
index 855d39f..dc3ad68 100644
--- a/src/Device/Context.cpp
+++ b/src/Device/Context.cpp
@@ -170,22 +170,9 @@
 		stencilBuffer = nullptr;
 
 		stencilEnable = false;
-		stencilCompareMode = VK_COMPARE_OP_ALWAYS;
-		stencilReference = 0;
-		stencilMask = 0xFFFFFFFF;
-		stencilFailOperation = VK_STENCIL_OP_KEEP;
-		stencilPassOperation = VK_STENCIL_OP_KEEP;
-		stencilZFailOperation = VK_STENCIL_OP_KEEP;
-		stencilWriteMask = 0xFFFFFFFF;
-
 		twoSidedStencil = false;
-		stencilCompareModeCCW = VK_COMPARE_OP_ALWAYS;
-		stencilReferenceCCW = 0;
-		stencilMaskCCW = 0xFFFFFFFF;
-		stencilFailOperationCCW = VK_STENCIL_OP_KEEP;
-		stencilPassOperationCCW = VK_STENCIL_OP_KEEP;
-		stencilZFailOperationCCW = VK_STENCIL_OP_KEEP;
-		stencilWriteMaskCCW = 0xFFFFFFFF;
+		frontStencil = {};
+		backStencil = {};
 
 		rasterizerDiscard = false;
 
diff --git a/src/Device/Context.hpp b/src/Device/Context.hpp
index 6be2017..2405224 100644
--- a/src/Device/Context.hpp
+++ b/src/Device/Context.hpp
@@ -159,22 +159,9 @@
 		DrawType drawType;
 
 		bool stencilEnable;
-		VkCompareOp stencilCompareMode;
-		int stencilReference;
-		int stencilMask;
-		VkStencilOp stencilFailOperation;
-		VkStencilOp stencilPassOperation;
-		VkStencilOp stencilZFailOperation;
-		int stencilWriteMask;
-
 		bool twoSidedStencil;
-		VkCompareOp stencilCompareModeCCW;
-		int stencilReferenceCCW;
-		int stencilMaskCCW;
-		VkStencilOp stencilFailOperationCCW;
-		VkStencilOp stencilPassOperationCCW;
-		VkStencilOp stencilZFailOperationCCW;
-		int stencilWriteMaskCCW;
+		VkStencilOpState frontStencil;
+		VkStencilOpState backStencil;
 
 		// Pixel processor states
 		VkCullModeFlags cullMode;
diff --git a/src/Device/PixelProcessor.cpp b/src/Device/PixelProcessor.cpp
index da40dbe..df7f9e6 100644
--- a/src/Device/PixelProcessor.cpp
+++ b/src/Device/PixelProcessor.cpp
@@ -292,22 +292,9 @@
 		if(context->stencilActive())
 		{
 			state.stencilActive = true;
-			state.stencilCompareMode = context->stencilCompareMode;
-			state.stencilFailOperation = context->stencilFailOperation;
-			state.stencilPassOperation = context->stencilPassOperation;
-			state.stencilZFailOperation = context->stencilZFailOperation;
-			state.noStencilMask = (context->stencilMask == 0xFF);
-			state.noStencilWriteMask = (context->stencilWriteMask == 0xFF);
-			state.stencilWriteMasked = (context->stencilWriteMask == 0x00);
-
 			state.twoSidedStencil = context->twoSidedStencil;
-			state.stencilCompareModeCCW = context->twoSidedStencil ? context->stencilCompareModeCCW : state.stencilCompareMode;
-			state.stencilFailOperationCCW = context->twoSidedStencil ? context->stencilFailOperationCCW : state.stencilFailOperation;
-			state.stencilPassOperationCCW = context->twoSidedStencil ? context->stencilPassOperationCCW : state.stencilPassOperation;
-			state.stencilZFailOperationCCW = context->twoSidedStencil ? context->stencilZFailOperationCCW : state.stencilZFailOperation;
-			state.noStencilMaskCCW = context->twoSidedStencil ? (context->stencilMaskCCW == 0xFF) : state.noStencilMask;
-			state.noStencilWriteMaskCCW = context->twoSidedStencil ? (context->stencilWriteMaskCCW == 0xFF) : state.noStencilWriteMask;
-			state.stencilWriteMaskedCCW = context->twoSidedStencil ? (context->stencilWriteMaskCCW == 0x00) : state.stencilWriteMasked;
+			state.frontStencil = context->frontStencil;
+			state.backStencil = context->backStencil;
 		}
 
 		if(context->depthBufferActive())
diff --git a/src/Device/PixelProcessor.hpp b/src/Device/PixelProcessor.hpp
index 2d4437a..c15da8b 100644
--- a/src/Device/PixelProcessor.hpp
+++ b/src/Device/PixelProcessor.hpp
@@ -39,21 +39,9 @@
 			bool quadLayoutDepthBuffer;
 
 			bool stencilActive;
-			VkCompareOp stencilCompareMode;
-			VkStencilOp stencilFailOperation;
-			VkStencilOp stencilPassOperation;
-			VkStencilOp stencilZFailOperation;
-			bool noStencilMask;
-			bool noStencilWriteMask;
-			bool stencilWriteMasked;
 			bool twoSidedStencil;
-			VkCompareOp stencilCompareModeCCW;
-			VkStencilOp stencilFailOperationCCW;
-			VkStencilOp stencilPassOperationCCW;
-			VkStencilOp stencilZFailOperationCCW;
-			bool noStencilMaskCCW;
-			bool noStencilWriteMaskCCW;
-			bool stencilWriteMaskedCCW;
+			VkStencilOpState frontStencil;
+			VkStencilOpState backStencil;
 
 			bool depthTestActive;
 			bool occlusionEnabled;
diff --git a/src/Device/Renderer.cpp b/src/Device/Renderer.cpp
index 7a08703..2038d50 100644
--- a/src/Device/Renderer.cpp
+++ b/src/Device/Renderer.cpp
@@ -328,8 +328,8 @@
 
 		if(pixelState.stencilActive)
 		{
-			data->stencil[0].set(context->stencilReference, context->stencilMask, context->stencilWriteMask);
-			data->stencil[1].set(context->stencilReferenceCCW, context->stencilMaskCCW, context->stencilWriteMaskCCW);
+			data->stencil[0].set(context->frontStencil.reference, context->frontStencil.compareMask, context->frontStencil.writeMask);
+			data->stencil[1].set(context->backStencil.reference, context->backStencil.compareMask, context->backStencil.writeMask);
 		}
 
 		data->lineWidth = context->lineWidth;
diff --git a/src/Pipeline/PixelRoutine.cpp b/src/Pipeline/PixelRoutine.cpp
index aa4209e..b904014 100644
--- a/src/Pipeline/PixelRoutine.cpp
+++ b/src/Pipeline/PixelRoutine.cpp
@@ -290,33 +290,33 @@
 		}
 
 		Byte8 value = *Pointer<Byte8>(buffer);
-		Byte8 valueCCW = value;
+		Byte8 valueBack = value;
 
-		if(!state.noStencilMask)
+		if(state.frontStencil.compareMask != 0xff)
 		{
 			value &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[0].testMaskQ));
 		}
 
-		stencilTest(value, state.stencilCompareMode, false);
+		stencilTest(value, state.frontStencil.compareOp, false);
 
 		if(state.twoSidedStencil)
 		{
-			if(!state.noStencilMaskCCW)
+			if(state.backStencil.compareMask != 0xff)
 			{
-				valueCCW &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[1].testMaskQ));
+				valueBack &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[1].testMaskQ));
 			}
 
-			stencilTest(valueCCW, state.stencilCompareModeCCW, true);
+			stencilTest(valueBack, state.backStencil.compareOp, true);
 
 			value &= *Pointer<Byte8>(primitive + OFFSET(Primitive,clockwiseMask));
-			valueCCW &= *Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask));
-			value |= valueCCW;
+			valueBack &= *Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask));
+			value |= valueBack;
 		}
 
 		sMask = SignMask(value) & cMask;
 	}
 
-	void PixelRoutine::stencilTest(Byte8 &value, VkCompareOp stencilCompareMode, bool CCW)
+	void PixelRoutine::stencilTest(Byte8 &value, VkCompareOp stencilCompareMode, bool isBack)
 	{
 		Byte8 equal;
 
@@ -330,31 +330,31 @@
 			break;
 		case VK_COMPARE_OP_LESS:			// a < b ~ b > a
 			value += Byte8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
-			value = CmpGT(As<SByte8>(value), *Pointer<SByte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedSignedQ)));
+			value = CmpGT(As<SByte8>(value), *Pointer<SByte8>(data + OFFSET(DrawData,stencil[isBack].referenceMaskedSignedQ)));
 			break;
 		case VK_COMPARE_OP_EQUAL:
-			value = CmpEQ(value, *Pointer<Byte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedQ)));
+			value = CmpEQ(value, *Pointer<Byte8>(data + OFFSET(DrawData,stencil[isBack].referenceMaskedQ)));
 			break;
 		case VK_COMPARE_OP_NOT_EQUAL:		// a != b ~ !(a == b)
-			value = CmpEQ(value, *Pointer<Byte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedQ)));
+			value = CmpEQ(value, *Pointer<Byte8>(data + OFFSET(DrawData,stencil[isBack].referenceMaskedQ)));
 			value ^= Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
 			break;
 		case VK_COMPARE_OP_LESS_OR_EQUAL:	// a <= b ~ (b > a) || (a == b)
 			equal = value;
-			equal = CmpEQ(equal, *Pointer<Byte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedQ)));
+			equal = CmpEQ(equal, *Pointer<Byte8>(data + OFFSET(DrawData,stencil[isBack].referenceMaskedQ)));
 			value += Byte8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
-			value = CmpGT(As<SByte8>(value), *Pointer<SByte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedSignedQ)));
+			value = CmpGT(As<SByte8>(value), *Pointer<SByte8>(data + OFFSET(DrawData,stencil[isBack].referenceMaskedSignedQ)));
 			value |= equal;
 			break;
 		case VK_COMPARE_OP_GREATER:		// a > b
-			equal = *Pointer<Byte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedSignedQ));
+			equal = *Pointer<Byte8>(data + OFFSET(DrawData,stencil[isBack].referenceMaskedSignedQ));
 			value += Byte8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
 			equal = CmpGT(As<SByte8>(equal), As<SByte8>(value));
 			value = equal;
 			break;
 		case VK_COMPARE_OP_GREATER_OR_EQUAL:	// a >= b ~ !(a < b) ~ !(b > a)
 			value += Byte8(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80);
-			value = CmpGT(As<SByte8>(value), *Pointer<SByte8>(data + OFFSET(DrawData,stencil[CCW].referenceMaskedSignedQ)));
+			value = CmpGT(As<SByte8>(value), *Pointer<SByte8>(data + OFFSET(DrawData,stencil[isBack].referenceMaskedSignedQ)));
 			value ^= Byte8(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
 			break;
 		default:
@@ -729,15 +729,15 @@
 			return;
 		}
 
-		if(state.stencilPassOperation == VK_STENCIL_OP_KEEP && state.stencilZFailOperation == VK_STENCIL_OP_KEEP && state.stencilFailOperation == VK_STENCIL_OP_KEEP)
+		if(state.frontStencil.passOp == VK_STENCIL_OP_KEEP && state.frontStencil.depthFailOp == VK_STENCIL_OP_KEEP && state.frontStencil.failOp == VK_STENCIL_OP_KEEP)
 		{
-			if(!state.twoSidedStencil || (state.stencilPassOperationCCW == VK_STENCIL_OP_KEEP && state.stencilZFailOperationCCW == VK_STENCIL_OP_KEEP && state.stencilFailOperationCCW == VK_STENCIL_OP_KEEP))
+			if(!state.twoSidedStencil || (state.backStencil.passOp == VK_STENCIL_OP_KEEP && state.backStencil.depthFailOp == VK_STENCIL_OP_KEEP && state.backStencil.failOp == VK_STENCIL_OP_KEEP))
 			{
 				return;
 			}
 		}
 
-		if(state.stencilWriteMasked && (!state.twoSidedStencil || state.stencilWriteMaskedCCW))
+		if((state.frontStencil.writeMask == 0) && (!state.twoSidedStencil || (state.backStencil.writeMask == 0)))
 		{
 			return;
 		}
@@ -752,9 +752,9 @@
 		Byte8 bufferValue = *Pointer<Byte8>(buffer);
 
 		Byte8 newValue;
-		stencilOperation(newValue, bufferValue, state.stencilPassOperation, state.stencilZFailOperation, state.stencilFailOperation, false, zMask, sMask);
+		stencilOperation(newValue, bufferValue, state.frontStencil, false, zMask, sMask);
 
-		if(!state.noStencilWriteMask)
+		if(state.frontStencil.writeMask != 0)
 		{
 			Byte8 maskedValue = bufferValue;
 			newValue &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[0].writeMaskQ));
@@ -764,21 +764,21 @@
 
 		if(state.twoSidedStencil)
 		{
-			Byte8 newValueCCW;
+			Byte8 newValueBack;
 
-			stencilOperation(newValueCCW, bufferValue, state.stencilPassOperationCCW, state.stencilZFailOperationCCW, state.stencilFailOperationCCW, true, zMask, sMask);
+			stencilOperation(newValueBack, bufferValue, state.backStencil, true, zMask, sMask);
 
-			if(!state.noStencilWriteMaskCCW)
+			if(state.backStencil.writeMask != 0)
 			{
 				Byte8 maskedValue = bufferValue;
-				newValueCCW &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[1].writeMaskQ));
+				newValueBack &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[1].writeMaskQ));
 				maskedValue &= *Pointer<Byte8>(data + OFFSET(DrawData,stencil[1].invWriteMaskQ));
-				newValueCCW |= maskedValue;
+				newValueBack |= maskedValue;
 			}
 
 			newValue &= *Pointer<Byte8>(primitive + OFFSET(Primitive,clockwiseMask));
-			newValueCCW &= *Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask));
-			newValue |= newValueCCW;
+			newValueBack &= *Pointer<Byte8>(primitive + OFFSET(Primitive,invClockwiseMask));
+			newValue |= newValueBack;
 		}
 
 		newValue &= *Pointer<Byte8>(constants + OFFSET(Constants,maskB4Q) + 8 * cMask);
@@ -788,27 +788,27 @@
 		*Pointer<Byte4>(buffer) = Byte4(newValue);
 	}
 
-	void PixelRoutine::stencilOperation(Byte8 &newValue, Byte8 &bufferValue, VkStencilOp stencilPassOperation, VkStencilOp stencilZFailOperation, VkStencilOp stencilFailOperation, bool CCW, Int &zMask, Int &sMask)
+	void PixelRoutine::stencilOperation(Byte8 &newValue, Byte8 &bufferValue, VkStencilOpState const &ops, bool isBack, Int &zMask, Int &sMask)
 	{
 		Byte8 &pass = newValue;
 		Byte8 fail;
 		Byte8 zFail;
 
-		stencilOperation(pass, bufferValue, stencilPassOperation, CCW);
+		stencilOperation(pass, bufferValue, ops.passOp, isBack);
 
-		if(stencilZFailOperation != stencilPassOperation)
+		if(ops.depthFailOp != ops.passOp)
 		{
-			stencilOperation(zFail, bufferValue, stencilZFailOperation, CCW);
+			stencilOperation(zFail, bufferValue, ops.depthFailOp, isBack);
 		}
 
-		if(stencilFailOperation != stencilPassOperation || stencilFailOperation != stencilZFailOperation)
+		if(ops.failOp != ops.passOp || ops.failOp != ops.depthFailOp)
 		{
-			stencilOperation(fail, bufferValue, stencilFailOperation, CCW);
+			stencilOperation(fail, bufferValue, ops.failOp, isBack);
 		}
 
-		if(stencilFailOperation != stencilPassOperation || stencilFailOperation != stencilZFailOperation)
+		if(ops.failOp != ops.passOp || ops.failOp != ops.depthFailOp)
 		{
-			if(state.depthTestActive && stencilZFailOperation != stencilPassOperation)   // zMask valid and values not the same
+			if(state.depthTestActive && ops.depthFailOp != ops.passOp)   // zMask valid and values not the same
 			{
 				pass &= *Pointer<Byte8>(constants + OFFSET(Constants,maskB4Q) + 8 * zMask);
 				zFail &= *Pointer<Byte8>(constants + OFFSET(Constants,invMaskB4Q) + 8 * zMask);
@@ -821,7 +821,7 @@
 		}
 	}
 
-	void PixelRoutine::stencilOperation(Byte8 &output, Byte8 &bufferValue, VkStencilOp operation, bool CCW)
+	void PixelRoutine::stencilOperation(Byte8 &output, Byte8 &bufferValue, VkStencilOp operation, bool isBack)
 	{
 		switch(operation)
 		{
@@ -832,7 +832,7 @@
 			output = Byte8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
 			break;
 		case VK_STENCIL_OP_REPLACE:
-			output = *Pointer<Byte8>(data + OFFSET(DrawData,stencil[CCW].referenceQ));
+			output = *Pointer<Byte8>(data + OFFSET(DrawData,stencil[isBack].referenceQ));
 			break;
 		case VK_STENCIL_OP_INCREMENT_AND_CLAMP:
 			output = AddSat(bufferValue, Byte8(1, 1, 1, 1, 1, 1, 1, 1));
diff --git a/src/Pipeline/PixelRoutine.hpp b/src/Pipeline/PixelRoutine.hpp
index ff2044f..824c7ce 100644
--- a/src/Pipeline/PixelRoutine.hpp
+++ b/src/Pipeline/PixelRoutine.hpp
@@ -64,9 +64,9 @@
 	private:
 		Float4 interpolateCentroid(Float4 &x, Float4 &y, Float4 &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective);
 		void stencilTest(Pointer<Byte> &sBuffer, int q, Int &x, Int &sMask, Int &cMask);
-		void stencilTest(Byte8 &value, VkCompareOp stencilCompareMode, bool CCW);
-		void stencilOperation(Byte8 &newValue, Byte8 &bufferValue, VkStencilOp stencilPassOperation, VkStencilOp stencilZFailOperation, VkStencilOp stencilFailOperation, bool CCW, Int &zMask, Int &sMask);
-		void stencilOperation(Byte8 &output, Byte8 &bufferValue, VkStencilOp operation, bool CCW);
+		void stencilTest(Byte8 &value, VkCompareOp stencilCompareMode, bool isBack);
+		void stencilOperation(Byte8 &newValue, Byte8 &bufferValue, VkStencilOpState const &ops, bool isBack, Int &zMask, Int &sMask);
+		void stencilOperation(Byte8 &output, Byte8 &bufferValue, VkStencilOp operation, bool isBack);
 		Bool depthTest(Pointer<Byte> &zBuffer, int q, Int &x, Float4 &z, Int &sMask, Int &zMask, Int &cMask);
 
 		// Raster operations
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index 5cd45ce..c6b65ed 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -381,21 +381,8 @@
 		context.stencilEnable = context.twoSidedStencil = depthStencilState->stencilTestEnable;
 		if(context.stencilEnable)
 		{
-			context.stencilMask = depthStencilState->front.compareMask;
-			context.stencilCompareMode = depthStencilState->front.compareOp;
-			context.stencilZFailOperation = depthStencilState->front.depthFailOp;
-			context.stencilFailOperation = depthStencilState->front.failOp;
-			context.stencilPassOperation = depthStencilState->front.passOp;
-			context.stencilReference = depthStencilState->front.reference;
-			context.stencilWriteMask = depthStencilState->front.writeMask;
-
-			context.stencilMaskCCW = depthStencilState->back.compareMask;
-			context.stencilCompareModeCCW = depthStencilState->back.compareOp;
-			context.stencilZFailOperationCCW = depthStencilState->back.depthFailOp;
-			context.stencilFailOperationCCW = depthStencilState->back.failOp;
-			context.stencilPassOperationCCW = depthStencilState->back.passOp;
-			context.stencilReferenceCCW = depthStencilState->back.reference;
-			context.stencilWriteMaskCCW = depthStencilState->back.writeMask;
+			context.frontStencil = depthStencilState->front;
+			context.backStencil = depthStencilState->back;
 		}
 	}