u_sse.h revision 7ec681f3
1/************************************************************************** 2 * 3 * Copyright 2008-2021 VMware, Inc. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28/** 29 * @file 30 * SSE intrinsics portability header. 31 * 32 * Although the SSE intrinsics are support by all modern x86 and x86-64 33 * compilers, there are some intrisincs missing in some implementations 34 * (especially older MSVC versions). This header abstracts that away. 35 */ 36 37#ifndef U_SSE_H_ 38#define U_SSE_H_ 39 40#include "pipe/p_config.h" 41#include "pipe/p_compiler.h" 42#include "util/u_debug.h" 43 44#if defined(PIPE_ARCH_SSE) 45 46#include <emmintrin.h> 47 48 49union m128i { 50 __m128i m; 51 ubyte ub[16]; 52 ushort us[8]; 53 uint ui[4]; 54}; 55 56static inline void u_print_epi8(const char *name, __m128i r) 57{ 58 union { __m128i m; ubyte ub[16]; } u; 59 u.m = r; 60 61 debug_printf("%s: " 62 "%02x/" 63 "%02x/" 64 "%02x/" 65 "%02x/" 66 "%02x/" 67 "%02x/" 68 "%02x/" 69 "%02x/" 70 "%02x/" 71 "%02x/" 72 "%02x/" 73 "%02x/" 74 "%02x/" 75 "%02x/" 76 "%02x/" 77 "%02x\n", 78 name, 79 u.ub[0], u.ub[1], u.ub[2], u.ub[3], 80 u.ub[4], u.ub[5], u.ub[6], u.ub[7], 81 u.ub[8], u.ub[9], u.ub[10], u.ub[11], 82 u.ub[12], u.ub[13], u.ub[14], u.ub[15]); 83} 84 85static inline void u_print_epi16(const char *name, __m128i r) 86{ 87 union { __m128i m; ushort us[8]; } u; 88 u.m = r; 89 90 debug_printf("%s: " 91 "%04x/" 92 "%04x/" 93 "%04x/" 94 "%04x/" 95 "%04x/" 96 "%04x/" 97 "%04x/" 98 "%04x\n", 99 name, 100 u.us[0], u.us[1], u.us[2], u.us[3], 101 u.us[4], u.us[5], u.us[6], u.us[7]); 102} 103 104static inline void u_print_epi32(const char *name, __m128i r) 105{ 106 union { __m128i m; uint ui[4]; } u; 107 u.m = r; 108 109 debug_printf("%s: " 110 "%08x/" 111 "%08x/" 112 "%08x/" 113 "%08x\n", 114 name, 115 u.ui[0], u.ui[1], u.ui[2], u.ui[3]); 116} 117 118static inline void u_print_ps(const char *name, __m128 r) 119{ 120 union { __m128 m; float f[4]; } u; 121 u.m = r; 122 123 debug_printf("%s: " 124 "%f/" 125 "%f/" 126 "%f/" 127 "%f\n", 128 name, 129 u.f[0], u.f[1], u.f[2], u.f[3]); 130} 131 132 133#define U_DUMP_EPI32(a) u_print_epi32(#a, a) 134#define U_DUMP_EPI16(a) u_print_epi16(#a, a) 135#define U_DUMP_EPI8(a) u_print_epi8(#a, a) 136#define U_DUMP_PS(a) u_print_ps(#a, a) 137 138 139 140#if defined(PIPE_ARCH_SSSE3) 141 142#include <tmmintrin.h> 143 144#else /* !PIPE_ARCH_SSSE3 */ 145 146/** 147 * Describe _mm_shuffle_epi8() with gcc extended inline assembly, for cases 148 * where -mssse3 is not supported/enabled. 149 * 150 * MSVC will never get in here as its intrinsics support do not rely on 151 * compiler command line options. 152 */ 153static __inline __m128i 154#ifdef __clang__ 155 __attribute__((__always_inline__, __nodebug__)) 156#else 157 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) 158#endif 159_mm_shuffle_epi8(__m128i a, __m128i mask) 160{ 161 __m128i result; 162 __asm__("pshufb %1, %0" 163 : "=x" (result) 164 : "xm" (mask), "0" (a)); 165 return result; 166} 167 168#endif /* !PIPE_ARCH_SSSE3 */ 169 170 171/* 172 * Provide an SSE implementation of _mm_mul_epi32() in terms of 173 * _mm_mul_epu32(). 174 * 175 * Basically, albeit surprising at first (and second, and third...) look 176 * if a * b is done signed instead of unsigned, can just 177 * subtract b from the high bits of the result if a is negative 178 * (and the same for a if b is negative). Modular arithmetic at its best! 179 * 180 * So for int32 a,b in crude pseudo-code ("*" here denoting a widening mul) 181 * fixupb = (signmask(b) & a) << 32ULL 182 * fixupa = (signmask(a) & b) << 32ULL 183 * a * b = (unsigned)a * (unsigned)b - fixupb - fixupa 184 * = (unsigned)a * (unsigned)b -(fixupb + fixupa) 185 * 186 * This does both lo (dwords 0/2) and hi parts (1/3) at the same time due 187 * to some optimization potential. 188 */ 189static inline __m128i 190mm_mullohi_epi32(const __m128i a, const __m128i b, __m128i *res13) 191{ 192 __m128i a13, b13, mul02, mul13; 193 __m128i anegmask, bnegmask, fixup, fixup02, fixup13; 194 a13 = _mm_shuffle_epi32(a, _MM_SHUFFLE(2,3,0,1)); 195 b13 = _mm_shuffle_epi32(b, _MM_SHUFFLE(2,3,0,1)); 196 anegmask = _mm_srai_epi32(a, 31); 197 bnegmask = _mm_srai_epi32(b, 31); 198 fixup = _mm_add_epi32(_mm_and_si128(anegmask, b), 199 _mm_and_si128(bnegmask, a)); 200 mul02 = _mm_mul_epu32(a, b); 201 mul13 = _mm_mul_epu32(a13, b13); 202 fixup02 = _mm_slli_epi64(fixup, 32); 203 fixup13 = _mm_and_si128(fixup, _mm_set_epi32(-1,0,-1,0)); 204 *res13 = _mm_sub_epi64(mul13, fixup13); 205 return _mm_sub_epi64(mul02, fixup02); 206} 207 208 209/* Provide an SSE2 implementation of _mm_mullo_epi32() in terms of 210 * _mm_mul_epu32(). 211 * 212 * This always works regardless the signs of the operands, since 213 * the high bits (which would be different) aren't used. 214 * 215 * This seems close enough to the speed of SSE4 and the real 216 * _mm_mullo_epi32() intrinsic as to not justify adding an sse4 217 * dependency at this point. 218 */ 219static inline __m128i mm_mullo_epi32(const __m128i a, const __m128i b) 220{ 221 __m128i a4 = _mm_srli_epi64(a, 32); /* shift by one dword */ 222 __m128i b4 = _mm_srli_epi64(b, 32); /* shift by one dword */ 223 __m128i ba = _mm_mul_epu32(b, a); /* multply dwords 0, 2 */ 224 __m128i b4a4 = _mm_mul_epu32(b4, a4); /* multiply dwords 1, 3 */ 225 226 /* Interleave the results, either with shuffles or (slightly 227 * faster) direct bit operations: 228 * XXX: might be only true for some cpus (in particular 65nm 229 * Core 2). On most cpus (including that Core 2, but not Nehalem...) 230 * using _mm_shuffle_ps/_mm_shuffle_epi32 might also be faster 231 * than using the 3 instructions below. But logic should be fine 232 * as well, we can't have optimal solution for all cpus (if anything, 233 * should just use _mm_mullo_epi32() if sse41 is available...). 234 */ 235#if 0 236 __m128i ba8 = _mm_shuffle_epi32(ba, 8); 237 __m128i b4a48 = _mm_shuffle_epi32(b4a4, 8); 238 __m128i result = _mm_unpacklo_epi32(ba8, b4a48); 239#else 240 __m128i mask = _mm_setr_epi32(~0,0,~0,0); 241 __m128i ba_mask = _mm_and_si128(ba, mask); 242 __m128i b4a4_mask_shift = _mm_slli_epi64(b4a4, 32); 243 __m128i result = _mm_or_si128(ba_mask, b4a4_mask_shift); 244#endif 245 246 return result; 247} 248 249 250static inline void 251transpose4_epi32(const __m128i * restrict a, 252 const __m128i * restrict b, 253 const __m128i * restrict c, 254 const __m128i * restrict d, 255 __m128i * restrict o, 256 __m128i * restrict p, 257 __m128i * restrict q, 258 __m128i * restrict r) 259{ 260 __m128i t0 = _mm_unpacklo_epi32(*a, *b); 261 __m128i t1 = _mm_unpacklo_epi32(*c, *d); 262 __m128i t2 = _mm_unpackhi_epi32(*a, *b); 263 __m128i t3 = _mm_unpackhi_epi32(*c, *d); 264 265 *o = _mm_unpacklo_epi64(t0, t1); 266 *p = _mm_unpackhi_epi64(t0, t1); 267 *q = _mm_unpacklo_epi64(t2, t3); 268 *r = _mm_unpackhi_epi64(t2, t3); 269} 270 271 272/* 273 * Same as above, except the first two values are already interleaved 274 * (i.e. contain 64bit values). 275 */ 276static inline void 277transpose2_64_2_32(const __m128i * restrict a01, 278 const __m128i * restrict a23, 279 const __m128i * restrict c, 280 const __m128i * restrict d, 281 __m128i * restrict o, 282 __m128i * restrict p, 283 __m128i * restrict q, 284 __m128i * restrict r) 285{ 286 __m128i t0 = *a01; 287 __m128i t1 = _mm_unpacklo_epi32(*c, *d); 288 __m128i t2 = *a23; 289 __m128i t3 = _mm_unpackhi_epi32(*c, *d); 290 291 *o = _mm_unpacklo_epi64(t0, t1); 292 *p = _mm_unpackhi_epi64(t0, t1); 293 *q = _mm_unpacklo_epi64(t2, t3); 294 *r = _mm_unpackhi_epi64(t2, t3); 295} 296 297 298#define SCALAR_EPI32(m, i) _mm_shuffle_epi32((m), _MM_SHUFFLE(i,i,i,i)) 299 300 301/* 302 * Implements (1-w)*a + w*b = a - wa + wb = w(b-a) + a 303 * ((b-a)*w >> 8) + a 304 * The math behind negative sub results (logic shift/mask) is tricky. 305 * 306 * w -- weight values 307 * a -- src0 values 308 * b -- src1 values 309 */ 310static ALWAYS_INLINE __m128i 311util_sse2_lerp_epi16(__m128i w, __m128i a, __m128i b) 312{ 313 __m128i res; 314 315 res = _mm_sub_epi16(b, a); 316 res = _mm_mullo_epi16(res, w); 317 res = _mm_srli_epi16(res, 8); 318 /* use add_epi8 instead of add_epi16 so no need to mask off upper bits */ 319 res = _mm_add_epi8(res, a); 320 321 return res; 322} 323 324 325/* Apply premultiplied-alpha blending on two pixels simultaneously. 326 * All parameters are packed as 8.8 fixed point values in __m128i SSE 327 * registers, with the upper 8 bits all zero. 328 * 329 * a -- src alpha values 330 * d -- dst color values 331 * s -- src color values 332 */ 333static inline __m128i 334util_sse2_premul_blend_epi16( __m128i a, __m128i d, __m128i s) 335{ 336 __m128i da, d_sub_da, tmp; 337 tmp = _mm_mullo_epi16(d, a); 338 da = _mm_srli_epi16(tmp, 8); 339 d_sub_da = _mm_sub_epi16(d, da); 340 341 return _mm_add_epi16(s, d_sub_da); 342} 343 344 345/* Apply premultiplied-alpha blending on four pixels in packed BGRA 346 * format (one/inv_src_alpha blend mode). 347 * 348 * src -- four pixels (bgra8 format) 349 * dst -- four destination pixels (bgra8) 350 * return -- blended pixels (bgra8) 351 */ 352static ALWAYS_INLINE __m128i 353util_sse2_blend_premul_4(const __m128i src, 354 const __m128i dst) 355{ 356 357 __m128i al, ah, dl, dh, sl, sh, rl, rh; 358 __m128i zero = _mm_setzero_si128(); 359 360 /* Blend first two pixels: 361 */ 362 sl = _mm_unpacklo_epi8(src, zero); 363 dl = _mm_unpacklo_epi8(dst, zero); 364 365 al = _mm_shufflehi_epi16(sl, 0xff); 366 al = _mm_shufflelo_epi16(al, 0xff); 367 368 rl = util_sse2_premul_blend_epi16(al, dl, sl); 369 370 /* Blend second two pixels: 371 */ 372 sh = _mm_unpackhi_epi8(src, zero); 373 dh = _mm_unpackhi_epi8(dst, zero); 374 375 ah = _mm_shufflehi_epi16(sh, 0xff); 376 ah = _mm_shufflelo_epi16(ah, 0xff); 377 378 rh = util_sse2_premul_blend_epi16(ah, dh, sh); 379 380 /* Pack the results down to four bgra8 pixels: 381 */ 382 return _mm_packus_epi16(rl, rh); 383} 384 385 386/* Apply src-alpha blending on four pixels in packed BGRA 387 * format (srcalpha/inv_src_alpha blend mode). 388 * 389 * src -- four pixels (bgra8 format) 390 * dst -- four destination pixels (bgra8) 391 * return -- blended pixels (bgra8) 392 */ 393static ALWAYS_INLINE __m128i 394util_sse2_blend_srcalpha_4(const __m128i src, 395 const __m128i dst) 396{ 397 398 __m128i al, ah, dl, dh, sl, sh, rl, rh; 399 __m128i zero = _mm_setzero_si128(); 400 401 /* Blend first two pixels: 402 */ 403 sl = _mm_unpacklo_epi8(src, zero); 404 dl = _mm_unpacklo_epi8(dst, zero); 405 406 al = _mm_shufflehi_epi16(sl, 0xff); 407 al = _mm_shufflelo_epi16(al, 0xff); 408 409 rl = util_sse2_lerp_epi16(al, dl, sl); 410 411 /* Blend second two pixels: 412 */ 413 sh = _mm_unpackhi_epi8(src, zero); 414 dh = _mm_unpackhi_epi8(dst, zero); 415 416 ah = _mm_shufflehi_epi16(sh, 0xff); 417 ah = _mm_shufflelo_epi16(ah, 0xff); 418 419 rh = util_sse2_lerp_epi16(ah, dh, sh); 420 421 /* Pack the results down to four bgra8 pixels: 422 */ 423 return _mm_packus_epi16(rl, rh); 424} 425 426 427/** 428 * premultiplies src with constant alpha then 429 * does one/inv_src_alpha blend. 430 * 431 * src 16xi8 (normalized) 432 * dst 16xi8 (normalized) 433 * cst_alpha (constant alpha (u8 value)) 434 */ 435static ALWAYS_INLINE __m128i 436util_sse2_blend_premul_src_4(const __m128i src, 437 const __m128i dst, 438 const unsigned cst_alpha) 439{ 440 441 __m128i srca, d, s, rl, rh; 442 __m128i zero = _mm_setzero_si128(); 443 __m128i cst_alpha_vec = _mm_set1_epi16(cst_alpha); 444 445 /* Blend first two pixels: 446 */ 447 s = _mm_unpacklo_epi8(src, zero); 448 s = _mm_mullo_epi16(s, cst_alpha_vec); 449 /* the shift will cause some precision loss */ 450 s = _mm_srli_epi16(s, 8); 451 452 srca = _mm_shufflehi_epi16(s, 0xff); 453 srca = _mm_shufflelo_epi16(srca, 0xff); 454 455 d = _mm_unpacklo_epi8(dst, zero); 456 rl = util_sse2_premul_blend_epi16(srca, d, s); 457 458 /* Blend second two pixels: 459 */ 460 s = _mm_unpackhi_epi8(src, zero); 461 s = _mm_mullo_epi16(s, cst_alpha_vec); 462 /* the shift will cause some precision loss */ 463 s = _mm_srli_epi16(s, 8); 464 465 srca = _mm_shufflehi_epi16(s, 0xff); 466 srca = _mm_shufflelo_epi16(srca, 0xff); 467 468 d = _mm_unpackhi_epi8(dst, zero); 469 rh = util_sse2_premul_blend_epi16(srca, d, s); 470 471 /* Pack the results down to four bgra8 pixels: 472 */ 473 return _mm_packus_epi16(rl, rh); 474} 475 476 477/** 478 * Linear interpolation with SSE2. 479 * 480 * dst, src0, src1 are 16 x i8 vectors, with [0..255] normalized values. 481 * 482 * weight_lo and weight_hi should be a 8 x i16 vectors, in 8.8 fixed point 483 * format, for the low and high components. 484 * We'd want to pass these as values but MSVC limitation forces us to pass these 485 * as pointers since it will complain if more than 3 __m128 are passed by value. 486 */ 487static ALWAYS_INLINE __m128i 488util_sse2_lerp_epi8_fixed88(__m128i src0, __m128i src1, 489 const __m128i * restrict weight_lo, 490 const __m128i * restrict weight_hi) 491{ 492 const __m128i zero = _mm_setzero_si128(); 493 494 __m128i src0_lo = _mm_unpacklo_epi8(src0, zero); 495 __m128i src0_hi = _mm_unpackhi_epi8(src0, zero); 496 497 __m128i src1_lo = _mm_unpacklo_epi8(src1, zero); 498 __m128i src1_hi = _mm_unpackhi_epi8(src1, zero); 499 500 __m128i dst_lo; 501 __m128i dst_hi; 502 503 dst_lo = util_sse2_lerp_epi16(*weight_lo, src0_lo, src1_lo); 504 dst_hi = util_sse2_lerp_epi16(*weight_hi, src0_hi, src1_hi); 505 506 return _mm_packus_epi16(dst_lo, dst_hi); 507} 508 509 510/** 511 * Linear interpolation with SSE2. 512 * 513 * dst, src0, src1 are 16 x i8 vectors, with [0..255] normalized values. 514 * 515 * weight should be a 16 x i8 vector, in 0.8 fixed point values. 516 */ 517static ALWAYS_INLINE __m128i 518util_sse2_lerp_epi8_fixed08(__m128i src0, __m128i src1, 519 __m128i weight) 520{ 521 const __m128i zero = _mm_setzero_si128(); 522 __m128i weight_lo = _mm_unpacklo_epi8(weight, zero); 523 __m128i weight_hi = _mm_unpackhi_epi8(weight, zero); 524 525 return util_sse2_lerp_epi8_fixed88(src0, src1, 526 &weight_lo, &weight_hi); 527} 528 529 530/** 531 * Linear interpolation with SSE2. 532 * 533 * dst, src0, src1, and weight are 16 x i8 vectors, with [0..255] normalized 534 * values. 535 */ 536static ALWAYS_INLINE __m128i 537util_sse2_lerp_unorm8(__m128i src0, __m128i src1, 538 __m128i weight) 539{ 540 const __m128i zero = _mm_setzero_si128(); 541 __m128i weight_lo = _mm_unpacklo_epi8(weight, zero); 542 __m128i weight_hi = _mm_unpackhi_epi8(weight, zero); 543 544#if 0 545 /* 546 * Rescale from [0..255] to [0..256]. 547 */ 548 weight_lo = _mm_add_epi16(weight_lo, _mm_srli_epi16(weight_lo, 7)); 549 weight_hi = _mm_add_epi16(weight_hi, _mm_srli_epi16(weight_hi, 7)); 550#endif 551 552 return util_sse2_lerp_epi8_fixed88(src0, src1, 553 &weight_lo, &weight_hi); 554} 555 556 557/** 558 * Linear interpolation with SSE2. 559 * 560 * dst, src0, src1, src2, src3 are 16 x i8 vectors, with [0..255] normalized 561 * values. 562 * 563 * ws_lo, ws_hi, wt_lo, wt_hi should be a 8 x i16 vectors, in 8.8 fixed point 564 * format, for the low and high components. 565 * We'd want to pass these as values but MSVC limitation forces us to pass these 566 * as pointers since it will complain if more than 3 __m128 are passed by value. 567 * 568 * This uses ws_lo, ws_hi to interpolate between src0 and src1, as well as to 569 * interpolate between src2 and src3, then uses wt_lo and wt_hi to interpolate 570 * between the resulting vectors. 571 */ 572static ALWAYS_INLINE __m128i 573util_sse2_lerp_2d_epi8_fixed88(__m128i src0, __m128i src1, 574 const __m128i * restrict src2, 575 const __m128i * restrict src3, 576 const __m128i * restrict ws_lo, 577 const __m128i * restrict ws_hi, 578 const __m128i * restrict wt_lo, 579 const __m128i * restrict wt_hi) 580{ 581 const __m128i zero = _mm_setzero_si128(); 582 583 __m128i src0_lo = _mm_unpacklo_epi8(src0, zero); 584 __m128i src0_hi = _mm_unpackhi_epi8(src0, zero); 585 586 __m128i src1_lo = _mm_unpacklo_epi8(src1, zero); 587 __m128i src1_hi = _mm_unpackhi_epi8(src1, zero); 588 589 __m128i src2_lo = _mm_unpacklo_epi8(*src2, zero); 590 __m128i src2_hi = _mm_unpackhi_epi8(*src2, zero); 591 592 __m128i src3_lo = _mm_unpacklo_epi8(*src3, zero); 593 __m128i src3_hi = _mm_unpackhi_epi8(*src3, zero); 594 595 __m128i dst_lo, dst01_lo, dst23_lo; 596 __m128i dst_hi, dst01_hi, dst23_hi; 597 598 dst01_lo = util_sse2_lerp_epi16(*ws_lo, src0_lo, src1_lo); 599 dst01_hi = util_sse2_lerp_epi16(*ws_hi, src0_hi, src1_hi); 600 dst23_lo = util_sse2_lerp_epi16(*ws_lo, src2_lo, src3_lo); 601 dst23_hi = util_sse2_lerp_epi16(*ws_hi, src2_hi, src3_hi); 602 603 dst_lo = util_sse2_lerp_epi16(*wt_lo, dst01_lo, dst23_lo); 604 dst_hi = util_sse2_lerp_epi16(*wt_hi, dst01_hi, dst23_hi); 605 606 return _mm_packus_epi16(dst_lo, dst_hi); 607} 608 609/** 610 * Stretch a row of pixels using linear filter. 611 * 612 * Uses Bresenham's line algorithm using 16.16 fixed point representation for 613 * the error term. 614 * 615 * @param dst_width destination width in pixels 616 * @param src_x start x0 in 16.16 fixed point format 617 * @param src_xstep step in 16.16. fixed point format 618 * 619 * @return final src_x value (i.e., src_x + dst_width*src_xstep) 620 */ 621static ALWAYS_INLINE int32_t 622util_sse2_stretch_row_8unorm(__m128i * restrict dst, 623 int32_t dst_width, 624 const uint32_t * restrict src, 625 int32_t src_x, 626 int32_t src_xstep) 627{ 628 int16_t error0, error1, error2, error3; 629 __m128i error_lo, error_hi, error_step; 630 631 assert(dst_width >= 0); 632 assert(dst_width % 4 == 0); 633 634 error0 = src_x; 635 error1 = error0 + src_xstep; 636 error2 = error1 + src_xstep; 637 error3 = error2 + src_xstep; 638 639 error_lo = _mm_setr_epi16(error0, error0, error0, error0, 640 error1, error1, error1, error1); 641 error_hi = _mm_setr_epi16(error2, error2, error2, error2, 642 error3, error3, error3, error3); 643 error_step = _mm_set1_epi16(src_xstep << 2); 644 645 dst_width >>= 2; 646 while (dst_width) { 647 uint16_t src_x0; 648 uint16_t src_x1; 649 uint16_t src_x2; 650 uint16_t src_x3; 651 __m128i src0, src1; 652 __m128i weight_lo, weight_hi; 653 654 /* 655 * It is faster to re-compute the coordinates in the scalar integer unit here, 656 * than to fetch the values from the SIMD integer unit. 657 */ 658 659 src_x0 = src_x >> 16; 660 src_x += src_xstep; 661 src_x1 = src_x >> 16; 662 src_x += src_xstep; 663 src_x2 = src_x >> 16; 664 src_x += src_xstep; 665 src_x3 = src_x >> 16; 666 src_x += src_xstep; 667 668 /* 669 * Fetch pairs of pixels 64bit at a time, and then swizzle them inplace. 670 */ 671 672 { 673 __m128i src_00_10 = _mm_loadl_epi64((const __m128i *)&src[src_x0]); 674 __m128i src_01_11 = _mm_loadl_epi64((const __m128i *)&src[src_x1]); 675 __m128i src_02_12 = _mm_loadl_epi64((const __m128i *)&src[src_x2]); 676 __m128i src_03_13 = _mm_loadl_epi64((const __m128i *)&src[src_x3]); 677 678 __m128i src_00_01_10_11 = _mm_unpacklo_epi32(src_00_10, src_01_11); 679 __m128i src_02_03_12_13 = _mm_unpacklo_epi32(src_02_12, src_03_13); 680 681 src0 = _mm_unpacklo_epi64(src_00_01_10_11, src_02_03_12_13); 682 src1 = _mm_unpackhi_epi64(src_00_01_10_11, src_02_03_12_13); 683 } 684 685 weight_lo = _mm_srli_epi16(error_lo, 8); 686 weight_hi = _mm_srli_epi16(error_hi, 8); 687 688 *dst = util_sse2_lerp_epi8_fixed88(src0, src1, 689 &weight_lo, &weight_hi); 690 691 error_lo = _mm_add_epi16(error_lo, error_step); 692 error_hi = _mm_add_epi16(error_hi, error_step); 693 694 ++dst; 695 --dst_width; 696 } 697 698 return src_x; 699} 700 701 702 703#endif /* PIPE_ARCH_SSE */ 704 705#endif /* U_SSE_H_ */ 706