New format conversion classes and routines

- A new routine has been added to convert from any component of
  8bit sRGB data to 8bit linear RGB, using a precomputed array.
- Two new classes have been added to easily convert to and from
  the RGB9E5 format and the R11G11B10F format.

Change-Id: I85ca58bed30bcd5a9130bca5040d351badabb19e
Reviewed-on: https://swiftshader-review.googlesource.com/3990
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/Common/Math.cpp b/src/Common/Math.cpp
index d0e488c..e8ae3d2 100644
--- a/src/Common/Math.cpp
+++ b/src/Common/Math.cpp
@@ -31,4 +31,18 @@
 
 		return hash;
 	}
+
+	unsigned char sRGB8toLinear8(unsigned char value)
+	{
+		static unsigned char sRGBtoLinearTable[256] = { 255 };
+		if(sRGBtoLinearTable[0] == 255)
+		{
+			for(int i = 0; i < 256; i++)
+			{
+				sRGBtoLinearTable[i] = static_cast<unsigned char>(sw::sRGBtoLinear(static_cast<float>(i) / 255.0f) * 255.0f + 0.5f);
+			}
+		}
+
+		return sRGBtoLinearTable[value];
+	}
 }
diff --git a/src/Common/Math.hpp b/src/Common/Math.hpp
index 07cb7a0..e2d7409 100644
--- a/src/Common/Math.hpp
+++ b/src/Common/Math.hpp
@@ -280,6 +280,8 @@
 		}

 	}

 

+	unsigned char sRGB8toLinear8(unsigned char value);

+

 	uint64_t FNV_1a(const unsigned char *data, int size);   // Fowler-Noll-Vo hash function

 

 	// Round up to the next multiple of alignment

@@ -287,6 +289,317 @@
 	{

 		return ((value + alignment - 1) / alignment) * alignment;

 	}

+

+	class RGB9E5Data

+	{

+		union

+		{

+			struct

+			{

+				unsigned int R : 9;

+				unsigned int G : 9;

+				unsigned int B : 9;

+				unsigned int E : 5;

+			};

+			unsigned int uint;

+		};

+

+		// Exponent Bias

+		static const int Bias = 15;

+

+		// Number of mantissa bits per component

+		static const int MantissaBits = 9;

+

+	public:

+		RGB9E5Data(float red, float green, float blue)

+		{

+			// Maximum allowed biased exponent value

+			static const int MaxExponent = 31;

+

+			static const float MaxValue = ((pow(2.0f, MantissaBits) - 1) / pow(2.0f, MantissaBits)) * pow(2.0f, MaxExponent - Bias);

+

+			const float red_c = sw::max(0.0f, sw::min(MaxValue, red));

+			const float green_c = sw::max(0.0f, sw::min(MaxValue, green));

+			const float blue_c = sw::max(0.0f, sw::min(MaxValue, blue));

+

+			const float max_c = sw::max(sw::max(red_c, green_c), blue_c);

+			const float exp_p = sw::max(-Bias - 1.0f, floor(log(max_c))) + 1.0f + Bias;

+			const int max_s = static_cast<int>(floor((max_c / (pow(2.0f, exp_p - Bias - MantissaBits))) + 0.5f));

+			const int exp_s = static_cast<int>((max_s < pow(2.0f, MantissaBits)) ? exp_p : exp_p + 1);

+

+			R = static_cast<unsigned int>(floor((red_c / (pow(2.0f, exp_s - Bias - MantissaBits))) + 0.5f));

+			G = static_cast<unsigned int>(floor((green_c / (pow(2.0f, exp_s - Bias - MantissaBits))) + 0.5f));

+			B = static_cast<unsigned int>(floor((blue_c / (pow(2.0f, exp_s - Bias - MantissaBits))) + 0.5f));

+			E = exp_s;

+		}

+

+		void toRGBFloats(float *red, float *green, float *blue) const

+		{

+			*red = R * pow(2.0f, (int)E - Bias - MantissaBits);

+			*green = G * pow(2.0f, (int)E - Bias - MantissaBits);

+			*blue = B * pow(2.0f, (int)E - Bias - MantissaBits);

+		}

+

+		unsigned int toUInt() const

+		{

+			return uint;

+		}

+	};

