Fix sRGB conversion precision issues

When sampling an sRGB texture format, we have a vector of 16-bit
elements where 0xFF00 represents 1.0, but we were using a lookup table
which produced results in a 0xFFFF base.

Also on linear to sRGB conversion, precision was lost due to truncating
to 12-bit. Adding a rounding factor before truncating preserves
precision.

Bug: b/149574741
Change-Id: I19218c958867c4b5e97dc3b62b4ea83f37161134
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/41268
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Device/Blitter.cpp b/src/Device/Blitter.cpp
index f85c524..4b1b485 100644
--- a/src/Device/Blitter.cpp
+++ b/src/Device/Blitter.cpp
@@ -1354,7 +1354,7 @@
 	return y * pitchB + x * bytes;
 }
 
-Float4 Blitter::LinearToSRGB(Float4 &c)
+Float4 Blitter::LinearToSRGB(const Float4 &c)
 {
 	Float4 lc = Min(c, Float4(0.0031308f)) * Float4(12.92f);
 	Float4 ec = Float4(1.055f) * power(c, Float4(1.0f / 2.4f)) - Float4(0.055f);
@@ -1365,7 +1365,7 @@
 	return s;
 }
 
-Float4 Blitter::sRGBtoLinear(Float4 &c)
+Float4 Blitter::sRGBtoLinear(const Float4 &c)
 {
 	Float4 lc = c * Float4(1.0f / 12.92f);
 	Float4 ec = power((c + Float4(0.055f)) * Float4(1.0f / 1.055f), Float4(2.4f));
diff --git a/src/Device/Blitter.hpp b/src/Device/Blitter.hpp
index ef8977e..5c99072 100644
--- a/src/Device/Blitter.hpp
+++ b/src/Device/Blitter.hpp
@@ -161,8 +161,8 @@
 	void write(Int4 &color, Pointer<Byte> element, const State &state);
 	static void ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled = false);
 	static Int ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes);
-	static Float4 LinearToSRGB(Float4 &color);
-	static Float4 sRGBtoLinear(Float4 &color);
+	static Float4 LinearToSRGB(const Float4 &color);
+	static Float4 sRGBtoLinear(const Float4 &color);
 
 	using BlitFunction = FunctionT<void(const BlitData *)>;
 	using BlitRoutineType = BlitFunction::RoutineType;
diff --git a/src/Pipeline/Constants.cpp b/src/Pipeline/Constants.cpp
index 1f93ded..df4b1b2 100644
--- a/src/Pipeline/Constants.cpp
+++ b/src/Pipeline/Constants.cpp
@@ -270,7 +270,7 @@
 
 	for(int i = 0; i < 256; i++)
 	{
-		sRGBtoLinear8_16[i] = (unsigned short)(sRGBtoLinear((float)i / 0xFF) * 0xFFFF + 0.5f);
+		sRGBtoLinearFF_FF00[i] = (unsigned short)(sRGBtoLinear((float)i / 0xFF) * 0xFF00 + 0.5f);
 	}
 
 	for(int i = 0; i < 0x1000; i++)
diff --git a/src/Pipeline/Constants.hpp b/src/Pipeline/Constants.hpp
index 88448e0..d80bf36 100644
--- a/src/Pipeline/Constants.hpp
+++ b/src/Pipeline/Constants.hpp
@@ -72,7 +72,7 @@
 	word4 mask5551Q[16];  // 4 bit writemask -> A1R5G5B5 bit patterns, replicated 4x
 	dword4 mask11X[8];    // 3 bit writemask -> B10G11R11 bit patterns, replicated 4x
 
-	unsigned short sRGBtoLinear8_16[256];
+	unsigned short sRGBtoLinearFF_FF00[256];
 
 	unsigned short linearToSRGB12_16[4096];
 	unsigned short sRGBtoLinear12_16[4096];
diff --git a/src/Pipeline/PixelRoutine.cpp b/src/Pipeline/PixelRoutine.cpp
index 6a46978..8543a5e 100644
--- a/src/Pipeline/PixelRoutine.cpp
+++ b/src/Pipeline/PixelRoutine.cpp
@@ -2711,9 +2711,9 @@
 {
 	Pointer<Byte> LUT = constants + OFFSET(Constants, sRGBtoLinear12_16);
 
-	c.x = As<UShort4>(c.x) >> 4;
-	c.y = As<UShort4>(c.y) >> 4;
-	c.z = As<UShort4>(c.z) >> 4;
+	c.x = AddSat(As<UShort4>(c.x), UShort4(0x0007)) >> 4;
+	c.y = AddSat(As<UShort4>(c.y), UShort4(0x0007)) >> 4;
+	c.z = AddSat(As<UShort4>(c.z), UShort4(0x0007)) >> 4;
 
 	c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 0))), 0);
 	c.x = Insert(c.x, *Pointer<Short>(LUT + 2 * Int(Extract(c.x, 1))), 1);
