Source code

Revision control

Copy as Markdown

Other Tools

/*
* 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 <memory>
#include <new>
#include "config/av1_rtcd.h"
#include "aom_ports/aom_timer.h"
#include "aom_ports/bitops.h"
#include "gtest/gtest.h"
#include "test/acm_random.h"
#include "test/util.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);
const int src_buf_size = (width_ / 2) * height_;
const int dest_buf_size = (width_ * height_) / 4;
src_ = std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[src_buf_size]);
ASSERT_NE(src_, nullptr);
ref_dest_ =
std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[dest_buf_size]);
ASSERT_NE(ref_dest_, nullptr);
test_dest_ =
std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[dest_buf_size]);
ASSERT_NE(test_dest_, nullptr);
}
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_.get(), ref_dest_.get(), width2, height2 << 1,
height2, width2, 0);
test_fun_(src_.get(), test_dest_.get(), width2, height2 << 1, height2,
width2, 0);
AssertOutputBufferEq(ref_dest_.get(), test_dest_.get(), 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_.get(), ref_dest_.get(), 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_.get(), test_dest_.get(), 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";
}
}
private:
LowBDResizeFunc test_fun_;
FrameDimension frame_dim_;
int width_;
int height_;
int n_levels_;
std::unique_ptr<uint8_t[]> src_;
std::unique_ptr<uint8_t[]> ref_dest_;
std::unique_ptr<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(286, 286), make_tuple(284, 284), make_tuple(282, 282),
make_tuple(280, 280), make_tuple(262, 262), make_tuple(258, 258),
make_tuple(256, 256), make_tuple(34, 34),
};
#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 filtered_length, 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);
const int src_buf_size = width_ * height_;
const int dest_buf_size = (width_ * height_) / 2;
src_ = std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[src_buf_size]);
ASSERT_NE(src_, nullptr);
ref_dest_ =
std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[dest_buf_size]);
ASSERT_NE(ref_dest_, nullptr);
test_dest_ =
std::unique_ptr<uint8_t[]>(new (std::nothrow) uint8_t[dest_buf_size]);
ASSERT_NE(test_dest_, nullptr);
}
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_.get(), width_, ref_dest_.get(), height_,
width2 << 1, width2);
test_fun_(src_.get(), width_, test_dest_.get(), height_, width2 << 1,
width2);
AssertOutputBufferEq(ref_dest_.get(), test_dest_.get(), 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_.get(), width_, ref_dest_.get(), 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_.get(), width_, test_dest_.get(), 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";
}
}
private:
LowBDResize_x_Func test_fun_;
FrameDimension frame_dim_;
int width_;
int height_;
int n_levels_;
std::unique_ptr<uint8_t[]> src_;
std::unique_ptr<uint8_t[]> ref_dest_;
std::unique_ptr<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(); }
#if 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