Optimize sRGB8 lookups by using lut.

Change-Id: I8e77ed3d6572130658b67f8b1dcccad68583d2e6
diff --git a/Android.mk b/Android.mk
index 68fe0bd..be05333 100644
--- a/Android.mk
+++ b/Android.mk
@@ -659,6 +659,7 @@
 	modules/glshared/glsUniformBlockCase.cpp \
 	modules/glshared/glsVertexArrayTests.cpp \
 	modules/internal/ditBuildInfoTests.cpp \
+	modules/internal/ditSRGB8ConversionTest.cpp \
 	modules/internal/ditDelibsTests.cpp \
 	modules/internal/ditFrameworkTests.cpp \
 	modules/internal/ditImageCompareTests.cpp \
diff --git a/framework/common/tcuSRGB8Lut.inl b/framework/common/tcuSRGB8Lut.inl
new file mode 100644
index 0000000..f38a499
--- /dev/null
+++ b/framework/common/tcuSRGB8Lut.inl
@@ -0,0 +1,257 @@
+	// Generated on x86_64 linux
+	0x0u,
+	0x399f22b4u,
+	0x3a1f22b4u,
+	0x3a6eb40eu,
+	0x3a9f22b4u,
+	0x3ac6eb61u,
+	0x3aeeb40eu,
+	0x3b0b3e5du,
+	0x3b1f22b4u,
+	0x3b33070bu,
+	0x3b46eb61u,
+	0x3b5b518du,
+	0x3b70f18du,
+	0x3b83e1c6u,
+	0x3b8fe616u,
+	0x3b9c87fdu,
+	0x3ba9c9b6u,
+	0x3bb7ad6fu,
+	0x3bc63549u,
+	0x3bd56361u,
+	0x3be539c1u,
+	0x3bf5ba70u,
+	0x3c0373b5u,
+	0x3c0c6152u,
+	0x3c15a703u,
+	0x3c1f45beu,
+	0x3c293e6bu,
+	0x3c3391f7u,
+	0x3c3e4149u,
+	0x3c494d43u,
+	0x3c54b6c7u,
+	0x3c607eb1u,
+	0x3c6ca5dfu,
+	0x3c792d22u,
+	0x3c830aa8u,
+	0x3c89af9eu,
+	0x3c9085dbu,
+	0x3c978dc5u,
+	0x3c9ec7c2u,
+	0x3ca63434u,
+	0x3cadd37du,
+	0x3cb5a601u,
+	0x3cbdac20u,
+	0x3cc5e639u,
+	0x3cce54abu,
+	0x3cd6f7d5u,
+	0x3cdfd010u,
+	0x3ce8ddb9u,
+	0x3cf2212cu,
+	0x3cfb9ac1u,
+	0x3d02a569u,
+	0x3d0798dcu,
+	0x3d0ca7e6u,
+	0x3d11d2afu,
+	0x3d171963u,
+	0x3d1c7c2eu,
+	0x3d21fb3cu,
+	0x3d2796b2u,
+	0x3d2d4ebbu,
+	0x3d332380u,
+	0x3d39152bu,
+	0x3d3f23e3u,
+	0x3d454fd0u,
+	0x3d4b991cu,
+	0x3d51ffeeu,
+	0x3d58846au,
+	0x3d5f26b7u,
+	0x3d65e6feu,
+	0x3d6cc564u,
+	0x3d73c210u,
+	0x3d7add29u,
+	0x3d810b67u,
+	0x3d84b795u,
+	0x3d887330u,
+	0x3d8c3e4au,
+	0x3d9018f6u,
+	0x3d940345u,
+	0x3d97fd4au,
+	0x3d9c0716u,
+	0x3da020bbu,
+	0x3da44a4bu,
+	0x3da883d6u,
+	0x3daccd70u,
+	0x3db12728u,
+	0x3db59112u,
+	0x3dba0b3au,
+	0x3dbe95b5u,
+	0x3dc33092u,
+	0x3dc7dbe2u,
+	0x3dcc97b6u,
+	0x3dd1641fu,
+	0x3dd6412cu,
+	0x3ddb2eefu,
+	0x3de02d77u,
+	0x3de53cd5u,
+	0x3dea5d19u,
+	0x3def8e52u,
+	0x3df4d091u,
+	0x3dfa23e8u,
+	0x3dff8861u,
+	0x3e027f07u,
+	0x3e054280u,
+	0x3e080ea3u,
+	0x3e0ae378u,
+	0x3e0dc105u,
+	0x3e10a754u,
+	0x3e13966bu,
+	0x3e168e52u,
+	0x3e198f10u,
+	0x3e1c98adu,
+	0x3e1fab30u,
+	0x3e22c6a3u,
+	0x3e25eb09u,
+	0x3e29186cu,
+	0x3e2c4ed0u,
+	0x3e2f8e42u,
+	0x3e32d6c4u,
+	0x3e362861u,
+	0x3e39831eu,
+	0x3e3ce702u,
+	0x3e405416u,
+	0x3e43ca5eu,
+	0x3e4749e4u,
+	0x3e4ad2aeu,
+	0x3e4e64c2u,
+	0x3e520027u,
+	0x3e55a4e6u,
+	0x3e595303u,
+	0x3e5d0a8au,
+	0x3e60cb7cu,
+	0x3e6495e0u,
+	0x3e6869bfu,
+	0x3e6c4720u,
+	0x3e702e0cu,
+	0x3e741e84u,
+	0x3e781890u,
+	0x3e7c1c38u,
+	0x3e8014c2u,
+	0x3e82203bu,
+	0x3e84308du,
+	0x3e8645bau,
+	0x3e885fc5u,
+	0x3e8a7eb2u,
+	0x3e8ca283u,
+	0x3e8ecb3cu,
+	0x3e90f8e1u,
+	0x3e932b74u,
+	0x3e9562f8u,
+	0x3e979f71u,
+	0x3e99e0e2u,
+	0x3e9c274eu,
+	0x3e9e72b8u,
+	0x3ea0c322u,
+	0x3ea31892u,
+	0x3ea57308u,
+	0x3ea7d28au,
+	0x3eaa3718u,
+	0x3eaca0b7u,
+	0x3eaf0f69u,
+	0x3eb18332u,
+	0x3eb3fc18u,
+	0x3eb67a18u,
+	0x3eb8fd37u,
+	0x3ebb8579u,
+	0x3ebe12e0u,
+	0x3ec0a571u,
+	0x3ec33d2du,
+	0x3ec5da17u,
+	0x3ec87c33u,
+	0x3ecb2383u,
+	0x3ecdd00bu,
+	0x3ed081ccu,
+	0x3ed338ccu,
+	0x3ed5f50au,
+	0x3ed8b68du,
+	0x3edb7d54u,
+	0x3ede4965u,
+	0x3ee11ac1u,
+	0x3ee3f16bu,
+	0x3ee6cd67u,
+	0x3ee9aeb6u,
+	0x3eec955du,
+	0x3eef815du,
+	0x3ef272bau,
+	0x3ef56976u,
+	0x3ef86594u,
+	0x3efb6717u,
+	0x3efe6e02u,
+	0x3f00bd2du,
+	0x3f02460eu,
+	0x3f03d1a7u,
+	0x3f055ff9u,
+	0x3f06f106u,
+	0x3f0884cfu,
+	0x3f0a1b56u,
+	0x3f0bb49bu,
+	0x3f0d50a0u,
+	0x3f0eef67u,
+	0x3f1090f1u,
+	0x3f12353eu,
+	0x3f13dc51u,
+	0x3f15862bu,
+	0x3f1732cdu,
+	0x3f18e239u,
+	0x3f1a946fu,
+	0x3f1c4972u,
+	0x3f1e0141u,
+	0x3f1fbbe0u,
+	0x3f21794eu,
+	0x3f23398eu,
+	0x3f24fca0u,
+	0x3f26c286u,
+	0x3f288b42u,
+	0x3f2a56d3u,
+	0x3f2c253du,
+	0x3f2df680u,
+	0x3f2fca9fu,
+	0x3f31a197u,
+	0x3f337b6cu,
+	0x3f355820u,
+	0x3f3737b2u,
+	0x3f391a26u,
+	0x3f3aff7cu,
+	0x3f3ce7b4u,
+	0x3f3ed2d2u,
+	0x3f40c0d4u,
+	0x3f42b1beu,
+	0x3f44a590u,
+	0x3f469c4bu,
+	0x3f4895f0u,
+	0x3f4a9282u,
+	0x3f4c9201u,
+	0x3f4e946eu,
+	0x3f5099cau,
+	0x3f52a218u,
+	0x3f54ad57u,
+	0x3f56bb8au,
+	0x3f58ccb0u,
+	0x3f5ae0cdu,
+	0x3f5cf7e0u,
+	0x3f5f11ecu,
+	0x3f612eeeu,
+	0x3f634eefu,
+	0x3f6571eau,
+	0x3f6797e3u,
+	0x3f69c0d6u,
+	0x3f6beccdu,
+	0x3f6e1bc0u,
+	0x3f704db8u,
+	0x3f7282afu,
+	0x3f74baaeu,
+	0x3f76f5aeu,
+	0x3f7933b8u,
+	0x3f7b74c6u,
+	0x3f7db8e0u,
+	0x3f800000u
diff --git a/framework/common/tcuTexture.cpp b/framework/common/tcuTexture.cpp
index 43c7616..a41d9c6 100644
--- a/framework/common/tcuTexture.cpp
+++ b/framework/common/tcuTexture.cpp
@@ -1187,8 +1187,21 @@
 // Texel lookup with color conversion.
 static inline Vec4 lookup (const ConstPixelBufferAccess& access, int i, int j, int k)
 {
-	Vec4 p = access.getPixel(i, j, k);
-	return isSRGB(access.getFormat()) ? sRGBToLinear(p) : p;
+	const TextureFormat&	format	= access.getFormat();
+
+	if (isSRGB(format))
+	{
+		if (format.type == TextureFormat::UNORM_INT8 && format.order == TextureFormat::sRGB)
+				return sRGB8ToLinear(access.getPixelUint(i, j, k));
+		else if (format.type == TextureFormat::UNORM_INT8 && format.order == TextureFormat::sRGBA)
+				return sRGBA8ToLinear(access.getPixelUint(i, j, k));
+		else
+			return sRGBToLinear(access.getPixel(i, j, k));
+	}
+	else
+	{
+		return access.getPixel(i, j, k);
+	}
 }
 
 // Border texel lookup with color conversion.
