Flutter Engine
The Flutter Engine
bilerp-study.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google LLC
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
8#include <algorithm>
9#include <cmath>
10#include <cstdio>
11#include <cstdint>
12
14
15struct Stats {
16 int64_t diff_8_bits = 0;
17 int64_t max_diff = 0;
18 int64_t min_diff = 0;
19 int64_t total = 0;
20
21 void log(int16_t golden, int16_t candidate) {
22 int64_t diff = candidate - golden;
23 max_diff = std::max(max_diff, diff);
24 min_diff = std::min(min_diff, diff);
25 diff_8_bits += candidate != golden;
26 total++;
27 }
28
29 void print() const {
30 printf("8-bit diff: %lld - %g%%\n", diff_8_bits, 100.0 * diff_8_bits / total);
31 printf("differences min: %lld max: %lld\n", min_diff, max_diff);
32 printf("total: %lld\n", total);
33 }
34};
35
36// This has all kinds of rounding issues.
37// TODO(herb): figure out rounding problems with this code.
38static float golden_bilerp(float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11) {
39 return (1.0f-tx) * (1.0f-ty) * p00
40 + (1.0f-tx) * ty * p01
41 + (1.0f-ty) * tx * p10
42 + tx * ty * p11;
43}
44
45static double golden_bilerp2(
46 float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11) {
47 // Double is needed to avoid rounding of lower bits.
48 double dtx(tx), dty(ty);
49
50 double top = (1.0 - dtx) * p00 + dtx * p10;
51 double bottom = (1.0 - dtx) * p01 + dtx * p11;
52
53 return (1.0 - dty) * top + dty * bottom;
54}
55
56static int16_t full_res_bilerp(
57 float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11) {
58 int32_t ftx(floor(tx * 65536.0f + 0.5f));
59 int64_t top = ftx * (p10 - p00) + 65536 * p00;
60 int64_t bottom = ftx * (p11 - p01) + 65536 * p01;
61
62 int64_t fty(floor(ty * 65536.0f + 0.5f));
63 int64_t temp = fty * (bottom - top) + top * 65536LL;
64 int64_t rounded = temp + (1LL << 31);
65 return rounded >> 32;
66}
67
68
69static int16_t bilerp_1(float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11) {
70 const int logPixelScale = 7;
71 const int16_t half = 1 << logPixelScale;
72 I16 qtx = floor(tx * 65536.0f - 32768.0f + 0.5f);
73 I16 qw = (p10 - p00) << logPixelScale;
74 U16 qm = (p10 + p00) << logPixelScale;
75 I16 top = (I16)((U16)(constrained_add(simulate_ssse3_mm_mulhrs_epi16(qtx, qw), qm) + 1) >> 1);
76
77 qw = (p11 - p01) << logPixelScale;
78 qm = (p11 + p01) << logPixelScale;
79 I16 bottom =
80 (I16)((U16)(constrained_add(simulate_ssse3_mm_mulhrs_epi16(qtx, qw), qm) + 1) >> 1);
81
82 I16 qty = floor(ty * 65536.0f - 32768.0f + 0.5f);
83
84 qw = bottom - top;
85 qm = (U16)bottom + (U16)top;
86 U16 scaledAnswer = constrained_add(simulate_ssse3_mm_mulhrs_epi16(qty, qw), qm);
87
88 return (scaledAnswer[0] + half) >> (logPixelScale + 1);
89}
90
91template <typename Bilerp>
92static Stats check_bilerp(Bilerp bilerp) {
94 const int step = 1;
95 auto interesting = {0, 1, 2, 3, 4, 5, 6, 7, 8, 60, 61, 62, 63, 64, 65, 66, 67, 68, 124, 125,
96 126, 127, 128, 129, 130, 131, 132, 188, 189, 190, 191, 192, 193, 194,
97 195, 196, 248, 249, 250, 251, 252, 253, 254, 255};
98 for (float tx : {0.0f, 0.25f, 0.5f, 0.75f, 1.0f - 1.0f/65536.0f})
99 for (float ty : {0.0f, 0.25f, 0.5f, 0.75f, 1.0f - 1.0f/65536.0f})
100 for (int p00 : interesting)
101 for (int p01 : interesting)
102 for (int p10 : interesting)
103 for (int p11 : interesting) {
104 // Having this be double causes the proper rounding.
105 double l = golden_bilerp2(tx, ty, p00, p10, p01, p11);
106 int16_t golden = floor(l + 0.5);
107 //l = golden_bilerp(tx, ty, p00, p10, p01, p11);
108 //int16_t golden2 = floor(l + 0.5f);
109 int16_t candidate = bilerp(tx, ty, p00, p10, p01, p11);
110 stats.log(golden, candidate);
111 }
112 return stats;
113}
114
115int main() {
116 Stats stats;
117
118 printf("\nUsing trunc_bilerp...\n");
120 stats.print();
121
122 printf("\nUsing full_res_bilerp...\n");
124 stats.print();
125
126 printf("Done.\n");
127 return 0;
128}
static int step(int x, SkScalar min, SkScalar max)
Definition: BlurTest.cpp:215
V< 8, int16_t > I16
Definition: QMath.h:30
static I16 simulate_ssse3_mm_mulhrs_epi16(I16 a, I16 b)
Definition: QMath.h:44
static U16 constrained_add(I16 a, U16 b)
Definition: QMath.h:34
V< 8, uint16_t > U16
Definition: QMath.h:31
static SkScalar bilerp(SkScalar tx, SkScalar ty, SkScalar c00, SkScalar c10, SkScalar c01, SkScalar c11)
static double golden_bilerp2(float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11)
static int16_t full_res_bilerp(float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11)
static Stats check_bilerp(Bilerp bilerp)
int main()
static float golden_bilerp(float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11)
static int16_t bilerp_1(float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11)
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float min(float r, float g, float b)
Definition: hsl.cpp:48
std::string printf(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: SkSLString.cpp:83
dictionary stats
Definition: malisc.py:20
SIN Vec< N, float > floor(const Vec< N, float > &x)
Definition: SkVx.h:703
int64_t total
void log(int16_t golden, int16_t candidate)
void print() const
int64_t min_diff
int64_t max_diff
int64_t diff_8_bits