blob: 83e56edefb8de0d92615bd66ea9058daea0e631e [file] [log] [blame]
/*
* Copyright (c) 2024, 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.
*/
#include "config/av1_rtcd.h"
#include "test/acm_random.h"
#include "test/util.h"
#include "aom_ports/aom_timer.h"
#include "aom_ports/bitops.h"
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
namespace {
using ::testing::Combine;
using ::testing::Values;
using ::testing::ValuesIn;
using std::make_tuple;
using std::tuple;
const int kIters = 1000;
typedef tuple<int, int> FrameDimension;
// 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 += width;
p2 += width;
continue;
}
for (int i = 0; i < width; ++i) {
ASSERT_EQ(p1[i], p2[i])
<< width << "x" << height << " Pixel mismatch at (" << i << ", " << j
<< ")";
}
}
}
typedef bool (*LowBDResizeFunc)(uint8_t *intbuf, uint8_t *output,
int out_stride, int height, int height2,
int stride, int start_wd);
// Test parameter list:
// <tst_fun, dims>
typedef tuple<LowBDResizeFunc, FrameDimension> ResizeTestParams;
class AV1ResizeYTest : public ::testing::TestWithParam<ResizeTestParams> {
public:
void SetUp() {
test_fun_ = GET_PARAM(0);
frame_dim_ = GET_PARAM(1);
width_ = std::get<0>(frame_dim_);
height_ = std::get<1>(frame_dim_);
const int msb = get_msb(AOMMIN(width_, height_));
n_levels_ = AOMMAX(msb - MIN_PYRAMID_SIZE_LOG2, 1);
src_ = (uint8_t *)aom_malloc((width_ / 2) * height_ * sizeof(*src_));
ref_dest_ =
(uint8_t *)aom_calloc((width_ * height_) / 4, sizeof(*ref_dest_));
test_dest_ =
(uint8_t *)aom_calloc((width_ * height_) / 4, sizeof(*test_dest_));
}
void RunTest() {
for (int i = 0; i < (width_ / 2) * height_; i++) src_[i] = rng_.Rand8();
for (int level = 1; level < n_levels_; level++) {
const int width2 = (width_ >> level);
const int height2 = (height_ >> level);
av1_resize_vert_dir_c(src_, ref_dest_, width2, height2 << 1, height2,
width2, 0);
test_fun_(src_, test_dest_, width2, height2 << 1, height2, width2, 0);
AssertOutputBufferEq(ref_dest_, test_dest_, width2, height2);
}
}
void SpeedTest() {
for (int i = 0; i < (width_ / 2) * height_; i++) src_[i] = rng_.Rand8();
for (int level = 1; level < n_levels_; level++) {
const int width2 = (width_ >> level);
const int height2 = (height_ >> level);
aom_usec_timer ref_timer;
aom_usec_timer_start(&ref_timer);
for (int j = 0; j < kIters; j++) {
av1_resize_vert_dir_c(src_, ref_dest_, width2, height2 << 1, height2,
width2, 0);
}
aom_usec_timer_mark(&ref_timer);
const int64_t ref_time = aom_usec_timer_elapsed(&ref_timer);
aom_usec_timer tst_timer;
aom_usec_timer_start(&tst_timer);
for (int j = 0; j < kIters; j++) {
test_fun_(src_, test_dest_, width2, height2 << 1, height2, width2, 0);
}
aom_usec_timer_mark(&tst_timer);
const int64_t tst_time = aom_usec_timer_elapsed(&tst_timer);
std::cout << "level: " << level << " [" << width2 << " x " << height2
<< "] C time = " << ref_time << " , SIMD time = " << tst_time
<< " scaling=" << float(1.00) * ref_time / tst_time << "x \n";
}
}
void TearDown() {
aom_free(src_);
aom_free(ref_dest_);
aom_free(test_dest_);
}
private:
LowBDResizeFunc test_fun_;
FrameDimension frame_dim_;
int width_;
int height_;
int n_levels_;
uint8_t *src_;
uint8_t *ref_dest_;
uint8_t *test_dest_;
libaom_test::ACMRandom rng_;
};
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1ResizeYTest);
TEST_P(AV1ResizeYTest, RunTest) { RunTest(); }
TEST_P(AV1ResizeYTest, DISABLED_SpeedTest) { SpeedTest(); }
#if HAVE_AVX2 || HAVE_SSE2
// Resolutions (width x height) to be tested for resizing.
const FrameDimension kFrameDim[] = {
make_tuple(3840, 2160), make_tuple(2560, 1440), make_tuple(1920, 1080),
make_tuple(1280, 720), make_tuple(640, 480), make_tuple(640, 360),
make_tuple(256, 256),
};
#endif
#if HAVE_AVX2
INSTANTIATE_TEST_SUITE_P(
AVX2, AV1ResizeYTest,
::testing::Combine(::testing::Values(av1_resize_vert_dir_avx2),
::testing::ValuesIn(kFrameDim)));
#endif
#if HAVE_SSE2
INSTANTIATE_TEST_SUITE_P(
SSE2, AV1ResizeYTest,
::testing::Combine(::testing::Values(av1_resize_vert_dir_sse2),
::testing::ValuesIn(kFrameDim)));
#endif
typedef void (*LowBDResize_x_Func)(const uint8_t *const input, int in_stride,
uint8_t *intbuf, int height,
int filteredlength, int width2);
typedef tuple<LowBDResize_x_Func, FrameDimension> Resize_x_TestParams;
class AV1ResizeXTest : public ::testing::TestWithParam<Resize_x_TestParams> {
public:
void SetUp() {
test_fun_ = GET_PARAM(0);
frame_dim_ = GET_PARAM(1);
width_ = std::get<0>(frame_dim_);
height_ = std::get<1>(frame_dim_);
const int msb = get_msb(AOMMIN(width_, height_));
n_levels_ = AOMMAX(msb - MIN_PYRAMID_SIZE_LOG2, 1);
src_ = (uint8_t *)aom_malloc(width_ * height_ * sizeof(*src_));
ref_dest_ =
(uint8_t *)aom_calloc((width_ * height_) / 2, sizeof(*ref_dest_));
test_dest_ =
(uint8_t *)aom_calloc((width_ * height_) / 2, sizeof(*test_dest_));
}
void RunTest() {
for (int i = 0; i < width_ * height_; ++i) src_[i] = rng_.Rand8();
for (int level = 1; level < n_levels_; ++level) {
const int width2 = (width_ >> level);
av1_resize_horz_dir_c(src_, width_, ref_dest_, height_, width2 << 1,
width2);
test_fun_(src_, width_, test_dest_, height_, width2 << 1, width2);
AssertOutputBufferEq(ref_dest_, test_dest_, width2, height_);
}
}
void SpeedTest() {
for (int i = 0; i < width_ * height_; ++i) src_[i] = rng_.Rand8();
for (int level = 1; level < n_levels_; ++level) {
const int width2 = (width_ >> level);
aom_usec_timer ref_timer;
aom_usec_timer_start(&ref_timer);
for (int j = 0; j < kIters; ++j) {
av1_resize_horz_dir_c(src_, width_, ref_dest_, height_, width2 << 1,
width2);
}
aom_usec_timer_mark(&ref_timer);
const int64_t ref_time = aom_usec_timer_elapsed(&ref_timer);
aom_usec_timer tst_timer;
aom_usec_timer_start(&tst_timer);
for (int j = 0; j < kIters; ++j) {
test_fun_(src_, width_, test_dest_, height_, width2 << 1, width2);
}
aom_usec_timer_mark(&tst_timer);
const int64_t tst_time = aom_usec_timer_elapsed(&tst_timer);
std::cout << "level: " << level << " [" << width2 << " x " << height_
<< "] C time = " << ref_time << " , SIMD time = " << tst_time
<< " scaling=" << float(1.00) * ref_time / tst_time << "x \n";
}
}
void TearDown() {
aom_free(src_);
aom_free(ref_dest_);
aom_free(test_dest_);
}
private:
LowBDResize_x_Func test_fun_;
FrameDimension frame_dim_;
int width_;
int height_;
int n_levels_;
uint8_t *src_;
uint8_t *ref_dest_;
uint8_t *test_dest_;
libaom_test::ACMRandom rng_;
};
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AV1ResizeXTest);
TEST_P(AV1ResizeXTest, RunTest) { RunTest(); }
TEST_P(AV1ResizeXTest, DISABLED_SpeedTest) { SpeedTest(); }
// TODO(https://crbug.com/aomedia/3575): Reenable this after test passes under
// 32-bit valgrind.
#if 0 // HAVE_SSE2
INSTANTIATE_TEST_SUITE_P(
SSE2, AV1ResizeXTest,
::testing::Combine(::testing::Values(av1_resize_horz_dir_sse2),
::testing::ValuesIn(kFrameDim)));
#endif
#if HAVE_AVX2
INSTANTIATE_TEST_SUITE_P(
AVX2, AV1ResizeXTest,
::testing::Combine(::testing::Values(av1_resize_horz_dir_avx2),
::testing::ValuesIn(kFrameDim)));
#endif
} // namespace