1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/* 2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2011 Google Inc. 3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * 4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be 5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file. 6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */ 71b03b2b8c46cc230a5f78a5617526d35da9fb29ereed@google.com 8bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkFloatBits.h" 91b03b2b8c46cc230a5f78a5617526d35da9fb29ereed@google.com#include "SkMathPriv.h" 10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/****************************************************************************** 12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFloatBits_toInt[Floor, Round, Ceil] are identical except for what they 13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com do right before they return ... >> exp; 14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com Floor - adds nothing 15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com Round - adds 1 << (exp - 1) 16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com Ceil - adds (1 << exp) - 1 17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com Floor and Cast are very similar, but Cast applies its sign after all other 19bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com computations on value. Also, Cast does not need to check for negative zero, 20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com as that value (0x80000000) "does the right thing" for Ceil. Note that it 21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com doesn't for Floor/Round/Ceil, hence the explicit check. 22bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com******************************************************************************/ 23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 24bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define EXP_BIAS (127+23) 25bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define MATISSA_MAGIC_BIG (1 << 23) 26bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 27bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline int unpack_exp(uint32_t packed) { 28bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return (packed << 1 >> 24); 29bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 30bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#if 0 32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// the ARM compiler generates an extra BIC, so I use the dirty version instead 33bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline int unpack_matissa(uint32_t packed) { 34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // we could mask with 0x7FFFFF, but that is harder for ARM to encode 35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return (packed & ~0xFF000000) | MATISSA_MAGIC_BIG; 36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif 38bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 39bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// returns the low 24-bits, so we need to OR in the magic_bit afterwards 40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic inline int unpack_matissa_dirty(uint32_t packed) { 41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return packed & ~0xFF000000; 42bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// same as (int)float 45bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comint32_t SkFloatBits_toIntCast(int32_t packed) { 46bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int exp = unpack_exp(packed) - EXP_BIAS; 47bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; 48935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp >= 0) { 50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp > 7) { // overflow 51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value = SK_MaxS32; 52bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value <<= exp; 54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com exp = -exp; 57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp > 25) { // underflow 58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com exp = 25; 59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value >>= exp; 61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return SkApplySign(value, SkExtractSign(packed)); 63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 64bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// same as (int)floor(float) 66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comint32_t SkFloatBits_toIntFloor(int32_t packed) { 67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // curse you negative 0 68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if ((packed << 1) == 0) { 69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return 0; 70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 71935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int exp = unpack_exp(packed) - EXP_BIAS; 73bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; 74bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 75bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp >= 0) { 76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp > 7) { // overflow 77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value = SK_MaxS32; 78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value <<= exp; 80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // apply the sign after we check for overflow 82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return SkApplySign(value, SkExtractSign(packed)); 83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 84bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // apply the sign before we right-shift 85bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value = SkApplySign(value, SkExtractSign(packed)); 86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com exp = -exp; 87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp > 25) { // underflow 88bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com exp = 25; 89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 90bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // int add = 0; 91bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return value >> exp; 92bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 94bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 95bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// same as (int)floor(float + 0.5) 96bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comint32_t SkFloatBits_toIntRound(int32_t packed) { 97bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // curse you negative 0 98bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if ((packed << 1) == 0) { 99bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return 0; 100bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 101935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 102bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int exp = unpack_exp(packed) - EXP_BIAS; 103bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; 104935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 105bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp >= 0) { 106bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp > 7) { // overflow 107bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value = SK_MaxS32; 108bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 109bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value <<= exp; 110bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 111bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // apply the sign after we check for overflow 112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return SkApplySign(value, SkExtractSign(packed)); 113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 114bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // apply the sign before we right-shift 115bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value = SkApplySign(value, SkExtractSign(packed)); 116bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com exp = -exp; 117bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp > 25) { // underflow 118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com exp = 25; 119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 120bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int add = 1 << (exp - 1); 121bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return (value + add) >> exp; 122bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 124bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 125bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// same as (int)ceil(float) 126bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comint32_t SkFloatBits_toIntCeil(int32_t packed) { 127bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // curse you negative 0 128bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if ((packed << 1) == 0) { 129bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return 0; 130bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 131935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 132bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int exp = unpack_exp(packed) - EXP_BIAS; 133bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int value = unpack_matissa_dirty(packed) | MATISSA_MAGIC_BIG; 134935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 135bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp >= 0) { 136bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp > 7) { // overflow 137bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value = SK_MaxS32; 138bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 139bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value <<= exp; 140bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 141bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // apply the sign after we check for overflow 142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return SkApplySign(value, SkExtractSign(packed)); 143bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 144bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // apply the sign before we right-shift 145bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value = SkApplySign(value, SkExtractSign(packed)); 146bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com exp = -exp; 147bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (exp > 25) { // underflow 148bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com exp = 25; 149bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 150bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int add = (1 << exp) - 1; 151bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return (value + add) >> exp; 152bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 153bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 154bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 155bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comfloat SkIntToFloatCast(int32_t value) { 156bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (0 == value) { 157bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return 0; 158bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 159bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 160bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int shift = EXP_BIAS; 161935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 162bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // record the sign and make value positive 163bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int sign = SkExtractSign(value); 164bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value = SkApplySign(value, sign); 165935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 166bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (value >> 24) { // value is too big (has more than 24 bits set) 167bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int bias = 8 - SkCLZ(value); 168bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkDebugf("value = %d, bias = %d\n", value, bias); 169bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(bias > 0 && bias < 8); 170bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value >>= bias; // need to round? 171bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com shift += bias; 172bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } else { 173bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int zeros = SkCLZ(value << 8); 174bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(zeros >= 0 && zeros <= 23); 175bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value <<= zeros; 176bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com shift -= zeros; 177bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 178935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 179bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // now value is left-aligned to 24 bits 180bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT((value >> 23) == 1); 181bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkASSERT(shift >= 0 && shift <= 255); 182935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 183bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFloatIntUnion data; 184bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com data.fSignBitInt = (sign << 31) | (shift << 23) | (value & ~MATISSA_MAGIC_BIG); 185bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return data.fFloat; 186bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 187bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 188bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comfloat SkIntToFloatCast_NoOverflowCheck(int32_t value) { 189bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com if (0 == value) { 190bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return 0; 191bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com } 192bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com 193bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int shift = EXP_BIAS; 194935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 195bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com // record the sign and make value positive 196bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int sign = SkExtractSign(value); 197bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value = SkApplySign(value, sign); 198935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 199bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com int zeros = SkCLZ(value << 8); 200bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com value <<= zeros; 201bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com shift -= zeros; 202935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com 203bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com SkFloatIntUnion data; 204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com data.fSignBitInt = (sign << 31) | (shift << 23) | (value & ~MATISSA_MAGIC_BIG); 205bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com return data.fFloat; 206bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com} 207