blob: ff96c7ace57ace917eb1b83e6b39ba1cc13a211c [file] [log] [blame]
/*
* Copyright (c) 2022, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 3-Clause Clear License
* and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
* License was not distributed with this source code in the LICENSE file, you
* can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. 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
* aomedia.org/license/patent-license/.
*/
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
#include "config/aom_config.h"
#include "config/aom_dsp_rtcd.h"
#include "config/av1_rtcd.h"
#include "aom_dsp/aom_dsp_common.h"
#include "av1/common/enums.h"
#include "av1/common/ccso.h"
#include "test/acm_random.h"
#include "test/function_equivalence_test.h"
#include "test/register_state_check.h"
using libaom_test::ACMRandom;
using libaom_test::FunctionEquivalenceTest;
namespace {
//////////////////////////////////////////////////////////////////////////////
// ccso_filter_block_hbd_wo_buf
//////////////////////////////////////////////////////////////////////////////
typedef void (*CCSO_WO_BUF)(const uint16_t *src_y, uint16_t *dst_yuv,
const int x, const int y, const int pic_width,
const int pic_height, int *src_cls,
const int8_t *offset_buf, const int src_y_stride,
const int dst_stride, const int y_uv_hscale,
const int y_uv_vscale, const int thr,
const int neg_thr, const int *src_loc,
const int max_val, const int blk_size,
const bool isSingleBand, const uint8_t shift_bits
#if CONFIG_CCSO_EDGE_CLF
,
const int edge_clf
#endif
#if CONFIG_CCSO_BO_ONLY_OPTION
,
const uint8_t ccso_bo_only
#endif
);
typedef libaom_test::FuncParam<CCSO_WO_BUF> TestFuncsCCSO_WO_BUF;
template <typename F>
class CCSOFilterTest : public FunctionEquivalenceTest<F> {
public:
static const int kIterations = 10000;
static const int kMaxWidth =
(MAX_SB_SIZE << 1) * 5; // * 5 to cover longer strides
static const int kMaxHeight = (MAX_SB_SIZE << 1) * 3;
static const int kBufSize = kMaxWidth * kMaxHeight;
static const int kMaxMaskWidth = 2 * MAX_SB_SIZE;
static const int kMaxMaskSize = kMaxMaskWidth;
virtual ~CCSOFilterTest() {}
virtual void Execute() = 0;
void Common() {
// we just test whether block level filter generate same results
y_uv_hscale_ = this->rng_(2);
y_uv_vscale_ = y_uv_hscale_;
pic_width_ = (MAX_SB_SIZE * 2) >> y_uv_hscale_;
pic_height_ = (MAX_SB_SIZE * 2) >> y_uv_vscale_;
blk_size_ = pic_width_;
// AVX2 fetch 16 elements, chroma 4:2:0 case 32
src_y_stride_ =
this->rng_(kMaxWidth + 1 - 32) + 32 + (CCSO_PADDING_SIZE << 1);
dst_stride_ = this->rng_(kMaxWidth + 1 - 32) + 32;
filter_sup_ = this->rng_(6);
derive_ccso_sample_pos(src_loc_, src_y_stride_, filter_sup_);
const uint8_t quant_sz[4] = { 16, 8, 32, 64 };
thr_ = quant_sz[this->rng_(4)];
neg_thr_ = -1 * thr_;
const uint8_t shift_bits_a[2] = { 8, 10 };
shift_bits_ = shift_bits_a[this->rng_(2)];
max_val_ = (1 << shift_bits_) - 1;
isSingleBand_ = this->rng_(2);
Execute();
}
uint16_t dst_ref_[kBufSize];
uint16_t dst_tst_[kBufSize];
int dst_stride_;
uint16_t src_y_[kBufSize];
int src_y_stride_;
int8_t offset_buf_[CCSO_BAND_NUM * 16];
uint8_t mask_[kMaxMaskSize];
int src_loc_[2];
int pic_width_;
int pic_height_;
int blk_size_;
uint8_t filter_sup_;
int y_uv_vscale_;
int y_uv_hscale_;
int thr_;
int neg_thr_;
int max_val_;
bool isSingleBand_;
uint8_t shift_bits_;
#if CONFIG_CCSO_EDGE_CLF
int edge_clf_;
#endif
};
class CCSOWOBUFTest : public CCSOFilterTest<CCSO_WO_BUF> {
protected:
void Execute() {
params_.ref_func(src_y_, dst_ref_, 0, 0, pic_width_, pic_height_, src_cls_,
offset_buf_, src_y_stride_, dst_stride_, y_uv_hscale_,
y_uv_vscale_, thr_, neg_thr_, src_loc_, max_val_,
blk_size_, isSingleBand_, shift_bits_
#if CONFIG_CCSO_EDGE_CLF
,
edge_clf_
#endif
#if CONFIG_CCSO_BO_ONLY_OPTION
,
0
#endif
);
ASM_REGISTER_STATE_CHECK(params_.tst_func(
src_y_, dst_tst_, 0, 0, pic_width_, pic_height_, src_cls_, offset_buf_,
src_y_stride_, dst_stride_, y_uv_hscale_, y_uv_vscale_, thr_, neg_thr_,
src_loc_, max_val_, blk_size_, isSingleBand_, shift_bits_
#if CONFIG_CCSO_EDGE_CLF
,
edge_clf_
#endif
#if CONFIG_CCSO_EDGE_CLF
,
0
#endif
));
for (int r = 0; r < blk_size_; ++r) {
for (int c = 0; c < blk_size_; ++c) {
ASSERT_EQ(dst_ref_[r * dst_stride_ + c], dst_tst_[r * dst_stride_ + c]);
}
}
}
int src_cls_[2];
};
TEST_P(CCSOWOBUFTest, RandomValues) {
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
const int hi = 1 << 10;
for (int i = 0; i < kBufSize; ++i) {
dst_ref_[i] = 0;
dst_tst_[i] = 0;
src_y_[i] = rng_(hi);
}
const int ccso_offset[8] = { -10, -7, -3, -1, 0, 1, 3, 7 };
for (int i = 0; i < CCSO_BAND_NUM * 16; i++) {
offset_buf_[i] = ccso_offset[rng_(8)];
}
Common();
}
}
//////////////////////////////////////////////////////////////////////////////
// ccso_filter_block_hbd_with_buf
//////////////////////////////////////////////////////////////////////////////
typedef void (*CCSO_With_BUF)(const uint16_t *src_y, uint16_t *dst_yuv,
const uint8_t *src_cls0, const uint8_t *src_cls1,
const int src_y_stride, const int dst_stride,
const int ccso_stride, const int x, const int y,
const int pic_width, const int pic_height,
const int8_t *offset_buf, const int blk_size,
const int y_uv_hscale, const int y_uv_vscale,
const int max_val, const uint8_t shift_bits
#if CONFIG_CCSO_BO_ONLY_OPTION
,
const uint8_t ccso_bo_only
#endif
);
typedef libaom_test::FuncParam<CCSO_With_BUF> TestFuncsCCSO_With_BUF;
class CCSOWITHBUFTest : public CCSOFilterTest<CCSO_With_BUF> {
protected:
void Execute() {
ccso_stride_ = src_y_stride_ - (CCSO_PADDING_SIZE << 1);
params_.ref_func(src_y_, dst_ref_, src_cls0_, src_cls1_, src_y_stride_,
dst_stride_, ccso_stride_, 0, 0, pic_width_, pic_height_,
offset_buf_, blk_size_, y_uv_hscale_, y_uv_vscale_,
max_val_, shift_bits_
#if CONFIG_CCSO_BO_ONLY_OPTION
,
0
#endif
);
ASM_REGISTER_STATE_CHECK(params_.tst_func(
src_y_, dst_tst_, src_cls0_, src_cls1_, src_y_stride_, dst_stride_,
ccso_stride_, 0, 0, pic_width_, pic_height_, offset_buf_, blk_size_,
y_uv_hscale_, y_uv_vscale_, max_val_, shift_bits_
#if CONFIG_CCSO_BO_ONLY_OPTION
,
0
#endif
));
for (int r = 0; r < blk_size_; ++r) {
for (int c = 0; c < blk_size_; ++c) {
ASSERT_EQ(dst_ref_[r * dst_stride_ + c], dst_tst_[r * dst_stride_ + c]);
}
}
}
uint8_t src_cls0_[kBufSize];
uint8_t src_cls1_[kBufSize];
int ccso_stride_;
};
TEST_P(CCSOWITHBUFTest, RandomValues) {
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
const int hi = 1 << 10;
for (int i = 0; i < kBufSize; ++i) {
dst_ref_[i] = 0;
dst_tst_[i] = 0;
src_cls0_[i] = rng_(3);
src_cls1_[i] = rng_(3);
src_y_[i] = rng_(hi);
}
const int ccso_offset[8] = { -10, -7, -3, -1, 0, 1, 3, 7 };
for (int i = 0; i < CCSO_BAND_NUM * 16; i++) {
offset_buf_[i] = ccso_offset[rng_(8)];
}
Common();
}
}
//////////////////////////////////////////////////////////////////////////////
// ccso_derive_src_block_avx2
//////////////////////////////////////////////////////////////////////////////
typedef void (*CCSO_Derive_Src)(const uint16_t *src_y, uint8_t *const src_cls0,
uint8_t *const src_cls1, const int src_y_stride,
const int ccso_stride, const int x, const int y,
const int pic_width, const int pic_height,
const int y_uv_hscale, const int y_uv_vscale,
const int thr, const int neg_thr,
const int *src_loc, const int blk_size
#if CONFIG_CCSO_EDGE_CLF
,
const int edge_clf
#endif
);
typedef libaom_test::FuncParam<CCSO_Derive_Src> TestFuncsCCSO_Derive_Src;
class CCSODeriveSrcTest : public CCSOFilterTest<CCSO_Derive_Src> {
protected:
void Execute() {
ccso_stride_ = src_y_stride_ - (CCSO_PADDING_SIZE << 1);
params_.ref_func(src_y_, src_cls0_ref, src_cls1_ref, src_y_stride_,
ccso_stride_, 0, 0, pic_width_, pic_height_, y_uv_hscale_,
y_uv_vscale_, thr_, neg_thr_, src_loc_, blk_size_
#if CONFIG_CCSO_EDGE_CLF
,
edge_clf_
#endif
);
ASM_REGISTER_STATE_CHECK(params_.tst_func(
src_y_, src_cls0_tst, src_cls1_tst, src_y_stride_, ccso_stride_, 0, 0,
pic_width_, pic_height_, y_uv_hscale_, y_uv_vscale_, thr_, neg_thr_,
src_loc_, blk_size_
#if CONFIG_CCSO_EDGE_CLF
,
edge_clf_
#endif
));
for (int r = 0; r < blk_size_; ++r) {
for (int c = 0; c < blk_size_; ++c) {
ASSERT_EQ(src_cls0_ref[(r << y_uv_vscale_) * ccso_stride_ +
(c << y_uv_hscale_)],
src_cls0_tst[(r << y_uv_vscale_) * ccso_stride_ +
(c << y_uv_hscale_)]);
ASSERT_EQ(src_cls1_ref[(r << y_uv_vscale_) * ccso_stride_ +
(c << y_uv_hscale_)],
src_cls1_tst[(r << y_uv_vscale_) * ccso_stride_ +
(c << y_uv_hscale_)]);
}
}
}
uint8_t src_cls0_ref[kBufSize];
uint8_t src_cls1_ref[kBufSize];
uint8_t src_cls0_tst[kBufSize];
uint8_t src_cls1_tst[kBufSize];
int ccso_stride_;
};
TEST_P(CCSODeriveSrcTest, RandomValues) {
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
const int hi = 1 << 10;
for (int i = 0; i < kBufSize; ++i) {
dst_ref_[i] = 0;
dst_tst_[i] = 0;
src_cls0_ref[i] = 0;
src_cls1_ref[i] = 0;
src_cls0_tst[i] = 0;
src_cls1_tst[i] = 0;
src_y_[i] = rng_(hi);
}
Common();
}
}
//////////////////////////////////////////////////////////////////////////////
// compute_distortion_block_avx2
//////////////////////////////////////////////////////////////////////////////
typedef uint64_t (*CCSO_Dist_Block)(const uint16_t *org, const int org_stride,
const uint16_t *rec16, const int rec_stride,
const int x, const int y,
const int log2_filter_unit_size,
const int height, const int width);
typedef libaom_test::FuncParam<CCSO_Dist_Block> TestFuncsCCSO_Dist_Block;
class CCSODistBlockTest : public CCSOFilterTest<CCSO_Dist_Block> {
protected:
void Execute() {
org_ = src_y_;
org_stride_ = src_y_stride_;
rec16_ = dst_ref_;
rec_stride_ = src_y_stride_;
log2_filter_unit_size_ = 1 - y_uv_hscale_ + 7;
height_ = pic_height_;
width_ = pic_width_;
uint64_t ref = params_.ref_func(org_, org_stride_, rec16_, rec_stride_, 0,
0, log2_filter_unit_size_, height_, width_);
uint64_t tst;
ASM_REGISTER_STATE_CHECK(
tst = params_.tst_func(org_, org_stride_, rec16_, rec_stride_, 0, 0,
log2_filter_unit_size_, height_, width_));
ASSERT_EQ(ref, tst);
}
uint16_t *org_;
int org_stride_;
uint16_t *rec16_;
int rec_stride_;
int log2_filter_unit_size_;
int height_;
int width_;
};
TEST_P(CCSODistBlockTest, RandomValues) {
for (int iter = 0; iter < kIterations && !HasFatalFailure(); ++iter) {
const int hi = 1 << 10;
for (int i = 0; i < kBufSize; ++i) {
dst_ref_[i] = rng_(hi);
src_y_[i] = rng_(hi);
}
Common();
}
}
#if HAVE_AVX2
INSTANTIATE_TEST_SUITE_P(
AVX2, CCSODistBlockTest,
::testing::Values(TestFuncsCCSO_Dist_Block(compute_distortion_block_c,
compute_distortion_block_avx2)));
INSTANTIATE_TEST_SUITE_P(
AVX2, CCSODeriveSrcTest,
::testing::Values(TestFuncsCCSO_Derive_Src(ccso_derive_src_block_c,
ccso_derive_src_block_avx2)));
INSTANTIATE_TEST_SUITE_P(AVX2, CCSOWITHBUFTest,
::testing::Values(TestFuncsCCSO_With_BUF(
ccso_filter_block_hbd_with_buf_c,
ccso_filter_block_hbd_with_buf_avx2)));
INSTANTIATE_TEST_SUITE_P(
AVX2, CCSOWOBUFTest,
::testing::Values(TestFuncsCCSO_WO_BUF(ccso_filter_block_hbd_wo_buf_c,
ccso_filter_block_hbd_wo_buf_avx2)));
#endif // HAVE_AVX2
} // namespace