Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(874)

Side by Side Diff: third_party/WebKit/Source/platform/image-encoders/JPEGImageEncoder.cpp

Issue 2576223002: NEON-ize RGBA to RGB code (Closed)
Patch Set: Copyright, fix Windows build. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2010, Google Inc. All rights reserved. 2 * Copyright (c) 2010, Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 15 matching lines...) Expand all
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 #include "platform/image-encoders/JPEGImageEncoder.h" 31 #include "platform/image-encoders/JPEGImageEncoder.h"
32 32
33 #include "SkColorPriv.h" 33 #include "SkColorPriv.h"
34 #include "platform/geometry/IntSize.h" 34 #include "platform/geometry/IntSize.h"
35 #include "platform/graphics/ImageBuffer.h" 35 #include "platform/graphics/ImageBuffer.h"
36 #include "platform/image-encoders/RGBAtoRGB.h"
36 #include "wtf/CurrentTime.h" 37 #include "wtf/CurrentTime.h"
37 #include "wtf/PtrUtil.h" 38 #include "wtf/PtrUtil.h"
38 #include <memory> 39 #include <memory>
39 40
40 extern "C" { 41 extern "C" {
41 #include <setjmp.h> 42 #include <setjmp.h>
42 #include <stdio.h> // jpeglib.h needs stdio.h FILE 43 #include <stdio.h> // jpeglib.h needs stdio.h FILE
43 #include "jpeglib.h" 44 #include "jpeglib.h"
44 } 45 }
45 46
46 namespace blink { 47 namespace blink {
47 48
49 void RGBAtoRGBScalar(const unsigned char* pixels,
msarett1 2016/12/16 13:07:54 libjpeg-turbo actually supports RGBA input (in add
cavalcantii1 2016/12/17 02:35:33 Acknowledged.
50 unsigned pixelCount,
51 unsigned char* output) {
52 // Per <canvas> spec, composite the input image pixels source-over on black.
53 for (; pixelCount-- > 0; pixels += 4) {
54 unsigned char alpha = pixels[3];
55 if (alpha != 255) {
56 *output++ = SkMulDiv255Round(pixels[0], alpha);
57 *output++ = SkMulDiv255Round(pixels[1], alpha);
58 *output++ = SkMulDiv255Round(pixels[2], alpha);
59 } else {
60 *output++ = pixels[0];
61 *output++ = pixels[1];
62 *output++ = pixels[2];
63 }
64 }
65 }
66
67 // TODO(cavalcantii): use regular macro, see https://crbug.com/673067.
68 #ifdef __ARM_NEON__
69 void RGBAtoRGBNeon(const unsigned char* input,
70 const unsigned pixelCount,
71 unsigned char* output) {
72 const unsigned pixelsPerLoad = 16;
73 const unsigned rgbaStep = pixelsPerLoad * 4, rgbStep = pixelsPerLoad * 3;
74 // Input registers.
75 uint8x16x4_t rgba;
76 // Output registers.
77 uint8x16x3_t rgb;
78 // Intermediate registers.
79 uint16x8_t low, high;
80 uint8x16_t result;
81 unsigned counter;
82
83 for (counter = 0; counter + pixelsPerLoad <= pixelCount;
84 counter += pixelsPerLoad) {
85 // Reads 16 pixels at once, each color channel in a different
86 // 128 bits register.
87 rgba = vld4q_u8(input);
88
89 // Extracts the low/high part of the 128 bits, multiplying by the
90 // respective alpha channel.
91 low = vmull_u8(vget_low_u8(rgba.val[0]), vget_low_u8(rgba.val[3]));
92 high = vmull_u8(vget_high_u8(rgba.val[0]), vget_high_u8(rgba.val[3]));
93
94 // Original Skia formula is: (x + (x >> 8)) >> 8, where x = a*b + 128.
95 // This shifts and accumulates following by rounding in a single
96 // instruction.
97 low = vrsraq_n_u16(low, low, 8);
msarett1 2016/12/16 13:07:54 Skia has a NEON implementation of "mul and rounded
cavalcantii1 2016/12/17 02:35:33 I searched for SkSwizzler_opts.h and it seems it i
98 high = vrsraq_n_u16(high, high, 8);
99
100 // And now to the last shift and combining the vector.
101 result = vcombine_u8(vqrshrn_n_u16(low, 8), vqrshrn_n_u16(high, 8));
102
103 // Write back the Red channel to the first 128 bits register.
104 rgb.val[0] = result;
105
106 // Now the Green channel (don't trust the compiler to unroll the loop).
msarett1 2016/12/16 13:07:54 What about using an inline helper function? Ex: m
cavalcantii1 2016/12/17 02:35:33 I tested moving the pixel manipulation code to a l
107 low = vmull_u8(vget_low_u8(rgba.val[1]), vget_low_u8(rgba.val[3]));
108 high = vmull_u8(vget_high_u8(rgba.val[1]), vget_high_u8(rgba.val[3]));
109 low = vrsraq_n_u16(low, low, 8);
110 high = vrsraq_n_u16(high, high, 8);
111 result = vcombine_u8(vqrshrn_n_u16(low, 8), vqrshrn_n_u16(high, 8));
112 rgb.val[1] = result;
113
114 // Finally the Blue channel.
115 low = vmull_u8(vget_low_u8(rgba.val[2]), vget_low_u8(rgba.val[3]));
116 high = vmull_u8(vget_high_u8(rgba.val[2]), vget_high_u8(rgba.val[3]));
117 low = vrsraq_n_u16(low, low, 8);
118 high = vrsraq_n_u16(high, high, 8);
119 result = vcombine_u8(vqrshrn_n_u16(low, 8), vqrshrn_n_u16(high, 8));
120 rgb.val[2] = result;
121
122 // Write back (interleaved) results to output.
123 vst3q_u8(output, rgb);
124
125 // Advance to next elements (could be avoided loading register with
126 // increment after i.e. "vld4 {vector}, [r1]!").
127 input += rgbaStep;
128 output += rgbStep;
129 }
130
131 // Handle the tail elements.
132 unsigned remaining = pixelCount;
133 remaining -= counter;
134 if (remaining != 0) {
135 RGBAtoRGBScalar(input, remaining, output);
136 }
137 }
138 #endif
139
48 struct JPEGOutputBuffer : public jpeg_destination_mgr { 140 struct JPEGOutputBuffer : public jpeg_destination_mgr {
49 DISALLOW_NEW(); 141 DISALLOW_NEW();
50 Vector<unsigned char>* output; 142 Vector<unsigned char>* output;
51 Vector<unsigned char> buffer; 143 Vector<unsigned char> buffer;
52 }; 144 };
53 145
54 class JPEGImageEncoderStateImpl final : public JPEGImageEncoderState { 146 class JPEGImageEncoderStateImpl final : public JPEGImageEncoderState {
55 public: 147 public:
56 JPEGImageEncoderStateImpl() {} 148 JPEGImageEncoderStateImpl() {}
57 ~JPEGImageEncoderStateImpl() override { 149 ~JPEGImageEncoderStateImpl() override {
(...skipping 30 matching lines...) Expand all
88 JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest); 180 JPEGOutputBuffer* out = static_cast<JPEGOutputBuffer*>(cinfo->dest);
89 const size_t size = out->buffer.size() - out->free_in_buffer; 181 const size_t size = out->buffer.size() - out->free_in_buffer;
90 out->output->append(out->buffer.data(), size); 182 out->output->append(out->buffer.data(), size);
91 } 183 }
92 184
93 static void handleError(j_common_ptr common) { 185 static void handleError(j_common_ptr common) {
94 jmp_buf* jumpBufferPtr = static_cast<jmp_buf*>(common->client_data); 186 jmp_buf* jumpBufferPtr = static_cast<jmp_buf*>(common->client_data);
95 longjmp(*jumpBufferPtr, -1); 187 longjmp(*jumpBufferPtr, -1);
96 } 188 }
97 189
98 static void RGBAtoRGB(const unsigned char* pixels,
99 unsigned pixelCount,
100 unsigned char* output) {
101 // Per <canvas> spec, composite the input image pixels source-over on black.
102
103 for (; pixelCount-- > 0; pixels += 4) {
104 unsigned char alpha = pixels[3];
105 if (alpha != 255) {
106 *output++ = SkMulDiv255Round(pixels[0], alpha);
107 *output++ = SkMulDiv255Round(pixels[1], alpha);
108 *output++ = SkMulDiv255Round(pixels[2], alpha);
109 } else {
110 *output++ = pixels[0];
111 *output++ = pixels[1];
112 *output++ = pixels[2];
113 }
114 }
115 }
116
117 static void disableSubsamplingForHighQuality(jpeg_compress_struct* cinfo, 190 static void disableSubsamplingForHighQuality(jpeg_compress_struct* cinfo,
118 int quality) { 191 int quality) {
119 if (quality < 100) 192 if (quality < 100)
120 return; 193 return;
121 194
122 for (int i = 0; i < MAX_COMPONENTS; ++i) { 195 for (int i = 0; i < MAX_COMPONENTS; ++i) {
123 cinfo->comp_info[i].h_samp_factor = 1; 196 cinfo->comp_info[i].h_samp_factor = 1;
124 cinfo->comp_info[i].v_samp_factor = 1; 197 cinfo->comp_info[i].v_samp_factor = 1;
125 } 198 }
126 } 199 }
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 std::unique_ptr<JPEGImageEncoderState> encoderState = 323 std::unique_ptr<JPEGImageEncoderState> encoderState =
251 JPEGImageEncoderState::create(imageData.size(), quality, output); 324 JPEGImageEncoderState::create(imageData.size(), quality, output);
252 if (!encoderState) 325 if (!encoderState)
253 return false; 326 return false;
254 327
255 return JPEGImageEncoder::encodeWithPreInitializedState( 328 return JPEGImageEncoder::encodeWithPreInitializedState(
256 std::move(encoderState), imageData.pixels()); 329 std::move(encoderState), imageData.pixels());
257 } 330 }
258 331
259 } // namespace blink 332 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698