1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef SkMath_DEFINED
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkMath_DEFINED
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTypes.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1557212f9469c8056bab3c85243dbb904e386eab95reed@google.com// 64bit -> 32bit utilities
1657212f9469c8056bab3c85243dbb904e386eab95reed@google.com
1757212f9469c8056bab3c85243dbb904e386eab95reed@google.com/**
1857212f9469c8056bab3c85243dbb904e386eab95reed@google.com *  Return true iff the 64bit value can exactly be represented in signed 32bits
1957212f9469c8056bab3c85243dbb904e386eab95reed@google.com */
2057212f9469c8056bab3c85243dbb904e386eab95reed@google.comstatic inline bool sk_64_isS32(int64_t value) {
2157212f9469c8056bab3c85243dbb904e386eab95reed@google.com    return (int32_t)value == value;
2257212f9469c8056bab3c85243dbb904e386eab95reed@google.com}
2357212f9469c8056bab3c85243dbb904e386eab95reed@google.com
2457212f9469c8056bab3c85243dbb904e386eab95reed@google.com/**
2557212f9469c8056bab3c85243dbb904e386eab95reed@google.com *  Return the 64bit argument as signed 32bits, asserting in debug that the arg
2657212f9469c8056bab3c85243dbb904e386eab95reed@google.com *  exactly fits in signed 32bits. In the release build, no checks are preformed
2757212f9469c8056bab3c85243dbb904e386eab95reed@google.com *  and the return value if the arg does not fit is undefined.
2857212f9469c8056bab3c85243dbb904e386eab95reed@google.com */
2957212f9469c8056bab3c85243dbb904e386eab95reed@google.comstatic inline int32_t sk_64_asS32(int64_t value) {
3057212f9469c8056bab3c85243dbb904e386eab95reed@google.com    SkASSERT(sk_64_isS32(value));
3157212f9469c8056bab3c85243dbb904e386eab95reed@google.com    return (int32_t)value;
3257212f9469c8056bab3c85243dbb904e386eab95reed@google.com}
3357212f9469c8056bab3c85243dbb904e386eab95reed@google.com
3457212f9469c8056bab3c85243dbb904e386eab95reed@google.com// Handy util that can be passed two ints, and will automatically promote to
3557212f9469c8056bab3c85243dbb904e386eab95reed@google.com// 64bits before the multiply, so the caller doesn't have to remember to cast
3657212f9469c8056bab3c85243dbb904e386eab95reed@google.com// e.g. (int64_t)a * b;
3757212f9469c8056bab3c85243dbb904e386eab95reed@google.comstatic inline int64_t sk_64_mul(int64_t a, int64_t b) {
3857212f9469c8056bab3c85243dbb904e386eab95reed@google.com    return a * b;
3957212f9469c8056bab3c85243dbb904e386eab95reed@google.com}
4057212f9469c8056bab3c85243dbb904e386eab95reed@google.com
414b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com///////////////////////////////////////////////////////////////////////////////
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
430f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org/**
440f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org *  Computes numer1 * numer2 / denom in full 64 intermediate precision.
450f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org *  It is an error for denom to be 0. There is no special handling if
460f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org *  the result overflows 32bits.
470f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org */
480f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.orgstatic inline int32_t SkMulDiv(int32_t numer1, int32_t numer2, int32_t denom) {
490f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org    SkASSERT(denom);
50f7927dd60761ca45f26059a8ab434018676cb2e7skia.committer@gmail.com
510f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org    int64_t tmp = sk_64_mul(numer1, numer2) / denom;
520f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org    return sk_64_asS32(tmp);
530f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org}
540f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org
550f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org/**
560f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org *  Return the integer square root of value, with a bias of bitBias
570f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org */
580f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.orgint32_t SkSqrtBits(int32_t value, int bitBias);
590f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org
600f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org/** Return the integer square root of n, treated as a SkFixed (16.16)
610f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org */
620f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org#define SkSqrt32(n)         SkSqrtBits(n, 15)
630f1fef834c73cb4f38023de0f98d05562d24f2bccommit-bot@chromium.org
644b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com/**
654b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com *  Returns (value < 0 ? 0 : value) efficiently (i.e. no compares or branches)
664b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com */
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline int SkClampPos(int value) {
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return value & ~(value >> 31);
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/** Given an integer and a positive (max) integer, return the value
724b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com *  pinned against 0 and max, inclusive.
734b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com *  @param value    The value we want returned pinned between [0...max]
744b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com *  @param max      The positive max value
754b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com *  @return 0 if value < 0, max if value > max, else value
764b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com */
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline int SkClampMax(int value, int max) {
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // ensure that max is positive
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(max >= 0);
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (value < 0) {
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        value = 0;
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (value > max) {
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        value = max;
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return value;
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
894b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com/**
904b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com *  Returns true if value is a power of 2. Does not explicitly check for
914b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com *  value <= 0.
92f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com */
93883c8efae702462fa28e7ce4f17199bbfa1ce360mtkleintemplate <typename T> constexpr inline bool SkIsPow2(T value) {
94f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com    return (value & (value - 1)) == 0;
95f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com}
96f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
994b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com/**
1004b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com *  Return a*b/((1 << shift) - 1), rounding any fractional bits.
1014b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com *  Only valid if a and b are unsigned and <= 32767 and shift is > 0 and <= 8
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
103ea774d2a5a049bf89474c0f047ed6a4e521de126reed@google.comstatic inline unsigned SkMul16ShiftRound(U16CPU a, U16CPU b, int shift) {
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(a <= 32767);
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(b <= 32767);
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(shift > 0 && shift <= 8);
1073848427d884b72114854c8eef9662691f23fae7bmtklein    unsigned prod = a*b + (1 << (shift - 1));
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (prod + (prod >> shift)) >> shift;
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1114b163ed2c22facbe8891616874ae07ba7827d9c9reed@google.com/**
112ea774d2a5a049bf89474c0f047ed6a4e521de126reed@google.com *  Return a*b/255, rounding any fractional bits.
113ea774d2a5a049bf89474c0f047ed6a4e521de126reed@google.com *  Only valid if a and b are unsigned and <= 32767.
114a0f5d1546d499ef0cd7dbfba9a866ae5a27e1541reed@android.com */
115ea774d2a5a049bf89474c0f047ed6a4e521de126reed@google.comstatic inline U8CPU SkMulDiv255Round(U16CPU a, U16CPU b) {
116ea774d2a5a049bf89474c0f047ed6a4e521de126reed@google.com    SkASSERT(a <= 32767);
117ea774d2a5a049bf89474c0f047ed6a4e521de126reed@google.com    SkASSERT(b <= 32767);
1183848427d884b72114854c8eef9662691f23fae7bmtklein    unsigned prod = a*b + 128;
119a0f5d1546d499ef0cd7dbfba9a866ae5a27e1541reed@android.com    return (prod + (prod >> 8)) >> 8;
120a0f5d1546d499ef0cd7dbfba9a866ae5a27e1541reed@android.com}
121a0f5d1546d499ef0cd7dbfba9a866ae5a27e1541reed@android.com
1222c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org/**
1232c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org * Stores numer/denom and numer%denom into div and mod respectively.
1242c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org */
1252c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.orgtemplate <typename In, typename Out>
1262c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.orginline void SkTDivMod(In numer, In denom, Out* div, Out* mod) {
1273a2682a77f996f649de7699c9f7bee046c6d4f17mtklein#ifdef SK_CPU_ARM32
1282c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    // If we wrote this as in the else branch, GCC won't fuse the two into one
1292c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    // divmod call, but rather a div call followed by a divmod.  Silly!  This
1302c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    // version is just as fast as calling __aeabi_[u]idivmod manually, but with
1312c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    // prettier code.
1322c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    //
1332c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    // This benches as around 2x faster than the code in the else branch.
1342c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    const In d = numer/denom;
1352c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    *div = static_cast<Out>(d);
1362c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    *mod = static_cast<Out>(numer-d*denom);
1372c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org#else
1382c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    // On x86 this will just be a single idiv.
1392c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    *div = static_cast<Out>(numer/denom);
1402c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org    *mod = static_cast<Out>(numer%denom);
1413a2682a77f996f649de7699c9f7bee046c6d4f17mtklein#endif
1422c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org}
1432c86fbb0b14a1f674bf56ea5ad6a086cc004a76ecommit-bot@chromium.org
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
145