Refactor sRGB color space conversions

We had duplicate sRGBtoLinear() functions between the Blitter and
SpirvShaderImage. The only difference was that the former only
modifies RGB components. This is now handled at the call site in the
Blitter itself, using a component mask.

This refactoring makes LinearToSRGB() available in SpirvShaderImage
for subsequent use by the OpImageWrite implementation.

Bug: b/224796232
Change-Id: I8c65a6e5b6ab7078e036f9963b2dfb9e8c25dd92
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/64948
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: 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 871f43d..1c18a23 100644
--- a/src/Device/Blitter.cpp
+++ b/src/Device/Blitter.cpp
@@ -30,17 +30,15 @@
 #	include <emmintrin.h>
 #endif
 
-namespace {
-rr::RValue<rr::Int> PackFields(rr::Int4 const &ints, const sw::int4 shifts)
+namespace sw {
+
+static rr::RValue<rr::Int> PackFields(rr::Int4 const &ints, const sw::int4 shifts)
 {
 	return (rr::Int(ints.x) << shifts[0]) |
 	       (rr::Int(ints.y) << shifts[1]) |
 	       (rr::Int(ints.z) << shifts[2]) |
 	       (rr::Int(ints.w) << shifts[3]);
 }
-}  // namespace
-
-namespace sw {
 
 Blitter::Blitter()
     : blitMutex()
@@ -1450,7 +1448,7 @@
 	{
 		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.xyz = (srcSRGB && !preScaled) ? sRGBtoLinear(value) : linearToSRGB(value);
 		value *= Float4(scale.x, scale.y, scale.z, scale.w);  // Apply scale
 	}
 	else if(unscale != scale)
@@ -1484,30 +1482,6 @@
 	return z * sliceB + y * pitchB + x * bytes;
 }
 
-Float4 Blitter::LinearToSRGB(const Float4 &c)
-{
-	Float4 lc = Min(c, 0.0031308f) * 12.92f;
-	Float4 ec = Float4(1.055f) * Pow<Mediump>(c, (1.0f / 2.4f)) - 0.055f;  // TODO(b/149574741): Use a custom approximation.
-
-	Float4 s = c;
-	s.xyz = Max(lc, ec);
-
-	return s;
-}
-
-Float4 Blitter::sRGBtoLinear(const Float4 &c)
-{
-	Float4 lc = c * (1.0f / 12.92f);
-	Float4 ec = Pow<Mediump>((c + 0.055f) * (1.0f / 1.055f), 2.4f);  // TODO(b/149574741): Use a custom approximation.
-
-	Int4 linear = CmpLT(c, 0.04045f);
-
-	Float4 s = c;
-	s.xyz = As<Float4>((linear & As<Int4>(lc)) | (~linear & As<Int4>(ec)));  // TODO: IfThenElse()
-
-	return s;
-}
-
 Float4 Blitter::sample(Pointer<Byte> &source, Float &x, Float &y, Float &z,
                        Int &sWidth, Int &sHeight, Int &sDepth,
                        Int &sSliceB, Int &sPitchB, const State &state)
diff --git a/src/Device/Blitter.hpp b/src/Device/Blitter.hpp
index 65a9cf6..c7a9108 100644
--- a/src/Device/Blitter.hpp
+++ b/src/Device/Blitter.hpp
@@ -169,8 +169,6 @@
 	static void ApplyScaleAndClamp(Float4 &value, const State &state, bool preScaled = false);
 	static Int ComputeOffset(Int &x, Int &y, Int &pitchB, int bytes);
 	static Int ComputeOffset(Int &x, Int &y, Int &z, Int &sliceB, Int &pitchB, int bytes);
-	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/ShaderCore.cpp b/src/Pipeline/ShaderCore.cpp
index a3bc666..42a289d 100644
--- a/src/Pipeline/ShaderCore.cpp
+++ b/src/Pipeline/ShaderCore.cpp
@@ -699,6 +699,23 @@
 	return (UInt(truncBits.x) >> 20) | (UInt(truncBits.y) >> 9) | (UInt(truncBits.z) << 1);
 }
 
