1972b46ca8
For reasons I don't understand, rewrite-includes suddenly started detecting these experimental files as needing their includes rewritten. Change-Id: Ie62e8861169dfb988840e74976248992633874e2 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/455160 Commit-Queue: John Stiles <johnstiles@google.com> Commit-Queue: Kevin Lubick <kjlubick@google.com> Auto-Submit: John Stiles <johnstiles@google.com> Reviewed-by: Kevin Lubick <kjlubick@google.com>
141 lines
4.6 KiB
C++
141 lines
4.6 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.
|
|
*/
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <cstdint>
|
|
|
|
#include "experimental/lowp-basic/QMath.h"
|
|
|
|
struct Stats {
|
|
int64_t diff_8_bits = 0;
|
|
int64_t max_diff = 0;
|
|
int64_t min_diff = 0;
|
|
int64_t total = 0;
|
|
|
|
void log(int16_t golden, int16_t candidate) {
|
|
int64_t diff = candidate - golden;
|
|
max_diff = std::max(max_diff, diff);
|
|
min_diff = std::min(min_diff, diff);
|
|
diff_8_bits += candidate != golden;
|
|
total++;
|
|
}
|
|
|
|
void print() const {
|
|
printf("8-bit diff: %lld - %g%%\n", diff_8_bits, 100.0 * diff_8_bits / total);
|
|
printf("differences min: %lld max: %lld\n", min_diff, max_diff);
|
|
printf("total: %lld\n", total);
|
|
}
|
|
};
|
|
|
|
// This has all kinds of rounding issues.
|
|
// TODO(herb): figure out rounding problems with this code.
|
|
static float golden_bilerp(float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11) {
|
|
return (1.0f-tx) * (1.0f-ty) * p00
|
|
+ (1.0f-tx) * ty * p01
|
|
+ (1.0f-ty) * tx * p10
|
|
+ tx * ty * p11;
|
|
}
|
|
|
|
static double golden_bilerp2(
|
|
float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11) {
|
|
// Double is needed to avoid rounding of lower bits.
|
|
double dtx(tx), dty(ty);
|
|
|
|
double top = (1.0 - dtx) * p00 + dtx * p10;
|
|
double bottom = (1.0 - dtx) * p01 + dtx * p11;
|
|
|
|
return (1.0 - dty) * top + dty * bottom;
|
|
}
|
|
|
|
static int16_t full_res_bilerp(
|
|
float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11) {
|
|
int32_t ftx(floor(tx * 65536.0f + 0.5f));
|
|
int64_t top = ftx * (p10 - p00) + 65536 * p00;
|
|
int64_t bottom = ftx * (p11 - p01) + 65536 * p01;
|
|
|
|
int64_t fty(floor(ty * 65536.0f + 0.5f));
|
|
int64_t temp = fty * (bottom - top) + top * 65536LL;
|
|
int64_t rounded = temp + (1LL << 31);
|
|
return rounded >> 32;
|
|
}
|
|
|
|
// Change of parameters on t from [0, 1) to [-1, 1). This cuts the number if differences in half.
|
|
static int16_t lerp(float t, int16_t a, int16_t b) {
|
|
const int logPixelScale = 7;
|
|
const uint16_t half = 1 << logPixelScale;
|
|
// t on [-1, 1).
|
|
Q15 qt (floor(t * 65536.0f - 32768.0f + 0.5f));
|
|
// need to pick logPixelScale to scale by addition 1/2.
|
|
Q15 qw ((b - a) << logPixelScale);
|
|
Q15 qm ((a + b) << logPixelScale);
|
|
Q15 answer = simulate_ssse3_mm_mulhrs_epi16(qt, qw) + qm;
|
|
// Extra shift to divide by 2.
|
|
return (answer[0] + half) >> (logPixelScale + 1);
|
|
}
|
|
|
|
static int16_t bilerp_1(float tx, float ty, int16_t p00, int16_t p10, int16_t p01, int16_t p11) {
|
|
const int logPixelScale = 7;
|
|
const int16_t half = 1 << logPixelScale;
|
|
Q15 qtx = floor(tx * 65536.0f - 32768.0f + 0.5f);
|
|
Q15 qw = (p10 - p00) << logPixelScale;
|
|
Q15 qm = (p10 + p00) << logPixelScale;
|
|
Q15 top = (simulate_ssse3_mm_mulhrs_epi16(qtx, qw) + qm + 1) >> 1;
|
|
|
|
qw = (p11 - p01) << logPixelScale;
|
|
qm = (p11 + p01) << logPixelScale;
|
|
Q15 bottom = (simulate_ssse3_mm_mulhrs_epi16(qtx, qw) + qm + 1) >> 1;
|
|
|
|
Q15 qty = floor(ty * 65536.0f - 32768.0f + 0.5f);
|
|
|
|
qw = bottom - top;
|
|
qm = bottom + top;
|
|
Q15 scaledAnswer = simulate_ssse3_mm_mulhrs_epi16(qty, qw) + qm;
|
|
|
|
return (scaledAnswer[0] + half) >> (logPixelScale + 1);
|
|
}
|
|
|
|
template <typename Bilerp>
|
|
static Stats check_bilerp(Bilerp bilerp) {
|
|
Stats stats;
|
|
const int step = 1;
|
|
auto interesting = {0, 1, 2, 3, 4, 5, 6, 7, 8, 60, 61, 62, 63, 64, 65, 66, 67, 68, 124, 125,
|
|
126, 127, 128, 129, 130, 131, 132, 188, 189, 190, 191, 192, 193, 194,
|
|
195, 196, 248, 249, 250, 251, 252, 253, 254, 255};
|
|
for (float tx : {0.0f, 0.25f, 0.5f, 0.75f, 1.0f - 1.0f/65536.0f})
|
|
for (float ty : {0.0f, 0.25f, 0.5f, 0.75f, 1.0f - 1.0f/65536.0f})
|
|
for (int p00 : interesting)
|
|
for (int p01 : interesting)
|
|
for (int p10 : interesting)
|
|
for (int p11 : interesting) {
|
|
// Having this be double causes the proper rounding.
|
|
double l = golden_bilerp2(tx, ty, p00, p10, p01, p11);
|
|
int16_t golden = floor(l + 0.5);
|
|
//l = golden_bilerp(tx, ty, p00, p10, p01, p11);
|
|
//int16_t golden2 = floor(l + 0.5f);
|
|
int16_t candidate = bilerp(tx, ty, p00, p10, p01, p11);
|
|
stats.log(golden, candidate);
|
|
}
|
|
return stats;
|
|
}
|
|
|
|
int main() {
|
|
Stats stats;
|
|
|
|
printf("\nUsing trunc_bilerp...\n");
|
|
stats = check_bilerp(bilerp_1);
|
|
stats.print();
|
|
|
|
printf("\nUsing full_res_bilerp...\n");
|
|
stats = check_bilerp(full_res_bilerp);
|
|
stats.print();
|
|
|
|
printf("Done.\n");
|
|
return 0;
|
|
}
|