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