Skip to content

Commit

Permalink
Speed avifrgbtoyuvtest up
Browse files Browse the repository at this point in the history
Split it into avifrgbtoyuvthreadingtest.
  • Loading branch information
y-guyon committed Feb 13, 2024
1 parent 72632ca commit 3756e83
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 848 deletions.
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ if(AVIF_ENABLE_GTEST)
add_avif_gtest_with_data(avifreadimagetest)
add_avif_internal_gtest(avifrgbtest)
add_avif_gtest(avifrgbtoyuvtest)
add_avif_gtest(avifrgbtoyuvthreadingtest)
add_avif_gtest_with_data(avifscaletest)
add_avif_internal_gtest(avifstreamtest)
add_avif_internal_gtest(aviftilingtest)
Expand Down
182 changes: 48 additions & 134 deletions tests/gtest/avifrgbtoyuvtest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ INSTANTIATE_TEST_SUITE_P(
// bring any loss in the roundtrip.
INSTANTIATE_TEST_SUITE_P(Identity8b, RGBToYUVTest,
Combine(/*rgb_depth=*/Values(8),
/*yuv_depth=*/Values(8, 10, 12, 16),
/*yuv_depth=*/Values(8, 12, 16),
Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV444),
Values(AVIF_RANGE_FULL),
Expand Down Expand Up @@ -531,8 +531,7 @@ INSTANTIATE_TEST_SUITE_P(
Combine(
/*rgb_depth=*/Values(8),
/*yuv_depth=*/Values(8), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422,
AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_FULL), Values(kMatrixCoefficientsBT601),
Values(AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC),
/*add_noise=*/Values(false),
Expand All @@ -546,7 +545,7 @@ INSTANTIATE_TEST_SUITE_P(
// depth should be lossless.
INSTANTIATE_TEST_SUITE_P(MonochromeLossless8b, RGBToYUVTest,
Combine(/*rgb_depth=*/Values(8),
/*yuv_depth=*/Values(8, 10, 12, 16),
/*yuv_depth=*/Values(8),
Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV400),
Values(AVIF_RANGE_FULL),
Expand All @@ -558,7 +557,7 @@ INSTANTIATE_TEST_SUITE_P(MonochromeLossless8b, RGBToYUVTest,
/*min_psnr=*/Values(99.)));
INSTANTIATE_TEST_SUITE_P(MonochromeLossless10b, RGBToYUVTest,
Combine(/*rgb_depth=*/Values(10),
/*yuv_depth=*/Values(10, 12, 16),
/*yuv_depth=*/Values(10),
Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV400),
Values(AVIF_RANGE_FULL),
Expand All @@ -570,7 +569,7 @@ INSTANTIATE_TEST_SUITE_P(MonochromeLossless10b, RGBToYUVTest,
/*min_psnr=*/Values(99.)));
INSTANTIATE_TEST_SUITE_P(MonochromeLossless12b, RGBToYUVTest,
Combine(/*rgb_depth=*/Values(12),
/*yuv_depth=*/Values(12, 16),
/*yuv_depth=*/Values(12),
Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV400),
Values(AVIF_RANGE_FULL),
Expand Down Expand Up @@ -599,8 +598,36 @@ INSTANTIATE_TEST_SUITE_P(
Combine(
/*rgb_depth=*/Values(8),
/*yuv_depth=*/Values(8, 10, 12), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV420), Values(AVIF_RANGE_FULL),
Values(kMatrixCoefficientsBT601),
Values(AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV),
/*add_noise=*/Values(true),
/*rgb_step=*/Values(17),
/*max_abs_average_diff=*/Values(1.2), // Sharp YUV introduces some
// color shift.
/*min_psnr=*/Values(34.) // SharpYuv distortion is acceptable.
));
INSTANTIATE_TEST_SUITE_P(
SharpYuv8BitRanges, RGBToYUVTest,
Combine(
/*rgb_depth=*/Values(8),
/*yuv_depth=*/Values(8), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_LIMITED, AVIF_RANGE_FULL),
Values(kMatrixCoefficientsBT601),
Values(AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV),
/*add_noise=*/Values(true),
/*rgb_step=*/Values(17),
/*max_abs_average_diff=*/Values(1.2), // Sharp YUV introduces some
// color shift.
/*min_psnr=*/Values(34.) // SharpYuv distortion is acceptable.
));
INSTANTIATE_TEST_SUITE_P(
SharpYuv8BitMatrixCoefficients, RGBToYUVTest,
Combine(
/*rgb_depth=*/Values(8),
/*yuv_depth=*/Values(8), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV420), Values(AVIF_RANGE_FULL),
Values(kMatrixCoefficientsBT601, kMatrixCoefficientsBT709),
Values(AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV),
/*add_noise=*/Values(true),
Expand All @@ -613,9 +640,8 @@ INSTANTIATE_TEST_SUITE_P(
SharpYuv10Bit, RGBToYUVTest,
Combine(
/*rgb_depth=*/Values(10),
/*yuv_depth=*/Values(8, 10, 12), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_LIMITED, AVIF_RANGE_FULL),
/*yuv_depth=*/Values(10), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV420), Values(AVIF_RANGE_FULL),
Values(kMatrixCoefficientsBT601),
Values(AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV),
/*add_noise=*/Values(true),
Expand All @@ -629,8 +655,7 @@ INSTANTIATE_TEST_SUITE_P(
Combine(
/*rgb_depth=*/Values(12),
/*yuv_depth=*/Values(8, 10, 12), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_LIMITED, AVIF_RANGE_FULL),
Values(AVIF_PIXEL_FORMAT_YUV420), Values(AVIF_RANGE_FULL),
Values(kMatrixCoefficientsBT601),
Values(AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV),
/*add_noise=*/Values(true),
Expand All @@ -645,8 +670,7 @@ INSTANTIATE_TEST_SUITE_P(
/*rgb_depth=*/Values(16),
// TODO(yguyon): Why max_abs_average_diff>28 if RGB16 to YUV10 full rng?
/*yuv_depth=*/Values(8, /*10,*/ 12), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_LIMITED, AVIF_RANGE_FULL),
Values(AVIF_PIXEL_FORMAT_YUV420), Values(AVIF_RANGE_FULL),
Values(kMatrixCoefficientsBT601),
Values(AVIF_CHROMA_DOWNSAMPLING_SHARP_YUV),
/*add_noise=*/Values(true),
Expand All @@ -659,14 +683,13 @@ INSTANTIATE_TEST_SUITE_P(
// Can be used to print the drift of all RGB to YUV conversion possibilities.
// Also used for coverage.
INSTANTIATE_TEST_SUITE_P(
All8b, RGBToYUVTest,
All8bTo8b, RGBToYUVTest,
Combine(/*rgb_depth=*/Values(8),
/*yuv_depth=*/Values(8, 10, 12, 16),
/*yuv_depth=*/Values(8),
Values(AVIF_RGB_FORMAT_RGBA, AVIF_RGB_FORMAT_BGR),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422,
AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_LIMITED, AVIF_RANGE_FULL),
Values(kMatrixCoefficientsBT601),
Values(AVIF_RANGE_LIMITED), Values(kMatrixCoefficientsBT601),
Values(AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC),
/*add_noise=*/Bool(),
/*rgb_step=*/Values(61), // High or it would be too slow.
Expand All @@ -676,11 +699,9 @@ INSTANTIATE_TEST_SUITE_P(
INSTANTIATE_TEST_SUITE_P(
All10b, RGBToYUVTest,
Combine(/*rgb_depth=*/Values(10),
/*yuv_depth=*/Values(8, 10, 12, 16), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422,
AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_LIMITED, AVIF_RANGE_FULL),
Values(kMatrixCoefficientsBT601),
/*yuv_depth=*/Values(10), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_FULL), Values(kMatrixCoefficientsBT601),
Values(AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC),
/*add_noise=*/Bool(),
/*rgb_step=*/Values(211), // High or it would be too slow.
Expand All @@ -690,11 +711,9 @@ INSTANTIATE_TEST_SUITE_P(
INSTANTIATE_TEST_SUITE_P(
All12b, RGBToYUVTest,
Combine(/*rgb_depth=*/Values(12),
/*yuv_depth=*/Values(8, 10, 12, 16), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422,
AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_LIMITED, AVIF_RANGE_FULL),
Values(kMatrixCoefficientsBT601),
/*yuv_depth=*/Values(12), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_LIMITED), Values(kMatrixCoefficientsBT601),
Values(AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC),
/*add_noise=*/Bool(),
/*rgb_step=*/Values(809), // High or it would be too slow.
Expand All @@ -705,10 +724,8 @@ INSTANTIATE_TEST_SUITE_P(
All16b, RGBToYUVTest,
Combine(/*rgb_depth=*/Values(16),
/*yuv_depth=*/Values(16), Values(AVIF_RGB_FORMAT_RGBA),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV422,
AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_LIMITED, AVIF_RANGE_FULL),
Values(kMatrixCoefficientsBT601),
Values(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_YUV420),
Values(AVIF_RANGE_FULL), Values(kMatrixCoefficientsBT601),
Values(AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC),
/*add_noise=*/Bool(),
/*rgb_step=*/Values(16001), // High or it would be too slow.
Expand All @@ -731,108 +748,5 @@ INSTANTIATE_TEST_SUITE_P(
/*max_abs_average_diff=*/Values(10.),
/*min_psnr=*/Values(10.)));

// Converts YUV pixels to RGB using one thread and multiple threads and checks
// whether the results of both are identical.
class YUVToRGBThreadingTest
: public testing::TestWithParam<std::tuple<
/*rgb_depth=*/int, /*yuv_depth=*/int,
/*width=*/int, /*height=*/int, avifRGBFormat, avifPixelFormat,
/*threads=*/int, /*avoidLibYUV=*/bool, avifChromaUpsampling,
/*has_alpha=*/bool>> {};

TEST_P(YUVToRGBThreadingTest, TestIdentical) {
const int rgb_depth = std::get<0>(GetParam());
const int yuv_depth = std::get<1>(GetParam());
const int width = std::get<2>(GetParam());
const int height = std::get<3>(GetParam());
const avifRGBFormat rgb_format = std::get<4>(GetParam());
const avifPixelFormat yuv_format = std::get<5>(GetParam());
const int maxThreads = std::get<6>(GetParam());
const bool avoidLibYUV = std::get<7>(GetParam());
const avifChromaUpsampling chromaUpsampling = std::get<8>(GetParam());
const bool has_alpha = std::get<9>(GetParam());

if (rgb_depth > 8 && rgb_format == AVIF_RGB_FORMAT_RGB_565) {
return;
}

ImagePtr yuv(avifImageCreate(width, height, yuv_depth, yuv_format));
ASSERT_NE(yuv, nullptr);
yuv->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
yuv->yuvRange = AVIF_RANGE_FULL;

// Fill YUVA planes with random values.
srand(0xAABBCCDD);
const int yuv_max = (1 << yuv_depth);
ASSERT_EQ(avifImageAllocatePlanes(
yuv.get(), has_alpha ? AVIF_PLANES_ALL : AVIF_PLANES_YUV),
AVIF_RESULT_OK);
for (int plane = AVIF_CHAN_Y; plane <= AVIF_CHAN_A; ++plane) {
const uint32_t plane_width = avifImagePlaneWidth(yuv.get(), plane);
if (plane_width == 0) continue;
const uint32_t plane_height = avifImagePlaneHeight(yuv.get(), plane);
const uint32_t rowBytes = avifImagePlaneRowBytes(yuv.get(), plane);
uint8_t* row = avifImagePlane(yuv.get(), plane);
for (uint32_t y = 0; y < plane_height; ++y, row += rowBytes) {
for (uint32_t x = 0; x < plane_width; ++x) {
if (yuv_depth == 8) {
row[x] = (uint8_t)(rand() % yuv_max);
} else {
((uint16_t*)row)[x] = (uint16_t)(rand() % yuv_max);
}
}
}
}

// Convert to RGB with 1 thread.
testutil::AvifRgbImage rgb(yuv.get(), rgb_depth, rgb_format);
rgb.avoidLibYUV = avoidLibYUV;
rgb.chromaUpsampling = chromaUpsampling;
ASSERT_EQ(avifImageYUVToRGB(yuv.get(), &rgb), AVIF_RESULT_OK);

// Convert to RGB with multiple threads.
testutil::AvifRgbImage rgb_threaded(yuv.get(), rgb_depth, rgb_format);
rgb_threaded.avoidLibYUV = avoidLibYUV;
rgb_threaded.chromaUpsampling = chromaUpsampling;
rgb_threaded.maxThreads = maxThreads;
ASSERT_EQ(avifImageYUVToRGB(yuv.get(), &rgb_threaded), AVIF_RESULT_OK);

EXPECT_TRUE(testutil::AreImagesEqual(rgb, rgb_threaded));
}

INSTANTIATE_TEST_SUITE_P(
YUVToRGBThreadingTestInstance, YUVToRGBThreadingTest,
Combine(/*rgb_depth=*/Values(8, 16),
/*yuv_depth=*/Values(8, 10),
/*width=*/Values(1, 2, 127, 200),
/*height=*/Values(1, 2, 127, 200),
Values(AVIF_RGB_FORMAT_RGB, AVIF_RGB_FORMAT_RGBA),
Range(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_COUNT),
// Test an odd and even number for threads. Not adding all possible
// thread values to keep the number of test instances low.
/*threads=*/Values(2, 7),
/*avoidLibYUV=*/Bool(),
Values(AVIF_CHROMA_UPSAMPLING_FASTEST,
AVIF_CHROMA_UPSAMPLING_BILINEAR),
/*has_alpha=*/Bool()));

// This will generate a large number of test instances and hence it is disabled
// by default. It can be run manually if necessary.
INSTANTIATE_TEST_SUITE_P(
DISABLED_ExhaustiveYUVToRGBThreadingTestInstance, YUVToRGBThreadingTest,
Combine(/*rgb_depth=*/Values(8, 10, 12, 16),
/*yuv_depth=*/Values(8, 10, 12),
/*width=*/Values(1, 2, 127, 200),
/*height=*/Values(1, 2, 127, 200),
Range(AVIF_RGB_FORMAT_RGB, AVIF_RGB_FORMAT_COUNT),
Range(AVIF_PIXEL_FORMAT_YUV444, AVIF_PIXEL_FORMAT_COUNT),
/*threads=*/Range(0, 9),
/*avoidLibYUV=*/Bool(),
Values(AVIF_CHROMA_UPSAMPLING_AUTOMATIC,
AVIF_CHROMA_UPSAMPLING_FASTEST,
AVIF_CHROMA_UPSAMPLING_NEAREST,
AVIF_CHROMA_UPSAMPLING_BILINEAR),
/*has_alpha=*/Bool()));

} // namespace
} // namespace avif
Loading

0 comments on commit 3756e83

Please sign in to comment.