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