blob: 0dc69c884ee43679cfb6f7d996a7900c258722cb [file] [log] [blame] [edit]
/*
* Copyright (c) 2025, 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 <cstdlib>
#include <string>
#include <tuple>
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
#include "config/aom_config.h"
#include "config/av1_rtcd.h"
#include "av1/common/av1_common_int.h"
#include "aom_ports/aom_timer.h"
#include "av1/common/gdf_block.h"
#include "av1/common/gdf.h"
#include "test/acm_random.h"
#include "test/clear_system_state.h"
#include "test/util.h"
using libaom_test::ACMRandom;
namespace {
typedef void (*gdf_set_lap_and_cls_unit_func)(
const int i_min, const int i_max, const int j_min, const int j_max,
const int stripe_size, const uint16_t *rec_pnt, const int rec_stride,
const int bit_depth, uint16_t *const *gdf_lap_y, const int gdf_lap_y_stride,
uint32_t *gdf_cls_y, const int gdf_cls_y_stride);
typedef void (*gdf_inference_unit_func)(
const int i_min, const int i_max, const int j_min, const int j_max,
const int stripe_size, const int qp_idx, const uint16_t *rec_pnt,
const int rec_stride, uint16_t *const *gdf_lap_pnt,
const int gdf_lap_stride, const uint32_t *gdf_cls_pnt,
const int gdf_cls_stride, int16_t *err_pnt, const int err_stride,
const int pxl_shift, const int ref_dst_idx);
typedef void (*gdf_compensation_unit_func)(
uint16_t *rec_pnt, const int rec_stride, int16_t *err_pnt,
const int err_stride, const int err_shift, const int scale,
const int pxl_max, const int blk_height, const int blk_width);
typedef std::tuple<gdf_set_lap_and_cls_unit_func, gdf_set_lap_and_cls_unit_func,
gdf_inference_unit_func, gdf_inference_unit_func,
gdf_compensation_unit_func, gdf_compensation_unit_func, int,
int, int, int, int, int>
gdf_param_t;
constexpr int max_test_tile_size = 512;
class GDFTest : public ::testing::TestWithParam<gdf_param_t> {
public:
virtual ~GDFTest() {}
virtual void SetUp() {
lapgdf = GET_PARAM(0);
ref_lapgdf = GET_PARAM(1);
infgdf = GET_PARAM(2);
ref_infgdf = GET_PARAM(3);
compgdf = GET_PARAM(4);
ref_compgdf = GET_PARAM(5);
height = GET_PARAM(6);
width = GET_PARAM(7);
bd = GET_PARAM(8);
qp_idx = GET_PARAM(9);
ref_dst = GET_PARAM(10);
mib_size = GET_PARAM(11);
}
virtual void TearDown() { libaom_test::ClearSystemState(); }
protected:
gdf_set_lap_and_cls_unit_func lapgdf;
gdf_set_lap_and_cls_unit_func ref_lapgdf;
gdf_inference_unit_func infgdf;
gdf_inference_unit_func ref_infgdf;
gdf_compensation_unit_func compgdf;
gdf_compensation_unit_func ref_compgdf;
int height;
int width;
int bd;
int qp_idx;
int ref_dst;
int mib_size;
};
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GDFTest);
void test_gdf(int iterations, int height, int width, int depth, int qp_idx,
int ref_dst, int mib_size, gdf_set_lap_and_cls_unit_func lapgdf,
gdf_set_lap_and_cls_unit_func ref_lapgdf,
gdf_inference_unit_func infgdf,
gdf_inference_unit_func ref_infgdf,
gdf_compensation_unit_func compgdf,
gdf_compensation_unit_func ref_compgdf) {
ACMRandom rnd(ACMRandom::DeterministicSeed());
DECLARE_ALIGNED(16, static uint16_t,
rec[(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2) *
(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2 +
GDF_ERR_STRIDE_MARGIN)]);
DECLARE_ALIGNED(16, static uint16_t,
out[(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2) *
(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2 +
GDF_ERR_STRIDE_MARGIN)]);
DECLARE_ALIGNED(
16, static uint16_t,
ref_out[(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2) *
(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2 +
GDF_ERR_STRIDE_MARGIN)]);
GdfInfo gi, ref_gi;
memset(&gi, 0, sizeof(gi));
memset(&ref_gi, 0, sizeof(ref_gi));
init_gdf(&gi, mib_size, height, width);
init_gdf(&ref_gi, mib_size, height, width);
alloc_gdf_buffers(&gi);
alloc_gdf_buffers(&ref_gi);
int err = 0, is_lap_err = 0, is_cls_err = 0;
int is_inf_err = 0, is_comp_err = 0;
const int stripe_size = gi.gdf_stripe_size;
const int rec_stride =
(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2 +
GDF_ERR_STRIDE_MARGIN);
const int pxl_max = (1 << depth) - 1;
const int pxl_shift = GDF_TEST_INP_PREC - depth;
const int err_shift = GDF_RDO_SCALE_NUM_LOG2 + pxl_shift;
for (int iter = 0; iter < iterations && !err; iter++) {
memset(rec, 0, sizeof(rec));
for (uint16_t &i : rec) {
i = clamp(rnd.Rand16() & ((1 << depth) - 1), 0, (1 << depth) - 1);
}
for (int y_pos = -GDF_TEST_STRIPE_OFF; y_pos < height;
y_pos += gi.gdf_block_size) {
for (int x_pos = 0; x_pos < width; x_pos += gi.gdf_block_size) {
for (int v_pos = y_pos;
v_pos < y_pos + gi.gdf_block_size && v_pos < height;
v_pos += gi.gdf_unit_size) {
for (int u_pos = x_pos;
u_pos < x_pos + gi.gdf_block_size && u_pos < width;
u_pos += gi.gdf_unit_size) {
int i_min = AOMMAX(v_pos, GDF_TEST_FRAME_BOUNDARY_SIZE);
int i_max = AOMMIN(v_pos + gi.gdf_unit_size,
height - GDF_TEST_FRAME_BOUNDARY_SIZE);
int j_min = AOMMAX(u_pos, GDF_TEST_FRAME_BOUNDARY_SIZE);
int j_max = AOMMIN(u_pos + gi.gdf_unit_size,
width - GDF_TEST_FRAME_BOUNDARY_SIZE);
const uint16_t *inp_ptr = rec + i_min * rec_stride + j_min;
lapgdf(i_min, i_max, j_min, j_max, stripe_size, inp_ptr, rec_stride,
depth, gi.lap_ptr, gi.lap_stride, gi.cls_ptr, gi.cls_stride);
ref_lapgdf(i_min, i_max, j_min, j_max, stripe_size, inp_ptr,
rec_stride, depth, ref_gi.lap_ptr, ref_gi.lap_stride,
ref_gi.cls_ptr, ref_gi.cls_stride);
const int lap_height = (i_max - i_min) >> 1;
const int lap_width = (j_max - j_min);
const int cls_width = (j_max - j_min) >> 1;
const int res_height = (i_max - i_min);
const int res_width = (j_max - j_min);
for (int i = 0; i < lap_height && !err; i++) {
for (int grd_idx = 0;
grd_idx < GDF_NET_INP_GRD_NUM && !is_lap_err; grd_idx++) {
is_lap_err =
memcmp(gi.lap_ptr[grd_idx], ref_gi.lap_ptr[grd_idx],
sizeof(uint16_t) * lap_width);
}
is_cls_err = memcmp(gi.cls_ptr, ref_gi.cls_ptr,
sizeof(uint32_t) * cls_width);
err = is_lap_err | is_cls_err;
}
infgdf(i_min, i_max, j_min, j_max, gi.gdf_stripe_size, qp_idx,
inp_ptr, rec_stride, gi.lap_ptr, gi.lap_stride, gi.cls_ptr,
gi.cls_stride, gi.err_ptr, gi.err_stride, pxl_shift,
ref_dst);
ref_infgdf(i_min, i_max, j_min, j_max, ref_gi.gdf_stripe_size,
qp_idx, inp_ptr, rec_stride, ref_gi.lap_ptr,
ref_gi.lap_stride, ref_gi.cls_ptr, ref_gi.cls_stride,
ref_gi.err_ptr, ref_gi.err_stride, pxl_shift, ref_dst);
for (int i = 0; i < res_height && !err; i++) {
is_inf_err = memcmp(gi.err_ptr, ref_gi.err_ptr,
sizeof(int16_t) * res_width);
err |= is_inf_err;
}
for (int s = 1; s <= GDF_RDO_SCALE_NUM && !err; s++) {
memcpy(
out, rec,
sizeof(uint16_t) *
(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2) *
(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2 +
GDF_ERR_STRIDE_MARGIN));
compgdf(out, rec_stride, gi.err_ptr, gi.err_stride, err_shift, s,
pxl_max, i_max - i_min, j_max - j_min);
memcpy(
ref_out, rec,
sizeof(uint16_t) *
(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2) *
(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2 +
GDF_ERR_STRIDE_MARGIN));
ref_compgdf(ref_out, rec_stride, ref_gi.err_ptr,
ref_gi.err_stride, err_shift, s, pxl_max,
i_max - i_min, j_max - j_min);
is_comp_err = memcmp(
out, ref_out,
sizeof(uint16_t) *
(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2) *
(max_test_tile_size + GDF_TEST_FRAME_BOUNDARY_SIZE * 2 +
GDF_ERR_STRIDE_MARGIN));
err |= is_comp_err;
}
}
}
}
}
}
free_gdf_buffers(&gi);
free_gdf_buffers(&ref_gi);
EXPECT_EQ(err, 0) << "Error: GDFTest, SIMD and C mismatch."
<< "is_lap_err : " << is_lap_err << std::endl
<< "is_cls_err : " << is_cls_err << std::endl
<< "is_inf_err : " << is_inf_err << std::endl
<< "is_com_err : " << is_comp_err << std::endl
<< std::endl;
}
TEST_P(GDFTest, TestSIMDNoMismatchGDF) {
test_gdf(1, height, width, bd, qp_idx, ref_dst, mib_size, lapgdf, ref_lapgdf,
infgdf, ref_infgdf, compgdf, ref_compgdf);
}
using std::make_tuple;
#if defined(_WIN64) || !defined(_MSC_VER) || defined(__clang__)
#if HAVE_AVX2
INSTANTIATE_TEST_SUITE_P(
AVX2, GDFTest,
::testing::Combine(::testing::Values(&gdf_set_lap_and_cls_unit_c),
::testing::Values(&gdf_set_lap_and_cls_unit_avx2),
::testing::Values(&gdf_inference_unit_c),
::testing::Values(&gdf_inference_unit_avx2),
::testing::Values(&gdf_compensation_unit_c),
::testing::Values(&gdf_compensation_unit_avx2),
::testing::Values(128, max_test_tile_size),
::testing::Values(128, max_test_tile_size),
::testing::Values(8, 10, 12),
::testing::Range(0, GDF_TRAIN_QP_NUM),
::testing::Range(0, GDF_TRAIN_REFDST_NUM + 1),
::testing::Values(32, 64)));
#endif
#endif
} // namespace