Chromium Code Reviews| Index: third_party/WebKit/Source/platform/image-encoders/JPEGImageEncoderTest.cpp |
| diff --git a/third_party/WebKit/Source/platform/image-encoders/JPEGImageEncoderTest.cpp b/third_party/WebKit/Source/platform/image-encoders/JPEGImageEncoderTest.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b6d7489915e55f5142712f2ca714dbad98bb50fa |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/platform/image-encoders/JPEGImageEncoderTest.cpp |
| @@ -0,0 +1,260 @@ |
| +/* |
| + * Copyright 2016 The Chromium Authors. All rights reserved. |
|
esprehn
2016/12/15 05:01:25
Use the new short copyright on new files.
|
| + * |
| + * Redistribution and use in source and binary forms, with or without |
| + * modification, are permitted provided that the following conditions are |
| + * met: |
| + * |
| + * * Redistributions of source code must retain the above copyright |
| + * notice, this list of conditions and the following disclaimer. |
| + * * Redistributions in binary form must reproduce the above |
| + * copyright notice, this list of conditions and the following disclaimer |
| + * in the documentation and/or other materials provided with the |
| + * distribution. |
| + * * Neither the name of Chromium nor the names of its |
| + * contributors may be used to endorse or promote products derived from |
| + * this software without specific prior written permission. |
| + * |
| + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| + */ |
| + |
| +#include "base/timer/elapsed_timer.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +// TODO(cavalcantii): use regular macro, see https://crbug.com/673067. |
| +#ifdef __ARM_NEON__ |
| +#include "platform/image-encoders/RGBAtoRGB.h" |
| +#endif |
| + |
| +namespace blink { |
| + |
| +static const size_t channelsRGBA = 4; |
| +static const size_t channelsRGB = 3; |
| + |
| +class RGBAtoRGBTest : public ::testing::Test { |
| + public: |
| + RGBAtoRGBTest() {} |
| +}; |
| + |
| +TEST_F(RGBAtoRGBTest, testEmpty) { |
| + EXPECT_TRUE(true); |
| +} |
| + |
| +inline size_t calculateRGBAPixels(size_t inputBufferSize) { |
| + size_t pixels = inputBufferSize / channelsRGBA; |
| + return pixels; |
| +} |
| + |
| +inline size_t calculateRGBOutputSize(size_t inputBufferSize) { |
| + size_t pixels = calculateRGBAPixels(inputBufferSize); |
| + pixels *= channelsRGB; |
| + return pixels; |
| +} |
| + |
| +#ifdef __ARM_NEON__ |
| +TEST_F(RGBAtoRGBTest, testOpaqueCaseEven8pixels) { |
| + unsigned char canvas[] = {255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, |
| + 255, 255, 0, 0, 255, 0, 255, 0, 255, 0, 255, |
| + 0, 255, 0, 255, 0, 255, 0, 255, 0, 255}; |
| + |
| + unsigned char expected[] = {255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 0, |
| + 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0}; |
| + |
| + size_t pixels = calculateRGBAPixels(sizeof(canvas)); |
| + size_t rgbSize = calculateRGBOutputSize(sizeof(canvas)); |
| + unsigned char output[rgbSize]; |
| + memset(output, 0, rgbSize); |
| + |
| + blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); |
| + |
| + EXPECT_EQ(memcmp(expected, output, rgbSize), 0); |
| +} |
| + |
| +TEST_F(RGBAtoRGBTest, testCaseEven16pixels) { |
| + unsigned char canvas[] = { |
| + 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, |
| + 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, |
| + 0, 255, 0, 255, 0, 255, 0, 0, 255, 128, 0, 0, 255, |
| + 128, 0, 0, 255, 128, 0, 0, 255, 128, 128, 128, 128, 128, |
| + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}; |
| + |
| + size_t pixels = calculateRGBAPixels(sizeof(canvas)); |
| + size_t rgbSize = calculateRGBOutputSize(sizeof(canvas)); |
| + unsigned char output[rgbSize]; |
| + unsigned char expected[rgbSize]; |
| + memset(output, 0, rgbSize); |
| + memset(expected, 0, rgbSize); |
| + |
| + blink::RGBAtoRGBScalar(canvas, static_cast<unsigned>(pixels), expected); |
| + blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); |
| + |
| + EXPECT_EQ(memcmp(expected, output, rgbSize), 0); |
| +} |
| + |
| +TEST_F(RGBAtoRGBTest, testCaseOdd17pixels) { |
| + unsigned char canvas[] = { |
| + 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, |
| + 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, |
| + 0, 255, 0, 255, 0, 0, 255, 128, 0, 0, 255, 128, 0, 0, |
| + 255, 128, 0, 0, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| + 128, 128, 128, 128, 128, 128, 128, 128, 10, 10, 10, 100}; |
| + |
| + size_t pixels = calculateRGBAPixels(sizeof(canvas)); |
| + size_t rgbSize = calculateRGBOutputSize(sizeof(canvas)); |
| + unsigned char output[rgbSize]; |
| + unsigned char expected[rgbSize]; |
| + memset(output, 0, rgbSize); |
| + memset(expected, 0, rgbSize); |
| + |
| + blink::RGBAtoRGBScalar(canvas, static_cast<unsigned>(pixels), expected); |
| + blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); |
| + |
| + EXPECT_EQ(memcmp(expected, output, rgbSize), 0); |
| +} |
| + |
| +TEST_F(RGBAtoRGBTest, testCaseEven32pixels) { |
| + unsigned char canvas[] = { |
| + 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, |
| + 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, |
| + 0, 255, 0, 0, 255, 128, 0, 0, 255, 128, 0, 0, 255, 128, 0, |
| + 0, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, |
| + 128, 128, 128, 128, 128, 128, 128, 255, 128, 128, 128, 255, 128, 128, 128, |
| + 255, 128, 128, 128, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, |
| + 0, 255, 255, 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, |
| + 255, 0, 255, 0, 255, 0, 255, 0, 0, 255, 128, 0, 0, 255, 128, |
| + 0, 0, 255, 128, 0, 0, 255, 128}; |
| + |
| + size_t pixels = calculateRGBAPixels(sizeof(canvas)); |
| + size_t rgbSize = calculateRGBOutputSize(sizeof(canvas)); |
| + unsigned char output[rgbSize]; |
| + unsigned char expected[rgbSize]; |
| + memset(output, 0, rgbSize); |
| + memset(expected, 0, rgbSize); |
| + |
| + blink::RGBAtoRGBScalar(canvas, static_cast<unsigned>(pixels), expected); |
| + blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); |
| + |
| + EXPECT_EQ(memcmp(expected, output, rgbSize), 0); |
| +} |
| + |
| +static base::TimeDelta testNpixels(bool fastPath = true, |
| + const size_t width = 1024, |
| + const size_t height = 1024, |
| + bool setAlpha = true) { |
| + size_t pixels = width * height; |
| + size_t canvasLen = channelsRGBA * width * height; |
| + size_t outputLen = channelsRGB * width * height; |
| + unsigned char* canvas = new unsigned char[canvasLen]; |
| + unsigned char* output = new unsigned char[outputLen]; |
| + |
| + auto cleanup = [&]() { |
| + if (canvas) |
| + delete[] canvas; |
| + if (output) |
| + delete[] output; |
| + }; |
| + |
| + if (!canvas || !output) { |
| + cleanup(); |
| + return base::TimeDelta(); |
| + } |
| + |
| + if (setAlpha) { |
| + memset(canvas, 128, canvasLen); |
| + } else { |
| + memset(canvas, 200, canvasLen); |
| + } |
| + |
| + base::ElapsedTimer runTime; |
| + if (fastPath) { |
| + blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); |
| + } else { |
| + blink::RGBAtoRGBScalar(canvas, static_cast<unsigned>(pixels), output); |
| + } |
| + |
| + auto result = runTime.Elapsed(); |
| + cleanup(); |
| + return result; |
| +} |
| + |
| +TEST_F(RGBAtoRGBTest, testPerf1k) { |
| + auto neonElapsed = testNpixels(); |
| + auto scalarElapsed = testNpixels(false); |
| + |
| + EXPECT_TRUE(neonElapsed < scalarElapsed) |
| + << "Neon: " << neonElapsed << "\tScalar: " << scalarElapsed << std::endl; |
| +} |
| + |
| +TEST_F(RGBAtoRGBTest, testPerf4k) { |
| + auto neonElapsed = testNpixels(true, 4000, 4000); |
| + auto scalarElapsed = testNpixels(false, 4000, 4000); |
| + |
| + EXPECT_TRUE(neonElapsed < scalarElapsed) |
| + << "Neon: " << neonElapsed << "\tScalar: " << scalarElapsed << std::endl; |
| +} |
| + |
| +// This width will force the tail case, cause width = (16 * 64) + 15. |
| +static bool testRandNpixels(const size_t width = 1039, |
| + const size_t height = 1024, |
| + bool setAlpha = true) { |
| + size_t pixels = width * height; |
| + size_t canvasLen = channelsRGBA * pixels; |
| + size_t outputLen = channelsRGB * pixels; |
| + unsigned char* canvas = new unsigned char[canvasLen]; |
| + unsigned char* expected = new unsigned char[outputLen]; |
| + unsigned char* output = new unsigned char[outputLen]; |
| + |
| + auto cleanup = [&]() { |
| + if (canvas) |
| + delete[] canvas; |
| + if (expected) |
| + delete[] expected; |
| + if (output) |
| + delete[] output; |
| + }; |
| + |
| + if (!canvas || !output || !expected) { |
| + cleanup(); |
| + return false; |
| + } |
| + |
| + if (setAlpha) { |
| + memset(canvas, 128, canvasLen); |
| + } else { |
| + memset(canvas, 200, canvasLen); |
| + } |
| + |
| + srand(time(0)); |
| + unsigned char* ptr = canvas; |
| + for (size_t i = 0; i < pixels; ++i) { |
| + *ptr++ = static_cast<unsigned char>(rand() % 255); |
| + *ptr++ = static_cast<unsigned char>(rand() % 255); |
| + *ptr++ = static_cast<unsigned char>(rand() % 255); |
| + *ptr++ = static_cast<unsigned char>(rand() % 255); |
| + } |
| + |
| + blink::RGBAtoRGBScalar(canvas, static_cast<unsigned>(pixels), expected); |
| + blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); |
| + |
| + bool result = memcmp(expected, output, outputLen) == 0; |
| + |
| + cleanup(); |
| + return result; |
| +} |
| + |
| +TEST_F(RGBAtoRGBTest, randomPixels) { |
| + EXPECT_TRUE(testRandNpixels()); |
| +} |
| + |
| +#endif |
| +} // namespace blink |