diff options
author | jvanverth <jvanverth@google.com> | 2014-11-26 13:15:59 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-26 13:15:59 -0800 |
commit | 936799204b34e7a2f20ac6c0868058799ceb851e (patch) | |
tree | c1dd34971c393de4bf7247aed276a91b123400fd /src/core/SkHalf.cpp | |
parent | 9881d63c57002ffbdf2adf623965ece280279989 (diff) |
Add float-to-half (binary16) conversion functions.
Based on code by Fabian Giesen at
https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/.
These will be needed for creating binary16 textures from floating point data.
BUG=skia:3103
Review URL: https://codereview.chromium.org/760753003
Diffstat (limited to 'src/core/SkHalf.cpp')
-rw-r--r-- | src/core/SkHalf.cpp | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/src/core/SkHalf.cpp b/src/core/SkHalf.cpp new file mode 100644 index 0000000000..0db979bc76 --- /dev/null +++ b/src/core/SkHalf.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkHalf.h" +#include "SkFloatBits.h" + +uint16_t halfMantissa(SkHalf h) { + return h & 0x03ff; +} + +uint16_t halfExponent(SkHalf h) { + return (h >> 10) & 0x001f; +} + +uint16_t halfSign(SkHalf h) { + return h >> 15; +} + +union FloatUIntUnion { + uint32_t fUInt; // this must come first for the initializations below to work + float fFloat; +}; + +// based on Fabien Giesen's float_to_half_fast3() +// see https://gist.github.com/rygorous/2156668 +SkHalf SkFloatToHalf(float f) { + static const uint32_t f32infty = { 255 << 23 }; + static const uint32_t f16infty = { 31 << 23 }; + static const FloatUIntUnion magic = { 15 << 23 }; + static const uint32_t sign_mask = 0x80000000u; + static const uint32_t round_mask = ~0xfffu; + SkHalf o = 0; + + FloatUIntUnion floatUnion; + floatUnion.fFloat = f; + + uint32_t sign = floatUnion.fUInt & sign_mask; + floatUnion.fUInt ^= sign; + + // NOTE all the integer compares in this function can be safely + // compiled into signed compares since all operands are below + // 0x80000000. Important if you want fast straight SSE2 code + // (since there's no unsigned PCMPGTD). + + // Inf or NaN (all exponent bits set) + if (floatUnion.fUInt >= f32infty) + // NaN->qNaN and Inf->Inf + o = (floatUnion.fUInt > f32infty) ? 0x7e00 : 0x7c00; + // (De)normalized number or zero + else { + floatUnion.fUInt &= round_mask; + floatUnion.fFloat *= magic.fFloat; + floatUnion.fUInt -= round_mask; + // Clamp to signed infinity if overflowed + if (floatUnion.fUInt > f16infty) { + floatUnion.fUInt = f16infty; + } + + o = floatUnion.fUInt >> 13; // Take the bits! + } + + o |= sign >> 16; + return o; +} + +// based on Fabien Giesen's half_to_float_fast2() +// see https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/ +float SkHalfToFloat(SkHalf h) { + static const FloatUIntUnion magic = { 126 << 23 }; + FloatUIntUnion o; + + if (halfExponent(h) == 0) + { + // Zero / Denormal + o.fUInt = magic.fUInt + halfMantissa(h); + o.fFloat -= magic.fFloat; + } + else + { + // Set mantissa + o.fUInt = halfMantissa(h) << 13; + // Set exponent + if (halfExponent(h) == 0x1f) + // Inf/NaN + o.fUInt |= (255 << 23); + else + o.fUInt |= ((127 - 15 + halfExponent(h)) << 23); + } + + // Set sign + o.fUInt |= (halfSign(h) << 31); + return o.fFloat; +} |