+

+	class R11G11B10FData

+	{

+		union

+		{

+			struct

+			{

+				unsigned int R : 11;

+				unsigned int G : 11;

+				unsigned int B : 10;

+			};

+

+			unsigned int uint;

+		};

+

+		static inline unsigned short float32ToFloat11(float fp32)

+		{

+			const unsigned int float32MantissaMask = 0x7FFFFF;

+			const unsigned int float32ExponentMask = 0x7F800000;

+			const unsigned int float32SignMask = 0x80000000;

+			const unsigned int float32ValueMask = ~float32SignMask;

+			const unsigned int float32ExponentFirstBit = 23;

+			const unsigned int float32ExponentBias = 127;

+

+			const unsigned short float11Max = 0x7BF;

+			const unsigned short float11MantissaMask = 0x3F;

+			const unsigned short float11ExponentMask = 0x7C0;

+			const unsigned short float11BitMask = 0x7FF;

+			const unsigned int float11ExponentBias = 14;

+

+			const unsigned int float32Maxfloat11 = 0x477E0000;

+			const unsigned int float32Minfloat11 = 0x38800000;

+

+			const unsigned int float32Bits = *(unsigned int*)(&fp32);

+			const bool float32Sign = (float32Bits & float32SignMask) == float32SignMask;

+

+			unsigned int float32Val = float32Bits & float32ValueMask;

+

+			if((float32Val & float32ExponentMask) == float32ExponentMask)

+			{

+				// INF or NAN

+				if((float32Val & float32MantissaMask) != 0)

+				{

+					return float11ExponentMask | (((float32Val >> 17) | (float32Val >> 11) | (float32Val >> 6) | (float32Val)) & float11MantissaMask);

+				}

+				else if(float32Sign)

+				{

+					// -INF is clamped to 0 since float11 is positive only

+					return 0;

+				}

+				else

+				{

+					return float11ExponentMask;

+				}

+			}

+			else if(float32Sign)

+			{

+				// float11 is positive only, so clamp to zero

+				return 0;

+			}

+			else if(float32Val > float32Maxfloat11)

+			{

+				// The number is too large to be represented as a float11, set to max

+				return float11Max;

+			}

+			else

+			{

+				if(float32Val < float32Minfloat11)

+				{

+					// The number is too small to be represented as a normalized float11

+					// Convert it to a denormalized value.

+					const unsigned int shift = (float32ExponentBias - float11ExponentBias) - (float32Val >> float32ExponentFirstBit);

+					float32Val = ((1 << float32ExponentFirstBit) | (float32Val & float32MantissaMask)) >> shift;

+				}

+				else

+				{

+					// Rebias the exponent to represent the value as a normalized float11

+					float32Val += 0xC8000000;

+				}

+

+				return ((float32Val + 0xFFFF + ((float32Val >> 17) & 1)) >> 17) & float11BitMask;

+			}

+		}

+

+		static inline unsigned short float32ToFloat10(float fp32)

+		{

+			const unsigned int float32MantissaMask = 0x7FFFFF;

+			const unsigned int float32ExponentMask = 0x7F800000;

+			const unsigned int float32SignMask = 0x80000000;

+			const unsigned int float32ValueMask = ~float32SignMask;

+			const unsigned int float32ExponentFirstBit = 23;

+			const unsigned int float32ExponentBias = 127;

+

+			const unsigned short float10Max = 0x3DF;

+			const unsigned short float10MantissaMask = 0x1F;

+			const unsigned short float10ExponentMask = 0x3E0;

+			const unsigned short float10BitMask = 0x3FF;

+			const unsigned int float10ExponentBias = 14;

+

+			const unsigned int float32Maxfloat10 = 0x477C0000;

+			const unsigned int float32Minfloat10 = 0x38800000;

+

+			const unsigned int float32Bits = *(unsigned int*)(&fp32);

+			const bool float32Sign = (float32Bits & float32SignMask) == float32SignMask;

+

+			unsigned int float32Val = float32Bits & float32ValueMask;

+

+			if((float32Val & float32ExponentMask) == float32ExponentMask)

+			{

+				// INF or NAN

+				if((float32Val & float32MantissaMask) != 0)

+				{

+					return float10ExponentMask | (((float32Val >> 18) | (float32Val >> 13) | (float32Val >> 3) | (float32Val)) & float10MantissaMask);

+				}

+				else if(float32Sign)

+				{

+					// -INF is clamped to 0 since float11 is positive only

+					return 0;

+				}

+				else

+				{

+					return float10ExponentMask;

+				}

+			}

+			else if(float32Sign)

+			{

+				// float10 is positive only, so clamp to zero

+				return 0;

+			}

+			else if(float32Val > float32Maxfloat10)

+			{

+				// The number is too large to be represented as a float11, set to max

+				return float10Max;

+			}

+			else

+			{

+				if(float32Val < float32Minfloat10)

+				{

+					// The number is too small to be represented as a normalized float11

+					// Convert it to a denormalized value.

+					const unsigned int shift = (float32ExponentBias - float10ExponentBias) - (float32Val >> float32ExponentFirstBit);

+					float32Val = ((1 << float32ExponentFirstBit) | (float32Val & float32MantissaMask)) >> shift;

+				}

+				else

+				{

+					// Rebias the exponent to represent the value as a normalized float11

+					float32Val += 0xC8000000;

+				}

+

+				return ((float32Val + 0x1FFFF + ((float32Val >> 18) & 1)) >> 18) & float10BitMask;

+			}

+		}

+

+		static inline float float11ToFloat32(unsigned short fp11)

+		{

+			unsigned short exponent = (fp11 >> 6) & 0x1F;

+			unsigned short mantissa = fp11 & 0x3F;

+

+			unsigned int output;

+			if(exponent == 0x1F)

+			{

+				// INF or NAN

+				output = 0x7f800000 | (mantissa << 17);

+			}

+			else

+			{

+				if(exponent != 0)

+				{

+					// normalized

+				}

+				else if(mantissa != 0)

+				{

+					// The value is denormalized

+					exponent = 1;

+

+					do

+					{

+						exponent--;

+						mantissa <<= 1;

+					} while((mantissa & 0x40) == 0);

+

+					mantissa = mantissa & 0x3F;

+				}

+				else // The value is zero

+				{

+					exponent = static_cast<unsigned short>(-112);

+				}

+

+				output = ((exponent + 112) << 23) | (mantissa << 17);

+			}

+

+			return *(float*)(&output);

+		}

+

+		static inline float float10ToFloat32(unsigned short fp10)

+		{

+			unsigned short exponent = (fp10 >> 5) & 0x1F;

+			unsigned short mantissa = fp10 & 0x1F;

+

+			unsigned int output;

+			if(exponent == 0x1F)

+			{

+				// INF or NAN

+				output = 0x7f800000 | (mantissa << 17);

+			}

+			else

+			{

+				if(exponent != 0)

+				{

+					// normalized

+				}

+				else if(mantissa != 0)

+				{

+					// The value is denormalized

+					exponent = 1;

+

+					do

+					{

+						exponent--;

+						mantissa <<= 1;

+					} while((mantissa & 0x20) == 0);

+

+					mantissa = mantissa & 0x1F;

+				}

+				else // The value is zero

+				{

+					exponent = static_cast<unsigned short>(-112);

+				}

+

+				output = ((exponent + 112) << 23) | (mantissa << 18);

+			}

+

+			return *(float*)(&output);

+		}

+

+	public:

+		R11G11B10FData(float r, float g, float b)

+		{

+			R = float32ToFloat11(r);

+			G = float32ToFloat11(g);

+			B = float32ToFloat10(b);

+		}

+

+		void toRGBFloats(float *red, float *green, float *blue) const

+		{

+			*red = float11ToFloat32(R);

+			*green = float11ToFloat32(G);

+			*blue = float10ToFloat32(B);

+		}

+

+		unsigned int toUInt() const

+		{

+			return uint;

+		}

+	};

 }

 

 #endif   // sw_Math_hpp