OLD | NEW |
1 // Copyright 2014 Google Inc. All Rights Reserved. | 1 // Copyright 2014 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
4 // that can be found in the COPYING file in the root of the source | 4 // that can be found in the COPYING file in the root of the source |
5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
9 // | 9 // |
10 // SSE2 variant of methods for lossless decoder | 10 // SSE2 variant of methods for lossless decoder |
11 // | 11 // |
12 // Author: Skal (pascal.massimino@gmail.com) | 12 // Author: Skal (pascal.massimino@gmail.com) |
13 | 13 |
14 #include "./dsp.h" | 14 #include "./dsp.h" |
15 | 15 |
| 16 #if defined(WEBP_USE_SSE2) |
16 #include <assert.h> | 17 #include <assert.h> |
17 | |
18 #if defined(WEBP_USE_SSE2) | |
19 #include <emmintrin.h> | 18 #include <emmintrin.h> |
20 #include "./lossless.h" | 19 #include "./lossless.h" |
21 | 20 |
22 //------------------------------------------------------------------------------ | 21 //------------------------------------------------------------------------------ |
23 // Predictor Transform | 22 // Predictor Transform |
24 | 23 |
25 static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1, | 24 static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1, |
26 uint32_t c2) { | 25 uint32_t c2) { |
27 const __m128i zero = _mm_setzero_si128(); | 26 const __m128i zero = _mm_setzero_si128(); |
28 const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero); | 27 const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 return pred; | 148 return pred; |
150 } | 149 } |
151 static uint32_t Predictor13(uint32_t left, const uint32_t* const top) { | 150 static uint32_t Predictor13(uint32_t left, const uint32_t* const top) { |
152 const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]); | 151 const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]); |
153 return pred; | 152 return pred; |
154 } | 153 } |
155 | 154 |
156 //------------------------------------------------------------------------------ | 155 //------------------------------------------------------------------------------ |
157 // Subtract-Green Transform | 156 // Subtract-Green Transform |
158 | 157 |
159 static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixels) { | 158 static void AddGreenToBlueAndRed(uint32_t* argb_data, int num_pixels) { |
160 const __m128i mask = _mm_set1_epi32(0x0000ff00); | |
161 int i; | 159 int i; |
162 for (i = 0; i + 4 <= num_pixels; i += 4) { | 160 for (i = 0; i + 4 <= num_pixels; i += 4) { |
163 const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); | 161 const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb |
164 const __m128i in_00g0 = _mm_and_si128(in, mask); // 00g0|00g0|... | 162 const __m128i A = _mm_srli_epi16(in, 8); // 0 a 0 g |
165 const __m128i in_0g00 = _mm_slli_epi32(in_00g0, 8); // 0g00|0g00|... | 163 const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0)); |
166 const __m128i in_000g = _mm_srli_epi32(in_00g0, 8); // 000g|000g|... | 164 const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // 0g0g |
167 const __m128i in_0g0g = _mm_or_si128(in_0g00, in_000g); | 165 const __m128i out = _mm_add_epi8(in, C); |
168 const __m128i out = _mm_sub_epi8(in, in_0g0g); | |
169 _mm_storeu_si128((__m128i*)&argb_data[i], out); | 166 _mm_storeu_si128((__m128i*)&argb_data[i], out); |
170 } | 167 } |
171 // fallthrough and finish off with plain-C | 168 // fallthrough and finish off with plain-C |
172 VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i); | |
173 } | |
174 | |
175 static void AddGreenToBlueAndRed(uint32_t* argb_data, int num_pixels) { | |
176 const __m128i mask = _mm_set1_epi32(0x0000ff00); | |
177 int i; | |
178 for (i = 0; i + 4 <= num_pixels; i += 4) { | |
179 const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); | |
180 const __m128i in_00g0 = _mm_and_si128(in, mask); // 00g0|00g0|... | |
181 const __m128i in_0g00 = _mm_slli_epi32(in_00g0, 8); // 0g00|0g00|... | |
182 const __m128i in_000g = _mm_srli_epi32(in_00g0, 8); // 000g|000g|... | |
183 const __m128i in_0g0g = _mm_or_si128(in_0g00, in_000g); | |
184 const __m128i out = _mm_add_epi8(in, in_0g0g); | |
185 _mm_storeu_si128((__m128i*)&argb_data[i], out); | |
186 } | |
187 // fallthrough and finish off with plain-C | |
188 VP8LAddGreenToBlueAndRed_C(argb_data + i, num_pixels - i); | 169 VP8LAddGreenToBlueAndRed_C(argb_data + i, num_pixels - i); |
189 } | 170 } |
190 | 171 |
191 //------------------------------------------------------------------------------ | 172 //------------------------------------------------------------------------------ |
192 // Color Transform | 173 // Color Transform |
193 | 174 |
194 static WEBP_INLINE __m128i ColorTransformDelta(__m128i color_pred, | 175 static void TransformColorInverse(const VP8LMultipliers* const m, |
195 __m128i color) { | 176 uint32_t* argb_data, int num_pixels) { |
196 // We simulate signed 8-bit multiplication as: | 177 // sign-extended multiplying constants, pre-shifted by 5. |
197 // * Left shift the two (8-bit) numbers by 8 bits, | 178 #define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend |
198 // * Perform a 16-bit signed multiplication and retain the higher 16-bits. | 179 const __m128i mults_rb = _mm_set_epi16( |
199 const __m128i color_pred_shifted = _mm_slli_epi32(color_pred, 8); | 180 CST(green_to_red_), CST(green_to_blue_), |
200 const __m128i color_shifted = _mm_slli_epi32(color, 8); | 181 CST(green_to_red_), CST(green_to_blue_), |
201 // Note: This performs multiplication on 8 packed 16-bit numbers, 4 of which | 182 CST(green_to_red_), CST(green_to_blue_), |
202 // happen to be zeroes. | 183 CST(green_to_red_), CST(green_to_blue_)); |
203 const __m128i signed_mult = | 184 const __m128i mults_b2 = _mm_set_epi16( |
204 _mm_mulhi_epi16(color_pred_shifted, color_shifted); | 185 CST(red_to_blue_), 0, CST(red_to_blue_), 0, |
205 return _mm_srli_epi32(signed_mult, 5); | 186 CST(red_to_blue_), 0, CST(red_to_blue_), 0); |
206 } | 187 #undef CST |
207 | 188 const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks |
208 static WEBP_INLINE void TransformColor(const VP8LMultipliers* const m, | |
209 uint32_t* argb_data, | |
210 int num_pixels) { | |
211 const __m128i g_to_r = _mm_set1_epi32(m->green_to_red_); // multipliers | |
212 const __m128i g_to_b = _mm_set1_epi32(m->green_to_blue_); | |
213 const __m128i r_to_b = _mm_set1_epi32(m->red_to_blue_); | |
214 | |
215 int i; | 189 int i; |
216 | |
217 for (i = 0; i + 4 <= num_pixels; i += 4) { | 190 for (i = 0; i + 4 <= num_pixels; i += 4) { |
218 const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); | 191 const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb |
219 const __m128i alpha_green_mask = _mm_set1_epi32(0xff00ff00); // masks | 192 const __m128i A = _mm_and_si128(in, mask_ag); // a 0 g 0 |
220 const __m128i red_mask = _mm_set1_epi32(0x00ff0000); | 193 const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0)); |
221 const __m128i green_mask = _mm_set1_epi32(0x0000ff00); | 194 const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // g0g0 |
222 const __m128i lower_8bit_mask = _mm_set1_epi32(0x000000ff); | 195 const __m128i D = _mm_mulhi_epi16(C, mults_rb); // x dr x db1 |
223 const __m128i ag = _mm_and_si128(in, alpha_green_mask); // alpha, green | 196 const __m128i E = _mm_add_epi8(in, D); // x r' x b' |
224 const __m128i r = _mm_srli_epi32(_mm_and_si128(in, red_mask), 16); | 197 const __m128i F = _mm_slli_epi16(E, 8); // r' 0 b' 0 |
225 const __m128i g = _mm_srli_epi32(_mm_and_si128(in, green_mask), 8); | 198 const __m128i G = _mm_mulhi_epi16(F, mults_b2); // x db2 0 0 |
226 const __m128i b = in; | 199 const __m128i H = _mm_srli_epi32(G, 8); // 0 x db2 0 |
227 | 200 const __m128i I = _mm_add_epi8(H, F); // r' x b'' 0 |
228 const __m128i r_delta = ColorTransformDelta(g_to_r, g); // red | 201 const __m128i J = _mm_srli_epi16(I, 8); // 0 r' 0 b'' |
229 const __m128i r_new = | 202 const __m128i out = _mm_or_si128(J, A); |
230 _mm_and_si128(_mm_sub_epi32(r, r_delta), lower_8bit_mask); | |
231 const __m128i r_new_shifted = _mm_slli_epi32(r_new, 16); | |
232 | |
233 const __m128i b_delta_1 = ColorTransformDelta(g_to_b, g); // blue | |
234 const __m128i b_delta_2 = ColorTransformDelta(r_to_b, r); | |
235 const __m128i b_delta = _mm_add_epi32(b_delta_1, b_delta_2); | |
236 const __m128i b_new = | |
237 _mm_and_si128(_mm_sub_epi32(b, b_delta), lower_8bit_mask); | |
238 | |
239 const __m128i out = _mm_or_si128(_mm_or_si128(ag, r_new_shifted), b_new); | |
240 _mm_storeu_si128((__m128i*)&argb_data[i], out); | 203 _mm_storeu_si128((__m128i*)&argb_data[i], out); |
241 } | 204 } |
242 | |
243 // Fall-back to C-version for left-overs. | |
244 VP8LTransformColor_C(m, argb_data + i, num_pixels - i); | |
245 } | |
246 | |
247 static WEBP_INLINE void TransformColorInverse(const VP8LMultipliers* const m, | |
248 uint32_t* argb_data, | |
249 int num_pixels) { | |
250 const __m128i g_to_r = _mm_set1_epi32(m->green_to_red_); // multipliers | |
251 const __m128i g_to_b = _mm_set1_epi32(m->green_to_blue_); | |
252 const __m128i r_to_b = _mm_set1_epi32(m->red_to_blue_); | |
253 | |
254 int i; | |
255 | |
256 for (i = 0; i + 4 <= num_pixels; i += 4) { | |
257 const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); | |
258 const __m128i alpha_green_mask = _mm_set1_epi32(0xff00ff00); // masks | |
259 const __m128i red_mask = _mm_set1_epi32(0x00ff0000); | |
260 const __m128i green_mask = _mm_set1_epi32(0x0000ff00); | |
261 const __m128i lower_8bit_mask = _mm_set1_epi32(0x000000ff); | |
262 const __m128i ag = _mm_and_si128(in, alpha_green_mask); // alpha, green | |
263 const __m128i r = _mm_srli_epi32(_mm_and_si128(in, red_mask), 16); | |
264 const __m128i g = _mm_srli_epi32(_mm_and_si128(in, green_mask), 8); | |
265 const __m128i b = in; | |
266 | |
267 const __m128i r_delta = ColorTransformDelta(g_to_r, g); // red | |
268 const __m128i r_new = | |
269 _mm_and_si128(_mm_add_epi32(r, r_delta), lower_8bit_mask); | |
270 const __m128i r_new_shifted = _mm_slli_epi32(r_new, 16); | |
271 | |
272 const __m128i b_delta_1 = ColorTransformDelta(g_to_b, g); // blue | |
273 const __m128i b_delta_2 = ColorTransformDelta(r_to_b, r_new); | |
274 const __m128i b_delta = _mm_add_epi32(b_delta_1, b_delta_2); | |
275 const __m128i b_new = | |
276 _mm_and_si128(_mm_add_epi32(b, b_delta), lower_8bit_mask); | |
277 | |
278 const __m128i out = _mm_or_si128(_mm_or_si128(ag, r_new_shifted), b_new); | |
279 _mm_storeu_si128((__m128i*)&argb_data[i], out); | |
280 } | |
281 | |
282 // Fall-back to C-version for left-overs. | 205 // Fall-back to C-version for left-overs. |
283 VP8LTransformColorInverse_C(m, argb_data + i, num_pixels - i); | 206 VP8LTransformColorInverse_C(m, argb_data + i, num_pixels - i); |
284 } | 207 } |
285 | 208 |
286 //------------------------------------------------------------------------------ | 209 //------------------------------------------------------------------------------ |
287 // Color-space conversion functions | 210 // Color-space conversion functions |
288 | 211 |
289 static void ConvertBGRAToRGBA(const uint32_t* src, | 212 static void ConvertBGRAToRGBA(const uint32_t* src, |
290 int num_pixels, uint8_t* dst) { | 213 int num_pixels, uint8_t* dst) { |
291 const __m128i* in = (const __m128i*)src; | 214 const __m128i* in = (const __m128i*)src; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
411 _mm_storel_epi64((__m128i*)(dst + 12), c4); | 334 _mm_storel_epi64((__m128i*)(dst + 12), c4); |
412 _mm_storel_epi64((__m128i*)(dst + 18), c6); | 335 _mm_storel_epi64((__m128i*)(dst + 18), c6); |
413 dst += 24; | 336 dst += 24; |
414 num_pixels -= 8; | 337 num_pixels -= 8; |
415 } | 338 } |
416 // left-overs | 339 // left-overs |
417 VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, dst); | 340 VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, dst); |
418 } | 341 } |
419 | 342 |
420 //------------------------------------------------------------------------------ | 343 //------------------------------------------------------------------------------ |
421 | 344 // Entry point |
422 #define LINE_SIZE 16 // 8 or 16 | |
423 static void AddVector(const uint32_t* a, const uint32_t* b, uint32_t* out, | |
424 int size) { | |
425 int i; | |
426 assert(size % LINE_SIZE == 0); | |
427 for (i = 0; i < size; i += LINE_SIZE) { | |
428 const __m128i a0 = _mm_loadu_si128((__m128i*)&a[i + 0]); | |
429 const __m128i a1 = _mm_loadu_si128((__m128i*)&a[i + 4]); | |
430 #if (LINE_SIZE == 16) | |
431 const __m128i a2 = _mm_loadu_si128((__m128i*)&a[i + 8]); | |
432 const __m128i a3 = _mm_loadu_si128((__m128i*)&a[i + 12]); | |
433 #endif | |
434 const __m128i b0 = _mm_loadu_si128((__m128i*)&b[i + 0]); | |
435 const __m128i b1 = _mm_loadu_si128((__m128i*)&b[i + 4]); | |
436 #if (LINE_SIZE == 16) | |
437 const __m128i b2 = _mm_loadu_si128((__m128i*)&b[i + 8]); | |
438 const __m128i b3 = _mm_loadu_si128((__m128i*)&b[i + 12]); | |
439 #endif | |
440 _mm_storeu_si128((__m128i*)&out[i + 0], _mm_add_epi32(a0, b0)); | |
441 _mm_storeu_si128((__m128i*)&out[i + 4], _mm_add_epi32(a1, b1)); | |
442 #if (LINE_SIZE == 16) | |
443 _mm_storeu_si128((__m128i*)&out[i + 8], _mm_add_epi32(a2, b2)); | |
444 _mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3)); | |
445 #endif | |
446 } | |
447 } | |
448 | |
449 static void AddVectorEq(const uint32_t* a, uint32_t* out, int size) { | |
450 int i; | |
451 assert(size % LINE_SIZE == 0); | |
452 for (i = 0; i < size; i += LINE_SIZE) { | |
453 const __m128i a0 = _mm_loadu_si128((__m128i*)&a[i + 0]); | |
454 const __m128i a1 = _mm_loadu_si128((__m128i*)&a[i + 4]); | |
455 #if (LINE_SIZE == 16) | |
456 const __m128i a2 = _mm_loadu_si128((__m128i*)&a[i + 8]); | |
457 const __m128i a3 = _mm_loadu_si128((__m128i*)&a[i + 12]); | |
458 #endif | |
459 const __m128i b0 = _mm_loadu_si128((__m128i*)&out[i + 0]); | |
460 const __m128i b1 = _mm_loadu_si128((__m128i*)&out[i + 4]); | |
461 #if (LINE_SIZE == 16) | |
462 const __m128i b2 = _mm_loadu_si128((__m128i*)&out[i + 8]); | |
463 const __m128i b3 = _mm_loadu_si128((__m128i*)&out[i + 12]); | |
464 #endif | |
465 _mm_storeu_si128((__m128i*)&out[i + 0], _mm_add_epi32(a0, b0)); | |
466 _mm_storeu_si128((__m128i*)&out[i + 4], _mm_add_epi32(a1, b1)); | |
467 #if (LINE_SIZE == 16) | |
468 _mm_storeu_si128((__m128i*)&out[i + 8], _mm_add_epi32(a2, b2)); | |
469 _mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3)); | |
470 #endif | |
471 } | |
472 } | |
473 #undef LINE_SIZE | |
474 | |
475 // Note we are adding uint32_t's as *signed* int32's (using _mm_add_epi32). But | |
476 // that's ok since the histogram values are less than 1<<28 (max picture size). | |
477 static void HistogramAdd(const VP8LHistogram* const a, | |
478 const VP8LHistogram* const b, | |
479 VP8LHistogram* const out) { | |
480 int i; | |
481 const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_); | |
482 assert(a->palette_code_bits_ == b->palette_code_bits_); | |
483 if (b != out) { | |
484 AddVector(a->literal_, b->literal_, out->literal_, NUM_LITERAL_CODES); | |
485 AddVector(a->red_, b->red_, out->red_, NUM_LITERAL_CODES); | |
486 AddVector(a->blue_, b->blue_, out->blue_, NUM_LITERAL_CODES); | |
487 AddVector(a->alpha_, b->alpha_, out->alpha_, NUM_LITERAL_CODES); | |
488 } else { | |
489 AddVectorEq(a->literal_, out->literal_, NUM_LITERAL_CODES); | |
490 AddVectorEq(a->red_, out->red_, NUM_LITERAL_CODES); | |
491 AddVectorEq(a->blue_, out->blue_, NUM_LITERAL_CODES); | |
492 AddVectorEq(a->alpha_, out->alpha_, NUM_LITERAL_CODES); | |
493 } | |
494 for (i = NUM_LITERAL_CODES; i < literal_size; ++i) { | |
495 out->literal_[i] = a->literal_[i] + b->literal_[i]; | |
496 } | |
497 for (i = 0; i < NUM_DISTANCE_CODES; ++i) { | |
498 out->distance_[i] = a->distance_[i] + b->distance_[i]; | |
499 } | |
500 } | |
501 | |
502 #endif // WEBP_USE_SSE2 | |
503 | |
504 //------------------------------------------------------------------------------ | |
505 | 345 |
506 extern void VP8LDspInitSSE2(void); | 346 extern void VP8LDspInitSSE2(void); |
507 | 347 |
508 void VP8LDspInitSSE2(void) { | 348 WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE2(void) { |
509 #if defined(WEBP_USE_SSE2) | |
510 VP8LPredictors[5] = Predictor5; | 349 VP8LPredictors[5] = Predictor5; |
511 VP8LPredictors[6] = Predictor6; | 350 VP8LPredictors[6] = Predictor6; |
512 VP8LPredictors[7] = Predictor7; | 351 VP8LPredictors[7] = Predictor7; |
513 VP8LPredictors[8] = Predictor8; | 352 VP8LPredictors[8] = Predictor8; |
514 VP8LPredictors[9] = Predictor9; | 353 VP8LPredictors[9] = Predictor9; |
515 VP8LPredictors[10] = Predictor10; | 354 VP8LPredictors[10] = Predictor10; |
516 VP8LPredictors[11] = Predictor11; | 355 VP8LPredictors[11] = Predictor11; |
517 VP8LPredictors[12] = Predictor12; | 356 VP8LPredictors[12] = Predictor12; |
518 VP8LPredictors[13] = Predictor13; | 357 VP8LPredictors[13] = Predictor13; |
519 | 358 |
520 VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed; | |
521 VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed; | 359 VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed; |
522 | |
523 VP8LTransformColor = TransformColor; | |
524 VP8LTransformColorInverse = TransformColorInverse; | 360 VP8LTransformColorInverse = TransformColorInverse; |
525 | 361 |
526 VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA; | 362 VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA; |
527 VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444; | 363 VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444; |
528 VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565; | 364 VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565; |
529 VP8LConvertBGRAToBGR = ConvertBGRAToBGR; | 365 VP8LConvertBGRAToBGR = ConvertBGRAToBGR; |
530 | |
531 VP8LHistogramAdd = HistogramAdd; | |
532 #endif // WEBP_USE_SSE2 | |
533 } | 366 } |
534 | 367 |
535 //------------------------------------------------------------------------------ | 368 #else // !WEBP_USE_SSE2 |
| 369 |
| 370 WEBP_DSP_INIT_STUB(VP8LDspInitSSE2) |
| 371 |
| 372 #endif // WEBP_USE_SSE2 |
OLD | NEW |