diff --git a/test/buffer.h b/test/buffer.h new file mode 100644 index 000000000..7819bc494 --- /dev/null +++ b/test/buffer.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2016 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_BUFFER_H_ +#define TEST_BUFFER_H_ + +#include + +#include + +#include "third_party/googletest/src/include/gtest/gtest.h" + +#include "vpx/vpx_integer.h" + +namespace libvpx_test { + +template +class Buffer { + public: + Buffer(int width, int height, int top_padding, int left_padding, + int right_padding, int bottom_padding) + : width_(width), height_(height), top_padding_(top_padding), + left_padding_(left_padding), right_padding_(right_padding), + bottom_padding_(bottom_padding) { + Init(); + } + + Buffer(int width, int height, int padding) + : width_(width), height_(height), top_padding_(padding), + left_padding_(padding), right_padding_(padding), + bottom_padding_(padding) { + Init(); + } + + ~Buffer() { delete[] raw_buffer_; } + + T *TopLeftPixel() const; + + int stride() const { return stride_; } + + // Set the buffer (excluding padding) to 'value'. + void Set(const int value); + + void DumpBuffer() const; + + bool HasPadding() const; + + // Sets all the values in the buffer to 'padding_value'. + void SetPadding(const int padding_value); + + // Checks if all the values (excluding padding) are equal to 'value'. + bool CheckValues(const int value) const; + + // Check that padding matches the expected value or there is no padding. + bool CheckPadding() const; + + private: + void Init() { + ASSERT_GT(width_, 0); + ASSERT_GT(height_, 0); + ASSERT_GE(top_padding_, 0); + ASSERT_GE(left_padding_, 0); + ASSERT_GE(right_padding_, 0); + ASSERT_GE(bottom_padding_, 0); + stride_ = left_padding_ + width_ + right_padding_; + raw_size_ = stride_ * (top_padding_ + height_ + bottom_padding_); + raw_buffer_ = new (std::nothrow) T[raw_size_]; + ASSERT_TRUE(raw_buffer_ != NULL); + SetPadding(std::numeric_limits::max()); + } + + const int width_; + const int height_; + const int top_padding_; + const int left_padding_; + const int right_padding_; + const int bottom_padding_; + int padding_value_; + int stride_; + int raw_size_; + T *raw_buffer_; +}; + +template +T *Buffer::TopLeftPixel() const { + return raw_buffer_ + (top_padding_ * stride()) + left_padding_; +} + +template +void Buffer::Set(const int value) { + T *src = TopLeftPixel(); + for (int height = 0; height < height_; ++height) { + for (int width = 0; width < width_; ++width) { + src[width] = value; + } + src += stride(); + } +} + +template +void Buffer::DumpBuffer() const { + for (int height = 0; height < height_ + top_padding_ + bottom_padding_; + ++height) { + for (int width = 0; width < stride(); ++width) { + printf("%4d", raw_buffer_[height + width * stride()]); + } + printf("\n"); + } +} + +template +bool Buffer::HasPadding() const { + return top_padding_ || left_padding_ || right_padding_ || bottom_padding_; +} + +template +void Buffer::SetPadding(const int padding_value) { + padding_value_ = padding_value; + + T *src = raw_buffer_; + for (int i = 0; i < raw_size_; ++i) { + src[i] = padding_value; + } +} + +template +bool Buffer::CheckValues(const int value) const { + T *src = TopLeftPixel(); + for (int height = 0; height < height_; ++height) { + for (int width = 0; width < width_; ++width) { + if (value != src[width]) { + return false; + } + } + src += stride(); + } + return true; +} + +template +bool Buffer::CheckPadding() const { + if (!HasPadding()) { + return true; + } + + // Top padding. + T const *top = raw_buffer_; + for (int i = 0; i < stride() * top_padding_; ++i) { + if (padding_value_ != top[i]) { + return false; + } + } + + // Left padding. + T const *left = TopLeftPixel() - left_padding_; + for (int height = 0; height < height_; ++height) { + for (int width = 0; width < left_padding_; ++width) { + if (padding_value_ != left[width]) { + return false; + } + } + left += stride(); + } + + // Right padding. + T const *right = TopLeftPixel() + width_; + for (int height = 0; height < height_; ++height) { + for (int width = 0; width < right_padding_; ++width) { + if (padding_value_ != right[width]) { + return false; + } + } + right += stride(); + } + + // Bottom padding + T const *bottom = raw_buffer_ + (top_padding_ + height_) * stride(); + for (int i = 0; i < stride() * bottom_padding_; ++i) { + if (padding_value_ != bottom[i]) { + return false; + } + } + + return true; +} +} // namespace libvpx_test +#endif // TEST_BUFFER_H_ diff --git a/test/idct_test.cc b/test/idct_test.cc index 700da77e3..084b2ed0c 100644 --- a/test/idct_test.cc +++ b/test/idct_test.cc @@ -13,6 +13,7 @@ #include "third_party/googletest/src/include/gtest/gtest.h" +#include "test/buffer.h" #include "test/clear_system_state.h" #include "test/register_state_check.h" #include "vpx/vpx_integer.h" @@ -21,110 +22,148 @@ typedef void (*IdctFunc)(int16_t *input, unsigned char *pred_ptr, int pred_stride, unsigned char *dst_ptr, int dst_stride); namespace { + +using libvpx_test::Buffer; + class IDCTTest : public ::testing::TestWithParam { protected: virtual void SetUp() { - int i; - UUT = GetParam(); - memset(input, 0, sizeof(input)); - /* Set up guard blocks */ - for (i = 0; i < 256; i++) output[i] = ((i & 0xF) < 4 && (i < 64)) ? 0 : -1; + + input = new (std::nothrow) Buffer(4, 4, 0); + ASSERT_TRUE(input != NULL); + predict = new (std::nothrow) Buffer(4, 4, 3); + ASSERT_TRUE(predict != NULL); + output = new (std::nothrow) Buffer(4, 4, 3); + ASSERT_TRUE(output != NULL); } - virtual void TearDown() { libvpx_test::ClearSystemState(); } + virtual void TearDown() { + delete input; + delete predict; + delete output; + libvpx_test::ClearSystemState(); + } IdctFunc UUT; - int16_t input[16]; - unsigned char output[256]; - unsigned char predict[256]; + Buffer *input; + Buffer *predict; + Buffer *output; }; -TEST_P(IDCTTest, TestGuardBlocks) { - int i; - - for (i = 0; i < 256; i++) { - if ((i & 0xF) < 4 && i < 64) - EXPECT_EQ(0, output[i]) << i; - else - EXPECT_EQ(255, output[i]); - } -} - TEST_P(IDCTTest, TestAllZeros) { - int i; + // When the input is '0' the output will be '0'. + input->Set(0); + predict->Set(0); + output->Set(0); - ASM_REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16)); + ASM_REGISTER_STATE_CHECK(UUT(input->TopLeftPixel(), predict->TopLeftPixel(), + predict->stride(), output->TopLeftPixel(), + output->stride())); - for (i = 0; i < 256; i++) { - if ((i & 0xF) < 4 && i < 64) - EXPECT_EQ(0, output[i]) << "i==" << i; - else - EXPECT_EQ(255, output[i]) << "i==" << i; - } + ASSERT_TRUE(input->CheckValues(0)); + ASSERT_TRUE(input->CheckPadding()); + ASSERT_TRUE(output->CheckValues(0)); + ASSERT_TRUE(output->CheckPadding()); } TEST_P(IDCTTest, TestAllOnes) { - int i; + input->Set(0); + // When the first element is '4' it will fill the output buffer with '1'. + input->TopLeftPixel()[0] = 4; + predict->Set(0); + output->Set(0); - input[0] = 4; - ASM_REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16)); + ASM_REGISTER_STATE_CHECK(UUT(input->TopLeftPixel(), predict->TopLeftPixel(), + predict->stride(), output->TopLeftPixel(), + output->stride())); - for (i = 0; i < 256; i++) { - if ((i & 0xF) < 4 && i < 64) - EXPECT_EQ(1, output[i]) << "i==" << i; - else - EXPECT_EQ(255, output[i]) << "i==" << i; - } + ASSERT_TRUE(output->CheckValues(1)); + ASSERT_TRUE(output->CheckPadding()); } TEST_P(IDCTTest, TestAddOne) { - int i; + // Set the transform output to '1' and make sure it gets added to the + // prediction buffer. + input->Set(0); + input->TopLeftPixel()[0] = 4; + output->Set(0); - for (i = 0; i < 256; i++) predict[i] = i; - input[0] = 4; - ASM_REGISTER_STATE_CHECK(UUT(input, predict, 16, output, 16)); - - for (i = 0; i < 256; i++) { - if ((i & 0xF) < 4 && i < 64) - EXPECT_EQ(i + 1, output[i]) << "i==" << i; - else - EXPECT_EQ(255, output[i]) << "i==" << i; + uint8_t *pred = predict->TopLeftPixel(); + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + pred[y * predict->stride() + x] = y * 4 + x; + } } + + ASM_REGISTER_STATE_CHECK(UUT(input->TopLeftPixel(), predict->TopLeftPixel(), + predict->stride(), output->TopLeftPixel(), + output->stride())); + + uint8_t const *out = output->TopLeftPixel(); + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + EXPECT_EQ(1 + y * 4 + x, out[y * output->stride() + x]); + } + } + + if (HasFailure()) { + output->DumpBuffer(); + } + + ASSERT_TRUE(output->CheckPadding()); } TEST_P(IDCTTest, TestWithData) { - int i; + // Test a single known input. + predict->Set(0); - for (i = 0; i < 16; i++) input[i] = i; - - ASM_REGISTER_STATE_CHECK(UUT(input, output, 16, output, 16)); - - for (i = 0; i < 256; i++) { - if ((i & 0xF) > 3 || i > 63) - EXPECT_EQ(255, output[i]) << "i==" << i; - else if (i == 0) - EXPECT_EQ(11, output[i]) << "i==" << i; - else if (i == 34) - EXPECT_EQ(1, output[i]) << "i==" << i; - else if (i == 2 || i == 17 || i == 32) - EXPECT_EQ(3, output[i]) << "i==" << i; - else - EXPECT_EQ(0, output[i]) << "i==" << i; + int16_t *in = input->TopLeftPixel(); + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + in[y * input->stride() + x] = y * 4 + x; + } } + + ASM_REGISTER_STATE_CHECK(UUT(input->TopLeftPixel(), predict->TopLeftPixel(), + predict->stride(), output->TopLeftPixel(), + output->stride())); + + uint8_t *out = output->TopLeftPixel(); + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + switch (y * 4 + x) { + case 0: EXPECT_EQ(11, out[y * output->stride() + x]); break; + case 2: + case 5: + case 8: EXPECT_EQ(3, out[y * output->stride() + x]); break; + case 10: EXPECT_EQ(1, out[y * output->stride() + x]); break; + default: EXPECT_EQ(0, out[y * output->stride() + x]); + } + } + } + + if (HasFailure()) { + output->DumpBuffer(); + } + + ASSERT_TRUE(output->CheckPadding()); } INSTANTIATE_TEST_CASE_P(C, IDCTTest, ::testing::Values(vp8_short_idct4x4llm_c)); + #if HAVE_NEON INSTANTIATE_TEST_CASE_P(NEON, IDCTTest, ::testing::Values(vp8_short_idct4x4llm_neon)); -#endif +#endif // HAVE_NEON + #if HAVE_MMX INSTANTIATE_TEST_CASE_P(MMX, IDCTTest, ::testing::Values(vp8_short_idct4x4llm_mmx)); -#endif +#endif // HAVE_MMX + #if HAVE_MSA INSTANTIATE_TEST_CASE_P(MSA, IDCTTest, ::testing::Values(vp8_short_idct4x4llm_msa)); -#endif +#endif // HAVE_MSA } diff --git a/test/test.mk b/test/test.mk index e25463e46..c5ed65385 100644 --- a/test/test.mk +++ b/test/test.mk @@ -1,4 +1,5 @@ LIBVPX_TEST_SRCS-yes += acm_random.h +LIBVPX_TEST_SRCS-yes += buffer.h LIBVPX_TEST_SRCS-yes += clear_system_state.h LIBVPX_TEST_SRCS-yes += codec_factory.h LIBVPX_TEST_SRCS-yes += md5_helper.h