+Float4 linearToSRGB(const Float4 &c)
+{
+	Float4 lc = Min(c, 0.0031308f) * 12.92f;
+	Float4 ec = Float4(1.055f) * Pow<Mediump>(c, (1.0f / 2.4f)) - 0.055f;  // TODO(b/149574741): Use a custom approximation.
+
+	return Max(lc, ec);
+}
+
+Float4 sRGBtoLinear(const Float4 &c)
+{
+	Float4 lc = c * (1.0f / 12.92f);
+	Float4 ec = Pow<Mediump>((c + 0.055f) * (1.0f / 1.055f), 2.4f);  // TODO(b/149574741): Use a custom approximation.
+
+	Int4 linear = CmpLT(c, 0.04045f);
+	return As<Float4>((linear & As<Int4>(lc)) | (~linear & As<Int4>(ec)));  // TODO: IfThenElse()
+}
+
 RValue<Bool> AnyTrue(const RValue<SIMD::Int> &bools)
 {
 	return SignMask(bools) != 0;
diff --git a/src/Pipeline/ShaderCore.hpp b/src/Pipeline/ShaderCore.hpp
index c9bc3e1..68d9da4 100644
--- a/src/Pipeline/ShaderCore.hpp
+++ b/src/Pipeline/ShaderCore.hpp
@@ -241,6 +241,8 @@
 sw::SIMD::UInt floatToHalfBits(sw::SIMD::UInt floatBits, bool storeInUpperBits);
 Float4 r11g11b10Unpack(UInt r11g11b10bits);
 UInt r11g11b10Pack(const Float4 &value);
+Float4 linearToSRGB(const Float4 &c);
+Float4 sRGBtoLinear(const Float4 &c);
 
 RValue<Bool> AnyTrue(const RValue<SIMD::Int> &bools);
 RValue<Bool> AnyFalse(const RValue<SIMD::Int> &bools);
diff --git a/src/Pipeline/SpirvShaderImage.cpp b/src/Pipeline/SpirvShaderImage.cpp
index 57f96e6..9f224d4 100644
--- a/src/Pipeline/SpirvShaderImage.cpp
+++ b/src/Pipeline/SpirvShaderImage.cpp
@@ -21,11 +21,9 @@
 
 #include <spirv/unified1/spirv.hpp>
 
-namespace {
+namespace sw {
 
-using namespace sw;
-
-vk::Format SpirvFormatToVulkanFormat(spv::ImageFormat format)
+static vk::Format SpirvFormatToVulkanFormat(spv::ImageFormat format)
 {
 	switch(format)
 	{
@@ -76,20 +74,6 @@
 	}
 }
 
-SIMD::Float sRGBtoLinear(SIMD::Float c)
-{
-	SIMD::Float lc = c * (1.0f / 12.92f);
-	SIMD::Float ec = Pow<Mediump>((c + 0.055f) * (1.0f / 1.055f), 2.4f);  // TODO(b/149574741): Use a custom approximation.
-
-	SIMD::Int linear = CmpLT(c, 0.04045f);
-
-	return rr::As<SIMD::Float>((linear & rr::As<SIMD::Int>(lc)) | (~linear & rr::As<SIMD::Int>(ec)));  // TODO: IfThenElse()
-}
-
-}  // anonymous namespace
-
-namespace sw {
-
 SpirvShader::ImageInstruction::ImageInstruction(InsnIterator insn, const SpirvShader &spirv)
     : ImageInstructionSignature(parseVariantAndMethod(insn))
     , position(insn.distanceFrom(spirv.begin()))
@@ -909,9 +893,9 @@
 		break;
 	case VK_FORMAT_R8G8B8A8_SRGB:
 	case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
-		dst.move(0, ::sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
-		dst.move(1, ::sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
-		dst.move(2, ::sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
+		dst.move(0, sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
+		dst.move(1, sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
+		dst.move(2, sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
 		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
 		break;
 	case VK_FORMAT_B8G8R8A8_UNORM:
@@ -921,9 +905,9 @@
 		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
 		break;
 	case VK_FORMAT_B8G8R8A8_SRGB:
-		dst.move(0, ::sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
-		dst.move(1, ::sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
-		dst.move(2, ::sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
+		dst.move(0, sRGBtoLinear(SIMD::Float((packed[0] >> 16) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
+		dst.move(1, sRGBtoLinear(SIMD::Float((packed[0] >> 8) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
+		dst.move(2, sRGBtoLinear(SIMD::Float(packed[0] & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF)));
 		dst.move(3, SIMD::Float((packed[0] >> 24) & SIMD::Int(0xFF)) * SIMD::Float(1.0f / 0xFF));
 		break;
 	case VK_FORMAT_R8G8B8A8_UINT: