/* * Copyright (c) 2020, Alliance for Open Media. All rights reserved. * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License * was not distributed with this source code in the LICENSE file, you can * obtain it at www.aomedia.org/license/software. If the Alliance for Open * Media Patent License 1.0 was not distributed with this source code in the * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
// TODO(any): Remove following INTERP_FILTERS_ALL define, so that 12-tap filter // is tested once 12-tap filter SIMD is done. #undef INTERP_FILTERS_ALL #define INTERP_FILTERS_ALL 4
// All single reference convolve tests are parameterized on block size, // bit-depth, and function to test. // // Note that parameterizing on these variables (and not other parameters) is // a conscious decision - Jenkins needs some degree of parallelization to run // the tests within the time limit, but if the number of parameters increases // too much, the gtest framework does not handle it well (increased overhead per // test, huge amount of output to stdout, etc.). // // Also note that the test suites must be named with the architecture, e.g., // C, C_X, AVX2_X, ... The test suite that runs on Jenkins sometimes runs tests // that cannot deal with intrinsics (e.g., the Valgrind tests on 32-bit x86 // binaries) and will disable tests using a filter like // --gtest_filter=-:SSE4_1.*. If the test suites are not named this way, the // testing infrastructure will not selectively filter them properly. class BlockSize { public:
BlockSize(int w, int h) : width_(w), height_(h) {}
int Width() const { return width_; } int Height() const { return height_; }
// Block size / bit depth / test function used to parameterize the tests. template <typename T> class TestParam { public:
TestParam(const BlockSize &block, int bd, T test_func)
: block_(block), bd_(bd), test_func_(test_func) {}
// Generate the list of all block widths / heights that need to be tested, // includes chroma and luma sizes, for the given bit-depths. The test // function is the same for all generated parameters. template <typename T>
std::vector<TestParam<T>> GetTestParams(std::initializer_list<int> bit_depths,
T test_func) {
std::set<BlockSize> sizes; for (int b = BLOCK_4X4; b < BLOCK_SIZES_ALL; ++b) { constint w = block_size_wide[b]; constint h = block_size_high[b];
sizes.insert(BlockSize(w, h)); // Add in smaller chroma sizes as well. if (w == 4 || h == 4) {
sizes.insert(BlockSize(w / 2, h / 2));
}
}
std::vector<TestParam<T>> result; for (const BlockSize &block : sizes) { for (int bd : bit_depths) {
result.push_back(TestParam<T>(block, bd, test_func));
}
} return result;
}
// Test the test-parameters generators work as expected. class AV1ConvolveParametersTest : public ::testing::Test {};
TEST_F(AV1ConvolveParametersTest, GetLowbdTestParams) { auto v = GetLowbdTestParams(av1_convolve_x_sr_c);
ASSERT_EQ(27U, v.size()); for (constauto &p : v) {
ASSERT_EQ(8, p.BitDepth()); // Needed (instead of ASSERT_EQ(...) since gtest does not // have built in printing for arbitrary functions, which // causes a compilation error. bool same_fn = av1_convolve_x_sr_c == p.TestFunction();
ASSERT_TRUE(same_fn);
}
}
TEST_F(AV1ConvolveParametersTest, GetHighbdTestParams) { auto v = GetHighbdTestParams(av1_highbd_convolve_x_sr_c);
ASSERT_EQ(54U, v.size()); int num_10 = 0; int num_12 = 0; for (constauto &p : v) {
ASSERT_TRUE(p.BitDepth() == 10 || p.BitDepth() == 12); bool same_fn = av1_highbd_convolve_x_sr_c == p.TestFunction();
ASSERT_TRUE(same_fn); if (p.BitDepth() == 10) {
++num_10;
} else {
++num_12;
}
}
ASSERT_EQ(num_10, num_12);
} #endif// CONFIG_AV1_HIGHBITDEPTH
// AV1ConvolveTest is the base class that all convolve tests should derive from. // It provides storage/methods for generating randomized buffers for both // low bit-depth and high bit-depth, and setup/teardown methods for clearing // system state. Implementors can get the bit-depth / block-size / // test function by calling GetParam(). template <typename T> class AV1ConvolveTest : public ::testing::TestWithParam<TestParam<T>> { public:
~AV1ConvolveTest() override = default;
// Randomizes the 8-bit input buffer and returns a pointer to it. Note that // the pointer is safe to use with an 8-tap filter. The stride can range // from width to (width + kPadding). Also note that the pointer is to the // same memory location. static constexpr int kInputPadding = 12;
// Get a pointer to a buffer with stride == width. Note that we must have // the test param passed in explicitly -- the gtest framework does not // support calling GetParam() within a templatized class. // Note that FirstRandomInput8 always returns the same pointer -- if two // inputs are needed, also use SecondRandomInput8. const uint8_t *FirstRandomInput8(const TestParam<T> ¶m) { // Note we can't call GetParam() directly -- gtest does not support // this for parameterized types. return RandomInput8(input8_1_, param);
}
// Some of the intrinsics perform writes in 32 byte chunks. Moreover, some // of the instrinsics assume that the stride is also a multiple of 32. // To satisfy these constraints and also remain simple, output buffer strides // are assumed MAX_SB_SIZE. static constexpr int kOutputStride = MAX_SB_SIZE;
// Check that two 8-bit output buffers are identical. void AssertOutputBufferEq(const uint8_t *p1, const uint8_t *p2, int width, int height) {
ASSERT_TRUE(p1 != p2) << "Buffers must be at different memory locations"; for (int j = 0; j < height; ++j) { if (memcmp(p1, p2, sizeof(*p1) * width) == 0) {
p1 += kOutputStride;
p2 += kOutputStride; continue;
} for (int i = 0; i < width; ++i) {
ASSERT_EQ(p1[i], p2[i])
<< width << "x" << height << " Pixel mismatch at (" << i << ", "
<< j << ")";
}
}
}
// Check that two 16-bit output buffers are identical. void AssertOutputBufferEq(const uint16_t *p1, const uint16_t *p2, int width, int height) {
ASSERT_TRUE(p1 != p2) << "Buffers must be in different memory locations"; for (int j = 0; j < height; ++j) { if (memcmp(p1, p2, sizeof(*p1) * width) == 0) {
p1 += kOutputStride;
p2 += kOutputStride; continue;
} for (int i = 0; i < width; ++i) {
ASSERT_EQ(p1[i], p2[i])
<< width << "x" << height << " Pixel mismatch at (" << i << ", "
<< j << ")";
}
}
}
#if CONFIG_AV1_HIGHBITDEPTH // Note that the randomized values are capped by bit-depth. const uint16_t *FirstRandomInput16(const TestParam<T> ¶m) { return RandomInput16(input16_1_, param);
}
void Randomize(uint8_t *p, int size) { for (int i = 0; i < size; ++i) {
p[i] = rnd_.Rand8();
}
}
#if CONFIG_AV1_HIGHBITDEPTH const uint16_t *RandomInput16(uint16_t *p, const TestParam<T> ¶m) { // Check that this is only called with high bit-depths.
EXPECT_TRUE(param.BitDepth() == 10 || param.BitDepth() == 12);
EXPECT_GE(MAX_SB_SIZE, param.Block().Width());
EXPECT_GE(MAX_SB_SIZE, param.Block().Height()); constint padded_width = param.Block().Width() + kInputPadding; constint padded_height = param.Block().Height() + kInputPadding;
Randomize(p, padded_width * padded_height, param.BitDepth()); return p + (kInputPadding / 2) * padded_width + kInputPadding / 2;
}
void Randomize(uint16_t *p, int size, int bit_depth) { for (int i = 0; i < size; ++i) {
p[i] = rnd_.Rand16() & ((1 << bit_depth) - 1);
}
} #endif
static constexpr int kInputStride = MAX_SB_SIZE + kInputPadding;
libaom_test::ACMRandom rnd_; // Statically allocate all the memory that is needed for the tests. Note // that we cannot allocate output memory here. It must use DECLARE_ALIGNED, // which is a C99 feature and interacts badly with C++ member variables.
uint8_t input8_1_[kInputStride * kInputStride];
uint8_t input8_2_[kInputStride * kInputStride]; #if CONFIG_AV1_HIGHBITDEPTH
uint16_t input16_1_[kInputStride * kInputStride];
uint16_t input16_2_[kInputStride * kInputStride]; #endif
};
//////////////////////////////////////////////////////// // Single reference convolve-x functions (low bit-depth) //////////////////////////////////////////////////////// typedefvoid (*convolve_x_func)(const uint8_t *src, int src_stride,
uint8_t *dst, int dst_stride, int w, int h, const InterpFilterParams *filter_params_x, constint subpel_x_qn,
ConvolveParams *conv_params);
class AV1ConvolveXTest : public AV1ConvolveTest<convolve_x_func> { public: void RunTest() { // Do not test the no-op filter. for (int sub_x = 1; sub_x < 16; ++sub_x) { for (int filter = EIGHTTAP_REGULAR; filter <= INTERP_FILTERS_ALL;
++filter) {
InterpFilter f = static_cast<InterpFilter>(filter);
TestConvolve(sub_x, f);
}
}
}
//////////////////////////////////////////////////////////////// // Single reference convolve-x IntraBC functions (low bit-depth) ////////////////////////////////////////////////////////////////
class AV1ConvolveXIntraBCTest : public AV1ConvolveTest<convolve_x_func> { public: void RunTest() { // IntraBC functions only operate for subpel_x_qn = 8.
constexpr int kSubX = 8; constint width = GetParam().Block().Width(); constint height = GetParam().Block().Height(); const InterpFilterParams *filter_params_x = &av1_intrabc_filter_params; const uint8_t *input = FirstRandomInput8(GetParam());
ConvolveParams conv_params1 =
get_conv_params_no_round(0, 0, nullptr, 0, 0, 8);
DECLARE_ALIGNED(32, uint8_t, reference[MAX_SB_SQUARE]); // Use a stride different from width to avoid potential storing errors that // would go undetected. The input buffer is filled using a padding of 12, so // the stride can be anywhere between width and width + 12.
av1_convolve_x_sr_intrabc_c(input, width + 2, reference, kOutputStride,
width, height, filter_params_x, kSubX,
&conv_params1);
///////////////////////////////////////////////////////////////// // Single reference convolve-x IntraBC functions (high bit-depth) /////////////////////////////////////////////////////////////////
class AV1ConvolveXHighbdIntraBCTest
: public AV1ConvolveTest<highbd_convolve_x_func> { public: void RunTest() { // IntraBC functions only operate for subpel_x_qn = 8.
constexpr int kSubX = 8; constint width = GetParam().Block().Width(); constint height = GetParam().Block().Height(); constint bit_depth = GetParam().BitDepth(); const InterpFilterParams *filter_params_x = &av1_intrabc_filter_params; const uint16_t *input = FirstRandomInput16(GetParam());
ConvolveParams conv_params1 =
get_conv_params_no_round(0, 0, nullptr, 0, 0, bit_depth);
DECLARE_ALIGNED(32, uint16_t, reference[MAX_SB_SQUARE]); // Use a stride different from width to avoid potential storing errors that // would go undetected. The input buffer is filled using a padding of 12, so // the stride can be anywhere between width and width + 12.
av1_highbd_convolve_x_sr_intrabc_c(
input, width + 2, reference, kOutputStride, width, height,
filter_params_x, kSubX, &conv_params1, bit_depth);
//////////////////////////////////////////////////////////////// // Single reference convolve-y IntraBC functions (low bit-depth) ////////////////////////////////////////////////////////////////
class AV1ConvolveYIntraBCTest : public AV1ConvolveTest<convolve_y_func> { public: void RunTest() { // IntraBC functions only operate for subpel_y_qn = 8.
constexpr int kSubY = 8; constint width = GetParam().Block().Width(); constint height = GetParam().Block().Height(); const InterpFilterParams *filter_params_y = &av1_intrabc_filter_params; const uint8_t *input = FirstRandomInput8(GetParam());
DECLARE_ALIGNED(32, uint8_t, reference[MAX_SB_SQUARE]); // Use a stride different from width to avoid potential storing errors that // would go undetected. The input buffer is filled using a padding of 12, so // the stride can be anywhere between width and width + 12.
av1_convolve_y_sr_intrabc_c(input, width + 2, reference, kOutputStride,
width, height, filter_params_y, kSubY);
///////////////////////////////////////////////////////////////// // Single reference convolve-y IntraBC functions (high bit-depth) /////////////////////////////////////////////////////////////////
class AV1ConvolveYHighbdIntraBCTest
: public AV1ConvolveTest<highbd_convolve_y_func> { public: void RunTest() { // IntraBC functions only operate for subpel_y_qn = 8.
constexpr int kSubY = 8; constint width = GetParam().Block().Width(); constint height = GetParam().Block().Height(); constint bit_depth = GetParam().BitDepth(); const InterpFilterParams *filter_params_y = &av1_intrabc_filter_params; const uint16_t *input = FirstRandomInput16(GetParam());
DECLARE_ALIGNED(32, uint16_t, reference[MAX_SB_SQUARE]); // Use a stride different from width to avoid potential storing errors that // would go undetected. The input buffer is filled using a padding of 12, so // the stride can be anywhere between width and width + 12.
av1_highbd_convolve_y_sr_intrabc_c(input, width + 2, reference,
kOutputStride, width, height,
filter_params_y, kSubY, bit_depth);
// Note that even though these are AOM convolve functions, we are using the // newer AV1 test framework.
TEST_P(AV1ConvolveCopyTest, RunTest) { RunTest(); }
///////////////////////////////////////////////////////////////// // Single reference convolve-2D IntraBC functions (low bit-depth) /////////////////////////////////////////////////////////////////
class AV1Convolve2DIntraBCTest : public AV1ConvolveTest<convolve_2d_func> { public: void RunTest() { // IntraBC functions only operate for subpel_x_qn = 8 and subpel_y_qn = 8.
constexpr int kSubX = 8;
constexpr int kSubY = 8; constint width = GetParam().Block().Width(); constint height = GetParam().Block().Height(); const InterpFilterParams *filter_params_x = &av1_intrabc_filter_params; const InterpFilterParams *filter_params_y = &av1_intrabc_filter_params; const uint8_t *input = FirstRandomInput8(GetParam());
DECLARE_ALIGNED(32, uint8_t, reference[MAX_SB_SQUARE]);
ConvolveParams conv_params1 =
get_conv_params_no_round(0, 0, nullptr, 0, 0, 8); // Use a stride different from width to avoid potential storing errors that // would go undetected. The input buffer is filled using a padding of 12, so // the stride can be anywhere between width and width + 12.
av1_convolve_2d_sr_intrabc_c(input, width + 2, reference, kOutputStride,
width, height, filter_params_x,
filter_params_y, kSubX, kSubY, &conv_params1);
////////////////////////////////////////////////////////////////// // Single reference convolve-2d IntraBC functions (high bit-depth) //////////////////////////////////////////////////////////////////
class AV1Convolve2DHighbdIntraBCTest
: public AV1ConvolveTest<highbd_convolve_2d_func> { public: void RunTest() { // IntraBC functions only operate for subpel_x_qn = 8 and subpel_y_qn = 8.
constexpr int kSubX = 8;
constexpr int kSubY = 8; constint width = GetParam().Block().Width(); constint height = GetParam().Block().Height(); constint bit_depth = GetParam().BitDepth(); const InterpFilterParams *filter_params_x = &av1_intrabc_filter_params; const InterpFilterParams *filter_params_y = &av1_intrabc_filter_params; const uint16_t *input = FirstRandomInput16(GetParam());
DECLARE_ALIGNED(32, uint16_t, reference[MAX_SB_SQUARE]);
ConvolveParams conv_params1 =
get_conv_params_no_round(0, 0, nullptr, 0, 0, bit_depth); // Use a stride different from width to avoid potential storing errors that // would go undetected. The input buffer is filled using a padding of 12, so // the stride can be anywhere between width and width + 12.
av1_highbd_convolve_2d_sr_intrabc_c(input, width + 2, reference,
kOutputStride, width, height,
filter_params_x, filter_params_y, kSubX,
kSubY, &conv_params1, bit_depth);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.