blob: 88040b41df2a6c20bc28fdf41f87e55c25aa82c5 [file] [log] [blame]
// Copyright 2020 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/distance_weighted_blend.h"
#include <cassert>
#include <cstdint>
#include <ostream>
#include <string>
#include <type_traits>
#include "absl/strings/match.h"
#include "absl/strings/string_view.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/third_party/libvpx/acm_random.h"
#include "tests/utils.h"
namespace libgav1 {
namespace dsp {
namespace {
constexpr int kNumSpeedTests = 500000;
constexpr int kQuantizedDistanceLookup[4][2] = {
{9, 7}, {11, 5}, {12, 4}, {13, 3}};
template <int bitdepth, typename Pixel>
class DistanceWeightedBlendTest : public testing::TestWithParam<BlockSize>,
public test_utils::MaxAlignedAllocable {
public:
static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
DistanceWeightedBlendTest() = default;
~DistanceWeightedBlendTest() override = default;
void SetUp() override {
test_utils::ResetDspTable(bitdepth);
DistanceWeightedBlendInit_C();
const dsp::Dsp* const dsp = dsp::GetDspTable(bitdepth);
ASSERT_NE(dsp, nullptr);
base_func_ = dsp->distance_weighted_blend;
const testing::TestInfo* const test_info =
testing::UnitTest::GetInstance()->current_test_info();
const absl::string_view test_case = test_info->test_suite_name();
if (absl::StartsWith(test_case, "C/")) {
base_func_ = nullptr;
} else if (absl::StartsWith(test_case, "SSE41/")) {
if ((GetCpuInfo() & kSSE4_1) != 0) {
DistanceWeightedBlendInit_SSE4_1();
}
} else if (absl::StartsWith(test_case, "NEON/")) {
DistanceWeightedBlendInit_NEON();
} else {
FAIL() << "Unrecognized architecture prefix in test case name: "
<< test_case;
}
func_ = dsp->distance_weighted_blend;
}
protected:
void Test(const char* digest, int num_tests);
private:
using PredType =
typename std::conditional<bitdepth == 8, int16_t, uint16_t>::type;
static constexpr int kDestStride = kMaxSuperBlockSizeInPixels;
const int width_ = kBlockWidthPixels[GetParam()];
const int height_ = kBlockHeightPixels[GetParam()];
alignas(kMaxAlignment) PredType
source1_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
alignas(kMaxAlignment) PredType
source2_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels];
Pixel dest_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] = {};
Pixel reference_[kMaxSuperBlockSizeInPixels * kMaxSuperBlockSizeInPixels] =
{};
dsp::DistanceWeightedBlendFunc base_func_;
dsp::DistanceWeightedBlendFunc func_;
};
template <int bitdepth, typename Pixel>
void DistanceWeightedBlendTest<bitdepth, Pixel>::Test(const char* digest,
int num_tests) {
if (func_ == nullptr) return;
libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
PredType* src_1 = source1_;
PredType* src_2 = source2_;
const int index = rnd.Rand8() & 3;
const uint8_t weight_0 = kQuantizedDistanceLookup[index][0];
const uint8_t weight_1 = kQuantizedDistanceLookup[index][1];
// In libgav1, predictors have an offset which are later subtracted and
// clipped in distance weighted blending. Therefore we add the offset
// here to match libaom's implementation.
for (int y = 0; y < height_; ++y) {
for (int x = 0; x < width_; ++x) {
// distance_weighted_blend is applied to compound prediction values. This
// implies a range far exceeding that of pixel values.
// The ranges include kCompoundOffset in 10bpp and 12bpp.
// see: src/dsp/convolve.cc & src/dsp/warp.cc.
static constexpr int kCompoundPredictionRange[3][2] = {
// 8bpp
{-5132, 9212},
// 10bpp
{3988, 61532},
// 12bpp
{3974, 61559},
};
constexpr int bitdepth_index = (bitdepth - 8) >> 1;
const int min_val = kCompoundPredictionRange[bitdepth_index][0];
const int max_val = kCompoundPredictionRange[bitdepth_index][1];
src_1[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
src_2[x] = static_cast<PredType>(rnd(max_val - min_val) + min_val);
}
src_1 += width_;
src_2 += width_;
}
absl::Duration elapsed_time;
for (int i = 0; i < num_tests; ++i) {
const absl::Time start = absl::Now();
func_(source1_, source2_, weight_0, weight_1, width_, height_, dest_,
sizeof(Pixel) * kDestStride);
elapsed_time += absl::Now() - start;
}
test_utils::CheckMd5Digest("DistanceWeightedBlend", ToString(GetParam()),
digest, dest_, sizeof(dest_), elapsed_time);
}
const BlockSize kTestParam[] = {
kBlock4x4, kBlock4x8, kBlock4x16, kBlock8x4, kBlock8x8,
kBlock8x16, kBlock8x32, kBlock16x4, kBlock16x8, kBlock16x16,
kBlock16x32, kBlock16x64, kBlock32x8, kBlock32x16, kBlock32x32,
kBlock32x64, kBlock64x16, kBlock64x32, kBlock64x64, kBlock64x128,
kBlock128x64, kBlock128x128,
};
const char* GetDistanceWeightedBlendDigest8bpp(const BlockSize block_size) {
static const char* const kDigests[kMaxBlockSizes] = {
// 4xN
"ebf389f724f8ab46a2cac895e4e073ca",
"09acd567b6b12c8cf8eb51d8b86eb4bf",
"57bb4d65695d8ec6752f2bd8686b64fd",
// 8xN
"270905ac76f9a2cba8a552eb0bf7c8c1",
"f0801c8574d2c271ef2bbea77a1d7352",
"e761b580e3312be33a227492a233ce72",
"ff214dab1a7e98e2285961d6421720c6",
// 16xN
"4f712609a36e817f9752326d58562ff8",
"14243f5c5f7c7104160c1f2cef0a0fbc",
"3ac3f3161b7c8dd8436b02abfdde104a",
"81a00b704e0e41a5dbe6436ac70c098d",
"af8fd02017c7acdff788be742d700baa",
// 32xN
"ee34332c66a6d6ed8ce64031aafe776c",
"b5e3d22bd2dbdb624c8b86a1afb5ce6d",
"607ffc22098d81b7e37a7bf62f4af5d3",
"3823dbf043b4682f56d5ca698e755ea5",
// 64xN
"4acf556b921956c2bc24659cd5128401",
"a298c544c9c3b27924b4c23cc687ea5a",
"539e2df267782ce61c70103b23b7d922",
"3b0cb2a0b5d384efee4d81401025bec1",
// 128xN
"8b56b636dd712c2f8d138badb7219991",
"8cfc8836908902b8f915639b7bff45b3",
};
assert(block_size < kMaxBlockSizes);
return kDigests[block_size];
}
using DistanceWeightedBlendTest8bpp = DistanceWeightedBlendTest<8, uint8_t>;
TEST_P(DistanceWeightedBlendTest8bpp, Blending) {
Test(GetDistanceWeightedBlendDigest8bpp(GetParam()), 1);
}
TEST_P(DistanceWeightedBlendTest8bpp, DISABLED_Speed) {
Test(GetDistanceWeightedBlendDigest8bpp(GetParam()), kNumSpeedTests);
}
INSTANTIATE_TEST_SUITE_P(C, DistanceWeightedBlendTest8bpp,
testing::ValuesIn(kTestParam));
#if LIBGAV1_ENABLE_NEON
INSTANTIATE_TEST_SUITE_P(NEON, DistanceWeightedBlendTest8bpp,
testing::ValuesIn(kTestParam));
#endif
#if LIBGAV1_ENABLE_SSE4_1
INSTANTIATE_TEST_SUITE_P(SSE41, DistanceWeightedBlendTest8bpp,
testing::ValuesIn(kTestParam));
#endif
#if LIBGAV1_MAX_BITDEPTH >= 10
const char* GetDistanceWeightedBlendDigest10bpp(const BlockSize block_size) {
static const char* const kDigests[] = {
// 4xN
"55f594b56e16d5c401274affebbcc3d3",
"69df14da4bb33a8f7d7087921008e919",
"1b61f33604c54015794198a13bfebf46",
// 8xN
"825a938185b152f7cf09bf1c0723ce2b",
"85ea315c51d979bc9b45834d6b40ec6f",
"92ebde208e8c39f7ec6de2de82182dbb",
"520f84716db5b43684dbb703806383fe",
// 16xN
"12ca23e3e2930005a0511646e8c83da4",
"6208694a6744f4a3906f58c1add670e3",
"a33d63889df989a3bbf84ff236614267",
"34830846ecb0572a98bbd192fed02b16",
"34bb2f79c0bd7f9a80691b8af597f2a8",
// 32xN
"fa97f2d0e3143f1f44d3ac018b0d696d",
"3df4a22456c9ab6ed346ab1b9750ae7d",
"6276a058b35c6131bc0c94a4b4a37ebc",
"9ca42da5d2d5eb339df03ae2c7a26914",
// 64xN
"800e692c520f99223bc24c1ac95a0166",
"818b6d20426585ef7fe844015a03aaf5",
"fb48691ccfff083e01d74826e88e613f",
"0bd350bc5bc604a224d77a5f5a422698",
// 128xN
"a130840813cd6bd69d09bcf5f8d0180f",
"6ece1846bea55e8f8f2ed7fbf73718de",
};
assert(block_size < kMaxBlockSizes);
return kDigests[block_size];
}
using DistanceWeightedBlendTest10bpp = DistanceWeightedBlendTest<10, uint16_t>;
TEST_P(DistanceWeightedBlendTest10bpp, Blending) {
Test(GetDistanceWeightedBlendDigest10bpp(GetParam()), 1);
}
TEST_P(DistanceWeightedBlendTest10bpp, DISABLED_Speed) {
Test(GetDistanceWeightedBlendDigest10bpp(GetParam()), kNumSpeedTests);
}
INSTANTIATE_TEST_SUITE_P(C, DistanceWeightedBlendTest10bpp,
testing::ValuesIn(kTestParam));
#if LIBGAV1_ENABLE_SSE4_1
INSTANTIATE_TEST_SUITE_P(SSE41, DistanceWeightedBlendTest10bpp,
testing::ValuesIn(kTestParam));
#endif
#if LIBGAV1_ENABLE_NEON
INSTANTIATE_TEST_SUITE_P(NEON, DistanceWeightedBlendTest10bpp,
testing::ValuesIn(kTestParam));
#endif
#endif // LIBGAV1_MAX_BITDEPTH >= 10
#if LIBGAV1_MAX_BITDEPTH == 12
const char* GetDistanceWeightedBlendDigest12bpp(const BlockSize block_size) {
static const char* const kDigests[] = {
// 4xN
"e30bf8f5f294206ad1dd79bd10a20827",
"f0cfb60134562d9c5f2ec6ad106e01ef",
"ad0876244e1b769203266a9c75b74afc",
// 8xN
"5265b954479c15a80f427561c5f36ff4",
"7f157457d1671e4ecce7a0884e9e3f76",
"d2cef5cf217f2d1f787c8951b7fe7cb2",
"6d23059008adbbb84ac941c8b4968f5b",
// 16xN
"ae521a5656ed3440d1fa950c20d90a79",
"935bec0e12b5dd3e0c34b3de8ba51476",
"0334bafcdcd7ddddb673ded492bca25a",
"c5360f08d0be77c79dc19fb55a0c5fe0",
"c2d1e7a4244a8aaaac041aed0cefc148",
// 32xN
"ce7f3cf78ae4f836cf69763137f7f6a6",
"800e52ebb14d5831c047d391cd760f95",
"74aa2b412b42165f1967daf3042b4f17",
"140d4cc600944b629b1991e88a9fe97c",
// 64xN
"3d206f93229ee2cea5c5da4e0ac6445a",
"3d13028f8fffe79fd35752c0177291ca",
"e7a7669acb5979dc7b15a19eed09cd4c",
"599368f4971c203fc5fa32989fe8cb44",
// 128xN
"54b46af2e2c8d2081e26fa0315b4ffd7",
"602e769bb2104e78223e68e50e7e86a0",
};
assert(block_size < kMaxBlockSizes);
return kDigests[block_size];
}
using DistanceWeightedBlendTest12bpp = DistanceWeightedBlendTest<12, uint16_t>;
TEST_P(DistanceWeightedBlendTest12bpp, Blending) {
Test(GetDistanceWeightedBlendDigest12bpp(GetParam()), 1);
}
TEST_P(DistanceWeightedBlendTest12bpp, DISABLED_Speed) {
Test(GetDistanceWeightedBlendDigest12bpp(GetParam()), kNumSpeedTests);
}
INSTANTIATE_TEST_SUITE_P(C, DistanceWeightedBlendTest12bpp,
testing::ValuesIn(kTestParam));
#endif // LIBGAV1_MAX_BITDEPTH == 12
} // namespace
} // namespace dsp
static std::ostream& operator<<(std::ostream& os, const BlockSize param) {
return os << ToString(param);
}
} // namespace libgav1