diff options
Diffstat (limited to '')
-rw-r--r-- | image/test/gtest/TestDecodersPerf.cpp | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/image/test/gtest/TestDecodersPerf.cpp b/image/test/gtest/TestDecodersPerf.cpp new file mode 100644 index 0000000000..e9ada6ded9 --- /dev/null +++ b/image/test/gtest/TestDecodersPerf.cpp @@ -0,0 +1,159 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "gtest/gtest.h" +#include "gtest/MozGTestBench.h" + +#include "Common.h" +#include "Decoder.h" +#include "DecoderFactory.h" +#include "IDecodingTask.h" +#include "mozilla/RefPtr.h" +#include "ProgressTracker.h" +#include "SourceBuffer.h" + +using namespace mozilla; +using namespace mozilla::gfx; +using namespace mozilla::image; + +namespace { + +static void CheckDecoderState(const ImageTestCase& aTestCase, + image::Decoder* aDecoder, + const IntSize& aOutputSize) { + // image::Decoder should match what we asked for in the MIME type. + EXPECT_NE(aDecoder->GetType(), DecoderType::UNKNOWN); + EXPECT_EQ(aDecoder->GetType(), + DecoderFactory::GetDecoderType(aTestCase.mMimeType)); + + EXPECT_TRUE(aDecoder->GetDecodeDone()); + EXPECT_FALSE(aDecoder->HasError()); + + // Verify that the decoder made the expected progress. + Progress progress = aDecoder->TakeProgress(); + EXPECT_FALSE(bool(progress & FLAG_HAS_ERROR)); + EXPECT_FALSE(bool(aTestCase.mFlags & TEST_CASE_HAS_ERROR)); + + EXPECT_TRUE(bool(progress & FLAG_SIZE_AVAILABLE)); + EXPECT_TRUE(bool(progress & FLAG_DECODE_COMPLETE)); + EXPECT_TRUE(bool(progress & FLAG_FRAME_COMPLETE)); + EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_TRANSPARENT), + bool(progress & FLAG_HAS_TRANSPARENCY)); + EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_ANIMATED), + bool(progress & FLAG_IS_ANIMATED)); + + // The decoder should get the correct size. + IntSize size = aDecoder->Size(); + EXPECT_EQ(aTestCase.mSize.width, size.width); + EXPECT_EQ(aTestCase.mSize.height, size.height); + + // Get the current frame, which is always the first frame of the image + // because CreateAnonymousDecoder() forces a first-frame-only decode. + RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef(); + RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface(); + + // Verify that the resulting surfaces matches our expectations. + EXPECT_TRUE(surface->IsDataSourceSurface()); + EXPECT_TRUE(surface->GetFormat() == SurfaceFormat::OS_RGBX || + surface->GetFormat() == SurfaceFormat::OS_RGBA); + EXPECT_EQ(aOutputSize, surface->GetSize()); +} + +template <typename Func> +static void WithSingleChunkDecode(const ImageTestCase& aTestCase, + SourceBuffer* aSourceBuffer, + const Maybe<IntSize>& aOutputSize, + Func aResultChecker) { + auto sourceBuffer = WrapNotNull(RefPtr<SourceBuffer>(aSourceBuffer)); + + // Create a decoder. + DecoderType decoderType = DecoderFactory::GetDecoderType(aTestCase.mMimeType); + RefPtr<image::Decoder> decoder = DecoderFactory::CreateAnonymousDecoder( + decoderType, sourceBuffer, aOutputSize, DecoderFlags::FIRST_FRAME_ONLY, + aTestCase.mSurfaceFlags); + ASSERT_TRUE(decoder != nullptr); + RefPtr<IDecodingTask> task = + new AnonymousDecodingTask(WrapNotNull(decoder), /* aResumable */ false); + + // Run the full decoder synchronously. + task->Run(); + + // Call the lambda to verify the expected results. + aResultChecker(decoder); +} + +static void CheckDecode(const ImageTestCase& aTestCase, + SourceBuffer* aSourceBuffer) { + WithSingleChunkDecode( + aTestCase, aSourceBuffer, Nothing(), [&](image::Decoder* aDecoder) { + CheckDecoderState(aTestCase, aDecoder, aTestCase.mSize); + }); +} + +static void CheckDownscaleDuringDecode(const ImageTestCase& aTestCase, + SourceBuffer* aSourceBuffer) { + IntSize outputSize(20, 20); + WithSingleChunkDecode(aTestCase, aSourceBuffer, Some(outputSize), + [&](image::Decoder* aDecoder) { + CheckDecoderState(aTestCase, aDecoder, outputSize); + }); +} + +#define IMAGE_GTEST_BENCH_FIXTURE(test_fixture, test_case) \ + class test_fixture : public ImageBenchmarkBase { \ + protected: \ + test_fixture() : ImageBenchmarkBase(test_case()) {} \ + }; + +#define IMAGE_GTEST_NATIVE_BENCH_F(test_fixture) \ + MOZ_GTEST_BENCH_F(test_fixture, Native, \ + [this] { CheckDecode(mTestCase, mSourceBuffer); }); + +#define IMAGE_GTEST_DOWNSCALE_BENCH_F(test_fixture) \ + MOZ_GTEST_BENCH_F(test_fixture, Downscale, [this] { \ + CheckDownscaleDuringDecode(mTestCase, mSourceBuffer); \ + }); + +#define IMAGE_GTEST_NO_COLOR_MANAGEMENT_BENCH_F(test_fixture) \ + MOZ_GTEST_BENCH_F(test_fixture, NoColorManagement, [this] { \ + ImageTestCase testCase = mTestCase; \ + testCase.mSurfaceFlags |= SurfaceFlags::NO_COLORSPACE_CONVERSION; \ + CheckDecode(testCase, mSourceBuffer); \ + }); + +#define IMAGE_GTEST_NO_PREMULTIPLY_BENCH_F(test_fixture) \ + MOZ_GTEST_BENCH_F(test_fixture, NoPremultiplyAlpha, [this] { \ + ImageTestCase testCase = mTestCase; \ + testCase.mSurfaceFlags |= SurfaceFlags::NO_PREMULTIPLY_ALPHA; \ + CheckDecode(testCase, mSourceBuffer); \ + }); + +#define IMAGE_GTEST_BENCH_F(type, test) \ + IMAGE_GTEST_BENCH_FIXTURE(ImageDecodersPerf_##type##_##test, \ + Perf##test##type##TestCase) \ + IMAGE_GTEST_NATIVE_BENCH_F(ImageDecodersPerf_##type##_##test) \ + IMAGE_GTEST_DOWNSCALE_BENCH_F(ImageDecodersPerf_##type##_##test) \ + IMAGE_GTEST_NO_COLOR_MANAGEMENT_BENCH_F(ImageDecodersPerf_##type##_##test) + +#define IMAGE_GTEST_BENCH_ALPHA_F(type, test) \ + IMAGE_GTEST_BENCH_F(type, test) \ + IMAGE_GTEST_NO_PREMULTIPLY_BENCH_F(ImageDecodersPerf_##type##_##test) + +IMAGE_GTEST_BENCH_F(JPG, YCbCr) +IMAGE_GTEST_BENCH_F(JPG, Cmyk) +IMAGE_GTEST_BENCH_F(JPG, Gray) + +IMAGE_GTEST_BENCH_F(PNG, Rgb) +IMAGE_GTEST_BENCH_F(PNG, Gray) +IMAGE_GTEST_BENCH_ALPHA_F(PNG, RgbAlpha) +IMAGE_GTEST_BENCH_ALPHA_F(PNG, GrayAlpha) + +IMAGE_GTEST_BENCH_F(WebP, RgbLossless) +IMAGE_GTEST_BENCH_F(WebP, RgbLossy) +IMAGE_GTEST_BENCH_ALPHA_F(WebP, RgbAlphaLossless) +IMAGE_GTEST_BENCH_ALPHA_F(WebP, RgbAlphaLossy) + +IMAGE_GTEST_BENCH_F(GIF, Rgb) + +} // namespace |