Path: blob/21.2-virgl/src/util/format_r11g11b10f.h
4550 views
/*1* Copyright (C) 2011 Marek Olšák <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER20* DEALINGS IN THE SOFTWARE.21*/2223/* Based on code from The OpenGL Programming Guide / 7th Edition, Appendix J.24* Available here: http://www.opengl-redbook.com/appendices/25* The algorithm in the book contains a bug though, which is fixed in the code26* below.27*/2829#ifndef FORMAT_R11G11B10F_H30#define FORMAT_R11G11B10F_H3132#include <stdint.h>3334#define UF11(e, m) ((e << 6) | (m))35#define UF11_EXPONENT_BIAS 1536#define UF11_EXPONENT_BITS 0x1F37#define UF11_EXPONENT_SHIFT 638#define UF11_MANTISSA_BITS 0x3F39#define UF11_MANTISSA_SHIFT (23 - UF11_EXPONENT_SHIFT)40#define UF11_MAX_EXPONENT (UF11_EXPONENT_BITS << UF11_EXPONENT_SHIFT)4142#define UF10(e, m) ((e << 5) | (m))43#define UF10_EXPONENT_BIAS 1544#define UF10_EXPONENT_BITS 0x1F45#define UF10_EXPONENT_SHIFT 546#define UF10_MANTISSA_BITS 0x1F47#define UF10_MANTISSA_SHIFT (23 - UF10_EXPONENT_SHIFT)48#define UF10_MAX_EXPONENT (UF10_EXPONENT_BITS << UF10_EXPONENT_SHIFT)4950#define F32_INFINITY 0x7f8000005152static inline uint32_t f32_to_uf11(float val)53{54union {55float f;56uint32_t ui;57} f32 = {val};5859uint16_t uf11 = 0;6061/* Decode little-endian 32-bit floating-point value */62int sign = (f32.ui >> 16) & 0x8000;63/* Map exponent to the range [-127,128] */64int exponent = ((f32.ui >> 23) & 0xff) - 127;65int mantissa = f32.ui & 0x007fffff;6667if (exponent == 128) { /* Infinity or NaN */68/* From the GL_EXT_packed_float spec:69*70* "Additionally: negative infinity is converted to zero; positive71* infinity is converted to positive infinity; and both positive and72* negative NaN are converted to positive NaN."73*/74uf11 = UF11_MAX_EXPONENT;75if (mantissa) {76uf11 |= 1; /* NaN */77} else {78if (sign)79uf11 = 0; /* 0.0 */80}81} else if (sign) {82return 0;83} else if (val > 65024.0f) {84/* From the GL_EXT_packed_float spec:85*86* "Likewise, finite positive values greater than 65024 (the maximum87* finite representable unsigned 11-bit floating-point value) are88* converted to 65024."89*/90uf11 = UF11(30, 63);91} else if (exponent > -15) { /* Representable value */92exponent += UF11_EXPONENT_BIAS;93mantissa >>= UF11_MANTISSA_SHIFT;94uf11 = exponent << UF11_EXPONENT_SHIFT | mantissa;95}9697return uf11;98}99100static inline float uf11_to_f32(uint16_t val)101{102union {103float f;104uint32_t ui;105} f32;106107int exponent = (val & 0x07c0) >> UF11_EXPONENT_SHIFT;108int mantissa = (val & 0x003f);109110f32.f = 0.0;111112if (exponent == 0) {113if (mantissa != 0) {114const float scale = 1.0 / (1 << 20);115f32.f = scale * mantissa;116}117} else if (exponent == 31) {118f32.ui = F32_INFINITY | mantissa;119} else {120float scale, decimal;121exponent -= 15;122if (exponent < 0) {123scale = 1.0f / (1 << -exponent);124} else {125scale = (float) (1 << exponent);126}127decimal = 1.0f + (float) mantissa / 64;128f32.f = scale * decimal;129}130131return f32.f;132}133134static inline uint32_t f32_to_uf10(float val)135{136union {137float f;138uint32_t ui;139} f32 = {val};140141uint16_t uf10 = 0;142143/* Decode little-endian 32-bit floating-point value */144int sign = (f32.ui >> 16) & 0x8000;145/* Map exponent to the range [-127,128] */146int exponent = ((f32.ui >> 23) & 0xff) - 127;147int mantissa = f32.ui & 0x007fffff;148149if (exponent == 128) {150/* From the GL_EXT_packed_float spec:151*152* "Additionally: negative infinity is converted to zero; positive153* infinity is converted to positive infinity; and both positive and154* negative NaN are converted to positive NaN."155*/156uf10 = UF10_MAX_EXPONENT;157if (mantissa) {158uf10 |= 1; /* NaN */159} else {160if (sign)161uf10 = 0; /* 0.0 */162}163} else if (sign) {164return 0;165} else if (val > 64512.0f) {166/* From the GL_EXT_packed_float spec:167*168* "Likewise, finite positive values greater than 64512 (the maximum169* finite representable unsigned 10-bit floating-point value) are170* converted to 64512."171*/172uf10 = UF10(30, 31);173} else if (exponent > -15) { /* Representable value */174exponent += UF10_EXPONENT_BIAS;175mantissa >>= UF10_MANTISSA_SHIFT;176uf10 = exponent << UF10_EXPONENT_SHIFT | mantissa;177}178179return uf10;180}181182static inline float uf10_to_f32(uint16_t val)183{184union {185float f;186uint32_t ui;187} f32;188189int exponent = (val & 0x03e0) >> UF10_EXPONENT_SHIFT;190int mantissa = (val & 0x001f);191192f32.f = 0.0;193194if (exponent == 0) {195if (mantissa != 0) {196const float scale = 1.0 / (1 << 19);197f32.f = scale * mantissa;198}199} else if (exponent == 31) {200f32.ui = F32_INFINITY | mantissa;201} else {202float scale, decimal;203exponent -= 15;204if (exponent < 0) {205scale = 1.0f / (1 << -exponent);206}207else {208scale = (float) (1 << exponent);209}210decimal = 1.0f + (float) mantissa / 32;211f32.f = scale * decimal;212}213214return f32.f;215}216217static inline uint32_t float3_to_r11g11b10f(const float rgb[3])218{219return ( f32_to_uf11(rgb[0]) & 0x7ff) |220((f32_to_uf11(rgb[1]) & 0x7ff) << 11) |221((f32_to_uf10(rgb[2]) & 0x3ff) << 22);222}223224static inline void r11g11b10f_to_float3(uint32_t rgb, float retval[3])225{226retval[0] = uf11_to_f32( rgb & 0x7ff);227retval[1] = uf11_to_f32((rgb >> 11) & 0x7ff);228retval[2] = uf10_to_f32((rgb >> 22) & 0x3ff);229}230231#endif /* FORMAT_R11G11B10F_H */232233234