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