blob: b7f0c220562a11860c1a88f946b2c279a76dca08 [file] [log] [blame]
/*
* Copyright 2022 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/core/SkOpts.h"
#include "tests/Test.h"
#include <algorithm>
#include <array>
#include <cstddef>
#define SK_OPTS_NS RPOptsTest
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
#include "src/opts/SkRasterPipeline_opts.h"
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
constexpr auto F_ = SK_OPTS_NS::F_;
using F = SK_OPTS_NS::F;
using I32 = SK_OPTS_NS::I32;
template <size_t N>
static std::array<int32_t, N> make_masks(int bits) {
// Make an array of masks that correspond to the bit pattern of `bits`.
std::array<int32_t, N> masks;
for (size_t idx = 0; idx < N; ++idx) {
masks[idx] = (bits & 1) ? ~0 : 0;
bits >>= 1;
}
SkASSERT(!bits);
return masks;
}
DEF_TEST(SkRasterPipelineOpts_Any, r) {
static constexpr size_t N = sizeof(I32) / sizeof(int32_t);
for (int value = 0; value < (1 << N); ++value) {
// Load masks corresponding to the bit-pattern of `value` into lanes of `i`.
std::array<int32_t, N> masks = make_masks<N>(value);
I32 i = sk_unaligned_load<I32>(masks.data());
// Verify that the raster pipeline any() matches expectations.
REPORTER_ASSERT(r, SK_OPTS_NS::any(i) == std::any_of(masks.begin(), masks.end(),
[](int32_t m) { return m != 0; }));
}
}
DEF_TEST(SkRasterPipelineOpts_All, r) {
static constexpr size_t N = sizeof(I32) / sizeof(int32_t);
for (int value = 0; value < (1 << N); ++value) {
// Load masks corresponding to the bit-pattern of `value` into lanes of `i`.
std::array<int32_t, N> masks = make_masks<N>(value);
I32 i = sk_unaligned_load<I32>(masks.data());
// Verify that the raster pipeline all() matches expectations.
REPORTER_ASSERT(r, SK_OPTS_NS::all(i) == std::all_of(masks.begin(), masks.end(),
[](int32_t m) { return m != 0; }));
}
}
DEF_TEST(SkRasterPipelineOpts_Sin, r) {
constexpr float Pi = SK_ScalarPI;
constexpr float kTolerance = 0.000875f;
for (float rad = -5*Pi; rad <= 5*Pi; rad += 0.1f) {
F result = SK_OPTS_NS::sin_(F_(rad));
F expected = F_(std::sin(rad));
F delta = SK_OPTS_NS::abs_(expected - result);
REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
}
}
DEF_TEST(SkRasterPipelineOpts_Cos, r) {
constexpr float Pi = SK_ScalarPI;
constexpr float kTolerance = 0.000875f;
for (float rad = -5*Pi; rad <= 5*Pi; rad += 0.1f) {
F result = SK_OPTS_NS::cos_(F_(rad));
F expected = F_(std::cos(rad));
F delta = SK_OPTS_NS::abs_(expected - result);
REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
}
}
DEF_TEST(SkRasterPipelineOpts_Tan, r) {
// Our tangent diverges more as we get near infinities (x near +- Pi/2),
// so we bring in the domain a little.
constexpr float Pi = SK_ScalarPI;
constexpr float kEpsilon = 0.16f;
constexpr float kTolerance = 0.00175f;
// Test against various multiples of Pi, to check our periodicity
for (float period : {0.0f, -3*Pi, 3*Pi}) {
for (float rad = -Pi/2 + kEpsilon; rad <= Pi/2 - kEpsilon; rad += 0.01f) {
F result = SK_OPTS_NS::tan_(F_(rad + period));
F expected = F_(std::tan(rad));
F delta = SK_OPTS_NS::abs_(expected - result);
REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
}
}
}
DEF_TEST(SkRasterPipelineOpts_Asin, r) {
constexpr float kTolerance = 0.00175f;
for (float x = -1; x <= 1; x += 1.0f/64) {
F result = SK_OPTS_NS::asin_(F_(x));
F expected = F_(asinf(x));
F delta = SK_OPTS_NS::abs_(expected - result);
REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
}
}
DEF_TEST(SkRasterPipelineOpts_Acos, r) {
constexpr float kTolerance = 0.00175f;
for (float x = -1; x <= 1; x += 1.0f/64) {
F result = SK_OPTS_NS::acos_(F_(x));
F expected = F_(acosf(x));
F delta = SK_OPTS_NS::abs_(expected - result);
REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
}
}
DEF_TEST(SkRasterPipelineOpts_Atan, r) {
constexpr float kTolerance = 0.00175f;
for (float x = -10.0f; x <= 10.0f; x += 0.1f) {
F result = SK_OPTS_NS::atan_(F_(x));
F expected = F_(atanf(x));
F delta = SK_OPTS_NS::abs_(expected - result);
REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
}
}
DEF_TEST(SkRasterPipelineOpts_Atan2, r) {
constexpr float kTolerance = 0.00175f;
for (float y = -3.0f; y <= 3.0f; y += 0.1f) {
for (float x = -3.0f; x <= 3.0f; x += 0.1f) {
F result = SK_OPTS_NS::atan2_(F_(y), F_(x));
F expected = F_(std::atan2(y, x));
F delta = SK_OPTS_NS::abs_(expected - result);
REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
}
}
}
DEF_TEST(SkRasterPipelineOpts_Log2, r) {
constexpr float kTolerance = 0.001f;
for (float value : {0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f}) {
F result = SK_OPTS_NS::approx_log2(F_(value));
F expected = F_(std::log2(value));
F delta = SK_OPTS_NS::abs_(expected - result);
REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
}
}
DEF_TEST(SkRasterPipelineOpts_Pow2, r) {
constexpr float kTolerance = 0.001f;
for (float value : {-80, -5, -2, -1, 0, 1, 2, 3, 5}) {
F result = SK_OPTS_NS::approx_pow2(F_(value));
F expected = F_(std::pow(2.0, value));
F delta = SK_OPTS_NS::abs_(expected - result);
REPORTER_ASSERT(r, SK_OPTS_NS::all(delta < kTolerance));
}
F result = SK_OPTS_NS::approx_pow2(F_(160));
REPORTER_ASSERT(r, SK_OPTS_NS::all(result == INFINITY));
}