Move required interpolation logic to SpirvShader

Some of the interpolation logic is required to properly implement
the GLSLstd450Interpolate* operations. In order to prevent code
duplication and to make sure the logic is always identical between
the regular fragment input interpolation and the one performed by
the GLSLstd450Interpolate* operations, the interpolateCentroid()
function was moved to SpirvShader and renamed with a more generic
name, interpolateXY(), as it will be used to interpolate all modes
(centroid, sample and offset).

Bug: b/171415086
Change-Id: Ifbffa2b395a0b8c22fa120b36643db05f867a306
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/51731
Tested-by: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/PixelRoutine.cpp b/src/Pipeline/PixelRoutine.cpp
index 873700e..0653d7c 100644
--- a/src/Pipeline/PixelRoutine.cpp
+++ b/src/Pipeline/PixelRoutine.cpp
@@ -147,7 +147,7 @@
 
 			if(state.centroid)
 			{
-				rhwCentroid = reciprocal(interpolateCentroid(XXXX, YYYY, rhwCentroid, primitive + OFFSET(Primitive, w), false, false));
+				rhwCentroid = reciprocal(SpirvRoutine::interpolateAtXY(XXXX, YYYY, rhwCentroid, primitive + OFFSET(Primitive, w), false, false));
 			}
 		}
 
@@ -161,9 +161,9 @@
 					if(input.Centroid && state.enableMultiSampling)
 					{
 						routine.inputs[interpolant] =
-						    interpolateCentroid(XXXX, YYYY, rhwCentroid,
-						                        primitive + OFFSET(Primitive, V[interpolant]),
-						                        input.Flat, !input.NoPerspective);
+						    SpirvRoutine::interpolateAtXY(XXXX, YYYY, rhwCentroid,
+						                                  primitive + OFFSET(Primitive, V[interpolant]),
+						                                  input.Flat, !input.NoPerspective);
 					}
 					else
 					{
@@ -282,24 +282,6 @@
 	}
 }
 
-Float4 PixelRoutine::interpolateCentroid(const Float4 &x, const Float4 &y, const Float4 &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective)
-{
-	Float4 interpolant = *Pointer<Float4>(planeEquation + OFFSET(PlaneEquation, C), 16);
-
-	if(!flat)
-	{
-		interpolant += x * *Pointer<Float4>(planeEquation + OFFSET(PlaneEquation, A), 16) +
-		               y * *Pointer<Float4>(planeEquation + OFFSET(PlaneEquation, B), 16);
-
-		if(perspective)
-		{
-			interpolant *= rhw;
-		}
-	}
-
-	return interpolant;
-}
-
 void PixelRoutine::stencilTest(const Pointer<Byte> &sBuffer, int q, const Int &x, Int &sMask, const Int &cMask)
 {
 	if(!state.stencilActive)
diff --git a/src/Pipeline/PixelRoutine.hpp b/src/Pipeline/PixelRoutine.hpp
index d9d4f21..e4dc029 100644
--- a/src/Pipeline/PixelRoutine.hpp
+++ b/src/Pipeline/PixelRoutine.hpp
@@ -66,7 +66,6 @@
 	void linearToSRGB12_16(Vector4s &c);
 
 private:
-	Float4 interpolateCentroid(const Float4 &x, const Float4 &y, const Float4 &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective);
 	Byte8 stencilReplaceRef(bool isBack);
 	void stencilTest(const Pointer<Byte> &sBuffer, int q, const Int &x, Int &sMask, const Int &cMask);
 	void stencilTest(Byte8 &value, VkCompareOp stencilCompareMode, bool isBack);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index c479588..8631351 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -1406,6 +1406,8 @@
 	// common for all shader types.
 	void setImmutableInputBuiltins(SpirvShader const *shader);
 
+	static SIMD::Float interpolateAtXY(const SIMD::Float &x, const SIMD::Float &y, const SIMD::Float &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective);
+
 	// setInputBuiltin() calls f() with the builtin and value if the shader
 	// uses the input builtin, otherwise the call is a no-op.
 	// F is a function with the signature:
diff --git a/src/Pipeline/SpirvShaderGLSLstd450.cpp b/src/Pipeline/SpirvShaderGLSLstd450.cpp
index 1d82a5b..e43a298 100644
--- a/src/Pipeline/SpirvShaderGLSLstd450.cpp
+++ b/src/Pipeline/SpirvShaderGLSLstd450.cpp
@@ -15,14 +15,35 @@
 #include "SpirvShader.hpp"
 
 #include "ShaderCore.hpp"
+#include "Device/Primitive.hpp"
 
 #include <spirv/unified1/GLSL.std.450.h>
 #include <spirv/unified1/spirv.hpp>
 
 namespace {
 constexpr float PI = 3.141592653589793f;
+
+sw::SIMD::Float Interpolate(const sw::SIMD::Float &x, const sw::SIMD::Float &y, const sw::SIMD::Float &rhw,
+                            const sw::SIMD::Float &A, const sw::SIMD::Float &B, const sw::SIMD::Float &C,
+                            bool flat, bool perspective)
+{
+	sw::SIMD::Float interpolant = C;
+
+	if(!flat)
+	{
+		interpolant += x * A + y * B;
+
+		if(perspective)
+		{
+			interpolant *= rhw;
+		}
+	}
+
+	return interpolant;
 }
 
+}  // namespace
+
 namespace sw {
 
 SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitState *state) const
@@ -932,4 +953,19 @@
 	return EmitResult::Continue;
 }
 
+SIMD::Float SpirvRoutine::interpolateAtXY(const SIMD::Float &x, const SIMD::Float &y, const SIMD::Float &rhw, Pointer<Byte> planeEquation, bool flat, bool perspective)
+{
+	SIMD::Float A;
+	SIMD::Float B;
+	SIMD::Float C = *Pointer<SIMD::Float>(planeEquation + OFFSET(PlaneEquation, C), 16);
+
+	if(!flat)
+	{
+		A = *Pointer<SIMD::Float>(planeEquation + OFFSET(PlaneEquation, A), 16);
+		B = *Pointer<SIMD::Float>(planeEquation + OFFSET(PlaneEquation, B), 16);
+	}
+
+	return ::Interpolate(x, y, rhw, A, B, C, flat, perspective);
+}
+
 }  // namespace sw
\ No newline at end of file