83e99569bd
This adds check to make sure that the results in the last add of the lerp are in range. Also, Smooth out types. Change-Id: I853835e530f6b6790e16464db12964d68ab9ef8d Reviewed-on: https://skia-review.googlesource.com/c/skia/+/453718 Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com> Commit-Queue: Herb Derby <herb@google.com>
78 lines
2.0 KiB
C++
78 lines
2.0 KiB
C++
/*
|
|
* Copyright 2021 Google LLC
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
#ifndef QMath_DEFINED
|
|
#define QMath_DEFINED
|
|
|
|
template <int N, typename T> using V = T __attribute__((ext_vector_type(N)));
|
|
|
|
#if !defined(__clang__)
|
|
static_assert(false, "This only works on clang.");
|
|
#endif
|
|
|
|
#if defined(__SSSE3__)
|
|
#include <immintrin.h>
|
|
#endif
|
|
|
|
#if defined(__ARM_NEON)
|
|
// From section 5.5.5 of the ARM C Language Extensions (ACLE)
|
|
#include <arm_neon.h>
|
|
#endif
|
|
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
|
|
using Q15 = V<8, uint16_t>;
|
|
using I16 = V<8, int16_t>;
|
|
using U16 = V<8, uint16_t>;
|
|
|
|
|
|
static inline U16 constrained_add(I16 a, U16 b) {
|
|
for (size_t i = 0; i < 8; i++) {
|
|
// Ensure that a + b is on the interval [0, UINT16_MAX]
|
|
assert(-b[i] <= a[i] && a[i] <= UINT16_MAX - b[i]);
|
|
}
|
|
U16 answer = b + a;
|
|
return answer;
|
|
}
|
|
|
|
// A pure C version of the ssse3 intrinsic mm_mulhrs_epi16;
|
|
static inline I16 simulate_ssse3_mm_mulhrs_epi16(I16 a, I16 b) {
|
|
I16 result;
|
|
auto m = [](int16_t r, int16_t s) {
|
|
const int32_t rounding = 1 << 14;
|
|
int32_t temp = (int32_t)r * (int32_t)s + rounding;
|
|
return (int16_t)(temp >> 15);
|
|
};
|
|
for (int i = 0; i < 8; i++) {
|
|
result[i] = m(a[i], b[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// A pure C version of the neon intrinsic vqrdmulhq_s16;
|
|
static inline Q15 simulate_neon_vqrdmulhq_s16(Q15 a, Q15 b) {
|
|
Q15 result;
|
|
const int esize = 16;
|
|
auto m = [](int16_t r, int16_t s) {
|
|
const int64_t rounding = 1 << (esize - 1);
|
|
int64_t product = 2LL * (int64_t)r * (int64_t)s + rounding;
|
|
int64_t result = product >> esize;
|
|
|
|
// Saturate the result
|
|
if (int64_t limit = (1LL << (esize - 1)) - 1; result > limit) { result = limit; }
|
|
if (int64_t limit = -(1LL << (esize - 1)) ; result < limit) { result = limit; }
|
|
return result;
|
|
};
|
|
for (int i = 0; i < 8; i++) {
|
|
result[i] = m(a[i], b[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#endif // QMath_DEFINED
|