SkHalf.h 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. /*
  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. #ifndef SkHalf_DEFINED
  8. #define SkHalf_DEFINED
  9. #include "include/core/SkTypes.h"
  10. #include "include/private/SkNx.h"
  11. // 16-bit floating point value
  12. // format is 1 bit sign, 5 bits exponent, 10 bits mantissa
  13. // only used for storage
  14. typedef uint16_t SkHalf;
  15. static constexpr uint16_t SK_HalfMin = 0x0400; // 2^-14 (minimum positive normal value)
  16. static constexpr uint16_t SK_HalfMax = 0x7bff; // 65504
  17. static constexpr uint16_t SK_HalfEpsilon = 0x1400; // 2^-10
  18. static constexpr uint16_t SK_Half1 = 0x3C00; // 1
  19. // convert between half and single precision floating point
  20. float SkHalfToFloat(SkHalf h);
  21. SkHalf SkFloatToHalf(float f);
  22. // Convert between half and single precision floating point,
  23. // assuming inputs and outputs are both finite, and may
  24. // flush values which would be denormal half floats to zero.
  25. static inline Sk4f SkHalfToFloat_finite_ftz(uint64_t);
  26. static inline Sk4h SkFloatToHalf_finite_ftz(const Sk4f&);
  27. // ~~~~~~~~~~~ impl ~~~~~~~~~~~~~~ //
  28. // Like the serial versions in SkHalf.cpp, these are based on
  29. // https://fgiesen.wordpress.com/2012/03/28/half-to-float-done-quic/
  30. // GCC 4.9 lacks the intrinsics to use ARMv8 f16<->f32 instructions, so we use inline assembly.
  31. static inline Sk4f SkHalfToFloat_finite_ftz(uint64_t rgba) {
  32. Sk4h hs = Sk4h::Load(&rgba);
  33. #if !defined(SKNX_NO_SIMD) && defined(SK_CPU_ARM64)
  34. float32x4_t fs;
  35. asm ("fcvtl %[fs].4s, %[hs].4h \n" // vcvt_f32_f16(...)
  36. : [fs] "=w" (fs) // =w: write-only NEON register
  37. : [hs] "w" (hs.fVec)); // w: read-only NEON register
  38. return fs;
  39. #else
  40. Sk4i bits = SkNx_cast<int>(hs), // Expand to 32 bit.
  41. sign = bits & 0x00008000, // Save the sign bit for later...
  42. positive = bits ^ sign, // ...but strip it off for now.
  43. is_norm = 0x03ff < positive; // Exponent > 0?
  44. // For normal half floats, extend the mantissa by 13 zero bits,
  45. // then adjust the exponent from 15 bias to 127 bias.
  46. Sk4i norm = (positive << 13) + ((127 - 15) << 23);
  47. Sk4i merged = (sign << 16) | (norm & is_norm);
  48. return Sk4f::Load(&merged);
  49. #endif
  50. }
  51. static inline Sk4h SkFloatToHalf_finite_ftz(const Sk4f& fs) {
  52. #if !defined(SKNX_NO_SIMD) && defined(SK_CPU_ARM64)
  53. float32x4_t vec = fs.fVec;
  54. asm ("fcvtn %[vec].4h, %[vec].4s \n" // vcvt_f16_f32(vec)
  55. : [vec] "+w" (vec)); // +w: read-write NEON register
  56. return vreinterpret_u16_f32(vget_low_f32(vec));
  57. #else
  58. Sk4i bits = Sk4i::Load(&fs),
  59. sign = bits & 0x80000000, // Save the sign bit for later...
  60. positive = bits ^ sign, // ...but strip it off for now.
  61. will_be_norm = 0x387fdfff < positive; // greater than largest denorm half?
  62. // For normal half floats, adjust the exponent from 127 bias to 15 bias,
  63. // then drop the bottom 13 mantissa bits.
  64. Sk4i norm = (positive - ((127 - 15) << 23)) >> 13;
  65. Sk4i merged = (sign >> 16) | (will_be_norm & norm);
  66. return SkNx_cast<uint16_t>(merged);
  67. #endif
  68. }
  69. #endif