diff options
Diffstat (limited to 'src/dsp/intrapred_directional_test.cc')
-rw-r--r-- | src/dsp/intrapred_directional_test.cc | 929 |
1 files changed, 929 insertions, 0 deletions
diff --git a/src/dsp/intrapred_directional_test.cc b/src/dsp/intrapred_directional_test.cc new file mode 100644 index 0000000..ebf9da0 --- /dev/null +++ b/src/dsp/intrapred_directional_test.cc @@ -0,0 +1,929 @@ +// Copyright 2021 The libgav1 Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/dsp/intrapred_directional.h" + +#include <cmath> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <memory> +#include <ostream> + +#include "absl/strings/match.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "gtest/gtest.h" +#include "src/dsp/constants.h" +#include "src/dsp/dsp.h" +#include "src/utils/common.h" +#include "src/utils/constants.h" +#include "src/utils/cpu.h" +#include "src/utils/memory.h" +#include "tests/block_utils.h" +#include "tests/third_party/libvpx/acm_random.h" +#include "tests/utils.h" + +namespace libgav1 { +namespace dsp { +namespace { + +constexpr int kMaxBlockSize = 64; +constexpr int kTotalPixels = kMaxBlockSize * kMaxBlockSize; +constexpr int kNumDirectionalIntraPredictors = 3; + +constexpr int kBaseAngles[] = {45, 67, 90, 113, 135, 157, 180, 203}; + +const char* const kDirectionalPredNames[kNumDirectionalIntraPredictors] = { + "kDirectionalIntraPredictorZone1", "kDirectionalIntraPredictorZone2", + "kDirectionalIntraPredictorZone3"}; + +int16_t GetDirectionalIntraPredictorDerivative(const int angle) { + EXPECT_GE(angle, 3); + EXPECT_LE(angle, 87); + return kDirectionalIntraPredictorDerivative[DivideBy2(angle) - 1]; +} + +template <int bitdepth, typename Pixel> +class IntraPredTestBase : public testing::TestWithParam<TransformSize>, + public test_utils::MaxAlignedAllocable { + public: + IntraPredTestBase() { + switch (tx_size_) { + case kNumTransformSizes: + EXPECT_NE(tx_size_, kNumTransformSizes); + break; + default: + block_width_ = kTransformWidth[tx_size_]; + block_height_ = kTransformHeight[tx_size_]; + break; + } + } + + IntraPredTestBase(const IntraPredTestBase&) = delete; + IntraPredTestBase& operator=(const IntraPredTestBase&) = delete; + ~IntraPredTestBase() override = default; + + protected: + struct IntraPredMem { + void Reset(libvpx_test::ACMRandom* rnd) { + ASSERT_NE(rnd, nullptr); + Pixel* const left = left_mem + 16; + Pixel* const top = top_mem + 16; + const int mask = (1 << bitdepth) - 1; + for (auto& r : ref_src) r = rnd->Rand16() & mask; + for (int i = 0; i < kMaxBlockSize; ++i) left[i] = rnd->Rand16() & mask; + for (int i = -1; i < kMaxBlockSize; ++i) top[i] = rnd->Rand16() & mask; + + // Some directional predictors require top-right, bottom-left. + for (int i = kMaxBlockSize; i < 2 * kMaxBlockSize; ++i) { + left[i] = rnd->Rand16() & mask; + top[i] = rnd->Rand16() & mask; + } + // TODO(jzern): reorder this and regenerate the digests after switching + // random number generators. + // Upsampling in the directional predictors extends left/top[-1] to [-2]. + left[-1] = rnd->Rand16() & mask; + left[-2] = rnd->Rand16() & mask; + top[-2] = rnd->Rand16() & mask; + memset(left_mem, 0, sizeof(left_mem[0]) * 14); + memset(top_mem, 0, sizeof(top_mem[0]) * 14); + memset(top_mem + kMaxBlockSize * 2 + 16, 0, + sizeof(top_mem[0]) * kTopMemPadding); + } + + // Set ref_src, top-left, top and left to |pixel|. + void Set(const Pixel pixel) { + Pixel* const left = left_mem + 16; + Pixel* const top = top_mem + 16; + for (auto& r : ref_src) r = pixel; + // Upsampling in the directional predictors extends left/top[-1] to [-2]. + for (int i = -2; i < 2 * kMaxBlockSize; ++i) { + left[i] = top[i] = pixel; + } + } + + // DirectionalZone1_Large() overreads up to 7 pixels in |top_mem|. + static constexpr int kTopMemPadding = 7; + alignas(kMaxAlignment) Pixel dst[kTotalPixels]; + alignas(kMaxAlignment) Pixel ref_src[kTotalPixels]; + alignas(kMaxAlignment) Pixel left_mem[kMaxBlockSize * 2 + 16]; + alignas( + kMaxAlignment) Pixel top_mem[kMaxBlockSize * 2 + 16 + kTopMemPadding]; + }; + + void SetUp() override { test_utils::ResetDspTable(bitdepth); } + + const TransformSize tx_size_ = GetParam(); + int block_width_; + int block_height_; + IntraPredMem intra_pred_mem_; +}; + +//------------------------------------------------------------------------------ +// DirectionalIntraPredTest + +template <int bitdepth, typename Pixel> +class DirectionalIntraPredTest : public IntraPredTestBase<bitdepth, Pixel> { + public: + DirectionalIntraPredTest() = default; + DirectionalIntraPredTest(const DirectionalIntraPredTest&) = delete; + DirectionalIntraPredTest& operator=(const DirectionalIntraPredTest&) = delete; + ~DirectionalIntraPredTest() override = default; + + protected: + using IntraPredTestBase<bitdepth, Pixel>::tx_size_; + using IntraPredTestBase<bitdepth, Pixel>::block_width_; + using IntraPredTestBase<bitdepth, Pixel>::block_height_; + using IntraPredTestBase<bitdepth, Pixel>::intra_pred_mem_; + + enum Zone { kZone1, kZone2, kZone3, kNumZones }; + + enum { kAngleDeltaStart = -9, kAngleDeltaStop = 9, kAngleDeltaStep = 3 }; + + void SetUp() override { + IntraPredTestBase<bitdepth, Pixel>::SetUp(); + IntraPredDirectionalInit_C(); + + const Dsp* const dsp = GetDspTable(bitdepth); + ASSERT_NE(dsp, nullptr); + base_directional_intra_pred_zone1_ = dsp->directional_intra_predictor_zone1; + base_directional_intra_pred_zone2_ = dsp->directional_intra_predictor_zone2; + base_directional_intra_pred_zone3_ = dsp->directional_intra_predictor_zone3; + + const testing::TestInfo* const test_info = + testing::UnitTest::GetInstance()->current_test_info(); + const char* const test_case = test_info->test_suite_name(); + if (absl::StartsWith(test_case, "C/")) { + base_directional_intra_pred_zone1_ = nullptr; + base_directional_intra_pred_zone2_ = nullptr; + base_directional_intra_pred_zone3_ = nullptr; + } else if (absl::StartsWith(test_case, "NEON/")) { + IntraPredDirectionalInit_NEON(); + } else if (absl::StartsWith(test_case, "SSE41/")) { + if ((GetCpuInfo() & kSSE4_1) != 0) { + IntraPredDirectionalInit_SSE4_1(); + } + } else { + FAIL() << "Unrecognized architecture prefix in test case name: " + << test_case; + } + + cur_directional_intra_pred_zone1_ = dsp->directional_intra_predictor_zone1; + cur_directional_intra_pred_zone2_ = dsp->directional_intra_predictor_zone2; + cur_directional_intra_pred_zone3_ = dsp->directional_intra_predictor_zone3; + + // Skip functions that haven't been specialized for this particular + // architecture. + if (cur_directional_intra_pred_zone1_ == + base_directional_intra_pred_zone1_) { + cur_directional_intra_pred_zone1_ = nullptr; + } + if (cur_directional_intra_pred_zone2_ == + base_directional_intra_pred_zone2_) { + cur_directional_intra_pred_zone2_ = nullptr; + } + if (cur_directional_intra_pred_zone3_ == + base_directional_intra_pred_zone3_) { + cur_directional_intra_pred_zone3_ = nullptr; + } + } + + bool IsEdgeUpsampled(int delta, const int filter_type) const { + delta = std::abs(delta); + if (delta == 0 || delta >= 40) return false; + const int block_wh = block_width_ + block_height_; + return (filter_type == 1) ? block_wh <= 8 : block_wh <= 16; + } + + // Returns the minimum and maximum (exclusive) range of angles that the + // predictor should be applied to. + void GetZoneAngleRange(const Zone zone, int* const min_angle, + int* const max_angle) const { + ASSERT_NE(min_angle, nullptr); + ASSERT_NE(max_angle, nullptr); + switch (zone) { + // The overall minimum angle comes from mode D45_PRED, yielding: + // min_angle = 45-(MAX_ANGLE_DELTA*ANGLE_STEP) = 36 + // The overall maximum angle comes from mode D203_PRED, yielding: + // max_angle = 203+(MAX_ANGLE_DELTA*ANGLE_STEP) = 212 + // The angles 180 and 90 are not permitted because they correspond to + // V_PRED and H_PRED, which are handled in distinct functions. + case kZone1: + *min_angle = 36; + *max_angle = 87; + break; + case kZone2: + *min_angle = 93; + *max_angle = 177; + break; + case kZone3: + *min_angle = 183; + *max_angle = 212; + break; + case kNumZones: + FAIL() << "Invalid zone value: " << zone; + break; + } + } + + // These tests modify intra_pred_mem_. + void TestSpeed(const char* const digests[kNumDirectionalIntraPredictors], + Zone zone, int num_runs); + void TestSaturatedValues(); + void TestRandomValues(); + + DirectionalIntraPredictorZone1Func base_directional_intra_pred_zone1_; + DirectionalIntraPredictorZone2Func base_directional_intra_pred_zone2_; + DirectionalIntraPredictorZone3Func base_directional_intra_pred_zone3_; + DirectionalIntraPredictorZone1Func cur_directional_intra_pred_zone1_; + DirectionalIntraPredictorZone2Func cur_directional_intra_pred_zone2_; + DirectionalIntraPredictorZone3Func cur_directional_intra_pred_zone3_; +}; + +template <int bitdepth, typename Pixel> +void DirectionalIntraPredTest<bitdepth, Pixel>::TestSpeed( + const char* const digests[kNumDirectionalIntraPredictors], const Zone zone, + const int num_runs) { + switch (zone) { + case kZone1: + if (cur_directional_intra_pred_zone1_ == nullptr) return; + break; + case kZone2: + if (cur_directional_intra_pred_zone2_ == nullptr) return; + break; + case kZone3: + if (cur_directional_intra_pred_zone3_ == nullptr) return; + break; + case kNumZones: + FAIL() << "Invalid zone value: " << zone; + break; + } + ASSERT_NE(digests, nullptr); + const Pixel* const left = intra_pred_mem_.left_mem + 16; + const Pixel* const top = intra_pred_mem_.top_mem + 16; + + libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed()); + intra_pred_mem_.Reset(&rnd); + + // Allocate separate blocks for each angle + filter + upsampled combination. + // Add a 1 pixel right border to test for overwrites. + static constexpr int kMaxZoneAngles = 27; // zone 2 + static constexpr int kMaxFilterTypes = 2; + static constexpr int kBlockBorder = 1; + static constexpr int kBorderSize = + kBlockBorder * kMaxZoneAngles * kMaxFilterTypes; + const int ref_stride = + kMaxZoneAngles * kMaxFilterTypes * block_width_ + kBorderSize; + const size_t ref_alloc_size = sizeof(Pixel) * ref_stride * block_height_; + + using AlignedPtr = std::unique_ptr<Pixel[], decltype(&AlignedFree)>; + AlignedPtr ref_src(static_cast<Pixel*>(AlignedAlloc(16, ref_alloc_size)), + &AlignedFree); + AlignedPtr dest(static_cast<Pixel*>(AlignedAlloc(16, ref_alloc_size)), + &AlignedFree); + ASSERT_NE(ref_src, nullptr); + ASSERT_NE(dest, nullptr); + + const int mask = (1 << bitdepth) - 1; + for (size_t i = 0; i < ref_alloc_size / sizeof(ref_src[0]); ++i) { + ref_src[i] = rnd.Rand16() & mask; + } + + int min_angle = 0, max_angle = 0; + ASSERT_NO_FATAL_FAILURE(GetZoneAngleRange(zone, &min_angle, &max_angle)); + + absl::Duration elapsed_time; + for (int run = 0; run < num_runs; ++run) { + Pixel* dst = dest.get(); + memcpy(dst, ref_src.get(), ref_alloc_size); + for (const auto& base_angle : kBaseAngles) { + for (int filter_type = 0; filter_type <= 1; ++filter_type) { + for (int angle_delta = kAngleDeltaStart; angle_delta <= kAngleDeltaStop; + angle_delta += kAngleDeltaStep) { + const int predictor_angle = base_angle + angle_delta; + if (predictor_angle < min_angle || predictor_angle > max_angle) { + continue; + } + + ASSERT_GT(predictor_angle, 0) << "base_angle: " << base_angle + << " angle_delta: " << angle_delta; + const bool upsampled_left = + IsEdgeUpsampled(predictor_angle - 180, filter_type); + const bool upsampled_top = + IsEdgeUpsampled(predictor_angle - 90, filter_type); + const ptrdiff_t stride = ref_stride * sizeof(ref_src[0]); + if (predictor_angle < 90) { + ASSERT_EQ(zone, kZone1); + const int xstep = + GetDirectionalIntraPredictorDerivative(predictor_angle); + const absl::Time start = absl::Now(); + cur_directional_intra_pred_zone1_(dst, stride, top, block_width_, + block_height_, xstep, + upsampled_top); + elapsed_time += absl::Now() - start; + } else if (predictor_angle < 180) { + ASSERT_EQ(zone, kZone2); + const int xstep = + GetDirectionalIntraPredictorDerivative(180 - predictor_angle); + const int ystep = + GetDirectionalIntraPredictorDerivative(predictor_angle - 90); + const absl::Time start = absl::Now(); + cur_directional_intra_pred_zone2_( + dst, stride, top, left, block_width_, block_height_, xstep, + ystep, upsampled_top, upsampled_left); + elapsed_time += absl::Now() - start; + } else { + ASSERT_EQ(zone, kZone3); + ASSERT_LT(predictor_angle, 270); + const int ystep = + GetDirectionalIntraPredictorDerivative(270 - predictor_angle); + const absl::Time start = absl::Now(); + cur_directional_intra_pred_zone3_(dst, stride, left, block_width_, + block_height_, ystep, + upsampled_left); + elapsed_time += absl::Now() - start; + } + dst += block_width_ + kBlockBorder; + } + } + } + } + + test_utils::CheckMd5Digest(ToString(tx_size_), kDirectionalPredNames[zone], + digests[zone], dest.get(), ref_alloc_size, + elapsed_time); +} + +template <int bitdepth, typename Pixel> +void DirectionalIntraPredTest<bitdepth, Pixel>::TestSaturatedValues() { + const Pixel* const left = intra_pred_mem_.left_mem + 16; + const Pixel* const top = intra_pred_mem_.top_mem + 16; + const auto kMaxPixel = static_cast<Pixel>((1 << bitdepth) - 1); + intra_pred_mem_.Set(kMaxPixel); + + for (int i = kZone1; i < kNumZones; ++i) { + switch (i) { + case kZone1: + if (cur_directional_intra_pred_zone1_ == nullptr) continue; + break; + case kZone2: + if (cur_directional_intra_pred_zone2_ == nullptr) continue; + break; + case kZone3: + if (cur_directional_intra_pred_zone3_ == nullptr) continue; + break; + case kNumZones: + FAIL() << "Invalid zone value: " << i; + break; + } + int min_angle = 0, max_angle = 0; + ASSERT_NO_FATAL_FAILURE( + GetZoneAngleRange(static_cast<Zone>(i), &min_angle, &max_angle)); + + for (const auto& base_angle : kBaseAngles) { + for (int filter_type = 0; filter_type <= 1; ++filter_type) { + for (int angle_delta = kAngleDeltaStart; angle_delta <= kAngleDeltaStop; + angle_delta += kAngleDeltaStep) { + const int predictor_angle = base_angle + angle_delta; + if (predictor_angle <= min_angle || predictor_angle >= max_angle) { + continue; + } + ASSERT_GT(predictor_angle, 0) << "base_angle: " << base_angle + << " angle_delta: " << angle_delta; + + memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src, + sizeof(intra_pred_mem_.dst)); + + const bool upsampled_left = + IsEdgeUpsampled(predictor_angle - 180, filter_type); + const bool upsampled_top = + IsEdgeUpsampled(predictor_angle - 90, filter_type); + const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel); + if (predictor_angle < 90) { + const int xstep = + GetDirectionalIntraPredictorDerivative(predictor_angle); + cur_directional_intra_pred_zone1_(intra_pred_mem_.dst, stride, top, + block_width_, block_height_, + xstep, upsampled_top); + } else if (predictor_angle < 180) { + const int xstep = + GetDirectionalIntraPredictorDerivative(180 - predictor_angle); + const int ystep = + GetDirectionalIntraPredictorDerivative(predictor_angle - 90); + cur_directional_intra_pred_zone2_( + intra_pred_mem_.dst, stride, top, left, block_width_, + block_height_, xstep, ystep, upsampled_top, upsampled_left); + } else { + ASSERT_LT(predictor_angle, 270); + const int ystep = + GetDirectionalIntraPredictorDerivative(270 - predictor_angle); + cur_directional_intra_pred_zone3_(intra_pred_mem_.dst, stride, left, + block_width_, block_height_, + ystep, upsampled_left); + } + + if (!test_utils::CompareBlocks( + intra_pred_mem_.dst, intra_pred_mem_.ref_src, block_width_, + block_height_, kMaxBlockSize, kMaxBlockSize, true)) { + ADD_FAILURE() << "Expected " << kDirectionalPredNames[i] + << " (angle: " << predictor_angle + << " filter type: " << filter_type + << ") to produce a block containing '" + << static_cast<int>(kMaxPixel) << "'"; + return; + } + } + } + } + } +} + +template <int bitdepth, typename Pixel> +void DirectionalIntraPredTest<bitdepth, Pixel>::TestRandomValues() { + const Pixel* const left = intra_pred_mem_.left_mem + 16; + const Pixel* const top = intra_pred_mem_.top_mem + 16; + // Use an alternate seed to differentiate this test from TestSpeed(). + libvpx_test::ACMRandom rnd(test_utils::kAlternateDeterministicSeed); + + for (int i = kZone1; i < kNumZones; ++i) { + // Only run when there is a reference version (base) and a different + // optimized version (cur). + switch (i) { + case kZone1: + if (base_directional_intra_pred_zone1_ == nullptr || + cur_directional_intra_pred_zone1_ == nullptr) { + continue; + } + break; + case kZone2: + if (base_directional_intra_pred_zone2_ == nullptr || + cur_directional_intra_pred_zone2_ == nullptr) { + continue; + } + break; + case kZone3: + if (base_directional_intra_pred_zone3_ == nullptr || + cur_directional_intra_pred_zone3_ == nullptr) { + continue; + } + break; + case kNumZones: + FAIL() << "Invalid zone value: " << i; + break; + } + int min_angle = 0, max_angle = 0; + ASSERT_NO_FATAL_FAILURE( + GetZoneAngleRange(static_cast<Zone>(i), &min_angle, &max_angle)); + + for (const auto& base_angle : kBaseAngles) { + for (int n = 0; n < 1000; ++n) { + for (int filter_type = 0; filter_type <= 1; ++filter_type) { + for (int angle_delta = kAngleDeltaStart; + angle_delta <= kAngleDeltaStop; angle_delta += kAngleDeltaStep) { + const int predictor_angle = base_angle + angle_delta; + if (predictor_angle <= min_angle || predictor_angle >= max_angle) { + continue; + } + ASSERT_GT(predictor_angle, 0) << "base_angle: " << base_angle + << " angle_delta: " << angle_delta; + + intra_pred_mem_.Reset(&rnd); + memcpy(intra_pred_mem_.dst, intra_pred_mem_.ref_src, + sizeof(intra_pred_mem_.dst)); + + const bool upsampled_left = + IsEdgeUpsampled(predictor_angle - 180, filter_type); + const bool upsampled_top = + IsEdgeUpsampled(predictor_angle - 90, filter_type); + const ptrdiff_t stride = kMaxBlockSize * sizeof(Pixel); + if (predictor_angle < 90) { + const int xstep = + GetDirectionalIntraPredictorDerivative(predictor_angle); + base_directional_intra_pred_zone1_( + intra_pred_mem_.ref_src, stride, top, block_width_, + block_height_, xstep, upsampled_top); + cur_directional_intra_pred_zone1_( + intra_pred_mem_.dst, stride, top, block_width_, block_height_, + xstep, upsampled_top); + } else if (predictor_angle < 180) { + const int xstep = + GetDirectionalIntraPredictorDerivative(180 - predictor_angle); + const int ystep = + GetDirectionalIntraPredictorDerivative(predictor_angle - 90); + base_directional_intra_pred_zone2_( + intra_pred_mem_.ref_src, stride, top, left, block_width_, + block_height_, xstep, ystep, upsampled_top, upsampled_left); + cur_directional_intra_pred_zone2_( + intra_pred_mem_.dst, stride, top, left, block_width_, + block_height_, xstep, ystep, upsampled_top, upsampled_left); + } else { + ASSERT_LT(predictor_angle, 270); + const int ystep = + GetDirectionalIntraPredictorDerivative(270 - predictor_angle); + base_directional_intra_pred_zone3_( + intra_pred_mem_.ref_src, stride, left, block_width_, + block_height_, ystep, upsampled_left); + cur_directional_intra_pred_zone3_( + intra_pred_mem_.dst, stride, left, block_width_, + block_height_, ystep, upsampled_left); + } + + if (!test_utils::CompareBlocks( + intra_pred_mem_.dst, intra_pred_mem_.ref_src, block_width_, + block_height_, kMaxBlockSize, kMaxBlockSize, true)) { + ADD_FAILURE() << "Result from optimized version of " + << kDirectionalPredNames[i] + << " differs from reference at angle " + << predictor_angle << " with filter type " + << filter_type << " in iteration #" << n; + return; + } + } + } + } + } + } +} + +using DirectionalIntraPredTest8bpp = DirectionalIntraPredTest<8, uint8_t>; + +const char* const* GetDirectionalIntraPredDigests8bpp(TransformSize tx_size) { + static const char* const kDigests4x4[kNumDirectionalIntraPredictors] = { + "9cfc1da729ad08682e165826c29b280b", + "bb73539c7afbda7bddd2184723b932d6", + "9d2882800ffe948196e984a26a2da72c", + }; + static const char* const kDigests4x8[kNumDirectionalIntraPredictors] = { + "090efe6f83cc6fa301f65d3bbd5c38d2", + "d0fba4cdfb90f8bd293a94cae9db1a15", + "f7ad0eeab4389d0baa485d30fec87617", + }; + static const char* const kDigests4x16[kNumDirectionalIntraPredictors] = { + "1d32b33c75fe85248c48cdc8caa78d84", + "7000e18159443d366129a6cc6ef8fcee", + "06c02fac5f8575f687abb3f634eb0b4c", + }; + static const char* const kDigests8x4[kNumDirectionalIntraPredictors] = { + "1b591799685bc135982114b731293f78", + "5cd9099acb9f7b2618dafa6712666580", + "d023883efede88f99c19d006044d9fa1", + }; + static const char* const kDigests8x8[kNumDirectionalIntraPredictors] = { + "f1e46ecf62a2516852f30c5025adb7ea", + "864442a209c16998065af28d8cdd839a", + "411a6e554868982af577de69e53f12e8", + }; + static const char* const kDigests8x16[kNumDirectionalIntraPredictors] = { + "89278302be913a85cfb06feaea339459", + "6c42f1a9493490cd4529fd40729cec3c", + "2516b5e1c681e5dcb1acedd5f3d41106", + }; + static const char* const kDigests8x32[kNumDirectionalIntraPredictors] = { + "aea7078f3eeaa8afbfe6c959c9e676f1", + "cad30babf12729dda5010362223ba65c", + "ff384ebdc832007775af418a2aae1463", + }; + static const char* const kDigests16x4[kNumDirectionalIntraPredictors] = { + "964a821c313c831e12f4d32e616c0b55", + "adf6dad3a84ab4d16c16eea218bec57a", + "a54fa008d43895e523474686c48a81c2", + }; + static const char* const kDigests16x8[kNumDirectionalIntraPredictors] = { + "fe2851b4e4f9fcf924cf17d50415a4c0", + "50a0e279c481437ff315d08eb904c733", + "0682065c8fb6cbf9be4949316c87c9e5", + }; + static const char* const kDigests16x16[kNumDirectionalIntraPredictors] = { + "ef15503b1943642e7a0bace1616c0e11", + "bf1a4d3f855f1072a902a88ec6ce0350", + "7e87a03e29cd7fd843fd71b729a18f3f", + }; + static const char* const kDigests16x32[kNumDirectionalIntraPredictors] = { + "f7b636615d2e5bf289b5db452a6f188d", + "e95858c532c10d00b0ce7a02a02121dd", + "34a18ccf58ef490f32268e85ce8c7de4", + }; + static const char* const kDigests16x64[kNumDirectionalIntraPredictors] = { + "b250099986c2fab9670748598058846b", + "f25d80af4da862a9b6b72979f1e17cb4", + "5347dc7bc346733b4887f6c8ad5e0898", + }; + static const char* const kDigests32x8[kNumDirectionalIntraPredictors] = { + "72e4c9f8af043b1cb1263490351818ab", + "1fc010d2df011b9e4e3d0957107c78df", + "f4cbfa3ca941ef08b972a68d7e7bafc4", + }; + static const char* const kDigests32x16[kNumDirectionalIntraPredictors] = { + "37e5a1aaf7549d2bce08eece9d20f0f6", + "6a2794025d0aca414ab17baa3cf8251a", + "63dd37a6efdc91eeefef166c99ce2db1", + }; + static const char* const kDigests32x32[kNumDirectionalIntraPredictors] = { + "198aabc958992eb49cceab97d1acb43e", + "aee88b6c8bacfcf38799fe338e6c66e7", + "01e8f8f96696636f6d79d33951907a16", + }; + static const char* const kDigests32x64[kNumDirectionalIntraPredictors] = { + "0611390202c4f90f7add7aec763ded58", + "960240c7ceda2ccfac7c90b71460578a", + "7e7d97594aab8ad56e8c01c340335607", + }; + static const char* const kDigests64x16[kNumDirectionalIntraPredictors] = { + "7e1f567e7fc510757f2d89d638bc826f", + "c929d687352ce40a58670be2ce3c8c90", + "f6881e6a9ba3c3d3d730b425732656b1", + }; + static const char* const kDigests64x32[kNumDirectionalIntraPredictors] = { + "27b4c2a7081d4139f22003ba8b6dfdf2", + "301e82740866b9274108a04c872fa848", + "98d3aa4fef838f4abf00dac33806659f", + }; + static const char* const kDigests64x64[kNumDirectionalIntraPredictors] = { + "b31816db8fade3accfd975b21aa264c7", + "2adce01a03b9452633d5830e1a9b4e23", + "7b988fadba8b07c36e88d7be6b270494", + }; + + switch (tx_size) { + case kTransformSize4x4: + return kDigests4x4; + case kTransformSize4x8: + return kDigests4x8; + case kTransformSize4x16: + return kDigests4x16; + case kTransformSize8x4: + return kDigests8x4; + case kTransformSize8x8: + return kDigests8x8; + case kTransformSize8x16: + return kDigests8x16; + case kTransformSize8x32: + return kDigests8x32; + case kTransformSize16x4: + return kDigests16x4; + case kTransformSize16x8: + return kDigests16x8; + case kTransformSize16x16: + return kDigests16x16; + case kTransformSize16x32: + return kDigests16x32; + case kTransformSize16x64: + return kDigests16x64; + case kTransformSize32x8: + return kDigests32x8; + case kTransformSize32x16: + return kDigests32x16; + case kTransformSize32x32: + return kDigests32x32; + case kTransformSize32x64: + return kDigests32x64; + case kTransformSize64x16: + return kDigests64x16; + case kTransformSize64x32: + return kDigests64x32; + case kTransformSize64x64: + return kDigests64x64; + default: + ADD_FAILURE() << "Unknown transform size: " << tx_size; + return nullptr; + } +} + +TEST_P(DirectionalIntraPredTest8bpp, DISABLED_Speed) { + const auto num_runs = static_cast<int>(5e7 / (block_width_ * block_height_)); + for (int i = kZone1; i < kNumZones; ++i) { + TestSpeed(GetDirectionalIntraPredDigests8bpp(tx_size_), + static_cast<Zone>(i), num_runs); + } +} + +TEST_P(DirectionalIntraPredTest8bpp, FixedInput) { + for (int i = kZone1; i < kNumZones; ++i) { + TestSpeed(GetDirectionalIntraPredDigests8bpp(tx_size_), + static_cast<Zone>(i), 1); + } +} + +TEST_P(DirectionalIntraPredTest8bpp, Overflow) { TestSaturatedValues(); } +TEST_P(DirectionalIntraPredTest8bpp, Random) { TestRandomValues(); } + +//------------------------------------------------------------------------------ +#if LIBGAV1_MAX_BITDEPTH >= 10 + +using DirectionalIntraPredTest10bpp = DirectionalIntraPredTest<10, uint16_t>; + +const char* const* GetDirectionalIntraPredDigests10bpp(TransformSize tx_size) { + static const char* const kDigests4x4[kNumDirectionalIntraPredictors] = { + "a683f4d7ccd978737615f61ecb4d638d", + "90c94374eaf7e9501f197863937b8639", + "0d3969cd081523ac6a906eecc7980c43", + }; + static const char* const kDigests4x8[kNumDirectionalIntraPredictors] = { + "c3ffa2979b325644e4a56c882fe27347", + "1f61f5ee413a9a3b8d1d93869ec2aee0", + "4795ea944779ec4a783408769394d874", + }; + static const char* const kDigests4x16[kNumDirectionalIntraPredictors] = { + "45c3282c9aa51024c1d64a40f230aa45", + "5cd47dd69f8bd0b15365a0c5cfc0a49a", + "06336c507b05f98c1d6a21abc43e6182", + }; + static const char* const kDigests8x4[kNumDirectionalIntraPredictors] = { + "7370476ff0abbdc5e92f811b8879c861", + "a239a50adb28a4791b52a0dfff3bee06", + "4779a17f958a9ca04e8ec08c5aba1d36", + }; + static const char* const kDigests8x8[kNumDirectionalIntraPredictors] = { + "305463f346c376594f82aad8304e0362", + "0cd481e5bda286c87a645417569fd948", + "48c7899dc9b7163b0b1f61b3a2b4b73e", + }; + static const char* const kDigests8x16[kNumDirectionalIntraPredictors] = { + "5c18fd5339be90628c82b1fb6af50d5e", + "35eaa566ebd3bb7c903cfead5dc9ac78", + "9fdb0e790e5965810d02c02713c84071", + }; + static const char* const kDigests8x32[kNumDirectionalIntraPredictors] = { + "2168d6cc858c704748b7b343ced2ac3a", + "1d3ce273107447faafd2e55877e48ffb", + "d344164049d1fe9b65a3ae8764bbbd37", + }; + static const char* const kDigests16x4[kNumDirectionalIntraPredictors] = { + "dcef2cf51abe3fe150f388a14c762d30", + "6a810b289b1c14f8eab8ca1274e91ecd", + "c94da7c11f3fb11963d85c8804fce2d9", + }; + static const char* const kDigests16x8[kNumDirectionalIntraPredictors] = { + "50a0d08b0d99b7a574bad2cfb36efc39", + "2dcb55874db39da70c8ca1318559f9fe", + "6390bcd30ff3bc389ecc0a0952bea531", + }; + static const char* const kDigests16x16[kNumDirectionalIntraPredictors] = { + "7146c83c2620935606d49f3cb5876f41", + "2318ddf30c070a53c9b9cf199cd1b2c5", + "e9042e2124925aa7c1b6110617cb10e8", + }; + static const char* const kDigests16x32[kNumDirectionalIntraPredictors] = { + "c970f401de7b7c5bb4e3ad447fcbef8f", + "a18cc70730eecdaa31dbcf4306ff490f", + "32c1528ad4a576a2210399d6b4ccd46e", + }; + static const char* const kDigests16x64[kNumDirectionalIntraPredictors] = { + "00b3f0007da2e5d01380594a3d7162d5", + "1971af519e4a18967b7311f93efdd1b8", + "e6139769ce5a9c4982cfab9363004516", + }; + static const char* const kDigests32x8[kNumDirectionalIntraPredictors] = { + "08107ad971179cc9f465ae5966bd4901", + "b215212a3c0dfe9182c4f2e903d731f7", + "791274416a0da87c674e1ae318b3ce09", + }; + static const char* const kDigests32x16[kNumDirectionalIntraPredictors] = { + "94ea6cccae35b5d08799aa003ac08ccf", + "ae105e20e63fb55d4fd9d9e59dc62dde", + "973d0b2358ea585e4f486e7e645c5310", + }; + static const char* const kDigests32x32[kNumDirectionalIntraPredictors] = { + "d14c695c4853ddf5e5d8256bc1d1ed60", + "6bd0ebeb53adecc11442b1218b870cb7", + "e03bc402a9999aba8272275dce93e89f", + }; + static const char* const kDigests32x64[kNumDirectionalIntraPredictors] = { + "b21a8a8723758392ee659eeeae518a1e", + "e50285454896210ce44d6f04dfde05a7", + "f0f8ea0c6c2acc8d7d390927c3a90370", + }; + static const char* const kDigests64x16[kNumDirectionalIntraPredictors] = { + "ce51db16fd4fa56e601631397b098c89", + "aa87a8635e02c1e91d13158c61e443f6", + "4c1ee3afd46ef34bd711a34d0bf86f13", + }; + static const char* const kDigests64x32[kNumDirectionalIntraPredictors] = { + "25aaf5971e24e543e3e69a47254af777", + "eb6f444b3df127d69460778ab5bf8fc1", + "2f846cc0d506f90c0a58438600819817", + }; + static const char* const kDigests64x64[kNumDirectionalIntraPredictors] = { + "b26ce5b5f4b5d4a438b52e5987877fb8", + "35721a00a70938111939cf69988d928e", + "0af7ec35939483fac82c246a13845806", + }; + + switch (tx_size) { + case kTransformSize4x4: + return kDigests4x4; + case kTransformSize4x8: + return kDigests4x8; + case kTransformSize4x16: + return kDigests4x16; + case kTransformSize8x4: + return kDigests8x4; + case kTransformSize8x8: + return kDigests8x8; + case kTransformSize8x16: + return kDigests8x16; + case kTransformSize8x32: + return kDigests8x32; + case kTransformSize16x4: + return kDigests16x4; + case kTransformSize16x8: + return kDigests16x8; + case kTransformSize16x16: + return kDigests16x16; + case kTransformSize16x32: + return kDigests16x32; + case kTransformSize16x64: + return kDigests16x64; + case kTransformSize32x8: + return kDigests32x8; + case kTransformSize32x16: + return kDigests32x16; + case kTransformSize32x32: + return kDigests32x32; + case kTransformSize32x64: + return kDigests32x64; + case kTransformSize64x16: + return kDigests64x16; + case kTransformSize64x32: + return kDigests64x32; + case kTransformSize64x64: + return kDigests64x64; + default: + ADD_FAILURE() << "Unknown transform size: " << tx_size; + return nullptr; + } +} + +TEST_P(DirectionalIntraPredTest10bpp, DISABLED_Speed) { + const auto num_runs = static_cast<int>(5e7 / (block_width_ * block_height_)); + for (int i = kZone1; i < kNumZones; ++i) { + TestSpeed(GetDirectionalIntraPredDigests10bpp(tx_size_), + static_cast<Zone>(i), num_runs); + } +} + +TEST_P(DirectionalIntraPredTest10bpp, FixedInput) { + for (int i = kZone1; i < kNumZones; ++i) { + TestSpeed(GetDirectionalIntraPredDigests10bpp(tx_size_), + static_cast<Zone>(i), 1); + } +} + +TEST_P(DirectionalIntraPredTest10bpp, Overflow) { TestSaturatedValues(); } + +#endif // LIBGAV1_MAX_BITDEPTH >= 10 + +constexpr TransformSize kTransformSizes[] = { + kTransformSize4x4, kTransformSize4x8, kTransformSize4x16, + kTransformSize8x4, kTransformSize8x8, kTransformSize8x16, + kTransformSize8x32, kTransformSize16x4, kTransformSize16x8, + kTransformSize16x16, kTransformSize16x32, kTransformSize16x64, + kTransformSize32x8, kTransformSize32x16, kTransformSize32x32, + kTransformSize32x64, kTransformSize64x16, kTransformSize64x32, + kTransformSize64x64}; + +INSTANTIATE_TEST_SUITE_P(C, DirectionalIntraPredTest8bpp, + testing::ValuesIn(kTransformSizes)); +#if LIBGAV1_ENABLE_SSE4_1 +INSTANTIATE_TEST_SUITE_P(SSE41, DirectionalIntraPredTest8bpp, + testing::ValuesIn(kTransformSizes)); +#endif // LIBGAV1_ENABLE_SSE4_1 +#if LIBGAV1_ENABLE_NEON +INSTANTIATE_TEST_SUITE_P(NEON, DirectionalIntraPredTest8bpp, + testing::ValuesIn(kTransformSizes)); +#endif // LIBGAV1_ENABLE_NEON + +#if LIBGAV1_MAX_BITDEPTH >= 10 +INSTANTIATE_TEST_SUITE_P(C, DirectionalIntraPredTest10bpp, + testing::ValuesIn(kTransformSizes)); +#if LIBGAV1_ENABLE_SSE4_1 +INSTANTIATE_TEST_SUITE_P(SSE41, DirectionalIntraPredTest10bpp, + testing::ValuesIn(kTransformSizes)); +#endif // LIBGAV1_ENABLE_SSE4_1 +#if LIBGAV1_ENABLE_NEON +INSTANTIATE_TEST_SUITE_P(NEON, DirectionalIntraPredTest10bpp, + testing::ValuesIn(kTransformSizes)); +#endif // LIBGAV1_ENABLE_NEON + +#endif // LIBGAV1_MAX_BITDEPTH >= 10 + +} // namespace +} // namespace dsp + +static std::ostream& operator<<(std::ostream& os, const TransformSize tx_size) { + return os << ToString(tx_size); +} + +} // namespace libgav1 |