Fix sRGB linear filtering in blitter

Fixed sRGB filtering by performing the conversion
pre-filtering when appropriate.

Change-Id: Id24898feed7e9a7dadff45431198771af25efed7
Reviewed-on: https://swiftshader-review.googlesource.com/15409
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Renderer/Blitter.cpp b/src/Renderer/Blitter.cpp
index 6f9d3a4..efb2cad 100644
--- a/src/Renderer/Blitter.cpp
+++ b/src/Renderer/Blitter.cpp
@@ -1074,7 +1074,7 @@
 		return true;
 	}
 
-	bool Blitter::ApplyScaleAndClamp(Float4 &value, const State  &state)
+	bool Blitter::ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled)
 	{
 		float4 scale, unscale;
 		if(state.clearOperation &&
@@ -1108,20 +1108,12 @@
 		bool srcSRGB = Surface::isSRGBformat(state.sourceFormat);
 		bool dstSRGB = Surface::isSRGBformat(state.destFormat);
 
-		if(state.convertSRGB && (srcSRGB ^ dstSRGB))   // One of the formats is sRGB encoded.
+		if(state.convertSRGB && ((srcSRGB && !preScaled) || dstSRGB))   // One of the formats is sRGB encoded.
 		{
-			value = value * Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w);
-
-			if(srcSRGB)
-			{
-				value = sRGBtoLinear(value);
-			}
-			else   // dstSRGB
-			{
-				value = LinearToSRGB(value);
-			}
-
-			value = value * Float4(scale.x, scale.y, scale.z, scale.w);
+			value *= preScaled ? Float4(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z, 1.0f / scale.w) : // Unapply scale
+			                     Float4(1.0f / unscale.x, 1.0f / unscale.y, 1.0f / unscale.z, 1.0f / unscale.w); // Apply unscale
+			value = (srcSRGB && !preScaled) ? sRGBtoLinear(value) : LinearToSRGB(value);
+			value *= Float4(scale.x, scale.y, scale.z, scale.w); // Apply scale
 		}
 		else if(unscale != scale)
 		{
@@ -1297,6 +1289,7 @@
 					{
 						Float4 color;
 
+						bool preScaled = false;
 						if(!state.filter || intSrc)
 						{
 							Int X = Int(x);
@@ -1347,6 +1340,15 @@
 							Float4 c10; if(!read(c10, s10, state)) return nullptr;
 							Float4 c11; if(!read(c11, s11, state)) return nullptr;
 
+							if(state.convertSRGB && Surface::isSRGBformat(state.sourceFormat)) // sRGB -> RGB
+							{
+								if(!ApplyScaleAndClamp(c00, state)) return nullptr;
+								if(!ApplyScaleAndClamp(c01, state)) return nullptr;
+								if(!ApplyScaleAndClamp(c10, state)) return nullptr;
+								if(!ApplyScaleAndClamp(c11, state)) return nullptr;
+								preScaled = true;
+							}
+
 							Float4 fx = Float4(x0 - Float(X0));
 							Float4 fy = Float4(y0 - Float(Y0));
 							Float4 ix = Float4(1.0f) - fx;
@@ -1356,7 +1358,7 @@
 							        (c10 * ix + c11 * fx) * fy;
 						}
 
-						if(!ApplyScaleAndClamp(color, state))
+						if(!ApplyScaleAndClamp(color, state, preScaled))
 						{
 							return nullptr;
 						}
diff --git a/src/Renderer/Blitter.hpp b/src/Renderer/Blitter.hpp
index c411c09..e3db745 100644
--- a/src/Renderer/Blitter.hpp
+++ b/src/Renderer/Blitter.hpp
@@ -106,7 +106,7 @@
 		bool read(Int4 &color, Pointer<Byte> element, const State &state);
 		bool write(Int4 &color, Pointer<Byte> element, const State &state);
 		static bool GetScale(float4& scale, Format format);
-		static bool ApplyScaleAndClamp(Float4 &value, const State &state);
+		static bool ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled = false);
 		static Int ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes, bool quadLayout);
 		static Float4 LinearToSRGB(Float4 &color);
 		static Float4 sRGBtoLinear(Float4 &color);