blob: cc57823cb73aee20ccbaa67228949b9d81efa2e7 [file] [log] [blame]
jvanverth93679922014-11-26 13:15:59 -08001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkHalf_DEFINED
9#define SkHalf_DEFINED
10
mtkleinfff055c2016-02-11 06:30:03 -080011#include "SkNx.h"
jvanverth93679922014-11-26 13:15:59 -080012#include "SkTypes.h"
13
14// 16-bit floating point value
15// format is 1 bit sign, 5 bits exponent, 10 bits mantissa
16// only used for storage
17typedef uint16_t SkHalf;
18
msarett6bdbf442016-07-19 09:07:55 -070019static constexpr uint16_t SK_HalfMin = 0x0400; // 2^-24 (minimum positive normal value)
20static constexpr uint16_t SK_HalfMax = 0x7bff; // 65504
21static constexpr uint16_t SK_HalfEpsilon = 0x1400; // 2^-10
22static constexpr uint16_t SK_Half1 = 0x3C00; // 1
jvanverth28f9c602014-12-05 13:06:35 -080023
jvanverth93679922014-11-26 13:15:59 -080024// convert between half and single precision floating point
25float SkHalfToFloat(SkHalf h);
26SkHalf SkFloatToHalf(float f);
27
mtklein58e389b2016-07-15 07:00:11 -070028// Convert between half and single precision floating point,
mtklein8ae991e2016-08-22 13:20:18 -070029// assuming inputs and outputs are both finite, and
30// flushing values which would be denormal half floats to zero.
31static inline Sk4f SkHalfToFloat_finite_ftz(uint64_t);
32static inline Sk4h SkFloatToHalf_finite_ftz(const Sk4f&);
mtkleinfff055c2016-02-11 06:30:03 -080033
34// ~~~~~~~~~~~ impl ~~~~~~~~~~~~~~ //
35
36// Like the serial versions in SkHalf.cpp, these are based on
37// https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
38
mtkleinbe8c19e2016-02-19 09:40:24 -080039// GCC 4.9 lacks the intrinsics to use ARMv8 f16<->f32 instructions, so we use inline assembly.
40
mtklein8ae991e2016-08-22 13:20:18 -070041static inline Sk4f SkHalfToFloat_finite_ftz(const Sk4h& hs) {
mtkleinbe8c19e2016-02-19 09:40:24 -080042#if !defined(SKNX_NO_SIMD) && defined(SK_CPU_ARM64)
43 float32x4_t fs;
mtkleinf660b7c2016-07-26 08:01:19 -070044 asm ("fcvtl %[fs].4s, %[hs].4h \n" // vcvt_f32_f16(...)
mtkleinbe8c19e2016-02-19 09:40:24 -080045 : [fs] "=w" (fs) // =w: write-only NEON register
mtkleinf660b7c2016-07-26 08:01:19 -070046 : [hs] "w" (hs.fVec)); // w: read-only NEON register
mtkleinbe8c19e2016-02-19 09:40:24 -080047 return fs;
mtkleinfff055c2016-02-11 06:30:03 -080048#else
mtklein8ae991e2016-08-22 13:20:18 -070049 Sk4i bits = SkNx_cast<int>(hs), // Expand to 32 bit.
50 sign = bits & 0x00008000, // Save the sign bit for later...
51 positive = bits ^ sign, // ...but strip it off for now.
52 is_norm = 0x03ff < positive; // Exponent > 0?
mtklein58e389b2016-07-15 07:00:11 -070053
54 // For normal half floats, extend the mantissa by 13 zero bits,
55 // then adjust the exponent from 15 bias to 127 bias.
56 Sk4i norm = (positive << 13) + ((127 - 15) << 23);
57
mtklein8ae991e2016-08-22 13:20:18 -070058 Sk4i merged = (sign << 16) | (norm & is_norm);
mtklein58e389b2016-07-15 07:00:11 -070059 return Sk4f::Load(&merged);
mtkleinfff055c2016-02-11 06:30:03 -080060#endif
61}
62
mtklein8ae991e2016-08-22 13:20:18 -070063static inline Sk4f SkHalfToFloat_finite_ftz(uint64_t hs) {
64 return SkHalfToFloat_finite_ftz(Sk4h::Load(&hs));
mtkleinf660b7c2016-07-26 08:01:19 -070065}
66
mtklein8ae991e2016-08-22 13:20:18 -070067static inline Sk4h SkFloatToHalf_finite_ftz(const Sk4f& fs) {
mtkleinbe8c19e2016-02-19 09:40:24 -080068#if !defined(SKNX_NO_SIMD) && defined(SK_CPU_ARM64)
69 float32x4_t vec = fs.fVec;
70 asm ("fcvtn %[vec].4h, %[vec].4s \n" // vcvt_f16_f32(vec)
msarett6bdbf442016-07-19 09:07:55 -070071 : [vec] "+w" (vec)); // +w: read-write NEON register
72 return vreinterpret_u16_f32(vget_low_f32(vec));
mtkleinfff055c2016-02-11 06:30:03 -080073#else
mtklein8ae991e2016-08-22 13:20:18 -070074 Sk4i bits = Sk4i::Load(&fs),
75 sign = bits & 0x80000000, // Save the sign bit for later...
76 positive = bits ^ sign, // ...but strip it off for now.
77 will_be_norm = 0x387fdfff < positive; // greater than largest denorm half?
mtklein58e389b2016-07-15 07:00:11 -070078
79 // For normal half floats, adjust the exponent from 127 bias to 15 bias,
80 // then drop the bottom 13 mantissa bits.
81 Sk4i norm = (positive - ((127 - 15) << 23)) >> 13;
82
mtklein8ae991e2016-08-22 13:20:18 -070083 Sk4i merged = (sign >> 16) | (will_be_norm & norm);
msarett6bdbf442016-07-19 09:07:55 -070084 return SkNx_cast<uint16_t>(merged);
mtkleinfff055c2016-02-11 06:30:03 -080085#endif
86}
87
jvanverth93679922014-11-26 13:15:59 -080088#endif