Chromium Code Reviews| Index: third_party/WebKit/Source/platform/image-encoders/JPEGImageEncoder.cpp |
| diff --git a/third_party/WebKit/Source/platform/image-encoders/JPEGImageEncoder.cpp b/third_party/WebKit/Source/platform/image-encoders/JPEGImageEncoder.cpp |
| index 0a70e73db5f7e4733d051ac4b8799add20c74c29..f28a484206202faa7d815c0d8f882d450d083633 100644 |
| --- a/third_party/WebKit/Source/platform/image-encoders/JPEGImageEncoder.cpp |
| +++ b/third_party/WebKit/Source/platform/image-encoders/JPEGImageEncoder.cpp |
| @@ -33,6 +33,7 @@ |
| #include "SkColorPriv.h" |
| #include "platform/geometry/IntSize.h" |
| #include "platform/graphics/ImageBuffer.h" |
| +#include "platform/image-encoders/RGBAtoRGB.h" |
| #include "wtf/CurrentTime.h" |
| #include "wtf/PtrUtil.h" |
| #include <memory> |
| @@ -45,6 +46,90 @@ extern "C" { |
| namespace blink { |
| +void RGBAtoRGBScalar(const unsigned char* pixels, |
| + unsigned pixelCount, |
| + unsigned char* output) { |
| + // Per <canvas> spec, composite the input image pixels source-over on black. |
| + for (; pixelCount-- > 0; pixels += 4) { |
| + unsigned char alpha = pixels[3]; |
| + if (alpha != 255) { |
| + *output++ = SkMulDiv255Round(pixels[0], alpha); |
| + *output++ = SkMulDiv255Round(pixels[1], alpha); |
| + *output++ = SkMulDiv255Round(pixels[2], alpha); |
| + } else { |
| + *output++ = pixels[0]; |
| + *output++ = pixels[1]; |
| + *output++ = pixels[2]; |
| + } |
| + } |
| +} |
| + |
| +// TODO(cavalcantii): use regular macro, see https://crbug.com/673067. |
| +#ifdef __ARM_NEON__ |
| + |
| +// TODO(cavalcantii): this came straight from SkSwizzler_opts.h, I wonder |
| +// how to include it? |
|
msarett
2016/12/18 18:48:37
Sorry for being unclear, there's no plan to make t
|
| +inline uint8x8_t div255Round(uint16x8_t x) { |
| + return vraddhn_u16(x, vrshrq_n_u16(x, 8)); |
| +} |
| + |
| +inline uint8x8_t scale(uint8x8_t x, uint8x8_t y) { |
| + return div255Round(vmull_u8(x, y)); |
| +} |
| + |
| +void RGBAtoRGBNeon(const unsigned char* input, |
| + const unsigned pixelCount, |
| + unsigned char* output) { |
| + const unsigned pixelsPerLoad = 16; |
| + const unsigned rgbaStep = pixelsPerLoad * 4, rgbStep = pixelsPerLoad * 3; |
| + // Input registers. |
| + uint8x16x4_t rgba; |
| + // Output registers. |
| + uint8x16x3_t rgb; |
| + // Intermediate registers. |
| + uint8x8_t low, high; |
| + uint8x16_t result; |
| + unsigned counter; |
| + |
| + auto transformColor = [&](size_t channel) { |
| + // Extracts the low/high part of the 128 bits and scale using Skia code. |
| + low = vget_low_u8(rgba.val[channel]); |
| + high = vget_high_u8(rgba.val[channel]); |
| + low = scale(low, vget_low_u8(rgba.val[3])); |
| + high = scale(high, vget_high_u8(rgba.val[3])); |
| + result = vcombine_u8(low, high); |
| + // Write back the channel to a 128 bits register. |
| + rgb.val[channel] = result; |
| + }; |
| + |
| + for (counter = 0; counter + pixelsPerLoad <= pixelCount; |
| + counter += pixelsPerLoad) { |
| + // Reads 16 pixels at once, each color channel in a different |
| + // 128 bits register. |
| + rgba = vld4q_u8(input); |
| + |
| + transformColor(0); |
| + transformColor(1); |
| + transformColor(2); |
| + |
| + // Write back (interleaved) results to output. |
| + vst3q_u8(output, rgb); |
| + |
| + // Advance to next elements (could be avoided loading register with |
| + // increment after i.e. "vld4 {vector}, [r1]!"). |
| + input += rgbaStep; |
| + output += rgbStep; |
| + } |
| + |
| + // Handle the tail elements. |
| + unsigned remaining = pixelCount; |
| + remaining -= counter; |
| + if (remaining != 0) { |
| + RGBAtoRGBScalar(input, remaining, output); |
| + } |
| +} |
| +#endif |
| + |
| struct JPEGOutputBuffer : public jpeg_destination_mgr { |
| DISALLOW_NEW(); |
| Vector<unsigned char>* output; |
| @@ -95,25 +180,6 @@ static void handleError(j_common_ptr common) { |
| longjmp(*jumpBufferPtr, -1); |
| } |
| -static void RGBAtoRGB(const unsigned char* pixels, |
| - unsigned pixelCount, |
| - unsigned char* output) { |
| - // Per <canvas> spec, composite the input image pixels source-over on black. |
| - |
| - for (; pixelCount-- > 0; pixels += 4) { |
| - unsigned char alpha = pixels[3]; |
| - if (alpha != 255) { |
| - *output++ = SkMulDiv255Round(pixels[0], alpha); |
| - *output++ = SkMulDiv255Round(pixels[1], alpha); |
| - *output++ = SkMulDiv255Round(pixels[2], alpha); |
| - } else { |
| - *output++ = pixels[0]; |
| - *output++ = pixels[1]; |
| - *output++ = pixels[2]; |
| - } |
| - } |
| -} |
| - |
| static void disableSubsamplingForHighQuality(jpeg_compress_struct* cinfo, |
| int quality) { |
| if (quality < 100) |