Add luma inter pred test

This commit is contained in:
Harish Mahendrakar 2026-02-22 21:11:21 -08:00 committed by ram
parent c8327aa960
commit 141e971581
10 changed files with 534 additions and 0 deletions

View file

@ -42,6 +42,7 @@ endif()
include("${HEVC_ROOT}/cmake/utils.cmake")
libhevc_add_compile_options()
libhevc_add_gtest()
libhevc_add_definitions()
libhevc_set_link_libraries()
@ -54,3 +55,5 @@ include("${HEVC_ROOT}/test/encoder/hevcenc.cmake")
include("${HEVC_ROOT}/fuzzer/hevc_dec_fuzzer.cmake")
include("${HEVC_ROOT}/fuzzer/hevc_enc_fuzzer.cmake")
include("${HEVC_ROOT}/tests/common/common.cmake")

View file

@ -5,3 +5,6 @@ set(SYSTEM_PROCESSOR aarch32)
# armv7 targets
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# Build all binaries as static, so that they can be run using qemu
set(CMAKE_EXE_LINKER_FLAGS "-static")

View file

@ -11,3 +11,6 @@ set(CMAKE_C_COMPILER_AR
set(CMAKE_CXX_COMPILER_AR
aarch64-linux-gnu-gcc-ar
CACHE FILEPATH "Archiver")
# Build all binaries as static, so that they can be run using qemu
set(CMAKE_EXE_LINKER_FLAGS "-static")

View file

@ -118,3 +118,15 @@ endfunction()
function(libhevc_add_fuzzer NAME LIB)
libhevc_add_executable(${NAME} ${LIB} FUZZER 1 ${ARGV})
endfunction()
# Adds GoogleTest and Threads dependency
function(libhevc_add_gtest)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
endfunction()

18
tests/common/common.cmake Normal file
View file

@ -0,0 +1,18 @@
enable_testing()
add_executable(
ihevc_luma_inter_pred_test
${HEVC_ROOT}/tests/common/func_selector.cc
${HEVC_ROOT}/tests/common/tests_common.cc
${HEVC_ROOT}/tests/common/ihevc_luma_inter_pred_test.cc
)
target_link_libraries(
ihevc_luma_inter_pred_test
libhevcdec
GTest::gtest_main
)
if(DEFINED SANITIZE)
set_target_properties(ihevc_luma_inter_pred_test PROPERTIES LINK_FLAGS
-fsanitize=${SANITIZE})
endif()
include(GoogleTest)

View file

@ -0,0 +1,115 @@
/******************************************************************************
*
* Copyright (C) 2026 Ittiam Systems Pvt Ltd, Bangalore
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include <algorithm>
#include <cstring>
#include <gtest/gtest.h>
#include <random>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
// clang-format off
#include "ihevc_typedefs.h"
#include "ihevc_inter_pred.h"
#include "ihevcd_function_selector.h"
#include "iv.h"
#include "ivd.h"
// clang-format on
const func_selector_t ref = []() {
func_selector_t ret = {};
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
defined(_M_IX86)
ihevcd_init_function_ptr_generic(&ret);
#elif defined(__aarch64__) || defined(__arm__)
ihevcd_init_function_ptr_noneon(&ret);
#endif
return ret;
}();
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
defined(_M_IX86)
const func_selector_t test_ssse3 = []() {
func_selector_t ret = {};
ihevcd_init_function_ptr_ssse3(&ret);
return ret;
}();
const func_selector_t test_sse42 = []() {
func_selector_t ret = {};
ihevcd_init_function_ptr_sse42(&ret);
return ret;
}();
#ifndef DISABLE_AVX2
const func_selector_t test_avx2 = []() {
func_selector_t ret = {};
ihevcd_init_function_ptr_avx2(&ret);
return ret;
}();
#endif
#elif defined(__aarch64__)
const func_selector_t test_arm64 = []() {
func_selector_t ret = {};
#ifdef DARWIN
ihevcd_init_function_ptr_noneon(&ret);
#else
ihevcd_init_function_ptr_av8(&ret);
#endif
return ret;
}();
#elif defined(__arm__)
const func_selector_t test_arm32 = []() {
func_selector_t ret = {};
#ifdef DARWIN
ihevcd_init_function_ptr_noneon(&ret);
#else
ihevcd_init_function_ptr_a9q(&ret);
#endif
return ret;
}();
#endif
const func_selector_t *get_ref_func_ptr() { return &ref; }
const func_selector_t *get_tst_func_ptr(IVD_ARCH_T arch) {
switch (arch) {
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
defined(_M_IX86)
case ARCH_X86_SSSE3:
return &test_ssse3;
case ARCH_X86_SSE42:
return &test_sse42;
#ifndef DISABLE_AVX2
case ARCH_X86_AVX2:
return &test_avx2;
#endif
#elif defined(__aarch64__)
case ARCH_ARMV8_GENERIC:
return &test_arm64;
#elif defined(__arm__)
case ARCH_ARM_A9Q:
return &test_arm32;
#endif
default:
return nullptr;
}
}

View file

@ -0,0 +1,41 @@
/******************************************************************************
*
* Copyright (C) 2026 Ittiam Systems Pvt Ltd, Bangalore
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef __FUNC_SELECTOR_H__
#define __FUNC_SELECTOR_H__
#include <algorithm>
#include <cstring>
#include <gtest/gtest.h>
#include <random>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
// clang-format off
#include "ihevc_typedefs.h"
#include "ihevc_inter_pred.h"
#include "ihevcd_function_selector.h"
#include "iv.h"
#include "ivd.h"
// clang-format on
const func_selector_t *get_ref_func_ptr();
const func_selector_t *get_tst_func_ptr(IVD_ARCH_T arch);
#endif /* __FUNC_SELECTOR_H__ */

View file

@ -0,0 +1,179 @@
/******************************************************************************
*
* Copyright (C) 2026 Ittiam Systems Pvt Ltd, Bangalore
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include <algorithm>
#include <cstring>
#include <gtest/gtest.h>
#include <random>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
// clang-format off
#include "ihevc_typedefs.h"
#include "ihevc_inter_pred.h"
#include "ihevcd_function_selector.h"
#include "iv.h"
#include "ivd.h"
#include "func_selector.h"
#include "tests_common.h"
// clang-format on
// Test parameters: width, height, src_stride_mul, dst_stride_mul, coeff_idx,
// arch
using LumaInterPredTestParam =
std::tuple<std::pair<int, int>, int, int, int, IVD_ARCH_T>;
template <typename srcType, typename dstType>
class LumaInterPredTest
: public ::testing::TestWithParam<LumaInterPredTestParam> {
protected:
void SetUp() override {
std::pair<int, int> block_size;
std::tie(block_size, src_strd_mul, dst_strd_mul, coeff_idx, arch) =
GetParam();
std::tie(wd, ht) = block_size;
src_strd = wd * src_strd_mul;
dst_strd = wd * dst_strd_mul;
dst_buf_ref.resize(dst_strd * ht);
dst_buf_tst.resize(dst_strd * ht);
// Set pv_src to a valid position within src_buf to allow negative indexing
pv_src = (srcType *)g_src8_buf.data() + kTapSize / 2 * src_strd;
pv_dst_ref = dst_buf_ref.data();
pv_dst_tst = dst_buf_tst.data();
pi1_coeffs = gai1_ihevc_luma_filter[coeff_idx];
tst = get_tst_func_ptr(arch);
ref = get_ref_func_ptr();
}
template <typename FuncPtr> void RunTest(FuncPtr func_ptr) {
(ref->*func_ptr)(pv_src, pv_dst_ref, src_strd, dst_strd, pi1_coeffs, ht,
wd);
(tst->*func_ptr)(pv_src, pv_dst_tst, src_strd, dst_strd, pi1_coeffs, ht,
wd);
ASSERT_NO_FATAL_FAILURE(
compare_output<dstType>(dst_buf_ref, dst_buf_tst, wd, ht, dst_strd));
}
int wd, ht, src_strd_mul, dst_strd_mul, coeff_idx;
int src_strd, dst_strd;
std::vector<dstType> dst_buf_ref;
std::vector<dstType> dst_buf_tst;
srcType *pv_src;
dstType *pv_dst_ref;
dstType *pv_dst_tst;
WORD8 *pi1_coeffs;
IVD_ARCH_T arch;
const func_selector_t *tst;
const func_selector_t *ref;
};
class LumaInterPred_8_8_Test : public LumaInterPredTest<UWORD8, UWORD8> {};
class LumaInterPred_8_16_Test : public LumaInterPredTest<UWORD8, WORD16> {};
class LumaInterPred_16_8_Test : public LumaInterPredTest<WORD16, UWORD8> {};
class LumaInterPred_16_16_Test : public LumaInterPredTest<WORD16, WORD16> {};
TEST_P(LumaInterPred_8_8_Test, LumaCopyTest) {
RunTest(&func_selector_t::ihevc_inter_pred_luma_copy_fptr);
}
TEST_P(LumaInterPred_8_8_Test, LumaHorzTest) {
RunTest(&func_selector_t::ihevc_inter_pred_luma_horz_fptr);
}
TEST_P(LumaInterPred_8_8_Test, LumaVertTest) {
RunTest(&func_selector_t::ihevc_inter_pred_luma_vert_fptr);
}
TEST_P(LumaInterPred_8_16_Test, LumaCopyTest) {
RunTest(&func_selector_t::ihevc_inter_pred_luma_copy_w16out_fptr);
}
TEST_P(LumaInterPred_8_16_Test, LumaHorzTest) {
RunTest(&func_selector_t::ihevc_inter_pred_luma_horz_w16out_fptr);
}
TEST_P(LumaInterPred_8_16_Test, LumaVertTest) {
RunTest(&func_selector_t::ihevc_inter_pred_luma_vert_w16out_fptr);
}
TEST_P(LumaInterPred_16_8_Test, LumaVertTest) {
RunTest(&func_selector_t::ihevc_inter_pred_luma_vert_w16inp_fptr);
}
TEST_P(LumaInterPred_16_16_Test, LumaVertTest) {
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
defined(_M_IX86)
// TODO: SSE4.2 and SSSE3 are not matching C implementation
GTEST_SKIP() << "SSE4.2 and SSSE3 are not matching C implementation for "
"ihevc_inter_pred_luma_vert_w16inp_w16out_fptr";
#endif
RunTest(&func_selector_t::ihevc_inter_pred_luma_vert_w16inp_w16out_fptr);
}
auto kLumaInterPredTestParams =
::testing::Combine(::testing::ValuesIn(kPUBlockSizes),
::testing::Values(1, 2), // Src Stride Multiplier
::testing::Values(1, 2), // Dst Stride Multiplier
::testing::Values(0, 1, 2, 3), // Coeff index
::testing::ValuesIn(ga_tst_arch) // arch
);
std::string PrintLumaInterPredTestParam(
const testing::TestParamInfo<LumaInterPredTestParam> &info) {
int wd, ht, src_strd_mul, dst_strd_mul, coeff_idx;
IVD_ARCH_T arch;
std::pair<int, int> block_size;
std::tie(block_size, src_strd_mul, dst_strd_mul, coeff_idx, arch) =
info.param;
std::tie(wd, ht) = block_size;
std::stringstream ss;
ss << wd << "x" << ht << "_src_stride_" << src_strd_mul * wd << "_dst_stride_"
<< dst_strd_mul * wd << "_coeff_" << coeff_idx << "_"
<< get_arch_str(arch);
return ss.str();
}
INSTANTIATE_TEST_SUITE_P(LumaCopyTest, LumaInterPred_8_8_Test,
kLumaInterPredTestParams, PrintLumaInterPredTestParam);
INSTANTIATE_TEST_SUITE_P(LumaHorzTest, LumaInterPred_8_8_Test,
kLumaInterPredTestParams, PrintLumaInterPredTestParam);
INSTANTIATE_TEST_SUITE_P(LumaVertTest, LumaInterPred_8_8_Test,
kLumaInterPredTestParams, PrintLumaInterPredTestParam);
INSTANTIATE_TEST_SUITE_P(LumaCopyTest, LumaInterPred_8_16_Test,
kLumaInterPredTestParams, PrintLumaInterPredTestParam);
INSTANTIATE_TEST_SUITE_P(LumaHorzTest, LumaInterPred_8_16_Test,
kLumaInterPredTestParams, PrintLumaInterPredTestParam);
INSTANTIATE_TEST_SUITE_P(LumaVertTest, LumaInterPred_8_16_Test,
kLumaInterPredTestParams, PrintLumaInterPredTestParam);
INSTANTIATE_TEST_SUITE_P(LumaVertTest, LumaInterPred_16_8_Test,
kLumaInterPredTestParams, PrintLumaInterPredTestParam);
INSTANTIATE_TEST_SUITE_P(LumaVertTest, LumaInterPred_16_16_Test,
kLumaInterPredTestParams, PrintLumaInterPredTestParam);

View file

@ -0,0 +1,100 @@
/******************************************************************************
*
* Copyright (C) 2026 Ittiam Systems Pvt Ltd, Bangalore
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include <algorithm>
#include <cstring>
#include <gtest/gtest.h>
#include <random>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
// clang-format off
#include "ihevc_typedefs.h"
#include "ihevc_inter_pred.h"
#include "ihevcd_function_selector.h"
#include "iv.h"
#include "ivd.h"
#include "tests_common.h"
// clang-format on
const std::vector<std::pair<int, int>> kPUBlockSizes = {
// clang-format off
{4, 4},
{8, 8}, {8, 4}, {4, 8},
{16, 16}, {16, 12}, {16, 8}, {16, 4}, {12, 16}, {8, 16}, {4, 16},
{32, 32}, {32, 24}, {32, 16}, {32, 8}, {24, 32}, {16, 32}, {8, 32},
{64, 64}, {64, 48}, {64, 32}, {64, 16}, {48, 64}, {32, 64}, {16, 64},
// clang-format on
};
const std::vector<UWORD8> g_src8_buf = []() {
// allocate twice to account for WORD16 as well
std::vector<UWORD8> buf(kMaxSize * kMaxHeight * 2);
std::mt19937 rng(12345);
std::uniform_int_distribution<int> dist(0, 255);
for (auto &v : buf)
v = static_cast<UWORD8>(dist(rng));
return buf;
}();
std::string get_arch_str(IVD_ARCH_T arch) {
std::string arch_str;
switch (arch) {
case ARCH_X86_GENERIC:
arch_str = "GENERIC";
break;
case ARCH_X86_SSSE3:
arch_str = "SSSE3";
break;
case ARCH_X86_SSE42:
arch_str = "SSE42";
break;
case ARCH_X86_AVX2:
arch_str = "AVX2";
break;
case ARCH_ARMV8_GENERIC:
arch_str = "ARMV8";
break;
case ARCH_ARM_A9Q:
arch_str = "A9Q";
break;
default:
arch_str = "UNKNOWN";
break;
}
return arch_str;
}
const std::vector<IVD_ARCH_T> ga_tst_arch = {
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || \
defined(_M_IX86)
ARCH_X86_SSSE3,
ARCH_X86_SSE42,
#ifndef DISABLE_AVX2
ARCH_X86_AVX2,
#endif // DISABLE_AVX2
#elif defined(__aarch64__)
ARCH_ARMV8_GENERIC,
#elif defined(__arm__)
ARCH_ARM_A9Q,
#endif
};

View file

@ -0,0 +1,60 @@
/******************************************************************************
*
* Copyright (C) 2026 Ittiam Systems Pvt Ltd, Bangalore
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef __TESTS_COMMON_H__
#define __TESTS_COMMON_H__
#include <algorithm>
#include <cstring>
#include <gtest/gtest.h>
#include <random>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
// clang-format off
#include "ihevc_typedefs.h"
#include "ihevc_inter_pred.h"
#include "ihevcd_function_selector.h"
#include "iv.h"
#include "ivd.h"
// clang-format on
static constexpr int kMaxSize = 64;
static constexpr int kTapSize = 8;
static constexpr int kMaxHeight = kMaxSize + kTapSize;
extern const std::vector<std::pair<int, int>> kPUBlockSizes;
extern const std::vector<UWORD8> g_src8_buf;
extern const std::vector<IVD_ARCH_T> ga_tst_arch;
// Compare outputs
template <typename T>
static void compare_output(const std::vector<T> &ref, const std::vector<T> &test,
int wd, int ht, int dst_strd) {
int size_bytes = wd * sizeof(T);
for (int i = 0; i < ht; ++i) {
int cmp = memcmp(ref.data() + i * dst_strd, test.data() + i * dst_strd,
size_bytes);
ASSERT_EQ(0, cmp) << "Mismatch at row " << i << " for size " << wd << "x"
<< ht;
}
}
std::string get_arch_str(IVD_ARCH_T arch);
#endif /* __TESTS_COMMON_H__ */