blob: 081dcc1d067a50ac2a87e39bfc2827b73ed93d97 [file] [log] [blame]
// Copyright 2021 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/inverse_transform.h"
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <ostream>
#include "absl/strings/match.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "gtest/gtest.h"
#include "src/dsp/constants.h"
#include "src/dsp/dsp.h"
#include "src/utils/array_2d.h"
#include "src/utils/bit_mask_set.h"
#include "src/utils/common.h"
#include "src/utils/constants.h"
#include "src/utils/cpu.h"
#include "src/utils/memory.h"
#include "tests/block_utils.h"
#include "tests/third_party/libvpx/acm_random.h"
#include "tests/utils.h"
namespace libgav1 {
namespace dsp {
namespace {
constexpr int kMaxBlockSize = 64;
constexpr int kTotalPixels = kMaxBlockSize * kMaxBlockSize;
const char* const kTransform1dSizeNames[kNumTransform1dSizes] = {
"kTransform1dSize4", "kTransform1dSize8", "kTransform1dSize16",
"kTransform1dSize32", "kTransform1dSize64"};
constexpr Transform1dSize kRowTransform1dSizes[] = {
kTransform1dSize4, kTransform1dSize4, kTransform1dSize4,
kTransform1dSize8, kTransform1dSize8, kTransform1dSize8,
kTransform1dSize8, kTransform1dSize16, kTransform1dSize16,
kTransform1dSize16, kTransform1dSize16, kTransform1dSize16,
kTransform1dSize32, kTransform1dSize32, kTransform1dSize32,
kTransform1dSize32, kTransform1dSize64, kTransform1dSize64,
kTransform1dSize64};
constexpr Transform1dSize kColTransform1dSizes[] = {
kTransform1dSize4, kTransform1dSize8, kTransform1dSize16,
kTransform1dSize4, kTransform1dSize8, kTransform1dSize16,
kTransform1dSize32, kTransform1dSize4, kTransform1dSize8,
kTransform1dSize16, kTransform1dSize32, kTransform1dSize64,
kTransform1dSize8, kTransform1dSize16, kTransform1dSize32,
kTransform1dSize64, kTransform1dSize16, kTransform1dSize32,
kTransform1dSize64};
template <int bitdepth, typename SrcPixel, typename DstPixel>
class InverseTransformTestBase : public testing::TestWithParam<TransformSize>,
public test_utils::MaxAlignedAllocable {
public:
static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
InverseTransformTestBase() {
switch (tx_size_) {
case kNumTransformSizes:
EXPECT_NE(tx_size_, kNumTransformSizes);
break;
default:
block_width_ = kTransformWidth[tx_size_];
block_height_ = kTransformHeight[tx_size_];
break;
}
}
InverseTransformTestBase(const InverseTransformTestBase&) = delete;
InverseTransformTestBase& operator=(const InverseTransformTestBase&) = delete;
~InverseTransformTestBase() override = default;
protected:
struct InverseTransformMem {
void Reset(libvpx_test::ACMRandom* rnd, int width, int height) {
ASSERT_NE(rnd, nullptr);
// Limit the size of the residual values to bitdepth + sign in order
// to prevent outranging in the transforms.
const int num_bits = bitdepth + 1;
const int sign_shift = (bitdepth == 8 ? 16 : 32) - num_bits;
const int mask = (1 << num_bits) - 1;
// Fill residual with random data. For widths == 64, only fill the upper
// left 32 x min(block_height_, 32).
memset(ref_src, 0, sizeof(ref_src));
SrcPixel* r = ref_src;
const int stride = width;
for (int y = 0; y < std::min(height, 32); ++y) {
for (int x = 0; x < std::min(width, 32); ++x) {
r[x] = rnd->Rand16() & mask;
// The msb of num_bits is the sign bit, so force each 16 bit value to
// the correct sign.
r[x] = (r[x] << sign_shift) >> sign_shift;
}
r += stride;
}
// Set frame data to random values.
for (int y = 0; y < kMaxBlockSize; ++y) {
for (int x = 0; x < kMaxBlockSize; ++x) {
const int mask = (1 << bitdepth) - 1;
cur_frame[y * kMaxBlockSize + x] = base_frame[y * kMaxBlockSize + x] =
rnd->Rand16() & mask;
}
}
}
// Set ref_src to |pixel|.
void Set(const SrcPixel pixel) {
for (auto& r : ref_src) r = pixel;
}
alignas(kMaxAlignment) DstPixel base_frame[kTotalPixels];
alignas(kMaxAlignment) DstPixel cur_frame[kTotalPixels];
alignas(kMaxAlignment) SrcPixel base_residual[kTotalPixels];
alignas(kMaxAlignment) SrcPixel cur_residual[kTotalPixels];
alignas(kMaxAlignment) SrcPixel ref_src[kTotalPixels];
};
void SetUp() override { test_utils::ResetDspTable(bitdepth); }
const TransformSize tx_size_ = GetParam();
int block_width_;
int block_height_;
InverseTransformMem inverse_transform_mem_;
};
//------------------------------------------------------------------------------
// InverseTransformTest
template <int bitdepth, typename Pixel, typename DstPixel>
class InverseTransformTest
: public InverseTransformTestBase<bitdepth, Pixel, DstPixel> {
public:
static_assert(bitdepth >= kBitdepth8 && bitdepth <= LIBGAV1_MAX_BITDEPTH, "");
InverseTransformTest() = default;
InverseTransformTest(const InverseTransformTest&) = delete;
InverseTransformTest& operator=(const InverseTransformTest&) = delete;
~InverseTransformTest() override = default;
protected:
using InverseTransformTestBase<bitdepth, Pixel, DstPixel>::tx_size_;
using InverseTransformTestBase<bitdepth, Pixel, DstPixel>::block_width_;
using InverseTransformTestBase<bitdepth, Pixel, DstPixel>::block_height_;
using InverseTransformTestBase<bitdepth, Pixel,
DstPixel>::inverse_transform_mem_;
void SetUp() override {
InverseTransformTestBase<bitdepth, Pixel, DstPixel>::SetUp();
InverseTransformInit_C();
const Dsp* const dsp = GetDspTable(bitdepth);
ASSERT_NE(dsp, nullptr);
tx_size_1d_row_ = kRowTransform1dSizes[tx_size_];
tx_size_1d_column_ = kColTransform1dSizes[tx_size_];
memcpy(base_inverse_transforms_, dsp->inverse_transforms,
sizeof(base_inverse_transforms_));
const testing::TestInfo* const test_info =
testing::UnitTest::GetInstance()->current_test_info();
const char* const test_case = test_info->test_suite_name();
if (absl::StartsWith(test_case, "C/")) {
memset(base_inverse_transforms_, 0, sizeof(base_inverse_transforms_));
} else if (absl::StartsWith(test_case, "SSE41/")) {
if ((GetCpuInfo() & kSSE4_1) != 0) {
InverseTransformInit_SSE4_1();
}
} else if (absl::StartsWith(test_case, "NEON/")) {
InverseTransformInit_NEON();
InverseTransformInit10bpp_NEON();
} else {
FAIL() << "Unrecognized architecture prefix in test case name: "
<< test_case;
}
memcpy(cur_inverse_transforms_, dsp->inverse_transforms,
sizeof(cur_inverse_transforms_));
for (int i = 0; i < kNumTransform1ds; ++i) {
// skip functions that haven't been specialized for this particular
// architecture.
if (cur_inverse_transforms_[i][tx_size_1d_row_][kRow] ==
base_inverse_transforms_[i][tx_size_1d_row_][kRow]) {
cur_inverse_transforms_[i][tx_size_1d_row_][kRow] = nullptr;
}
if (cur_inverse_transforms_[i][tx_size_1d_column_][kColumn] ==
base_inverse_transforms_[i][tx_size_1d_column_][kColumn]) {
cur_inverse_transforms_[i][tx_size_1d_column_][kColumn] = nullptr;
}
}
base_frame_buffer_.Reset(kMaxBlockSize, kMaxBlockSize,
inverse_transform_mem_.base_frame);
cur_frame_buffer_.Reset(kMaxBlockSize, kMaxBlockSize,
inverse_transform_mem_.cur_frame);
}
// These tests modify inverse_transform_mem_.
void TestRandomValues(int num_tests);
void TestDcOnlyRandomValue(int num_tests);
Array2DView<DstPixel> base_frame_buffer_;
Array2DView<DstPixel> cur_frame_buffer_;
Transform1dSize tx_size_1d_row_ = kTransform1dSize4;
Transform1dSize tx_size_1d_column_ = kTransform1dSize4;
InverseTransformAddFuncs base_inverse_transforms_;
InverseTransformAddFuncs cur_inverse_transforms_;
};
constexpr TransformType kLibgav1TxType[kNumTransformTypes] = {
kTransformTypeDctDct, kTransformTypeAdstDct,
kTransformTypeDctAdst, kTransformTypeAdstAdst,
kTransformTypeFlipadstDct, kTransformTypeDctFlipadst,
kTransformTypeFlipadstFlipadst, kTransformTypeAdstFlipadst,
kTransformTypeFlipadstAdst, kTransformTypeIdentityIdentity,
kTransformTypeIdentityDct, kTransformTypeDctIdentity,
kTransformTypeIdentityAdst, kTransformTypeAdstIdentity,
kTransformTypeIdentityFlipadst, kTransformTypeFlipadstIdentity};
// Maps TransformType to dsp::Transform1d for the row transforms.
constexpr Transform1d kRowTransform[kNumTransformTypes] = {
kTransform1dDct, kTransform1dAdst, kTransform1dDct,
kTransform1dAdst, kTransform1dAdst, kTransform1dDct,
kTransform1dAdst, kTransform1dAdst, kTransform1dAdst,
kTransform1dIdentity, kTransform1dIdentity, kTransform1dDct,
kTransform1dIdentity, kTransform1dAdst, kTransform1dIdentity,
kTransform1dAdst};
// Maps TransformType to dsp::Transform1d for the column transforms.
constexpr Transform1d kColumnTransform[kNumTransformTypes] = {
kTransform1dDct, kTransform1dDct, kTransform1dAdst,
kTransform1dAdst, kTransform1dDct, kTransform1dAdst,
kTransform1dAdst, kTransform1dAdst, kTransform1dAdst,
kTransform1dIdentity, kTransform1dDct, kTransform1dIdentity,
kTransform1dAdst, kTransform1dIdentity, kTransform1dAdst,
kTransform1dIdentity};
// Mask indicating whether the transform sets contain a particular transform
// type. If |tx_type| is present in |tx_set|, then the |tx_type|th LSB is set.
constexpr BitMaskSet kTransformTypeInSetMask[kNumTransformSets] = {
BitMaskSet(0x1), BitMaskSet(0xE0F), BitMaskSet(0x20F),
BitMaskSet(0xFFFF), BitMaskSet(0xFFF), BitMaskSet(0x201)};
bool IsTxSizeTypeValid(TransformSize tx_size, TransformType tx_type) {
const TransformSize tx_size_square_max = kTransformSizeSquareMax[tx_size];
TransformSet tx_set;
if (tx_size_square_max > kTransformSize32x32) {
tx_set = kTransformSetDctOnly;
} else if (tx_size_square_max == kTransformSize32x32) {
tx_set = kTransformSetInter3;
} else if (tx_size_square_max == kTransformSize16x16) {
tx_set = kTransformSetInter2;
} else {
tx_set = kTransformSetInter1;
}
return kTransformTypeInSetMask[tx_set].Contains(tx_type);
}
template <int bitdepth, typename Pixel, typename DstPixel>
void InverseTransformTest<bitdepth, Pixel, DstPixel>::TestRandomValues(
int num_tests) {
libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
for (int tx_type_idx = -1; tx_type_idx < kNumTransformTypes; ++tx_type_idx) {
const TransformType tx_type = (tx_type_idx == -1)
? kTransformTypeDctDct
: kLibgav1TxType[tx_type_idx];
const Transform1d row_transform =
(tx_type_idx == -1) ? kTransform1dWht : kRowTransform[tx_type];
const Transform1d column_transform =
(tx_type_idx == -1) ? kTransform1dWht : kColumnTransform[tx_type];
// Skip the 'C' test case as this is used as the reference.
if (base_inverse_transforms_[row_transform][tx_size_1d_row_][kRow] ==
nullptr ||
cur_inverse_transforms_[row_transform][tx_size_1d_row_][kRow] ==
nullptr ||
base_inverse_transforms_[column_transform][tx_size_1d_column_]
[kColumn] == nullptr ||
cur_inverse_transforms_[column_transform][tx_size_1d_column_]
[kColumn] == nullptr) {
continue;
}
// Only test valid tx_size for given tx_type. See 5.11.40.
if (!IsTxSizeTypeValid(tx_size_, tx_type)) continue;
absl::Duration base_elapsed_time[2];
absl::Duration cur_elapsed_time[2];
for (int n = 0; n < num_tests; ++n) {
const int tx_height = std::min(block_height_, 32);
const int start_x = 0;
const int start_y = 0;
inverse_transform_mem_.Reset(&rnd, block_width_, block_height_);
memcpy(inverse_transform_mem_.base_residual,
inverse_transform_mem_.ref_src,
sizeof(inverse_transform_mem_.ref_src));
memcpy(inverse_transform_mem_.cur_residual,
inverse_transform_mem_.ref_src,
sizeof(inverse_transform_mem_.ref_src));
const absl::Time base_row_start = absl::Now();
base_inverse_transforms_[row_transform][tx_size_1d_row_][kRow](
tx_type, tx_size_, tx_height, inverse_transform_mem_.base_residual,
start_x, start_y, &base_frame_buffer_);
base_elapsed_time[kRow] += absl::Now() - base_row_start;
const absl::Time cur_row_start = absl::Now();
cur_inverse_transforms_[row_transform][tx_size_1d_row_][kRow](
tx_type, tx_size_, tx_height, inverse_transform_mem_.cur_residual,
start_x, start_y, &cur_frame_buffer_);
cur_elapsed_time[kRow] += absl::Now() - cur_row_start;
const absl::Time base_column_start = absl::Now();
base_inverse_transforms_[column_transform][tx_size_1d_column_][kColumn](
tx_type, tx_size_, tx_height, inverse_transform_mem_.base_residual,
start_x, start_y, &base_frame_buffer_);
base_elapsed_time[kColumn] += absl::Now() - base_column_start;
const absl::Time cur_column_start = absl::Now();
cur_inverse_transforms_[column_transform][tx_size_1d_column_][kColumn](
tx_type, tx_size_, tx_height, inverse_transform_mem_.cur_residual,
start_x, start_y, &cur_frame_buffer_);
cur_elapsed_time[kColumn] += absl::Now() - cur_column_start;
if (!test_utils::CompareBlocks(inverse_transform_mem_.base_frame,
inverse_transform_mem_.cur_frame,
block_width_, block_height_, kMaxBlockSize,
kMaxBlockSize, false)) {
ADD_FAILURE() << "Result from optimized version of "
<< ToString(
static_cast<Transform1dSize>(tx_size_1d_column_))
<< " differs from reference in iteration #" << n
<< " tx_type_idx:" << tx_type_idx;
break;
}
}
if (num_tests > 1) {
const auto base_row_elapsed_time_us =
static_cast<int>(absl::ToInt64Microseconds(base_elapsed_time[kRow]));
const auto cur_row_elapsed_time_us =
static_cast<int>(absl::ToInt64Microseconds(cur_elapsed_time[kRow]));
printf("TxType %30s[%19s]:: base_row: %5d us cur_row: %5d us %2.2fx \n",
(tx_type_idx == -1) ? ToString(row_transform) : ToString(tx_type),
kTransform1dSizeNames[tx_size_1d_row_], base_row_elapsed_time_us,
cur_row_elapsed_time_us,
static_cast<float>(base_row_elapsed_time_us) /
static_cast<float>(cur_row_elapsed_time_us));
const auto base_column_elapsed_time_us = static_cast<int>(
absl::ToInt64Microseconds(base_elapsed_time[kColumn]));
const auto cur_column_elapsed_time_us = static_cast<int>(
absl::ToInt64Microseconds(cur_elapsed_time[kColumn]));
printf(
"TxType %30s[%19s]:: base_col: %5d us cur_col: %5d us %2.2fx \n",
(tx_type_idx == -1) ? ToString(column_transform) : ToString(tx_type),
kTransform1dSizeNames[tx_size_1d_column_],
base_column_elapsed_time_us, cur_column_elapsed_time_us,
static_cast<float>(base_column_elapsed_time_us) /
static_cast<float>(cur_column_elapsed_time_us));
}
}
}
template <int bitdepth, typename Pixel, typename DstPixel>
void InverseTransformTest<bitdepth, Pixel, DstPixel>::TestDcOnlyRandomValue(
int num_tests) {
libvpx_test::ACMRandom rnd(libvpx_test::ACMRandom::DeterministicSeed());
for (int tx_type_idx = 0; tx_type_idx < kNumTransformTypes; ++tx_type_idx) {
const TransformType tx_type = kLibgav1TxType[tx_type_idx];
const Transform1d row_transform = kRowTransform[tx_type];
const Transform1d column_transform = kColumnTransform[tx_type];
if (cur_inverse_transforms_[row_transform][tx_size_1d_row_][kRow] ==
nullptr ||
cur_inverse_transforms_[column_transform][tx_size_1d_column_]
[kColumn] == nullptr) {
continue;
}
// Only test valid tx_size for given tx_type. See 5.11.40.
if (IsTxSizeTypeValid(tx_size_, tx_type) == 0) continue;
absl::Duration base_elapsed_time[2];
absl::Duration cur_elapsed_time[2];
for (int n = 0; n < num_tests; ++n) {
const int tx_height = std::min(block_height_, 32);
const int start_x = 0;
const int start_y = 0;
// Using width == 1 and height == 1 will reset only the dc value.
inverse_transform_mem_.Reset(&rnd, 1, 1);
memcpy(inverse_transform_mem_.base_residual,
inverse_transform_mem_.ref_src,
sizeof(inverse_transform_mem_.ref_src));
memcpy(inverse_transform_mem_.cur_residual,
inverse_transform_mem_.ref_src,
sizeof(inverse_transform_mem_.ref_src));
// For this test, the "base" contains the output when the
// tx_height is set to the max for the given block size. The
// "cur" contains the output when the passed in tx_height is 1.
// Compare the outputs for match.
const absl::Time base_row_start = absl::Now();
cur_inverse_transforms_[row_transform][tx_size_1d_row_][kRow](
tx_type, tx_size_, tx_height, inverse_transform_mem_.base_residual,
start_x, start_y, &base_frame_buffer_);
base_elapsed_time[kRow] += absl::Now() - base_row_start;
const absl::Time cur_row_start = absl::Now();
cur_inverse_transforms_[row_transform][tx_size_1d_row_][kRow](
tx_type, tx_size_, /*adjusted_tx_height=*/1,
inverse_transform_mem_.cur_residual, start_x, start_y,
&cur_frame_buffer_);
cur_elapsed_time[kRow] += absl::Now() - cur_row_start;
const absl::Time base_column_start = absl::Now();
cur_inverse_transforms_[column_transform][tx_size_1d_column_][kColumn](
tx_type, tx_size_, tx_height, inverse_transform_mem_.base_residual,
start_x, start_y, &base_frame_buffer_);
base_elapsed_time[kColumn] += absl::Now() - base_column_start;
const absl::Time cur_column_start = absl::Now();
cur_inverse_transforms_[column_transform][tx_size_1d_column_][kColumn](
tx_type, tx_size_, /*adjusted_tx_height=*/1,
inverse_transform_mem_.cur_residual, start_x, start_y,
&cur_frame_buffer_);
cur_elapsed_time[kColumn] += absl::Now() - cur_column_start;
if (!test_utils::CompareBlocks(inverse_transform_mem_.base_frame,
inverse_transform_mem_.cur_frame,
block_width_, block_height_, kMaxBlockSize,
kMaxBlockSize, false)) {
ADD_FAILURE() << "Result from dc only version of "
<< ToString(
static_cast<Transform1dSize>(tx_size_1d_column_))
<< " differs from reference in iteration #" << n
<< "tx_type_idx:" << tx_type_idx;
break;
}
}
if (num_tests > 1) {
const auto base_row_elapsed_time_us =
static_cast<int>(absl::ToInt64Microseconds(base_elapsed_time[kRow]));
const auto cur_row_elapsed_time_us =
static_cast<int>(absl::ToInt64Microseconds(cur_elapsed_time[kRow]));
printf("TxType %30s[%19s]:: base_row: %5d us cur_row: %5d us %2.2fx \n",
ToString(tx_type), kTransform1dSizeNames[tx_size_1d_row_],
base_row_elapsed_time_us, cur_row_elapsed_time_us,
static_cast<float>(base_row_elapsed_time_us) /
static_cast<float>(cur_row_elapsed_time_us));
const auto base_column_elapsed_time_us = static_cast<int>(
absl::ToInt64Microseconds(base_elapsed_time[kColumn]));
const auto cur_column_elapsed_time_us = static_cast<int>(
absl::ToInt64Microseconds(cur_elapsed_time[kColumn]));
printf("TxType %30s[%19s]:: base_col: %5d us cur_col: %5d us %2.2fx \n",
ToString(tx_type), kTransform1dSizeNames[tx_size_1d_column_],
base_column_elapsed_time_us, cur_column_elapsed_time_us,
static_cast<float>(base_column_elapsed_time_us) /
static_cast<float>(cur_column_elapsed_time_us));
}
}
}
using InverseTransformTest8bpp = InverseTransformTest<8, int16_t, uint8_t>;
TEST_P(InverseTransformTest8bpp, Random) { TestRandomValues(1); }
TEST_P(InverseTransformTest8bpp, DISABLED_Speed) { TestRandomValues(10000); }
TEST_P(InverseTransformTest8bpp, DcRandom) { TestDcOnlyRandomValue(1); }
constexpr TransformSize kTransformSizesAll[] = {
kTransformSize4x4, kTransformSize4x8, kTransformSize4x16,
kTransformSize8x4, kTransformSize8x8, kTransformSize8x16,
kTransformSize8x32, kTransformSize16x4, kTransformSize16x8,
kTransformSize16x16, kTransformSize16x32, kTransformSize16x64,
kTransformSize32x8, kTransformSize32x16, kTransformSize32x32,
kTransformSize32x64, kTransformSize64x16, kTransformSize64x32,
kTransformSize64x64};
INSTANTIATE_TEST_SUITE_P(C, InverseTransformTest8bpp,
testing::ValuesIn(kTransformSizesAll));
#if LIBGAV1_ENABLE_NEON
INSTANTIATE_TEST_SUITE_P(NEON, InverseTransformTest8bpp,
testing::ValuesIn(kTransformSizesAll));
#endif
#if LIBGAV1_ENABLE_SSE4_1
INSTANTIATE_TEST_SUITE_P(SSE41, InverseTransformTest8bpp,
testing::ValuesIn(kTransformSizesAll));
#endif
#if LIBGAV1_MAX_BITDEPTH >= 10
using InverseTransformTest10bpp = InverseTransformTest<10, int32_t, uint16_t>;
TEST_P(InverseTransformTest10bpp, Random) { TestRandomValues(1); }
TEST_P(InverseTransformTest10bpp, DISABLED_Speed) { TestRandomValues(10000); }
TEST_P(InverseTransformTest10bpp, DcRandom) { TestDcOnlyRandomValue(1); }
INSTANTIATE_TEST_SUITE_P(C, InverseTransformTest10bpp,
testing::ValuesIn(kTransformSizesAll));
#if LIBGAV1_ENABLE_NEON
INSTANTIATE_TEST_SUITE_P(NEON, InverseTransformTest10bpp,
testing::ValuesIn(kTransformSizesAll));
#endif
#endif // LIBGAV1_MAX_BITDEPTH >= 10
#if LIBGAV1_MAX_BITDEPTH == 12
using InverseTransformTest12bpp = InverseTransformTest<12, int32_t, uint16_t>;
TEST_P(InverseTransformTest12bpp, Random) { TestRandomValues(1); }
TEST_P(InverseTransformTest12bpp, DISABLED_Speed) { TestRandomValues(12000); }
TEST_P(InverseTransformTest12bpp, DcRandom) { TestDcOnlyRandomValue(1); }
INSTANTIATE_TEST_SUITE_P(C, InverseTransformTest12bpp,
testing::ValuesIn(kTransformSizesAll));
#endif // LIBGAV1_MAX_BITDEPTH == 12
} // namespace
} // namespace dsp
static std::ostream& operator<<(std::ostream& os, const TransformSize param) {
return os << ToString(param);
}
} // namespace libgav1