blob: 6d2817b7617881a73be6bb3965e414b0ae39c23f [file] [log] [blame]
// Copyright 2020 The libgav1 Authors
//
// 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 "src/dsp/dsp.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include "absl/strings/str_cat.h"
#include "gtest/gtest.h"
#include "src/dsp/constants.h"
#include "src/utils/constants.h"
#include "src/utils/cpu.h"
#if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
#include "tests/utils.h"
#endif
namespace libgav1 {
namespace dsp {
namespace {
// Maps 1D transform to the maximum valid size for the corresponding transform.
constexpr int kMaxTransform1dSize[kNumTransform1ds] = {
kTransform1dSize64, // Dct.
kTransform1dSize16, // Adst.
kTransform1dSize32, // Identity.
kTransform1dSize4, // Wht.
};
void CheckTables(bool c_only) {
#if LIBGAV1_MAX_BITDEPTH == 12
static constexpr int kBitdepths[] = {kBitdepth8, kBitdepth10, kBitdepth12};
#elif LIBGAV1_MAX_BITDEPTH >= 10
static constexpr int kBitdepths[] = {kBitdepth8, kBitdepth10};
#else
static constexpr int kBitdepths[] = {kBitdepth8};
#endif
for (const auto& bitdepth : kBitdepths) {
const Dsp* const dsp = GetDspTable(bitdepth);
ASSERT_NE(dsp, nullptr);
SCOPED_TRACE(absl::StrCat("bitdepth: ", bitdepth));
for (int i = 0; i < kNumTransformSizes; ++i) {
for (int j = 0; j < kNumIntraPredictors; ++j) {
EXPECT_NE(dsp->intra_predictors[i][j], nullptr)
<< "index [" << i << "][" << j << "]";
}
}
EXPECT_NE(dsp->directional_intra_predictor_zone1, nullptr);
EXPECT_NE(dsp->directional_intra_predictor_zone2, nullptr);
EXPECT_NE(dsp->directional_intra_predictor_zone3, nullptr);
EXPECT_NE(dsp->filter_intra_predictor, nullptr);
for (int i = 0; i < kNumTransformSizes; ++i) {
if (std::max(kTransformWidth[i], kTransformHeight[i]) == 64) {
EXPECT_EQ(dsp->cfl_intra_predictors[i], nullptr)
<< "index [" << i << "]";
for (int j = 0; j < kNumSubsamplingTypes; ++j) {
EXPECT_EQ(dsp->cfl_subsamplers[i][j], nullptr)
<< "index [" << i << "][" << j << "]";
}
} else {
EXPECT_NE(dsp->cfl_intra_predictors[i], nullptr)
<< "index [" << i << "]";
for (int j = 0; j < kNumSubsamplingTypes; ++j) {
EXPECT_NE(dsp->cfl_subsamplers[i][j], nullptr)
<< "index [" << i << "][" << j << "]";
}
}
}
EXPECT_NE(dsp->intra_edge_filter, nullptr);
EXPECT_NE(dsp->intra_edge_upsampler, nullptr);
for (int i = 0; i < kNumTransform1ds; ++i) {
for (int j = 0; j < kNumTransform1dSizes; ++j) {
for (int k = 0; k < 2; ++k) {
if (j <= kMaxTransform1dSize[i]) {
EXPECT_NE(dsp->inverse_transforms[i][j][k], nullptr)
<< "index [" << i << "][" << j << "][" << k << "]";
} else {
EXPECT_EQ(dsp->inverse_transforms[i][j][k], nullptr)
<< "index [" << i << "][" << j << "][" << k << "]";
}
}
}
}
for (int i = 0; i < kNumLoopFilterSizes; ++i) {
for (int j = 0; j < kNumLoopFilterTypes; ++j) {
EXPECT_NE(dsp->loop_filters[i][j], nullptr)
<< "index [" << i << "][" << j << "]";
}
}
for (int i = 0; i < 2; ++i) {
EXPECT_NE(dsp->loop_restorations[i], nullptr) << "index [" << i << "]";
}
bool super_res_coefficients_is_nonnull = LIBGAV1_ENABLE_NEON;
#if LIBGAV1_ENABLE_SSE4_1
const uint32_t cpu_features = GetCpuInfo();
super_res_coefficients_is_nonnull = (cpu_features & kSSE4_1) != 0;
#endif
if (c_only || bitdepth == kBitdepth12) {
super_res_coefficients_is_nonnull = false;
}
if (super_res_coefficients_is_nonnull) {
EXPECT_NE(dsp->super_res_coefficients, nullptr);
} else {
EXPECT_EQ(dsp->super_res_coefficients, nullptr);
}
EXPECT_NE(dsp->super_res, nullptr);
EXPECT_NE(dsp->cdef_direction, nullptr);
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 3; ++j) {
EXPECT_NE(dsp->cdef_filters[i][j], nullptr)
<< "index [" << i << "][" << j << "]";
}
}
for (auto convolve_func : dsp->convolve_scale) {
EXPECT_NE(convolve_func, nullptr);
}
for (int j = 0; j < 2; ++j) {
for (int k = 0; k < 2; ++k) {
for (int l = 0; l < 2; ++l) {
for (int m = 0; m < 2; ++m) {
if (j == 1 && k == 1) {
EXPECT_EQ(dsp->convolve[j][k][l][m], nullptr);
} else {
EXPECT_NE(dsp->convolve[j][k][l][m], nullptr);
}
}
}
}
}
for (const auto& m : dsp->mask_blend) {
for (int i = 0; i < 2; ++i) {
if (i == 0 || bitdepth >= 10) {
EXPECT_NE(m[i], nullptr);
} else {
EXPECT_EQ(m[i], nullptr);
}
}
}
for (const auto& m : dsp->inter_intra_mask_blend_8bpp) {
if (bitdepth == 8) {
EXPECT_NE(m, nullptr);
} else {
EXPECT_EQ(m, nullptr);
}
}
for (int i = kBlock4x4; i < kMaxBlockSizes; ++i) {
const int width_index = k4x4WidthLog2[i] - 1;
const int height_index = k4x4HeightLog2[i] - 1;
// Only block sizes >= 8x8 are handled with this function.
if (width_index < 0 || height_index < 0) continue;
for (size_t j = 0; j < 2; ++j) {
EXPECT_NE(dsp->weight_mask[width_index][height_index][j], nullptr)
<< ToString(static_cast<BlockSize>(i)) << " index [" << width_index
<< "]"
<< "[" << height_index << "][" << j << "]";
}
}
EXPECT_NE(dsp->average_blend, nullptr);
EXPECT_NE(dsp->distance_weighted_blend, nullptr);
for (int i = 0; i < kNumObmcDirections; ++i) {
EXPECT_NE(dsp->obmc_blend[i], nullptr)
<< "index [" << ToString(static_cast<ObmcDirection>(i)) << "]";
}
EXPECT_NE(dsp->warp, nullptr);
EXPECT_NE(dsp->warp_compound, nullptr);
for (int i = 0; i < kNumAutoRegressionLags - 1; ++i) {
EXPECT_NE(dsp->film_grain.luma_auto_regression[i], nullptr)
<< "index [" << i << "]";
}
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < kNumAutoRegressionLags; ++j) {
if (i == 0 && j == 0) {
EXPECT_EQ(dsp->film_grain.chroma_auto_regression[i][j], nullptr)
<< " index [" << i << "]"
<< "[" << j << "]";
} else {
EXPECT_NE(dsp->film_grain.chroma_auto_regression[i][j], nullptr)
<< " index [" << i << "]"
<< "[" << j << "]";
}
}
EXPECT_NE(dsp->film_grain.construct_noise_stripes[i], nullptr)
<< "index [" << i << "]";
EXPECT_NE(dsp->film_grain.blend_noise_chroma[i], nullptr)
<< "index [" << i << "]";
}
EXPECT_NE(dsp->film_grain.construct_noise_image_overlap, nullptr);
EXPECT_NE(dsp->film_grain.initialize_scaling_lut, nullptr);
EXPECT_NE(dsp->film_grain.blend_noise_luma, nullptr);
if (bitdepth == 8) {
EXPECT_NE(dsp->motion_field_projection_kernel, nullptr);
EXPECT_NE(dsp->mv_projection_compound[0], nullptr);
EXPECT_NE(dsp->mv_projection_compound[1], nullptr);
EXPECT_NE(dsp->mv_projection_compound[2], nullptr);
EXPECT_NE(dsp->mv_projection_single[0], nullptr);
EXPECT_NE(dsp->mv_projection_single[1], nullptr);
EXPECT_NE(dsp->mv_projection_single[2], nullptr);
} else {
EXPECT_EQ(dsp->motion_field_projection_kernel, nullptr);
EXPECT_EQ(dsp->mv_projection_compound[0], nullptr);
EXPECT_EQ(dsp->mv_projection_compound[1], nullptr);
EXPECT_EQ(dsp->mv_projection_compound[2], nullptr);
EXPECT_EQ(dsp->mv_projection_single[0], nullptr);
EXPECT_EQ(dsp->mv_projection_single[1], nullptr);
EXPECT_EQ(dsp->mv_projection_single[2], nullptr);
}
}
}
TEST(Dsp, TablesArePopulated) {
DspInit();
CheckTables(/*c_only=*/false);
}
#if LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
TEST(Dsp, TablesArePopulatedCOnly) {
test_utils::ResetDspTable(kBitdepth8);
#if LIBGAV1_MAX_BITDEPTH >= 10
test_utils::ResetDspTable(kBitdepth10);
#endif
#if LIBGAV1_MAX_BITDEPTH == 12
test_utils::ResetDspTable(kBitdepth12);
#endif
dsp_internal::DspInit_C();
CheckTables(/*c_only=*/true);
}
#endif // LIBGAV1_ENABLE_ALL_DSP_FUNCTIONS
TEST(Dsp, GetDspTable) {
EXPECT_EQ(GetDspTable(1), nullptr);
EXPECT_NE(GetDspTable(kBitdepth8), nullptr);
EXPECT_EQ(dsp_internal::GetWritableDspTable(1), nullptr);
EXPECT_NE(dsp_internal::GetWritableDspTable(kBitdepth8), nullptr);
#if LIBGAV1_MAX_BITDEPTH >= 10
EXPECT_NE(GetDspTable(kBitdepth10), nullptr);
EXPECT_NE(dsp_internal::GetWritableDspTable(kBitdepth10), nullptr);
#else
EXPECT_EQ(GetDspTable(kBitdepth10), nullptr);
EXPECT_EQ(dsp_internal::GetWritableDspTable(kBitdepth10), nullptr);
#endif
#if LIBGAV1_MAX_BITDEPTH == 12
EXPECT_NE(GetDspTable(kBitdepth12), nullptr);
EXPECT_NE(dsp_internal::GetWritableDspTable(kBitdepth12), nullptr);
#else
EXPECT_EQ(GetDspTable(kBitdepth12), nullptr);
EXPECT_EQ(dsp_internal::GetWritableDspTable(kBitdepth12), nullptr);
#endif
}
} // namespace
} // namespace dsp
} // namespace libgav1