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;
}
}