@@ -2733,9 +2733,9 @@
 
 void PixelRoutine::linearToSRGB16_12_16(Vector4s &c)
 {
-	c.x = As<UShort4>(c.x) >> 4;
-	c.y = As<UShort4>(c.y) >> 4;
-	c.z = As<UShort4>(c.z) >> 4;
+	c.x = AddSat(As<UShort4>(c.x), UShort4(0x0007)) >> 4;
+	c.y = AddSat(As<UShort4>(c.y), UShort4(0x0007)) >> 4;
+	c.z = AddSat(As<UShort4>(c.z), UShort4(0x0007)) >> 4;
 
 	linearToSRGB12_16(c);
 }
diff --git a/src/Pipeline/SamplerCore.cpp b/src/Pipeline/SamplerCore.cpp
index dfffa87..811865a 100644
--- a/src/Pipeline/SamplerCore.cpp
+++ b/src/Pipeline/SamplerCore.cpp
@@ -1746,7 +1746,10 @@
 		{
 			if(isRGBComponent(i))
 			{
-				sRGBtoLinear16_8_16(c[i]);
+				// The current table-based sRGB conversion requires 0xFF00 to represent 1.0.
+				ASSERT(state.textureFormat.has8bitTextureComponents());
+
+				sRGBtoLinearFF00(c[i]);
 			}
 		}
 	}
@@ -2492,11 +2495,11 @@
 	cf = Float4(As<UShort4>(cs)) * Float4(1.0f / 0xFFFF);
 }
 
-void SamplerCore::sRGBtoLinear16_8_16(Short4 &c)
+void SamplerCore::sRGBtoLinearFF00(Short4 &c)
 {
 	c = As<UShort4>(c) >> 8;
 
-	Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants, sRGBtoLinear8_16));
+	Pointer<Byte> LUT = Pointer<Byte>(constants + OFFSET(Constants, sRGBtoLinearFF_FF00));
 
 	c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 0))), 0);
 	c = Insert(c, *Pointer<Short>(LUT + 2 * Int(Extract(c, 1))), 1);
diff --git a/src/Pipeline/SamplerCore.hpp b/src/Pipeline/SamplerCore.hpp
index b1e925f..f7b6122 100644
--- a/src/Pipeline/SamplerCore.hpp
+++ b/src/Pipeline/SamplerCore.hpp
@@ -96,7 +96,7 @@
 
 	void convertSigned15(Float4 &cf, Short4 &ci);
 	void convertUnsigned16(Float4 &cf, Short4 &ci);
-	void sRGBtoLinear16_8_16(Short4 &c);
+	void sRGBtoLinearFF00(Short4 &c);
 
 	bool hasFloatTexture() const;
 	bool hasUnnormalizedIntegerTexture() const;
diff --git a/src/Pipeline/ShaderCore.cpp b/src/Pipeline/ShaderCore.cpp
index 2a1dc5b..fff67ad 100644
--- a/src/Pipeline/ShaderCore.cpp
+++ b/src/Pipeline/ShaderCore.cpp
@@ -162,13 +162,13 @@
 
 Float4 exponential(RValue<Float4> x, bool pp)
 {
-	// FIXME: Propagate the constant
+	// TODO: Propagate the constant
 	return exponential2(Float4(1.44269504f) * x, pp);  // 1/ln(2)
 }
 
 Float4 logarithm(RValue<Float4> x, bool pp)
 {
-	// FIXME: Propagate the constant
+	// TODO: Propagate the constant
 	return Float4(6.93147181e-1f) * logarithm2(x, pp);  // ln(2)
 }
 
diff --git a/src/System/Math.hpp b/src/System/Math.hpp
index 9004d9f..7dcffd7 100644
--- a/src/System/Math.hpp
+++ b/src/System/Math.hpp
@@ -330,11 +330,11 @@
 {
 	if(c <= 0.04045f)
 	{
-		return c * 0.07739938f;  // 1.0f / 12.92f;
+		return c / 12.92f;
 	}
 	else
 	{
-		return powf((c + 0.055f) * 0.9478673f, 2.4f);  // 1.0f / 1.055f
+		return powf((c + 0.055f) / 1.055f, 2.4f);
 	}
 }
 
@@ -346,7 +346,7 @@
 	}
 	else
 	{
-		return 1.055f * powf(c, 0.4166667f) - 0.055f;  // 1.0f / 2.4f
+		return 1.055f * powf(c, 1.0f / 2.4f) - 0.055f;
 	}
 }