blob: 8efd38f4ec4e6dbccf77e1a1455999b740a3a5e6 [file] [log] [blame]
/*-------------------------------------------------------------------------
* OpenGL Conformance Test Suite
* -----------------------------
*
* Copyright (c) 2017 The Khronos Group Inc.
*
* 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 glcMisc.cpp
* \brief Miscellaneous helper functions.
*/ /*-------------------------------------------------------------------*/
#include "glcMisc.hpp"
using namespace glw;
namespace glcts
{
/* utility functions from the book OpenGL ES 2.0 Programming Guide */
/* -15 stored using a single precision bias of 127 */
const unsigned int HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP = 0x38000000;
/* max exponent value in single precision that will be converted */
/* to Inf or Nan when stored as a half-float */
const unsigned int HALF_FLOAT_MAX_BIASED_EXP_AS_SINGLE_FP_EXP = 0x47800000;
/* 255 is the max exponent biased value */
const unsigned int FLOAT_MAX_BIASED_EXP = (0xFF << 23);
const unsigned int HALF_FLOAT_MAX_BIASED_EXP = (0x1F << 10);
GLhalf floatToHalfFloat(float f)
{
union {
float v;
unsigned int x;
};
v = f;
unsigned int sign = (GLhalf)(x >> 31);
unsigned int mantissa;
unsigned int exp;
GLhalf hf;
/* get mantissa */
mantissa = x & ((1 << 23) - 1);
/* get exponent bits */
exp = x & FLOAT_MAX_BIASED_EXP;
if (exp >= HALF_FLOAT_MAX_BIASED_EXP_AS_SINGLE_FP_EXP)
{
/* check if the original single precision float number is a NaN */
if (mantissa && (exp == FLOAT_MAX_BIASED_EXP))
{
/* we have a single precision NaN */
mantissa = (1 << 23) - 1;
}
else
{
/* 16-bit half-float representation stores number as Inf */
mantissa = 0;
}
hf = (((GLhalf)sign) << 15) | (GLhalf)(HALF_FLOAT_MAX_BIASED_EXP) | (GLhalf)(mantissa >> 13);
}
/* check if exponent is <= -15 */
else if (exp <= HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP)
{
/* store a denorm half-float value or zero */
exp = (HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP - exp) >> 23;
mantissa |= (1 << 23);
mantissa >>= (14 + exp);
hf = (((GLhalf)sign) << 15) | (GLhalf)(mantissa);
}
else
{
hf = (((GLhalf)sign) << 15) | (GLhalf)((exp - HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP) >> 13) |
(GLhalf)(mantissa >> 13);
}
return hf;
}
/* -15 stored using a single precision bias of 127 */
const unsigned int FLOAT11_MIN_BIASED_EXP_AS_SINGLE_FP_EXP = 0x38000000;
/* max exponent value in single precision that will be converted */
/* to Inf or Nan when stored as a half-float */
const unsigned int FLOAT11_MAX_BIASED_EXP_AS_SINGLE_FP_EXP = 0x47800000;
const unsigned int FLOAT11_MAX_BIASED_EXP = (0x1F << 6);
GLuint floatToUnisgnedF11(float f)
{
union {
float v;
unsigned int x;
};
v = f;
unsigned int sign = (GLhalf)(x >> 31);
unsigned int mantissa;
unsigned int exp;
GLuint f11;
/* get mantissa */
mantissa = x & ((1 << 23) - 1);
/* get exponent bits */
exp = x & FLOAT_MAX_BIASED_EXP;
/* minus f32 value */
if (sign > 0)
{
/* f32 NaN -> f11 NaN */
if (mantissa && (exp == FLOAT_MAX_BIASED_EXP))
{
f11 = (GLuint)(FLOAT11_MAX_BIASED_EXP) | (GLuint)(0x0000003F);
}
/* Others round to 0.0 */
else
{
f11 = 0x00000000;
}
return f11;
}
/* only check positive value below */
if (exp >= FLOAT11_MAX_BIASED_EXP_AS_SINGLE_FP_EXP)
{
/* check if the original single precision float number is a NaN */
if (mantissa && (exp == FLOAT_MAX_BIASED_EXP))
{
/* we have a single precision NaN */
mantissa = (1 << 23) - 1;
}
else
{
/* 11-bit float representation stores number as Inf */
mantissa = 0;
}
f11 = (GLuint)(FLOAT11_MAX_BIASED_EXP) | (GLuint)(mantissa >> 17);
}
/* check if exponent is <= -15 */
else if (exp <= FLOAT11_MIN_BIASED_EXP_AS_SINGLE_FP_EXP)
{
/* store a denorm 11-bit float value or zero */
exp = (FLOAT11_MIN_BIASED_EXP_AS_SINGLE_FP_EXP - exp) >> 23;
mantissa |= (1 << 23);
if (18 + exp >= sizeof(mantissa) * 8)
{
mantissa = 0;
}
else
{
mantissa >>= (18 + exp);
}
f11 = mantissa;
}
else
{
f11 = ((exp - FLOAT11_MIN_BIASED_EXP_AS_SINGLE_FP_EXP) >> 17) | (mantissa >> 17);
}
return f11;
}
/* -15 stored using a single precision bias of 127 */
const unsigned int FLOAT10_MIN_BIASED_EXP_AS_SINGLE_FP_EXP = 0x38000000;
/* max exponent value in single precision that will be converted */
/* to Inf or Nan when stored as a half-float */
const unsigned int FLOAT10_MAX_BIASED_EXP_AS_SINGLE_FP_EXP = 0x47800000;
const unsigned int FLOAT10_MAX_BIASED_EXP = (0x1F << 5);
GLuint floatToUnisgnedF10(float f)
{
union {
float v;
unsigned int x;
};
v = f;
unsigned int sign = (GLhalf)(x >> 31);
unsigned int mantissa;
unsigned int exp;
GLuint f10;
/* get mantissa */
mantissa = x & ((1 << 23) - 1);
/* get exponent bits */
exp = x & FLOAT_MAX_BIASED_EXP;
/* minus f32 value */
if (sign > 0)
{
/* f32 NaN -> f10 NaN */
if (mantissa && (exp == FLOAT_MAX_BIASED_EXP))
{
f10 = (GLuint)(FLOAT10_MAX_BIASED_EXP) | (GLuint)(0x0000001F);
}
/* Others round to 0.0 */
else
{
f10 = 0x00000000;
}
return f10;
}
/* only check positive value below */
if (exp >= FLOAT10_MAX_BIASED_EXP_AS_SINGLE_FP_EXP)
{
/* check if the original single precision float number is a NaN */
if (mantissa && (exp == FLOAT_MAX_BIASED_EXP))
{
/* we have a single precision NaN */
mantissa = (1 << 23) - 1;
}
else
{
/* 10-bit float representation stores number as Inf */
mantissa = 0;
}
f10 = (GLuint)(FLOAT10_MAX_BIASED_EXP) | (GLuint)(mantissa >> 18);
}
/* check if exponent is <= -15 */
else if (exp <= FLOAT10_MIN_BIASED_EXP_AS_SINGLE_FP_EXP)
{
/* store a denorm 11-bit float value or zero */
exp = (FLOAT10_MIN_BIASED_EXP_AS_SINGLE_FP_EXP - exp) >> 23;
mantissa |= (1 << 23);
if (19 + exp >= sizeof(mantissa) * 8)
{
mantissa = 0;
}
else
{
mantissa >>= (19 + exp);
}
f10 = mantissa;
}
else
{
f10 = ((exp - FLOAT10_MIN_BIASED_EXP_AS_SINGLE_FP_EXP) >> 18) | (mantissa >> 18);
}
return f10;
}
float halfFloatToFloat(GLhalf hf)
{
unsigned int sign = (unsigned int)(hf >> 15);
unsigned int mantissa = (unsigned int)(hf & ((1 << 10) - 1));
unsigned int exp = (unsigned int)(hf & HALF_FLOAT_MAX_BIASED_EXP);
union {
float f;
unsigned int ui;
};
if (exp == HALF_FLOAT_MAX_BIASED_EXP)
{
/* we have a half-float NaN or Inf */
/* half-float NaNs will be converted to a single precision NaN */
/* half-float Infs will be converted to a single precision Inf */
exp = FLOAT_MAX_BIASED_EXP;
if (mantissa)
mantissa = (1 << 23) - 1; /* set all bits to indicate a NaN */
}
else if (exp == 0x0)
{
/* convert half-float zero/denorm to single precision value */
if (mantissa)
{
mantissa <<= 1;
exp = HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP;
/* check for leading 1 in denorm mantissa */
while ((mantissa & (1 << 10)) == 0)
{
/* for every leading 0, decrement single precision exponent by 1 */
/* and shift half-float mantissa value to the left */
mantissa <<= 1;
exp -= (1 << 23);
}
/* clamp the mantissa to 10-bits */
mantissa &= ((1 << 10) - 1);
/* shift left to generate single-precision mantissa of 23-bits */
mantissa <<= 13;
}
}
else
{
/* shift left to generate single-precision mantissa of 23-bits */
mantissa <<= 13;
/* generate single precision biased exponent value */
exp = (exp << 13) + HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP;
}
ui = (sign << 31) | exp | mantissa;
return f;
}
float unsignedF11ToFloat(GLuint f11)
{
unsigned int mantissa = (unsigned int)(f11 & ((1 << 6) - 1));
unsigned int exp = (unsigned int)(f11 & FLOAT11_MAX_BIASED_EXP);
union {
float f;
unsigned int ui;
};
if (exp == FLOAT11_MAX_BIASED_EXP)
{
/* we have a f11 NaN or Inf */
/* f11 NaNs will be converted to a single precision NaN */
/* f11 Infs will be converted to a single precision Inf */
exp = FLOAT_MAX_BIASED_EXP;
if (mantissa)
mantissa = (1 << 23) - 1; /* set all bits to indicate a NaN */
}
else if (exp == 0x0)
{
/* convert f11 zero/denorm to single precision value */
if (mantissa)
{
mantissa <<= 1;
exp = FLOAT11_MIN_BIASED_EXP_AS_SINGLE_FP_EXP;
/* check for leading 1 in denorm mantissa */
while ((mantissa & (1 << 10)) == 0)
{
/* for every leading 0, decrement single precision exponent by 1 */
/* and shift half-float mantissa value to the left */
mantissa <<= 1;
exp -= (1 << 23);
}
/* clamp the mantissa to 6-bits */
mantissa &= ((1 << 6) - 1);
/* shift left to generate single-precision mantissa of 23-bits */
mantissa <<= 17;
}
}
else
{
/* shift left to generate single-precision mantissa of 23-bits */
mantissa <<= 17;
/* generate single precision biased exponent value */
exp = (exp << 17) + FLOAT11_MIN_BIASED_EXP_AS_SINGLE_FP_EXP;
}
ui = exp | mantissa;
return f;
}
float unsignedF10ToFloat(GLuint f10)
{
unsigned int mantissa = (unsigned int)(f10 & ((1 << 5) - 1));
unsigned int exp = (unsigned int)(f10 & FLOAT10_MAX_BIASED_EXP);
union {
float f;
unsigned int ui;
};
if (exp == FLOAT10_MAX_BIASED_EXP)
{
/* we have a f11 NaN or Inf */
/* f11 NaNs will be converted to a single precision NaN */
/* f11 Infs will be converted to a single precision Inf */
exp = FLOAT_MAX_BIASED_EXP;
if (mantissa)
mantissa = (1 << 23) - 1; /* set all bits to indicate a NaN */
}
else if (exp == 0x0)
{
/* convert f11 zero/denorm to single precision value */
if (mantissa)
{
mantissa <<= 1;
exp = FLOAT10_MIN_BIASED_EXP_AS_SINGLE_FP_EXP;
/* check for leading 1 in denorm mantissa */
while ((mantissa & (1 << 10)) == 0)
{
/* for every leading 0, decrement single precision exponent by 1 */
/* and shift half-float mantissa value to the left */
mantissa <<= 1;
exp -= (1 << 23);
}
/* clamp the mantissa to 5-bits */
mantissa &= ((1 << 5) - 1);
/* shift left to generate single-precision mantissa of 23-bits */
mantissa <<= 18;
}
}
else
{
/* shift left to generate single-precision mantissa of 23-bits */
mantissa <<= 18;
/* generate single precision biased exponent value */
exp = (exp << 18) + FLOAT10_MIN_BIASED_EXP_AS_SINGLE_FP_EXP;
}
ui = exp | mantissa;
return f;
}
} // glcts