diff --git a/framework/common/tcuTextureUtil.cpp b/framework/common/tcuTextureUtil.cpp
index f11778e..5ac30de 100644
--- a/framework/common/tcuTextureUtil.cpp
+++ b/framework/common/tcuTextureUtil.cpp
@@ -40,6 +40,19 @@
 		return deFloatPow((cs + 0.055f) / 1.055f, 2.4f);
 }
 
+static const deUint32 s_srgb8Lut[256] =
+{
+#include "tcuSRGB8Lut.inl"
+};
+
+static inline float sRGB8ChannelToLinear (deUint32 cs)
+{
+	DE_ASSERT(cs < 256);
+
+	// \note This triggers UB, but in practice it doesn't cause any problems
+	return ((const float*)s_srgb8Lut)[cs];
+}
+
 static inline float linearChannelToSRGB (float cl)
 {
 	if (cl <= 0.0f)
@@ -61,6 +74,22 @@
 				cs[3]);
 }
 
+Vec4 sRGB8ToLinear (const UVec4& cs)
+{
+	return Vec4(sRGB8ChannelToLinear(cs[0]),
+				sRGB8ChannelToLinear(cs[1]),
+				sRGB8ChannelToLinear(cs[2]),
+				1.0f);
+}
+
+Vec4 sRGBA8ToLinear (const UVec4& cs)
+{
+	return Vec4(sRGB8ChannelToLinear(cs[0]),
+				sRGB8ChannelToLinear(cs[1]),
+				sRGB8ChannelToLinear(cs[2]),
+				(float)cs[3] / 255.0f);
+}
+
 //! Convert from linear to sRGB colorspace
 Vec4 linearToSRGB (const Vec4& cl)
 {
diff --git a/framework/common/tcuTextureUtil.hpp b/framework/common/tcuTextureUtil.hpp
index b31f2d0..056a930 100644
--- a/framework/common/tcuTextureUtil.hpp
+++ b/framework/common/tcuTextureUtil.hpp
@@ -45,6 +45,8 @@
 
 // sRGB - linear conversion.
 Vec4					sRGBToLinear				(const Vec4& cs);
+Vec4					sRGB8ToLinear				(const UVec4& cs);
+Vec4					sRGBA8ToLinear				(const UVec4& cs);
 Vec4					linearToSRGB				(const Vec4& cl);
 bool					isSRGB						(TextureFormat format);
 
diff --git a/modules/internal/CMakeLists.txt b/modules/internal/CMakeLists.txt
index d14a271..a8f7983 100644
--- a/modules/internal/CMakeLists.txt
+++ b/modules/internal/CMakeLists.txt
@@ -19,6 +19,8 @@
 	ditTestPackage.hpp
 	ditSeedBuilderTests.hpp
 	ditSeedBuilderTests.cpp
+	ditSRGB8ConversionTest.hpp
+	ditSRGB8ConversionTest.cpp
 	)
 
 set(DE_INTERNAL_TESTS_LIBS
diff --git a/modules/internal/ditSRGB8ConversionTest.cpp b/modules/internal/ditSRGB8ConversionTest.cpp
new file mode 100644
index 0000000..5092e73
--- /dev/null
+++ b/modules/internal/ditSRGB8ConversionTest.cpp
@@ -0,0 +1,104 @@
+/*-------------------------------------------------------------------------
+ * drawElements Internal Test Module
+ * ---------------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief 8-bit sRGB conversion test.
+ *//*--------------------------------------------------------------------*/
+
+#include "ditSRGB8ConversionTest.hpp"
+
+#include "tcuFloat.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuTextureUtil.hpp"
+#include "tcuVectorUtil.hpp"
+
+namespace dit
+{
+namespace
+{
+
+deUint32 calculateDiscreteFloatDistance (float a, float b)
+{
+	const deUint32		au		= tcu::Float32(a).bits();
+	const deUint32		bu		= tcu::Float32(b).bits();
+
+	const bool			asign	= (au & (0x1u << 31u)) != 0u;
+	const bool			bsign	= (bu & (0x1u << 31u)) != 0u;
+
+	const deUint32		avalue	= (au & ((0x1u << 31u) - 1u));
+	const deUint32		bvalue	= (bu & ((0x1u << 31u) - 1u));
+
+	if (asign != bsign)
+		return avalue + bvalue + 1u;
+	else if (avalue < bvalue)
+		return bvalue - avalue;
+	else
+		return avalue - bvalue;
+}
+
+const tcu::UVec4 calculateDiscreteFloatDistance (const tcu::Vec4& ref, const tcu::Vec4& res)
+{
+	return tcu::UVec4(calculateDiscreteFloatDistance(ref[0], res[0]), calculateDiscreteFloatDistance(ref[1], res[1]), calculateDiscreteFloatDistance(ref[2], res[2]), calculateDiscreteFloatDistance(ref[3], res[3]));
+}
+
+class SRGB8ConversionTest : public tcu::TestCase
+{
+public:
+	SRGB8ConversionTest (tcu::TestContext& context)
+		: tcu::TestCase	(context, "srgb8", "SRGB8 conversion test")
+	{
+	}
+
+	IterateResult iterate (void)
+	{
+		bool			isOk	= true;
+		tcu::TestLog&	log		= m_testCtx.getLog();
+
+		for (int i = 0; i < 256; i++)
+		{
+			const tcu::UVec4	src					(i);
+			const tcu::Vec4		res					(tcu::sRGBA8ToLinear(src));
+			const tcu::Vec4		ref					(tcu::sRGBToLinear(src.cast<float>() / tcu::Vec4(255.0f)));
+			const tcu::Vec4		diff				(res - ref);
+			const tcu::UVec4	discreteFloatDiff	(calculateDiscreteFloatDistance(ref, res));
+
+			if (tcu::anyNotEqual(res, ref))
+				log << tcu::TestLog::Message << i << ", Res: " << res << ", Ref: " << ref << ", Diff: " << diff << ", Discrete float diff: " << discreteFloatDiff << tcu::TestLog::EndMessage;
+
+			if (tcu::boolAny(tcu::greaterThan(discreteFloatDiff, tcu::UVec4(1u))))
+				isOk = false;
+		}
+
+		if (isOk)
+			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
+		else
+			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Got ulp diffs greater than one.");
+
+		return STOP;
+	}
+};
+
+} // anonymous
+
+tcu::TestCase* createSRGB8ConversionTest (tcu::TestContext& context)
+{
+	return new SRGB8ConversionTest(context);
+}
+
+} // dit
diff --git a/modules/internal/ditSRGB8ConversionTest.hpp b/modules/internal/ditSRGB8ConversionTest.hpp
new file mode 100644
index 0000000..536babb
--- /dev/null
+++ b/modules/internal/ditSRGB8ConversionTest.hpp
@@ -0,0 +1,36 @@
+#ifndef _DITSRGB8CONVERSIONTEST_HPP
+#define _DITSRGB8CONVERSIONTEST_HPP
+/*-------------------------------------------------------------------------
+ * drawElements Internal Test Module
+ * ---------------------------------
+ *
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief 8-bit sRGB conversion test.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "tcuTestCase.hpp"
+
+namespace dit
+{
+
+tcu::TestCase* createSRGB8ConversionTest (tcu::TestContext& context);
+
+} // dit
+
+#endif // _DITSRGB8CONVERSIONTEST_HPP
diff --git a/modules/internal/ditTestPackage.cpp b/modules/internal/ditTestPackage.cpp
index a290c70..607a7d1 100644
--- a/modules/internal/ditTestPackage.cpp
+++ b/modules/internal/ditTestPackage.cpp
@@ -29,9 +29,26 @@
 #include "ditImageCompareTests.hpp"
 #include "ditTestLogTests.hpp"
 #include "ditSeedBuilderTests.hpp"
+#include "ditSRGB8ConversionTest.hpp"
 
 namespace dit
 {
+namespace
+{
+
+class TextureTests : public tcu::TestCaseGroup
+{
+public:
+	TextureTests (tcu::TestContext& testCtx)
+		: tcu::TestCaseGroup(testCtx, "texture", "Tests for tcu::Texture and utils.")
+	{
+	}
+
+	void init (void)
+	{
+		addChild(createSRGB8ConversionTest(m_testCtx));
+	}
+};
 
 class DeqpTests : public tcu::TestCaseGroup
 {
@@ -46,10 +63,13 @@
 		addChild(new TestLogTests		(m_testCtx));
 		addChild(new ImageIOTests		(m_testCtx));
 		addChild(new ImageCompareTests	(m_testCtx));
+		addChild(new TextureTests		(m_testCtx));
 		addChild(createSeedBuilderTests	(m_testCtx));
 	}
 };
 
+} // anonymous
+
 class TestCaseExecutor : public tcu::TestCaseExecutor
 {
 public: