1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2021 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
9*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
10*c8dee2aaSAndroid Build Coastguard Worker #include <cstdio>
11*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard Worker #include "experimental/lowp-basic/QMath.h"
14*c8dee2aaSAndroid Build Coastguard Worker
15*c8dee2aaSAndroid Build Coastguard Worker struct Stats {
16*c8dee2aaSAndroid Build Coastguard Worker int diff_8_bits = 0;
17*c8dee2aaSAndroid Build Coastguard Worker int max_diff = 0;
18*c8dee2aaSAndroid Build Coastguard Worker int min_diff = 0;
19*c8dee2aaSAndroid Build Coastguard Worker int64_t total = 0;
20*c8dee2aaSAndroid Build Coastguard Worker
logStats21*c8dee2aaSAndroid Build Coastguard Worker void log(int16_t golden, int16_t candidate) {
22*c8dee2aaSAndroid Build Coastguard Worker int diff = candidate - golden;
23*c8dee2aaSAndroid Build Coastguard Worker max_diff = std::max(max_diff, diff);
24*c8dee2aaSAndroid Build Coastguard Worker min_diff = std::min(min_diff, diff);
25*c8dee2aaSAndroid Build Coastguard Worker diff_8_bits += candidate != golden;
26*c8dee2aaSAndroid Build Coastguard Worker total++;
27*c8dee2aaSAndroid Build Coastguard Worker }
28*c8dee2aaSAndroid Build Coastguard Worker
printStats29*c8dee2aaSAndroid Build Coastguard Worker void print() const {
30*c8dee2aaSAndroid Build Coastguard Worker printf("8-bit diff: %d - %g%%\n", diff_8_bits, 100.0 * diff_8_bits / total);
31*c8dee2aaSAndroid Build Coastguard Worker printf("differences min: %d max: %d\n", min_diff, max_diff);
32*c8dee2aaSAndroid Build Coastguard Worker printf("total: %lld\n", total);
33*c8dee2aaSAndroid Build Coastguard Worker }
34*c8dee2aaSAndroid Build Coastguard Worker };
35*c8dee2aaSAndroid Build Coastguard Worker
golden_lerp(float t,int16_t a,int16_t b)36*c8dee2aaSAndroid Build Coastguard Worker static float golden_lerp(float t, int16_t a, int16_t b) {
37*c8dee2aaSAndroid Build Coastguard Worker return (1.0f - t) * a + t * b;
38*c8dee2aaSAndroid Build Coastguard Worker }
39*c8dee2aaSAndroid Build Coastguard Worker
40*c8dee2aaSAndroid Build Coastguard Worker template <int logPixelScale>
saturating_lerp(float t,int16_t a,int16_t b)41*c8dee2aaSAndroid Build Coastguard Worker static int16_t saturating_lerp(float t, int16_t a, int16_t b) {
42*c8dee2aaSAndroid Build Coastguard Worker const int16_t half = 1 << (logPixelScale - 1);
43*c8dee2aaSAndroid Build Coastguard Worker Q15 qt(floor(t * 32768.f + 0.5f));
44*c8dee2aaSAndroid Build Coastguard Worker Q15 qa(a << logPixelScale);
45*c8dee2aaSAndroid Build Coastguard Worker Q15 qb(b << logPixelScale);
46*c8dee2aaSAndroid Build Coastguard Worker
47*c8dee2aaSAndroid Build Coastguard Worker Q15 answer = simulate_neon_vqrdmulhq_s16(qt, qb - qa) + qa;
48*c8dee2aaSAndroid Build Coastguard Worker return (answer[0] + half) >> logPixelScale;
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker
51*c8dee2aaSAndroid Build Coastguard Worker template <int logPixelScale>
ssse3_lerp(float t,int16_t a,int16_t b)52*c8dee2aaSAndroid Build Coastguard Worker static int16_t ssse3_lerp(float t, int16_t a, int16_t b) {
53*c8dee2aaSAndroid Build Coastguard Worker const int16_t half = 1 << (logPixelScale - 1);
54*c8dee2aaSAndroid Build Coastguard Worker Q15 qt(floor(t * 32768.f + 0.5f));
55*c8dee2aaSAndroid Build Coastguard Worker Q15 qa(a << logPixelScale);
56*c8dee2aaSAndroid Build Coastguard Worker Q15 qb(b << logPixelScale);
57*c8dee2aaSAndroid Build Coastguard Worker
58*c8dee2aaSAndroid Build Coastguard Worker Q15 answer = simulate_ssse3_mm_mulhrs_epi16(qt, qb - qa) + qa;
59*c8dee2aaSAndroid Build Coastguard Worker return (answer[0] + half) >> logPixelScale;
60*c8dee2aaSAndroid Build Coastguard Worker }
61*c8dee2aaSAndroid Build Coastguard Worker
full_res_lerp(float t,int16_t a,int16_t b)62*c8dee2aaSAndroid Build Coastguard Worker static int16_t full_res_lerp(float t, int16_t a, int16_t b) {
63*c8dee2aaSAndroid Build Coastguard Worker int32_t ft(floor(t * 65536.0f + 0.5f));
64*c8dee2aaSAndroid Build Coastguard Worker
65*c8dee2aaSAndroid Build Coastguard Worker int32_t temp = ft * (b - a) + a * 65536;
66*c8dee2aaSAndroid Build Coastguard Worker int32_t rounded = temp + 32768;
67*c8dee2aaSAndroid Build Coastguard Worker return rounded >> 16;
68*c8dee2aaSAndroid Build Coastguard Worker }
69*c8dee2aaSAndroid Build Coastguard Worker
70*c8dee2aaSAndroid Build Coastguard Worker // Change of parameters on t from [0, 1) to [-1, 1). This cuts the number if differences in half.
71*c8dee2aaSAndroid Build Coastguard Worker template <int logPixelScale>
balanced_lerp(float t,int16_t a,int16_t b)72*c8dee2aaSAndroid Build Coastguard Worker static int16_t balanced_lerp(float t, int16_t a, int16_t b) {
73*c8dee2aaSAndroid Build Coastguard Worker const int16_t half = 1 << logPixelScale;
74*c8dee2aaSAndroid Build Coastguard Worker // t on [-1, 1).
75*c8dee2aaSAndroid Build Coastguard Worker Q15 qt (floor(t * 65536.0f - 32768.0f + 0.5f));
76*c8dee2aaSAndroid Build Coastguard Worker // need to pick logPixelScale to scale by addition 1/2.
77*c8dee2aaSAndroid Build Coastguard Worker Q15 qw ((b - a) << logPixelScale);
78*c8dee2aaSAndroid Build Coastguard Worker Q15 qm ((a + b) << logPixelScale);
79*c8dee2aaSAndroid Build Coastguard Worker Q15 answer = simulate_ssse3_mm_mulhrs_epi16(qt, qw) + qm;
80*c8dee2aaSAndroid Build Coastguard Worker // Extra shift to divide by 2.
81*c8dee2aaSAndroid Build Coastguard Worker return (answer[0] + half) >> (logPixelScale + 1);
82*c8dee2aaSAndroid Build Coastguard Worker }
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker template <typename Lerp>
check_lerp(Lerp lerp)85*c8dee2aaSAndroid Build Coastguard Worker static Stats check_lerp(Lerp lerp) {
86*c8dee2aaSAndroid Build Coastguard Worker Stats stats;
87*c8dee2aaSAndroid Build Coastguard Worker for (float t = 0; t < 1.0f - 1.0f / 65536.0f ; t += 1.0f/65536.0f)
88*c8dee2aaSAndroid Build Coastguard Worker for (int a = 255; a >= 0; a--)
89*c8dee2aaSAndroid Build Coastguard Worker for (int b = 255; b >= 0; b--) {
90*c8dee2aaSAndroid Build Coastguard Worker float l = golden_lerp(t, a, b);
91*c8dee2aaSAndroid Build Coastguard Worker int16_t golden = floor(l + 0.5f);
92*c8dee2aaSAndroid Build Coastguard Worker int16_t candidate = lerp(t, a, b);
93*c8dee2aaSAndroid Build Coastguard Worker stats.log(golden, candidate);
94*c8dee2aaSAndroid Build Coastguard Worker }
95*c8dee2aaSAndroid Build Coastguard Worker return stats;
96*c8dee2aaSAndroid Build Coastguard Worker }
97*c8dee2aaSAndroid Build Coastguard Worker
main()98*c8dee2aaSAndroid Build Coastguard Worker int main() {
99*c8dee2aaSAndroid Build Coastguard Worker Stats stats;
100*c8dee2aaSAndroid Build Coastguard Worker
101*c8dee2aaSAndroid Build Coastguard Worker printf("\nUsing full_res_lerp...\n");
102*c8dee2aaSAndroid Build Coastguard Worker stats = check_lerp(full_res_lerp);
103*c8dee2aaSAndroid Build Coastguard Worker stats.print();
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker printf("\nUsing vqrdmulhq_s16...\n");
106*c8dee2aaSAndroid Build Coastguard Worker stats = check_lerp(saturating_lerp<7>);
107*c8dee2aaSAndroid Build Coastguard Worker stats.print();
108*c8dee2aaSAndroid Build Coastguard Worker
109*c8dee2aaSAndroid Build Coastguard Worker printf("\nUsing mm_mulhrs_epi16...\n");
110*c8dee2aaSAndroid Build Coastguard Worker stats = check_lerp(ssse3_lerp<7>);
111*c8dee2aaSAndroid Build Coastguard Worker stats.print();
112*c8dee2aaSAndroid Build Coastguard Worker
113*c8dee2aaSAndroid Build Coastguard Worker printf("\nInterval [-1, 1) mm_mulhrs_epi16...\n");
114*c8dee2aaSAndroid Build Coastguard Worker stats = check_lerp(balanced_lerp<7>);
115*c8dee2aaSAndroid Build Coastguard Worker stats.print();
116*c8dee2aaSAndroid Build Coastguard Worker
117*c8dee2aaSAndroid Build Coastguard Worker printf("Done.");
118*c8dee2aaSAndroid Build Coastguard Worker return 0;
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker
121