23#include <winpr/wtypes.h>
24#include <freerdp/config.h>
26#include <winpr/sysinfo.h>
28#include <freerdp/types.h>
29#include <freerdp/primitives.h>
31#include "prim_internal.h"
32#include "prim_avxsse.h"
35#if defined(SSE_AVX_INTRINSICS_ENABLED)
45static inline __m128i* sse41_YUV444Pixel(__m128i* WINPR_RESTRICT dst, __m128i Yraw, __m128i Uraw,
46 __m128i Vraw, UINT8 pos)
48 const __m128i mapY[] = { mm_set_epu32(0x80800380, 0x80800280, 0x80800180, 0x80800080),
49 mm_set_epu32(0x80800780, 0x80800680, 0x80800580, 0x80800480),
50 mm_set_epu32(0x80800B80, 0x80800A80, 0x80800980, 0x80800880),
51 mm_set_epu32(0x80800F80, 0x80800E80, 0x80800D80, 0x80800C80) };
52 const __m128i mapUV[] = { mm_set_epu32(0x80038002, 0x80018000, 0x80808080, 0x80808080),
53 mm_set_epu32(0x80078006, 0x80058004, 0x80808080, 0x80808080),
54 mm_set_epu32(0x800B800A, 0x80098008, 0x80808080, 0x80808080),
55 mm_set_epu32(0x800F800E, 0x800D800C, 0x80808080, 0x80808080) };
56 const __m128i mask[] = { mm_set_epu32(0x80038080, 0x80028080, 0x80018080, 0x80008080),
57 mm_set_epu32(0x80800380, 0x80800280, 0x80800180, 0x80800080),
58 mm_set_epu32(0x80808003, 0x80808002, 0x80808001, 0x80808000) };
59 const __m128i c128 = _mm_set1_epi16(128);
60 __m128i BGRX = _mm_and_si128(LOAD_SI128(dst),
61 mm_set_epu32(0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000));
68 C = _mm_shuffle_epi8(Yraw, mapY[pos]);
72 const __m128i U = _mm_shuffle_epi8(Uraw, mapUV[pos]);
73 D = _mm_sub_epi16(U, c128);
77 const __m128i V = _mm_shuffle_epi8(Vraw, mapUV[pos]);
78 E = _mm_sub_epi16(V, c128);
82 const __m128i c403 = _mm_set1_epi16(403);
84 _mm_unpackhi_epi16(_mm_mullo_epi16(E, c403), _mm_mulhi_epi16(E, c403));
85 const __m128i Rs = _mm_add_epi32(C, e403);
86 const __m128i R32 = _mm_srai_epi32(Rs, 8);
87 const __m128i R16 = _mm_packs_epi32(R32, _mm_setzero_si128());
88 const __m128i R = _mm_packus_epi16(R16, _mm_setzero_si128());
89 const __m128i packed = _mm_shuffle_epi8(R, mask[0]);
90 BGRX = _mm_or_si128(BGRX, packed);
94 const __m128i c48 = _mm_set1_epi16(48);
96 _mm_unpackhi_epi16(_mm_mullo_epi16(D, c48), _mm_mulhi_epi16(D, c48));
97 const __m128i c120 = _mm_set1_epi16(120);
99 _mm_unpackhi_epi16(_mm_mullo_epi16(E, c120), _mm_mulhi_epi16(E, c120));
100 const __m128i de = _mm_add_epi32(d48, e120);
101 const __m128i Gs = _mm_sub_epi32(C, de);
102 const __m128i G32 = _mm_srai_epi32(Gs, 8);
103 const __m128i G16 = _mm_packs_epi32(G32, _mm_setzero_si128());
104 const __m128i G = _mm_packus_epi16(G16, _mm_setzero_si128());
105 const __m128i packed = _mm_shuffle_epi8(G, mask[1]);
106 BGRX = _mm_or_si128(BGRX, packed);
110 const __m128i c475 = _mm_set1_epi16(475);
112 _mm_unpackhi_epi16(_mm_mullo_epi16(D, c475), _mm_mulhi_epi16(D, c475));
113 const __m128i Bs = _mm_add_epi32(C, d475);
114 const __m128i B32 = _mm_srai_epi32(Bs, 8);
115 const __m128i B16 = _mm_packs_epi32(B32, _mm_setzero_si128());
116 const __m128i B = _mm_packus_epi16(B16, _mm_setzero_si128());
117 const __m128i packed = _mm_shuffle_epi8(B, mask[2]);
118 BGRX = _mm_or_si128(BGRX, packed);
121 STORE_SI128(dst++, BGRX);
125static inline pstatus_t sse41_YUV420ToRGB_BGRX(
const BYTE* WINPR_RESTRICT pSrc[],
126 const UINT32* WINPR_RESTRICT srcStep,
127 BYTE* WINPR_RESTRICT pDst, UINT32 dstStep,
130 const UINT32 nWidth = roi->width;
131 const UINT32 nHeight = roi->height;
132 const UINT32 pad = roi->width % 16;
133 const __m128i duplicate = _mm_set_epi8(7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0);
135 for (
size_t y = 0; y < nHeight; y++)
137 __m128i* dst = WINPR_PACKED_ALIGN_CAST(__m128i*, (pDst + dstStep * y));
138 const BYTE* YData = pSrc[0] + y * srcStep[0];
139 const BYTE* UData = pSrc[1] + (y / 2) * srcStep[1];
140 const BYTE* VData = pSrc[2] + (y / 2) * srcStep[2];
142 for (UINT32 x = 0; x < nWidth - pad; x += 16)
144 const __m128i Y = LOAD_SI128(YData);
145 const __m128i uRaw = LOAD_SI128(UData);
146 const __m128i vRaw = LOAD_SI128(VData);
147 const __m128i U = _mm_shuffle_epi8(uRaw, duplicate);
148 const __m128i V = _mm_shuffle_epi8(vRaw, duplicate);
152 dst = sse41_YUV444Pixel(dst, Y, U, V, 0);
153 dst = sse41_YUV444Pixel(dst, Y, U, V, 1);
154 dst = sse41_YUV444Pixel(dst, Y, U, V, 2);
155 dst = sse41_YUV444Pixel(dst, Y, U, V, 3);
158 for (UINT32 x = 0; x < pad; x++)
160 const BYTE Y = *YData++;
161 const BYTE U = *UData;
162 const BYTE V = *VData;
163 dst = WINPR_PACKED_ALIGN_CAST(
164 __m128i*, writeYUVPixel((BYTE*)dst, PIXEL_FORMAT_BGRX32, Y, U, V, writePixelBGRX));
174 return PRIMITIVES_SUCCESS;
177static pstatus_t sse41_YUV420ToRGB(
const BYTE* WINPR_RESTRICT pSrc[3],
const UINT32 srcStep[3],
178 BYTE* WINPR_RESTRICT pDst, UINT32 dstStep, UINT32 DstFormat,
183 case PIXEL_FORMAT_BGRX32:
184 case PIXEL_FORMAT_BGRA32:
185 return sse41_YUV420ToRGB_BGRX(pSrc, srcStep, pDst, dstStep, roi);
188 return generic->YUV420ToRGB_8u_P3AC4R(pSrc, srcStep, pDst, dstStep, DstFormat, roi);
192static inline void BGRX_fillRGB(
size_t offset, BYTE* WINPR_RESTRICT pRGB[2],
193 const BYTE* WINPR_RESTRICT pY[2],
const BYTE* WINPR_RESTRICT pU[2],
194 const BYTE* WINPR_RESTRICT pV[2], BOOL filter)
201 const UINT32 DstFormat = PIXEL_FORMAT_BGRX32;
202 const UINT32 bpp = 4;
204 for (
size_t i = 0; i < 2; i++)
206 for (
size_t j = 0; j < 2; j++)
208 const BYTE Y = pY[i][offset + j];
209 BYTE U = pU[i][offset + j];
210 BYTE V = pV[i][offset + j];
211 if ((i == 0) && (j == 0) && filter)
214 4 * pU[0][offset] - pU[0][offset + 1] - pU[1][offset] - pU[1][offset + 1];
216 4 * pV[0][offset] - pV[0][offset + 1] - pV[1][offset] - pV[1][offset + 1];
218 U = CONDITIONAL_CLIP(avgU, pU[0][offset]);
219 V = CONDITIONAL_CLIP(avgV, pV[0][offset]);
222 writeYUVPixel(&pRGB[i][(j + offset) * bpp], DstFormat, Y, U, V, writePixelBGRX);
228static inline __m128i sse41_yuv2x_single(
const __m128i Y, __m128i U, __m128i V,
const short iMulU,
231 const __m128i zero = _mm_set1_epi8(0);
233 __m128i Ylo = _mm_unpacklo_epi16(Y, zero);
234 __m128i Yhi = _mm_unpackhi_epi16(Y, zero);
237 const __m128i addX = _mm_set1_epi16(128);
238 const __m128i D = _mm_sub_epi16(U, addX);
239 const __m128i mulU = _mm_set1_epi16(iMulU);
240 const __m128i mulDlo = _mm_mullo_epi16(D, mulU);
241 const __m128i mulDhi = _mm_mulhi_epi16(D, mulU);
242 const __m128i Dlo = _mm_unpacklo_epi16(mulDlo, mulDhi);
243 Ylo = _mm_add_epi32(Ylo, Dlo);
245 const __m128i Dhi = _mm_unpackhi_epi16(mulDlo, mulDhi);
246 Yhi = _mm_add_epi32(Yhi, Dhi);
250 const __m128i addX = _mm_set1_epi16(128);
251 const __m128i E = _mm_sub_epi16(V, addX);
252 const __m128i mul = _mm_set1_epi16(iMulV);
253 const __m128i mulElo = _mm_mullo_epi16(E, mul);
254 const __m128i mulEhi = _mm_mulhi_epi16(E, mul);
255 const __m128i Elo = _mm_unpacklo_epi16(mulElo, mulEhi);
256 const __m128i esumlo = _mm_add_epi32(Ylo, Elo);
258 const __m128i Ehi = _mm_unpackhi_epi16(mulElo, mulEhi);
259 const __m128i esumhi = _mm_add_epi32(Yhi, Ehi);
264 const __m128i rYlo = _mm_srai_epi32(Ylo, 8);
265 const __m128i rYhi = _mm_srai_epi32(Yhi, 8);
266 const __m128i rY = _mm_packs_epi32(rYlo, rYhi);
271static inline __m128i sse41_yuv2x(
const __m128i Y, __m128i U, __m128i V,
const short iMulU,
274 const __m128i zero = _mm_set1_epi8(0);
280 const __m128i Ylo = _mm_unpacklo_epi8(zero, Y);
281 const __m128i Ulo = _mm_unpacklo_epi8(U, zero);
282 const __m128i Vlo = _mm_unpacklo_epi8(V, zero);
283 const __m128i preslo = sse41_yuv2x_single(Ylo, Ulo, Vlo, iMulU, iMulV);
285 const __m128i Yhi = _mm_unpackhi_epi8(zero, Y);
286 const __m128i Uhi = _mm_unpackhi_epi8(U, zero);
287 const __m128i Vhi = _mm_unpackhi_epi8(V, zero);
288 const __m128i preshi = sse41_yuv2x_single(Yhi, Uhi, Vhi, iMulU, iMulV);
289 const __m128i res = _mm_packus_epi16(preslo, preshi);
295static inline __m128i sse41_yuv2r(
const __m128i Y, __m128i U, __m128i V)
297 return sse41_yuv2x(Y, U, V, 0, 403);
301static inline __m128i sse41_yuv2g(
const __m128i Y, __m128i U, __m128i V)
303 return sse41_yuv2x(Y, U, V, -48, -120);
307static inline __m128i sse41_yuv2b(
const __m128i Y, __m128i U, __m128i V)
309 return sse41_yuv2x(Y, U, V, 475, 0);
312static inline void sse41_BGRX_fillRGB_pixel(BYTE* WINPR_RESTRICT pRGB, __m128i Y, __m128i U,
315 const __m128i zero = _mm_set1_epi8(0);
317 const __m128i r = sse41_yuv2r(Y, U, V);
318 const __m128i rx[2] = { _mm_unpackhi_epi8(r, zero), _mm_unpacklo_epi8(r, zero) };
320 const __m128i g = sse41_yuv2g(Y, U, V);
321 const __m128i b = sse41_yuv2b(Y, U, V);
323 const __m128i bg[2] = { _mm_unpackhi_epi8(b, g), _mm_unpacklo_epi8(b, g) };
325 const __m128i mask = mm_set_epu8(0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
326 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF);
328 __m128i* rgb = WINPR_PACKED_ALIGN_CAST(__m128i*, pRGB);
329 const __m128i bgrx0 = _mm_unpacklo_epi16(bg[1], rx[1]);
330 _mm_maskmoveu_si128(bgrx0, mask, (
char*)&rgb[0]);
331 const __m128i bgrx1 = _mm_unpackhi_epi16(bg[1], rx[1]);
332 _mm_maskmoveu_si128(bgrx1, mask, (
char*)&rgb[1]);
333 const __m128i bgrx2 = _mm_unpacklo_epi16(bg[0], rx[0]);
334 _mm_maskmoveu_si128(bgrx2, mask, (
char*)&rgb[2]);
335 const __m128i bgrx3 = _mm_unpackhi_epi16(bg[0], rx[0]);
336 _mm_maskmoveu_si128(bgrx3, mask, (
char*)&rgb[3]);
339static inline __m128i odd1sum(__m128i u1)
341 const __m128i zero = _mm_set1_epi8(0);
342 const __m128i u1hi = _mm_unpackhi_epi8(u1, zero);
343 const __m128i u1lo = _mm_unpacklo_epi8(u1, zero);
344 return _mm_hadds_epi16(u1lo, u1hi);
347static inline __m128i odd0sum(__m128i u0, __m128i u1sum)
351 const __m128i mask = mm_set_epu8(0x80, 0x0F, 0x80, 0x0D, 0x80, 0x0B, 0x80, 0x09, 0x80, 0x07,
352 0x80, 0x05, 0x80, 0x03, 0x80, 0x01);
353 const __m128i u0odd = _mm_shuffle_epi8(u0, mask);
354 return _mm_adds_epi16(u1sum, u0odd);
357static inline __m128i calcavg(__m128i u0even, __m128i sum)
359 const __m128i u4zero = _mm_slli_epi16(u0even, 2);
360 const __m128i uavg = _mm_sub_epi16(u4zero, sum);
361 const __m128i zero = _mm_set1_epi8(0);
362 const __m128i savg = _mm_packus_epi16(uavg, zero);
363 const __m128i smask = mm_set_epu8(0x80, 0x07, 0x80, 0x06, 0x80, 0x05, 0x80, 0x04, 0x80, 0x03,
364 0x80, 0x02, 0x80, 0x01, 0x80, 0x00);
365 return _mm_shuffle_epi8(savg, smask);
368static inline __m128i diffmask(__m128i avg, __m128i u0even)
373 const __m128i diff = _mm_subs_epi16(u0even, avg);
374 const __m128i absdiff = _mm_abs_epi16(diff);
375 const __m128i val30 = _mm_set1_epi16(30);
376 return _mm_cmplt_epi16(absdiff, val30);
379static inline void sse41_filter(__m128i pU[2])
381 const __m128i u1sum = odd1sum(pU[1]);
382 const __m128i sum = odd0sum(pU[0], u1sum);
385 const __m128i emask = mm_set_epu8(0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
386 0x00, 0xff, 0x00, 0xff, 0x00, 0xff);
387 const __m128i u0even = _mm_and_si128(pU[0], emask);
388 const __m128i avg = calcavg(u0even, sum);
389 const __m128i umask = diffmask(avg, u0even);
391 const __m128i u0orig = _mm_and_si128(u0even, umask);
392 const __m128i u0avg = _mm_andnot_si128(umask, avg);
393 const __m128i evenresult = _mm_or_si128(u0orig, u0avg);
394 const __m128i omask = mm_set_epu8(0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
395 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00);
396 const __m128i u0odd = _mm_and_si128(pU[0], omask);
397 const __m128i result = _mm_or_si128(evenresult, u0odd);
401static inline void sse41_BGRX_fillRGB(BYTE* WINPR_RESTRICT pRGB[2],
const __m128i pY[2],
402 __m128i pU[2], __m128i pV[2])
412 for (
size_t i = 0; i < 2; i++)
414 sse41_BGRX_fillRGB_pixel(pRGB[i], pY[i], pU[i], pV[i]);
418static inline pstatus_t sse41_YUV444ToRGB_8u_P3AC4R_BGRX_DOUBLE_ROW(
419 BYTE* WINPR_RESTRICT pDst[2],
const BYTE* WINPR_RESTRICT YData[2],
420 const BYTE* WINPR_RESTRICT UData[2],
const BYTE* WINPR_RESTRICT VData[2], UINT32 nWidth)
422 const UINT32 pad = nWidth % 16;
425 for (; x < nWidth - pad; x += 16)
427 const __m128i Y[] = { LOAD_SI128(&YData[0][x]), LOAD_SI128(&YData[1][x]) };
428 __m128i U[] = { LOAD_SI128(&UData[0][x]), LOAD_SI128(&UData[1][x]) };
429 __m128i V[] = { LOAD_SI128(&VData[0][x]), LOAD_SI128(&VData[1][x]) };
431 BYTE* dstp[] = { &pDst[0][x * 4], &pDst[1][x * 4] };
432 sse41_BGRX_fillRGB(dstp, Y, U, V);
435 for (; x < nWidth; x += 2)
437 BGRX_fillRGB(x, pDst, YData, UData, VData, TRUE);
440 return PRIMITIVES_SUCCESS;
443static inline void BGRX_fillRGB_single(
size_t offset, BYTE* WINPR_RESTRICT pRGB,
444 const BYTE* WINPR_RESTRICT pY,
const BYTE* WINPR_RESTRICT pU,
445 const BYTE* WINPR_RESTRICT pV, WINPR_ATTR_UNUSED BOOL filter)
452 const UINT32 bpp = 4;
454 for (
size_t j = 0; j < 2; j++)
456 const BYTE Y = pY[offset + j];
457 BYTE U = pU[offset + j];
458 BYTE V = pV[offset + j];
460 writeYUVPixel(&pRGB[(j + offset) * bpp], PIXEL_FORMAT_BGRX32, Y, U, V, writePixelBGRX);
464static inline pstatus_t sse41_YUV444ToRGB_8u_P3AC4R_BGRX_SINGLE_ROW(
465 BYTE* WINPR_RESTRICT pDst,
const BYTE* WINPR_RESTRICT YData,
const BYTE* WINPR_RESTRICT UData,
466 const BYTE* WINPR_RESTRICT VData, UINT32 nWidth)
468 for (
size_t x = 0; x < nWidth; x += 2)
470 BGRX_fillRGB_single(x, pDst, YData, UData, VData, TRUE);
473 return PRIMITIVES_SUCCESS;
476static inline pstatus_t sse41_YUV444ToRGB_8u_P3AC4R_BGRX(
const BYTE* WINPR_RESTRICT pSrc[],
477 const UINT32 srcStep[],
478 BYTE* WINPR_RESTRICT pDst, UINT32 dstStep,
481 const UINT32 nWidth = roi->width;
482 const UINT32 nHeight = roi->height;
485 for (; y < nHeight - nHeight % 2; y += 2)
487 BYTE* dst[] = { (pDst + dstStep * y), (pDst + dstStep * (y + 1)) };
488 const BYTE* YData[] = { pSrc[0] + y * srcStep[0], pSrc[0] + (y + 1) * srcStep[0] };
489 const BYTE* UData[] = { pSrc[1] + y * srcStep[1], pSrc[1] + (y + 1) * srcStep[1] };
490 const BYTE* VData[] = { pSrc[2] + y * srcStep[2], pSrc[2] + (y + 1) * srcStep[2] };
493 sse41_YUV444ToRGB_8u_P3AC4R_BGRX_DOUBLE_ROW(dst, YData, UData, VData, nWidth);
494 if (rc != PRIMITIVES_SUCCESS)
497 for (; y < nHeight; y++)
499 BYTE* dst = (pDst + dstStep * y);
500 const BYTE* YData = pSrc[0] + y * srcStep[0];
501 const BYTE* UData = pSrc[1] + y * srcStep[1];
502 const BYTE* VData = pSrc[2] + y * srcStep[2];
504 sse41_YUV444ToRGB_8u_P3AC4R_BGRX_SINGLE_ROW(dst, YData, UData, VData, nWidth);
505 if (rc != PRIMITIVES_SUCCESS)
509 return PRIMITIVES_SUCCESS;
512static pstatus_t sse41_YUV444ToRGB_8u_P3AC4R(
const BYTE* WINPR_RESTRICT pSrc[],
513 const UINT32 srcStep[], BYTE* WINPR_RESTRICT pDst,
514 UINT32 dstStep, UINT32 DstFormat,
519 case PIXEL_FORMAT_BGRX32:
520 case PIXEL_FORMAT_BGRA32:
521 return sse41_YUV444ToRGB_8u_P3AC4R_BGRX(pSrc, srcStep, pDst, dstStep, roi);
524 return generic->YUV444ToRGB_8u_P3AC4R(pSrc, srcStep, pDst, dstStep, DstFormat, roi);
528static inline void sse41_I444ToRGB_BGRX_ROW(BYTE* WINPR_RESTRICT pDst,
529 const BYTE* WINPR_RESTRICT YData,
530 const BYTE* WINPR_RESTRICT UData,
531 const BYTE* WINPR_RESTRICT VData, UINT32 nWidth)
533 const UINT32 pad = nWidth % 16;
536 for (; x < nWidth - pad; x += 16)
538 const __m128i Y = LOAD_SI128(&YData[x]);
539 const __m128i U = LOAD_SI128(&UData[x]);
540 const __m128i V = LOAD_SI128(&VData[x]);
542 sse41_BGRX_fillRGB_pixel(&pDst[x * 4], Y, U, V);
545 for (; x < nWidth; x++)
547 writeYUVPixel(&pDst[x * 4], PIXEL_FORMAT_BGRX32, YData[x], UData[x], VData[x],
552static pstatus_t sse41_I444ToRGB_8u(
const BYTE* WINPR_RESTRICT pSrc[],
const UINT32 srcStep[],
553 BYTE* WINPR_RESTRICT pDst, UINT32 dstStep, UINT32 DstFormat,
558 case PIXEL_FORMAT_BGRX32:
559 case PIXEL_FORMAT_BGRA32:
560 for (
size_t y = 0; y < roi->height; y++)
562 BYTE* dst = pDst + dstStep * y;
563 const BYTE* YData = pSrc[0] + y * srcStep[0];
564 const BYTE* UData = pSrc[1] + y * srcStep[1];
565 const BYTE* VData = pSrc[2] + y * srcStep[2];
567 sse41_I444ToRGB_BGRX_ROW(dst, YData, UData, VData, roi->width);
569 return PRIMITIVES_SUCCESS;
572 return generic->I444ToRGB_8u(pSrc, srcStep, pDst, dstStep, DstFormat, roi);
601#define BGRX_Y_FACTORS _mm_set_epi8(0, 27, 92, 9, 0, 27, 92, 9, 0, 27, 92, 9, 0, 27, 92, 9)
602#define BGRX_U_FACTORS \
603 _mm_set_epi8(0, -29, -99, 127, 0, -29, -99, 127, 0, -29, -99, 127, 0, -29, -99, 127)
604#define BGRX_V_FACTORS \
605 _mm_set_epi8(0, 127, -116, -12, 0, 127, -116, -12, 0, 127, -116, -12, 0, 127, -116, -12)
606#define CONST128_FACTORS _mm_set1_epi8(-128)
629static inline void sse41_BGRX_TO_YUV(
const BYTE* WINPR_RESTRICT pLine1, BYTE* WINPR_RESTRICT pYLine,
630 BYTE* WINPR_RESTRICT pULine, BYTE* WINPR_RESTRICT pVLine)
632 const BYTE r1 = pLine1[2];
633 const BYTE g1 = pLine1[1];
634 const BYTE b1 = pLine1[0];
637 pYLine[0] = RGB2Y(r1, g1, b1);
639 pULine[0] = RGB2U(r1, g1, b1);
641 pVLine[0] = RGB2V(r1, g1, b1);
646static inline void sse41_RGBToYUV420_BGRX_Y(
const BYTE* WINPR_RESTRICT src, BYTE* dst, UINT32 width)
648 const __m128i y_factors = BGRX_Y_FACTORS;
649 const __m128i* argb = WINPR_PACKED_ALIGN_CAST(
const __m128i*, src);
650 __m128i* ydst = WINPR_PACKED_ALIGN_CAST(__m128i*, dst);
654 for (; x < width - width % 16; x += 16)
657 __m128i x0 = LOAD_SI128(argb++);
659 x0 = _mm_maddubs_epi16(x0, y_factors);
661 __m128i x1 = LOAD_SI128(argb++);
662 x1 = _mm_maddubs_epi16(x1, y_factors);
663 x0 = _mm_hadds_epi16(x0, x1);
664 x0 = _mm_srli_epi16(x0, Y_SHIFT);
667 __m128i x2 = LOAD_SI128(argb++);
669 x2 = _mm_maddubs_epi16(x2, y_factors);
671 __m128i x3 = LOAD_SI128(argb++);
672 x3 = _mm_maddubs_epi16(x3, y_factors);
673 x2 = _mm_hadds_epi16(x2, x3);
674 x2 = _mm_srli_epi16(x2, Y_SHIFT);
677 x0 = _mm_packus_epi16(x0, x2);
679 STORE_SI128(ydst++, x0);
682 for (; x < width; x++)
684 sse41_BGRX_TO_YUV(&src[4ULL * x], &dst[x],
nullptr,
nullptr);
690static inline void sse41_RGBToYUV420_BGRX_UV(
const BYTE* WINPR_RESTRICT src1,
691 const BYTE* WINPR_RESTRICT src2,
692 BYTE* WINPR_RESTRICT dst1, BYTE* WINPR_RESTRICT dst2,
695 const __m128i u_factors = BGRX_U_FACTORS;
696 const __m128i v_factors = BGRX_V_FACTORS;
697 const __m128i vector128 = CONST128_FACTORS;
701 for (; x < width - width % 16; x += 16)
703 const __m128i* rgb1 = WINPR_PACKED_ALIGN_CAST(
const __m128i*, &src1[4ULL * x]);
704 const __m128i* rgb2 = WINPR_PACKED_ALIGN_CAST(
const __m128i*, &src2[4ULL * x]);
705 __m64* udst = WINPR_PACKED_ALIGN_CAST(__m64*, &dst1[x / 2]);
706 __m64* vdst = WINPR_PACKED_ALIGN_CAST(__m64*, &dst2[x / 2]);
709 __m128i x0 = LOAD_SI128(&rgb1[0]);
710 __m128i x4 = LOAD_SI128(&rgb2[0]);
711 x0 = _mm_avg_epu8(x0, x4);
713 __m128i x1 = LOAD_SI128(&rgb1[1]);
714 x4 = LOAD_SI128(&rgb2[1]);
715 x1 = _mm_avg_epu8(x1, x4);
717 __m128i x2 = LOAD_SI128(&rgb1[2]);
718 x4 = LOAD_SI128(&rgb2[2]);
719 x2 = _mm_avg_epu8(x2, x4);
721 __m128i x3 = LOAD_SI128(&rgb1[3]);
722 x4 = LOAD_SI128(&rgb2[3]);
723 x3 = _mm_avg_epu8(x3, x4);
731 x4 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x0), _mm_castsi128_ps(x1), 0x88));
732 x0 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x0), _mm_castsi128_ps(x1), 0xdd));
733 x0 = _mm_avg_epu8(x0, x4);
734 x4 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x2), _mm_castsi128_ps(x3), 0x88));
735 x1 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(x2), _mm_castsi128_ps(x3), 0xdd));
736 x1 = _mm_avg_epu8(x1, x4);
738 x2 = _mm_maddubs_epi16(x0, u_factors);
739 x3 = _mm_maddubs_epi16(x1, u_factors);
740 x4 = _mm_maddubs_epi16(x0, v_factors);
741 __m128i x5 = _mm_maddubs_epi16(x1, v_factors);
743 x0 = _mm_hadd_epi16(x2, x3);
744 x1 = _mm_hadd_epi16(x4, x5);
746 x0 = _mm_srai_epi16(x0, U_SHIFT);
747 x1 = _mm_srai_epi16(x1, V_SHIFT);
749 x0 = _mm_packs_epi16(x0, x1);
751 x0 = _mm_sub_epi8(x0, vector128);
753 _mm_storel_pi(udst, _mm_castsi128_ps(x0));
755 _mm_storeh_pi(vdst, _mm_castsi128_ps(x0));
758 for (; x < width - width % 2; x += 2)
760 BYTE u[4] = WINPR_C_ARRAY_INIT;
761 BYTE v[4] = WINPR_C_ARRAY_INIT;
762 sse41_BGRX_TO_YUV(&src1[4ULL * x],
nullptr, &u[0], &v[0]);
763 sse41_BGRX_TO_YUV(&src1[4ULL * (1ULL + x)],
nullptr, &u[1], &v[1]);
764 sse41_BGRX_TO_YUV(&src2[4ULL * x],
nullptr, &u[2], &v[2]);
765 sse41_BGRX_TO_YUV(&src2[4ULL * (1ULL + x)],
nullptr, &u[3], &v[3]);
766 const INT16 u4 = WINPR_ASSERTING_INT_CAST(INT16, (INT16)u[0] + u[1] + u[2] + u[3]);
767 const INT16 uu = WINPR_ASSERTING_INT_CAST(INT16, u4 / 4);
768 const BYTE u8 = CLIP(uu);
771 const INT16 v4 = WINPR_ASSERTING_INT_CAST(INT16, (INT16)v[0] + v[1] + v[2] + v[3]);
772 const INT16 vu = WINPR_ASSERTING_INT_CAST(INT16, v4 / 4);
773 const BYTE v8 = CLIP(vu);
778static pstatus_t sse41_RGBToYUV420_BGRX(
const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
779 BYTE* WINPR_RESTRICT pDst[],
const UINT32 dstStep[],
782 if (roi->height < 1 || roi->width < 1)
784 return !PRIMITIVES_SUCCESS;
789 const UINT32 width = roi->width - roi->width % 2;
790 const size_t height = roi->height - roi->height % 2;
792 for (
size_t y = 0; y < height; y += 2)
794 const BYTE* line1 = &pSrc[y * srcStep];
795 const BYTE* line2 = &pSrc[(1ULL + y) * srcStep];
796 BYTE* ydst1 = &pDst[0][y * dstStep[0]];
797 BYTE* ydst2 = &pDst[0][(1ULL + y) * dstStep[0]];
798 BYTE* udst = &pDst[1][y / 2 * dstStep[1]];
799 BYTE* vdst = &pDst[2][y / 2 * dstStep[2]];
801 sse41_RGBToYUV420_BGRX_UV(line1, line2, udst, vdst, width);
802 sse41_RGBToYUV420_BGRX_Y(line1, ydst1, width);
803 sse41_RGBToYUV420_BGRX_Y(line2, ydst2, width);
806 WINPR_ASSERT(generic);
809 if (width < roi->width)
811 const BYTE* src = &pSrc[4ULL * width];
812 BYTE* dst[3] = { &pDst[0][width], &pDst[1][width / 2], &pDst[2][width / 2] };
815 generic->RGBToYUV420_8u_P3AC4R(src, PIXEL_FORMAT_BGRX32, srcStep, dst, dstStep, &rest);
816 if (rc != PRIMITIVES_SUCCESS)
821 if ((height < roi->height) && (width > 0))
823 const BYTE* src = &pSrc[height * srcStep];
824 BYTE* dst[3] = { &pDst[0][height * dstStep[0]], &pDst[1][(height / 2) * dstStep[1]],
825 &pDst[2][(height / 2) * dstStep[2]] };
827 return generic->RGBToYUV420_8u_P3AC4R(src, PIXEL_FORMAT_BGRX32, srcStep, dst, dstStep,
831 return PRIMITIVES_SUCCESS;
834static pstatus_t sse41_RGBToYUV420(
const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
835 UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[],
836 const UINT32 dstStep[],
const prim_size_t* WINPR_RESTRICT roi)
840 case PIXEL_FORMAT_BGRX32:
841 case PIXEL_FORMAT_BGRA32:
842 return sse41_RGBToYUV420_BGRX(pSrc, srcStep, pDst, dstStep, roi);
845 return generic->RGBToYUV420_8u_P3AC4R(pSrc, srcFormat, srcStep, pDst, dstStep, roi);
853static inline void sse41_RGBToAVC444YUV_BGRX_DOUBLE_ROW(
854 const BYTE* WINPR_RESTRICT srcEven,
const BYTE* WINPR_RESTRICT srcOdd,
855 BYTE* WINPR_RESTRICT b1Even, BYTE* WINPR_RESTRICT b1Odd, BYTE* WINPR_RESTRICT b2,
856 BYTE* WINPR_RESTRICT b3, BYTE* WINPR_RESTRICT b4, BYTE* WINPR_RESTRICT b5,
857 BYTE* WINPR_RESTRICT b6, BYTE* WINPR_RESTRICT b7, UINT32 width)
859 const __m128i* argbEven = WINPR_PACKED_ALIGN_CAST(
const __m128i*, srcEven);
860 const __m128i* argbOdd = WINPR_PACKED_ALIGN_CAST(
const __m128i*, srcOdd);
861 const __m128i y_factors = BGRX_Y_FACTORS;
862 const __m128i u_factors = BGRX_U_FACTORS;
863 const __m128i v_factors = BGRX_V_FACTORS;
864 const __m128i vector128 = CONST128_FACTORS;
867 for (; x < width - width % 16; x += 16)
870 const __m128i xe1 = LOAD_SI128(argbEven++);
871 const __m128i xe2 = LOAD_SI128(argbEven++);
872 const __m128i xe3 = LOAD_SI128(argbEven++);
873 const __m128i xe4 = LOAD_SI128(argbEven++);
874 const __m128i xo1 = LOAD_SI128(argbOdd++);
875 const __m128i xo2 = LOAD_SI128(argbOdd++);
876 const __m128i xo3 = LOAD_SI128(argbOdd++);
877 const __m128i xo4 = LOAD_SI128(argbOdd++);
880 const __m128i ye1 = _mm_srli_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe1, y_factors),
881 _mm_maddubs_epi16(xe2, y_factors)),
883 const __m128i ye2 = _mm_srli_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe3, y_factors),
884 _mm_maddubs_epi16(xe4, y_factors)),
886 const __m128i ye = _mm_packus_epi16(ye1, ye2);
887 const __m128i yo1 = _mm_srli_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo1, y_factors),
888 _mm_maddubs_epi16(xo2, y_factors)),
890 const __m128i yo2 = _mm_srli_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo3, y_factors),
891 _mm_maddubs_epi16(xo4, y_factors)),
893 const __m128i yo = _mm_packus_epi16(yo1, yo2);
895 STORE_SI128(b1Even, ye);
900 STORE_SI128(b1Odd, yo);
912 __m128i uo = WINPR_C_ARRAY_INIT;
915 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe1, u_factors),
916 _mm_maddubs_epi16(xe2, u_factors)),
919 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe3, u_factors),
920 _mm_maddubs_epi16(xe4, u_factors)),
922 ue = _mm_sub_epi8(_mm_packs_epi16(ue1, ue2), vector128);
928 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo1, u_factors),
929 _mm_maddubs_epi16(xo2, u_factors)),
932 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo3, u_factors),
933 _mm_maddubs_epi16(xo4, u_factors)),
935 uo = _mm_sub_epi8(_mm_packs_epi16(uo1, uo2), vector128);
944 const __m128i ueh = _mm_unpackhi_epi8(ue, _mm_setzero_si128());
945 const __m128i uoh = _mm_unpackhi_epi8(uo, _mm_setzero_si128());
946 const __m128i hi = _mm_add_epi16(ueh, uoh);
947 const __m128i uel = _mm_unpacklo_epi8(ue, _mm_setzero_si128());
948 const __m128i uol = _mm_unpacklo_epi8(uo, _mm_setzero_si128());
949 const __m128i lo = _mm_add_epi16(uel, uol);
950 const __m128i added = _mm_hadd_epi16(lo, hi);
951 const __m128i avg16 = _mm_srai_epi16(added, 2);
952 const __m128i avg = _mm_packus_epi16(avg16, avg16);
953 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, b2), avg);
958 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
959 (
char)0x80, (
char)0x80, (
char)0x80, 14, 12, 10, 8, 6, 4, 2, 0);
960 const __m128i ud = _mm_shuffle_epi8(ue, mask);
961 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, b2), ud);
975 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
976 (
char)0x80, (
char)0x80, (
char)0x80, 15, 13, 11, 9, 7, 5, 3, 1);
977 const __m128i ude = _mm_shuffle_epi8(ue, mask);
978 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, b6), ude);
990 __m128i vo = WINPR_C_ARRAY_INIT;
993 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe1, v_factors),
994 _mm_maddubs_epi16(xe2, v_factors)),
997 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe3, v_factors),
998 _mm_maddubs_epi16(xe4, v_factors)),
1000 ve = _mm_sub_epi8(_mm_packs_epi16(ve1, ve2), vector128);
1006 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo1, v_factors),
1007 _mm_maddubs_epi16(xo2, v_factors)),
1010 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo3, v_factors),
1011 _mm_maddubs_epi16(xo4, v_factors)),
1013 vo = _mm_sub_epi8(_mm_packs_epi16(vo1, vo2), vector128);
1022 const __m128i veh = _mm_unpackhi_epi8(ve, _mm_setzero_si128());
1023 const __m128i voh = _mm_unpackhi_epi8(vo, _mm_setzero_si128());
1024 const __m128i hi = _mm_add_epi16(veh, voh);
1025 const __m128i vel = _mm_unpacklo_epi8(ve, _mm_setzero_si128());
1026 const __m128i vol = _mm_unpacklo_epi8(vo, _mm_setzero_si128());
1027 const __m128i lo = _mm_add_epi16(vel, vol);
1028 const __m128i added = _mm_hadd_epi16(lo, hi);
1029 const __m128i avg16 = _mm_srai_epi16(added, 2);
1030 const __m128i avg = _mm_packus_epi16(avg16, avg16);
1031 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, b3), avg);
1035 const __m128i mask =
1036 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
1037 (
char)0x80, (
char)0x80, (
char)0x80, 14, 12, 10, 8, 6, 4, 2, 0);
1038 const __m128i vd = _mm_shuffle_epi8(ve, mask);
1039 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, b3), vd);
1046 STORE_SI128(b5, vo);
1052 const __m128i mask =
1053 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
1054 (
char)0x80, (
char)0x80, (
char)0x80, 15, 13, 11, 9, 7, 5, 3, 1);
1055 const __m128i vde = _mm_shuffle_epi8(ve, mask);
1056 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, b7), vde);
1062 general_RGBToAVC444YUV_BGRX_DOUBLE_ROW(x, srcEven, srcOdd, b1Even, b1Odd, b2, b3, b4, b5, b6,
1066static pstatus_t sse41_RGBToAVC444YUV_BGRX(
const BYTE* WINPR_RESTRICT pSrc,
1067 WINPR_ATTR_UNUSED UINT32 srcFormat, UINT32 srcStep,
1068 BYTE* WINPR_RESTRICT pDst1[],
const UINT32 dst1Step[],
1069 BYTE* WINPR_RESTRICT pDst2[],
const UINT32 dst2Step[],
1072 if (roi->height < 1 || roi->width < 1)
1073 return !PRIMITIVES_SUCCESS;
1076 for (; y < roi->height - roi->height % 2; y += 2)
1078 const BYTE* srcEven = pSrc + y * srcStep;
1079 const BYTE* srcOdd = pSrc + (y + 1) * srcStep;
1080 const size_t i = y >> 1;
1081 const size_t n = (i & (size_t)~7) + i;
1082 BYTE* b1Even = pDst1[0] + y * dst1Step[0];
1083 BYTE* b1Odd = (b1Even + dst1Step[0]);
1084 BYTE* b2 = pDst1[1] + (y / 2) * dst1Step[1];
1085 BYTE* b3 = pDst1[2] + (y / 2) * dst1Step[2];
1086 BYTE* b4 = pDst2[0] + 1ULL * dst2Step[0] * n;
1087 BYTE* b5 = b4 + 8ULL * dst2Step[0];
1088 BYTE* b6 = pDst2[1] + (y / 2) * dst2Step[1];
1089 BYTE* b7 = pDst2[2] + (y / 2) * dst2Step[2];
1090 sse41_RGBToAVC444YUV_BGRX_DOUBLE_ROW(srcEven, srcOdd, b1Even, b1Odd, b2, b3, b4, b5, b6, b7,
1094 for (; y < roi->height; y++)
1096 const BYTE* srcEven = pSrc + y * srcStep;
1097 BYTE* b1Even = pDst1[0] + y * dst1Step[0];
1098 BYTE* b2 = pDst1[1] + (y / 2) * dst1Step[1];
1099 BYTE* b3 = pDst1[2] + (y / 2) * dst1Step[2];
1100 BYTE* b6 = pDst2[1] + (y / 2) * dst2Step[1];
1101 BYTE* b7 = pDst2[2] + (y / 2) * dst2Step[2];
1102 general_RGBToAVC444YUV_BGRX_DOUBLE_ROW(0, srcEven,
nullptr, b1Even,
nullptr, b2, b3,
1103 nullptr,
nullptr, b6, b7, roi->width);
1106 return PRIMITIVES_SUCCESS;
1109static pstatus_t sse41_RGBToAVC444YUV(
const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
1110 UINT32 srcStep, BYTE* WINPR_RESTRICT pDst1[],
1111 const UINT32 dst1Step[], BYTE* WINPR_RESTRICT pDst2[],
1112 const UINT32 dst2Step[],
1117 case PIXEL_FORMAT_BGRX32:
1118 case PIXEL_FORMAT_BGRA32:
1119 return sse41_RGBToAVC444YUV_BGRX(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2,
1123 return generic->RGBToAVC444YUV(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2,
1141static inline void sse41_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(
1142 const BYTE* WINPR_RESTRICT srcEven,
const BYTE* WINPR_RESTRICT srcOdd,
1143 BYTE* WINPR_RESTRICT yLumaDstEven, BYTE* WINPR_RESTRICT yLumaDstOdd,
1144 BYTE* WINPR_RESTRICT uLumaDst, BYTE* WINPR_RESTRICT vLumaDst,
1145 BYTE* WINPR_RESTRICT yEvenChromaDst1, BYTE* WINPR_RESTRICT yEvenChromaDst2,
1146 BYTE* WINPR_RESTRICT yOddChromaDst1, BYTE* WINPR_RESTRICT yOddChromaDst2,
1147 BYTE* WINPR_RESTRICT uChromaDst1, BYTE* WINPR_RESTRICT uChromaDst2,
1148 BYTE* WINPR_RESTRICT vChromaDst1, BYTE* WINPR_RESTRICT vChromaDst2, UINT32 width)
1150 const __m128i vector128 = CONST128_FACTORS;
1151 const __m128i* argbEven = WINPR_PACKED_ALIGN_CAST(
const __m128i*, srcEven);
1152 const __m128i* argbOdd = WINPR_PACKED_ALIGN_CAST(
const __m128i*, srcOdd);
1155 for (; x < width - width % 16; x += 16)
1160 const __m128i xe1 = LOAD_SI128(argbEven++);
1161 const __m128i xe2 = LOAD_SI128(argbEven++);
1162 const __m128i xe3 = LOAD_SI128(argbEven++);
1163 const __m128i xe4 = LOAD_SI128(argbEven++);
1164 const __m128i xo1 = LOAD_SI128(argbOdd++);
1165 const __m128i xo2 = LOAD_SI128(argbOdd++);
1166 const __m128i xo3 = LOAD_SI128(argbOdd++);
1167 const __m128i xo4 = LOAD_SI128(argbOdd++);
1170 const __m128i y_factors = BGRX_Y_FACTORS;
1171 const __m128i ye1 = _mm_srli_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe1, y_factors),
1172 _mm_maddubs_epi16(xe2, y_factors)),
1174 const __m128i ye2 = _mm_srli_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe3, y_factors),
1175 _mm_maddubs_epi16(xe4, y_factors)),
1177 const __m128i ye = _mm_packus_epi16(ye1, ye2);
1179 STORE_SI128(yLumaDstEven, ye);
1185 const __m128i y_factors = BGRX_Y_FACTORS;
1186 const __m128i yo1 = _mm_srli_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo1, y_factors),
1187 _mm_maddubs_epi16(xo2, y_factors)),
1189 const __m128i yo2 = _mm_srli_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo3, y_factors),
1190 _mm_maddubs_epi16(xo4, y_factors)),
1192 const __m128i yo = _mm_packus_epi16(yo1, yo2);
1193 STORE_SI128(yLumaDstOdd, yo);
1209 const __m128i u_factors = BGRX_U_FACTORS;
1211 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe1, u_factors),
1212 _mm_maddubs_epi16(xe2, u_factors)),
1215 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe3, u_factors),
1216 _mm_maddubs_epi16(xe4, u_factors)),
1218 const __m128i ueavg = _mm_hadd_epi16(ue1, ue2);
1219 ue = _mm_sub_epi8(_mm_packs_epi16(ue1, ue2), vector128);
1223 const __m128i u_factors = BGRX_U_FACTORS;
1225 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo1, u_factors),
1226 _mm_maddubs_epi16(xo2, u_factors)),
1229 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo3, u_factors),
1230 _mm_maddubs_epi16(xo4, u_factors)),
1232 const __m128i uoavg = _mm_hadd_epi16(uo1, uo2);
1233 uo = _mm_sub_epi8(_mm_packs_epi16(uo1, uo2), vector128);
1234 uavg = _mm_add_epi16(uavg, uoavg);
1235 uavg = _mm_srai_epi16(uavg, 2);
1236 uavg = _mm_packs_epi16(uavg, uoavg);
1237 uavg = _mm_sub_epi8(uavg, vector128);
1245 const __m128i mask =
1246 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
1247 (
char)0x80, (
char)0x80, (
char)0x80, 15, 13, 11, 9, 7, 5, 3, 1);
1248 const __m128i ude = _mm_shuffle_epi8(ue, mask);
1249 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, yEvenChromaDst1), ude);
1250 yEvenChromaDst1 += 8;
1255 const __m128i mask =
1256 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
1257 (
char)0x80, (
char)0x80, (
char)0x80, 15, 13, 11, 9, 7, 5, 3, 1);
1258 const __m128i udo = _mm_shuffle_epi8(uo, mask);
1259 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, yOddChromaDst1),
1261 yOddChromaDst1 += 8;
1266 const __m128i mask =
1267 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
1268 (
char)0x80, (
char)0x80, (
char)0x80, 14, 10, 6, 2, 12, 8, 4, 0);
1269 const __m128i ud = _mm_shuffle_epi8(uo, mask);
1270 int* uDst1 = WINPR_PACKED_ALIGN_CAST(
int*, uChromaDst1);
1271 int* vDst1 = WINPR_PACKED_ALIGN_CAST(
int*, vChromaDst1);
1272 const int* src = (
const int*)&ud;
1273 _mm_stream_si32(uDst1, src[0]);
1274 _mm_stream_si32(vDst1, src[1]);
1281 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, uLumaDst), uavg);
1286 const __m128i mask =
1287 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
1288 (
char)0x80, (
char)0x80, (
char)0x80, 14, 12, 10, 8, 6, 4, 2, 0);
1289 const __m128i ud = _mm_shuffle_epi8(ue, mask);
1290 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, uLumaDst), ud);
1301 const __m128i v_factors = BGRX_V_FACTORS;
1303 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe1, v_factors),
1304 _mm_maddubs_epi16(xe2, v_factors)),
1307 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xe3, v_factors),
1308 _mm_maddubs_epi16(xe4, v_factors)),
1310 const __m128i veavg = _mm_hadd_epi16(ve1, ve2);
1311 ve = _mm_sub_epi8(_mm_packs_epi16(ve1, ve2), vector128);
1315 const __m128i v_factors = BGRX_V_FACTORS;
1317 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo1, v_factors),
1318 _mm_maddubs_epi16(xo2, v_factors)),
1321 _mm_srai_epi16(_mm_hadd_epi16(_mm_maddubs_epi16(xo3, v_factors),
1322 _mm_maddubs_epi16(xo4, v_factors)),
1324 const __m128i voavg = _mm_hadd_epi16(vo1, vo2);
1325 vo = _mm_sub_epi8(_mm_packs_epi16(vo1, vo2), vector128);
1326 vavg = _mm_add_epi16(vavg, voavg);
1327 vavg = _mm_srai_epi16(vavg, 2);
1328 vavg = _mm_packs_epi16(vavg, voavg);
1329 vavg = _mm_sub_epi8(vavg, vector128);
1337 const __m128i mask =
1338 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
1339 (
char)0x80, (
char)0x80, (
char)0x80, 15, 13, 11, 9, 7, 5, 3, 1);
1340 __m128i vde = _mm_shuffle_epi8(ve, mask);
1341 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, yEvenChromaDst2), vde);
1342 yEvenChromaDst2 += 8;
1347 const __m128i mask =
1348 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
1349 (
char)0x80, (
char)0x80, (
char)0x80, 15, 13, 11, 9, 7, 5, 3, 1);
1350 __m128i vdo = _mm_shuffle_epi8(vo, mask);
1351 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, yOddChromaDst2), vdo);
1352 yOddChromaDst2 += 8;
1357 const __m128i mask =
1358 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
1359 (
char)0x80, (
char)0x80, (
char)0x80, 14, 10, 6, 2, 12, 8, 4, 0);
1360 const __m128i vd = _mm_shuffle_epi8(vo, mask);
1361 int* uDst2 = WINPR_PACKED_ALIGN_CAST(
int*, uChromaDst2);
1362 int* vDst2 = WINPR_PACKED_ALIGN_CAST(
int*, vChromaDst2);
1363 const int* src = (
const int*)&vd;
1364 _mm_stream_si32(uDst2, src[0]);
1365 _mm_stream_si32(vDst2, src[1]);
1372 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, vLumaDst), vavg);
1377 const __m128i mask =
1378 _mm_set_epi8((
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80, (
char)0x80,
1379 (
char)0x80, (
char)0x80, (
char)0x80, 14, 12, 10, 8, 6, 4, 2, 0);
1380 __m128i vd = _mm_shuffle_epi8(ve, mask);
1381 _mm_storel_epi64(WINPR_PACKED_ALIGN_CAST(__m128i*, vLumaDst), vd);
1387 general_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(x, srcEven, srcOdd, yLumaDstEven, yLumaDstOdd,
1388 uLumaDst, vLumaDst, yEvenChromaDst1, yEvenChromaDst2,
1389 yOddChromaDst1, yOddChromaDst2, uChromaDst1,
1390 uChromaDst2, vChromaDst1, vChromaDst2, width);
1393static pstatus_t sse41_RGBToAVC444YUVv2_BGRX(
const BYTE* WINPR_RESTRICT pSrc,
1394 WINPR_ATTR_UNUSED UINT32 srcFormat, UINT32 srcStep,
1395 BYTE* WINPR_RESTRICT pDst1[],
const UINT32 dst1Step[],
1396 BYTE* WINPR_RESTRICT pDst2[],
const UINT32 dst2Step[],
1399 if (roi->height < 1 || roi->width < 1)
1400 return !PRIMITIVES_SUCCESS;
1403 for (; y < roi->height - roi->height % 2; y += 2)
1405 const BYTE* srcEven = (pSrc + y * srcStep);
1406 const BYTE* srcOdd = (srcEven + srcStep);
1407 BYTE* dstLumaYEven = (pDst1[0] + y * dst1Step[0]);
1408 BYTE* dstLumaYOdd = (dstLumaYEven + dst1Step[0]);
1409 BYTE* dstLumaU = (pDst1[1] + (y / 2) * dst1Step[1]);
1410 BYTE* dstLumaV = (pDst1[2] + (y / 2) * dst1Step[2]);
1411 BYTE* dstEvenChromaY1 = (pDst2[0] + y * dst2Step[0]);
1412 BYTE* dstEvenChromaY2 = dstEvenChromaY1 + roi->width / 2;
1413 BYTE* dstOddChromaY1 = dstEvenChromaY1 + dst2Step[0];
1414 BYTE* dstOddChromaY2 = dstEvenChromaY2 + dst2Step[0];
1415 BYTE* dstChromaU1 = (pDst2[1] + (y / 2) * dst2Step[1]);
1416 BYTE* dstChromaV1 = (pDst2[2] + (y / 2) * dst2Step[2]);
1417 BYTE* dstChromaU2 = dstChromaU1 + roi->width / 4;
1418 BYTE* dstChromaV2 = dstChromaV1 + roi->width / 4;
1419 sse41_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(srcEven, srcOdd, dstLumaYEven, dstLumaYOdd, dstLumaU,
1420 dstLumaV, dstEvenChromaY1, dstEvenChromaY2,
1421 dstOddChromaY1, dstOddChromaY2, dstChromaU1,
1422 dstChromaU2, dstChromaV1, dstChromaV2, roi->width);
1425 for (; y < roi->height; y++)
1427 const BYTE* srcEven = (pSrc + y * srcStep);
1428 BYTE* dstLumaYEven = (pDst1[0] + y * dst1Step[0]);
1429 BYTE* dstLumaU = (pDst1[1] + (y / 2) * dst1Step[1]);
1430 BYTE* dstLumaV = (pDst1[2] + (y / 2) * dst1Step[2]);
1431 BYTE* dstEvenChromaY1 = (pDst2[0] + y * dst2Step[0]);
1432 BYTE* dstEvenChromaY2 = dstEvenChromaY1 + roi->width / 2;
1433 BYTE* dstChromaU1 = (pDst2[1] + (y / 2) * dst2Step[1]);
1434 BYTE* dstChromaV1 = (pDst2[2] + (y / 2) * dst2Step[2]);
1435 BYTE* dstChromaU2 = dstChromaU1 + roi->width / 4;
1436 BYTE* dstChromaV2 = dstChromaV1 + roi->width / 4;
1437 general_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(0, srcEven,
nullptr, dstLumaYEven,
nullptr,
1438 dstLumaU, dstLumaV, dstEvenChromaY1,
1439 dstEvenChromaY2,
nullptr,
nullptr, dstChromaU1,
1440 dstChromaU2, dstChromaV1, dstChromaV2, roi->width);
1443 return PRIMITIVES_SUCCESS;
1446static pstatus_t sse41_RGBToAVC444YUVv2(
const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
1447 UINT32 srcStep, BYTE* WINPR_RESTRICT pDst1[],
1448 const UINT32 dst1Step[], BYTE* WINPR_RESTRICT pDst2[],
1449 const UINT32 dst2Step[],
1454 case PIXEL_FORMAT_BGRX32:
1455 case PIXEL_FORMAT_BGRA32:
1456 return sse41_RGBToAVC444YUVv2_BGRX(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2,
1460 return generic->RGBToAVC444YUVv2(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2,
1465static pstatus_t sse41_LumaToYUV444(
const BYTE* WINPR_RESTRICT pSrcRaw[],
const UINT32 srcStep[],
1466 BYTE* WINPR_RESTRICT pDstRaw[],
const UINT32 dstStep[],
1469 const UINT32 nWidth = roi->right - roi->left;
1470 const UINT32 nHeight = roi->bottom - roi->top;
1471 const UINT32 halfWidth = (nWidth + 1) / 2;
1472 const UINT32 halfPad = halfWidth % 16;
1473 const UINT32 halfHeight = (nHeight + 1) / 2;
1474 const UINT32 oddY = 1;
1475 const UINT32 evenY = 0;
1476 const UINT32 oddX = 1;
1477 const UINT32 evenX = 0;
1478 const BYTE* pSrc[3] = { pSrcRaw[0] + 1ULL * roi->top * srcStep[0] + roi->left,
1479 pSrcRaw[1] + 1ULL * roi->top / 2 * srcStep[1] + roi->left / 2,
1480 pSrcRaw[2] + 1ULL * roi->top / 2 * srcStep[2] + roi->left / 2 };
1481 BYTE* pDst[3] = { pDstRaw[0] + 1ULL * roi->top * dstStep[0] + roi->left,
1482 pDstRaw[1] + 1ULL * roi->top * dstStep[1] + roi->left,
1483 pDstRaw[2] + 1ULL * roi->top * dstStep[2] + roi->left };
1487 for (
size_t y = 0; y < nHeight; y++)
1489 const BYTE* Ym = pSrc[0] + y * srcStep[0];
1490 BYTE* pY = pDst[0] + y * dstStep[0];
1491 memcpy(pY, Ym, nWidth);
1496 for (
size_t y = 0; y < halfHeight; y++)
1498 const size_t val2y = (2 * y + evenY);
1499 const size_t val2y1 = val2y + oddY;
1500 const BYTE* Um = pSrc[1] + 1ULL * srcStep[1] * y;
1501 const BYTE* Vm = pSrc[2] + 1ULL * srcStep[2] * y;
1502 BYTE* pU = pDst[1] + 1ULL * dstStep[1] * val2y;
1503 BYTE* pV = pDst[2] + 1ULL * dstStep[2] * val2y;
1504 BYTE* pU1 = pDst[1] + 1ULL * dstStep[1] * val2y1;
1505 BYTE* pV1 = pDst[2] + 1ULL * dstStep[2] * val2y1;
1508 for (; x < halfWidth - halfPad; x += 16)
1510 const __m128i unpackHigh = _mm_set_epi8(7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, 0);
1511 const __m128i unpackLow =
1512 _mm_set_epi8(15, 15, 14, 14, 13, 13, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8);
1514 const __m128i u = LOAD_SI128(&Um[x]);
1515 const __m128i uHigh = _mm_shuffle_epi8(u, unpackHigh);
1516 const __m128i uLow = _mm_shuffle_epi8(u, unpackLow);
1517 STORE_SI128(&pU[2ULL * x], uHigh);
1518 STORE_SI128(&pU[2ULL * x + 16], uLow);
1519 STORE_SI128(&pU1[2ULL * x], uHigh);
1520 STORE_SI128(&pU1[2ULL * x + 16], uLow);
1523 const __m128i u = LOAD_SI128(&Vm[x]);
1524 const __m128i uHigh = _mm_shuffle_epi8(u, unpackHigh);
1525 const __m128i uLow = _mm_shuffle_epi8(u, unpackLow);
1526 STORE_SI128(&pV[2 * x], uHigh);
1527 STORE_SI128(&pV[2 * x + 16], uLow);
1528 STORE_SI128(&pV1[2 * x], uHigh);
1529 STORE_SI128(&pV1[2 * x + 16], uLow);
1533 for (; x < halfWidth; x++)
1535 const size_t val2x = 2 * x + evenX;
1536 const size_t val2x1 = val2x + oddX;
1543 pU1[val2x1] = Um[x];
1544 pV1[val2x1] = Vm[x];
1548 return PRIMITIVES_SUCCESS;
1551static pstatus_t sse41_ChromaV1ToYUV444(
const BYTE* WINPR_RESTRICT pSrcRaw[3],
1552 const UINT32 srcStep[3], BYTE* WINPR_RESTRICT pDstRaw[3],
1553 const UINT32 dstStep[3],
1556 const UINT32 mod = 16;
1559 const UINT32 nWidth = roi->right - roi->left;
1560 const UINT32 nHeight = roi->bottom - roi->top;
1561 const UINT32 halfWidth = (nWidth + 1) / 2;
1562 const UINT32 halfPad = halfWidth % 16;
1563 const UINT32 halfHeight = (nHeight + 1) / 2;
1564 const UINT32 oddY = 1;
1565 const UINT32 evenY = 0;
1566 const UINT32 oddX = 1;
1569 const UINT32 padHeight = nHeight + 16 - nHeight % 16;
1570 const BYTE* pSrc[3] = { pSrcRaw[0] + 1ULL * roi->top * srcStep[0] + roi->left,
1571 pSrcRaw[1] + 1ULL * roi->top / 2 * srcStep[1] + roi->left / 2,
1572 pSrcRaw[2] + 1ULL * roi->top / 2 * srcStep[2] + roi->left / 2 };
1573 BYTE* pDst[3] = { pDstRaw[0] + 1ULL * roi->top * dstStep[0] + roi->left,
1574 pDstRaw[1] + 1ULL * roi->top * dstStep[1] + roi->left,
1575 pDstRaw[2] + 1ULL * roi->top * dstStep[2] + roi->left };
1576 const __m128i zero = _mm_setzero_si128();
1577 const __m128i mask = _mm_set_epi8(0, (
char)0x80, 0, (
char)0x80, 0, (
char)0x80, 0, (
char)0x80, 0,
1578 (
char)0x80, 0, (
char)0x80, 0, (
char)0x80, 0, (
char)0x80);
1582 for (
size_t y = 0; y < padHeight; y++)
1584 const BYTE* Ya = pSrc[0] + 1ULL * srcStep[0] * y;
1587 if ((y) % mod < (mod + 1) / 2)
1589 const UINT32 pos = (2 * uY++ + oddY);
1594 pX = pDst[1] + 1ULL * dstStep[1] * pos;
1598 const UINT32 pos = (2 * vY++ + oddY);
1603 pX = pDst[2] + 1ULL * dstStep[2] * pos;
1607 memcpy(pX, Ya, nWidth);
1611 for (
size_t y = 0; y < halfHeight; y++)
1613 const size_t val2y = (y * 2 + evenY);
1614 const BYTE* Ua = pSrc[1] + srcStep[1] * y;
1615 const BYTE* Va = pSrc[2] + srcStep[2] * y;
1616 BYTE* pU = pDst[1] + dstStep[1] * val2y;
1617 BYTE* pV = pDst[2] + dstStep[2] * val2y;
1620 for (; x < halfWidth - halfPad; x += 16)
1623 const __m128i u = LOAD_SI128(&Ua[x]);
1624 const __m128i u2 = _mm_unpackhi_epi8(u, zero);
1625 const __m128i u1 = _mm_unpacklo_epi8(u, zero);
1628 _mm_maskmoveu_si128(u1, mask, (
char*)&pU[2 * x + 1]);
1629 _mm_maskmoveu_si128(u2, mask, (
char*)&pU[2 * x + 17]);
1632 const __m128i u = LOAD_SI128(&Va[x]);
1633 const __m128i u2 = _mm_unpackhi_epi8(u, zero);
1634 const __m128i u1 = _mm_unpacklo_epi8(u, zero);
1636 _mm_maskmoveu_si128(u1, mask, (
char*)&pV[2 * x + 1]);
1637 _mm_maskmoveu_si128(u2, mask, (
char*)&pV[2 * x + 17]);
1641 for (; x < halfWidth; x++)
1643 const size_t val2x1 = (x * 2ULL + oddX);
1649 return PRIMITIVES_SUCCESS;
1652static pstatus_t sse41_ChromaV2ToYUV444(
const BYTE* WINPR_RESTRICT pSrc[3],
const UINT32 srcStep[3],
1653 UINT32 nTotalWidth, WINPR_ATTR_UNUSED UINT32 nTotalHeight,
1654 BYTE* WINPR_RESTRICT pDst[3],
const UINT32 dstStep[3],
1657 const UINT32 nWidth = roi->right - roi->left;
1658 const UINT32 nHeight = roi->bottom - roi->top;
1659 const UINT32 halfWidth = (nWidth + 1) / 2;
1660 const UINT32 halfPad = halfWidth % 16;
1661 const UINT32 halfHeight = (nHeight + 1) / 2;
1662 const UINT32 quaterWidth = (nWidth + 3) / 4;
1663 const UINT32 quaterPad = quaterWidth % 16;
1664 const __m128i zero = _mm_setzero_si128();
1665 const __m128i mask = _mm_set_epi8((
char)0x80, 0, (
char)0x80, 0, (
char)0x80, 0, (
char)0x80, 0,
1666 (
char)0x80, 0, (
char)0x80, 0, (
char)0x80, 0, (
char)0x80, 0);
1667 const __m128i mask2 = _mm_set_epi8(0, (
char)0x80, 0, (
char)0x80, 0, (
char)0x80, 0, (
char)0x80,
1668 0, (
char)0x80, 0, (
char)0x80, 0, (
char)0x80, 0, (
char)0x80);
1669 const __m128i shuffle1 =
1670 _mm_set_epi8((
char)0x80, 15, (
char)0x80, 14, (
char)0x80, 13, (
char)0x80, 12, (
char)0x80, 11,
1671 (
char)0x80, 10, (
char)0x80, 9, (
char)0x80, 8);
1672 const __m128i shuffle2 =
1673 _mm_set_epi8((
char)0x80, 7, (
char)0x80, 6, (
char)0x80, 5, (
char)0x80, 4, (
char)0x80, 3,
1674 (
char)0x80, 2, (
char)0x80, 1, (
char)0x80, 0);
1677 for (
size_t y = 0; y < nHeight; y++)
1679 const size_t yTop = y + roi->top;
1680 const BYTE* pYaU = pSrc[0] + srcStep[0] * yTop + roi->left / 2;
1681 const BYTE* pYaV = pYaU + nTotalWidth / 2;
1682 BYTE* pU = pDst[1] + 1ULL * dstStep[1] * yTop + roi->left;
1683 BYTE* pV = pDst[2] + 1ULL * dstStep[2] * yTop + roi->left;
1686 for (; x < halfWidth - halfPad; x += 16)
1689 const __m128i u = LOAD_SI128(&pYaU[x]);
1690 const __m128i u2 = _mm_unpackhi_epi8(zero, u);
1691 const __m128i u1 = _mm_unpacklo_epi8(zero, u);
1692 _mm_maskmoveu_si128(u1, mask, (
char*)&pU[2 * x]);
1693 _mm_maskmoveu_si128(u2, mask, (
char*)&pU[2 * x + 16]);
1696 const __m128i v = LOAD_SI128(&pYaV[x]);
1697 const __m128i v2 = _mm_unpackhi_epi8(zero, v);
1698 const __m128i v1 = _mm_unpacklo_epi8(zero, v);
1699 _mm_maskmoveu_si128(v1, mask, (
char*)&pV[2 * x]);
1700 _mm_maskmoveu_si128(v2, mask, (
char*)&pV[2 * x + 16]);
1704 for (; x < halfWidth; x++)
1706 const size_t odd = 2ULL * x + 1;
1713 for (
size_t y = 0; y < halfHeight; y++)
1715 const BYTE* pUaU = pSrc[1] + srcStep[1] * (y + roi->top / 2) + roi->left / 4;
1716 const BYTE* pUaV = pUaU + nTotalWidth / 4;
1717 const BYTE* pVaU = pSrc[2] + srcStep[2] * (y + roi->top / 2) + roi->left / 4;
1718 const BYTE* pVaV = pVaU + nTotalWidth / 4;
1719 BYTE* pU = pDst[1] + dstStep[1] * (2 * y + 1 + roi->top) + roi->left;
1720 BYTE* pV = pDst[2] + dstStep[2] * (2 * y + 1 + roi->top) + roi->left;
1723 for (; x < quaterWidth - quaterPad; x += 16)
1726 const __m128i uU = LOAD_SI128(&pUaU[x]);
1727 const __m128i uV = LOAD_SI128(&pVaU[x]);
1728 const __m128i uHigh = _mm_unpackhi_epi8(uU, uV);
1729 const __m128i uLow = _mm_unpacklo_epi8(uU, uV);
1730 const __m128i u1 = _mm_shuffle_epi8(uLow, shuffle2);
1731 const __m128i u2 = _mm_shuffle_epi8(uLow, shuffle1);
1732 const __m128i u3 = _mm_shuffle_epi8(uHigh, shuffle2);
1733 const __m128i u4 = _mm_shuffle_epi8(uHigh, shuffle1);
1734 _mm_maskmoveu_si128(u1, mask2, (
char*)&pU[4 * x + 0]);
1735 _mm_maskmoveu_si128(u2, mask2, (
char*)&pU[4 * x + 16]);
1736 _mm_maskmoveu_si128(u3, mask2, (
char*)&pU[4 * x + 32]);
1737 _mm_maskmoveu_si128(u4, mask2, (
char*)&pU[4 * x + 48]);
1740 const __m128i vU = LOAD_SI128(&pUaV[x]);
1741 const __m128i vV = LOAD_SI128(&pVaV[x]);
1742 const __m128i vHigh = _mm_unpackhi_epi8(vU, vV);
1743 const __m128i vLow = _mm_unpacklo_epi8(vU, vV);
1744 const __m128i v1 = _mm_shuffle_epi8(vLow, shuffle2);
1745 const __m128i v2 = _mm_shuffle_epi8(vLow, shuffle1);
1746 const __m128i v3 = _mm_shuffle_epi8(vHigh, shuffle2);
1747 const __m128i v4 = _mm_shuffle_epi8(vHigh, shuffle1);
1748 _mm_maskmoveu_si128(v1, mask2, (
char*)&pV[4 * x + 0]);
1749 _mm_maskmoveu_si128(v2, mask2, (
char*)&pV[4 * x + 16]);
1750 _mm_maskmoveu_si128(v3, mask2, (
char*)&pV[4 * x + 32]);
1751 _mm_maskmoveu_si128(v4, mask2, (
char*)&pV[4 * x + 48]);
1755 for (; x < quaterWidth; x++)
1757 pU[4 * x + 0] = pUaU[x];
1758 pV[4 * x + 0] = pUaV[x];
1759 pU[4 * x + 2] = pVaU[x];
1760 pV[4 * x + 2] = pVaV[x];
1764 return PRIMITIVES_SUCCESS;
1767static pstatus_t sse41_YUV420CombineToYUV444(avc444_frame_type type,
1768 const BYTE* WINPR_RESTRICT pSrc[3],
1769 const UINT32 srcStep[3], UINT32 nWidth, UINT32 nHeight,
1770 BYTE* WINPR_RESTRICT pDst[3],
const UINT32 dstStep[3],
1773 if (!pSrc || !pSrc[0] || !pSrc[1] || !pSrc[2])
1776 if (!pDst || !pDst[0] || !pDst[1] || !pDst[2])
1785 return sse41_LumaToYUV444(pSrc, srcStep, pDst, dstStep, roi);
1787 case AVC444_CHROMAv1:
1788 return sse41_ChromaV1ToYUV444(pSrc, srcStep, pDst, dstStep, roi);
1790 case AVC444_CHROMAv2:
1791 return sse41_ChromaV2ToYUV444(pSrc, srcStep, nWidth, nHeight, pDst, dstStep, roi);
1804static inline __m128i sse41_I444_mask(
size_t off,
size_t first)
1807 memset(m, 0x80,
sizeof(m));
1808 for (
size_t x = 0; x < 4; x++)
1809 m[2 * (first + x)] = (BYTE)(4 * x + off);
1810 return _mm_loadu_si128((
const __m128i*)m);
1814static inline void sse41_I444_YUV(__m128i r, __m128i g, __m128i b, __m128i* WINPR_RESTRICT y,
1815 __m128i* WINPR_RESTRICT u, __m128i* WINPR_RESTRICT v)
1817 const __m128i c128 = _mm_set1_epi16(128);
1820 __m128i t = _mm_add_epi16(_mm_mullo_epi16(r, _mm_set1_epi16(54)),
1821 _mm_mullo_epi16(g, _mm_set1_epi16(183)));
1822 t = _mm_add_epi16(t, _mm_mullo_epi16(b, _mm_set1_epi16(18)));
1823 *y = _mm_srli_epi16(t, 8);
1826 t = _mm_add_epi16(_mm_mullo_epi16(r, _mm_set1_epi16(29)),
1827 _mm_mullo_epi16(g, _mm_set1_epi16(99)));
1828 t = _mm_sub_epi16(_mm_slli_epi16(b, 7), t);
1829 *u = _mm_add_epi16(_mm_srai_epi16(t, 8), c128);
1832 t = _mm_add_epi16(_mm_mullo_epi16(g, _mm_set1_epi16(116)),
1833 _mm_mullo_epi16(b, _mm_set1_epi16(12)));
1834 t = _mm_sub_epi16(_mm_slli_epi16(r, 7), t);
1835 *v = _mm_add_epi16(_mm_srai_epi16(t, 8), c128);
1840static inline void sse41_I444_8px(
const BYTE* WINPR_RESTRICT src,
const __m128i masks[6],
1841 __m128i* WINPR_RESTRICT y, __m128i* WINPR_RESTRICT u,
1842 __m128i* WINPR_RESTRICT v)
1844 const __m128i p0 = LOAD_SI128(src);
1845 const __m128i p1 = LOAD_SI128(src + 16);
1846 const __m128i r = _mm_or_si128(_mm_shuffle_epi8(p0, masks[0]), _mm_shuffle_epi8(p1, masks[1]));
1847 const __m128i g = _mm_or_si128(_mm_shuffle_epi8(p0, masks[2]), _mm_shuffle_epi8(p1, masks[3]));
1848 const __m128i b = _mm_or_si128(_mm_shuffle_epi8(p0, masks[4]), _mm_shuffle_epi8(p1, masks[5]));
1849 sse41_I444_YUV(r, g, b, y, u, v);
1852static pstatus_t sse41_RGBToI444_32bpp(
const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
1853 BYTE* WINPR_RESTRICT pDst[3],
const UINT32 dstStep[3],
1854 const prim_size_t* WINPR_RESTRICT roi,
size_t rOff,
1855 size_t gOff,
size_t bOff)
1857 const __m128i masks[6] = { sse41_I444_mask(rOff, 0), sse41_I444_mask(rOff, 4),
1858 sse41_I444_mask(gOff, 0), sse41_I444_mask(gOff, 4),
1859 sse41_I444_mask(bOff, 0), sse41_I444_mask(bOff, 4) };
1860 const size_t width = roi->width;
1862 for (
size_t row = 0; row < roi->height; row++)
1864 const BYTE* src = &pSrc[row * srcStep];
1865 BYTE* yd = &pDst[0][row * dstStep[0]];
1866 BYTE* ud = &pDst[1][row * dstStep[1]];
1867 BYTE* vd = &pDst[2][row * dstStep[2]];
1870 for (; x + 16 <= width; x += 16)
1872 __m128i y0 = _mm_setzero_si128();
1873 __m128i u0 = _mm_setzero_si128();
1874 __m128i v0 = _mm_setzero_si128();
1875 __m128i y1 = _mm_setzero_si128();
1876 __m128i u1 = _mm_setzero_si128();
1877 __m128i v1 = _mm_setzero_si128();
1878 sse41_I444_8px(&src[4 * x], masks, &y0, &u0, &v0);
1879 sse41_I444_8px(&src[4 * x + 32], masks, &y1, &u1, &v1);
1880 STORE_SI128(&yd[x], _mm_packus_epi16(y0, y1));
1881 STORE_SI128(&ud[x], _mm_packus_epi16(u0, u1));
1882 STORE_SI128(&vd[x], _mm_packus_epi16(v0, v1));
1885 for (; x < width; x++)
1887 const BYTE* px = &src[4 * x];
1888 const BYTE R = px[rOff];
1889 const BYTE G = px[gOff];
1890 const BYTE B = px[bOff];
1891 yd[x] = RGB2Y(R, G, B);
1892 ud[x] = RGB2U(R, G, B);
1893 vd[x] = RGB2V(R, G, B);
1897 return PRIMITIVES_SUCCESS;
1900static pstatus_t sse41_RGBToI444_8u(
const BYTE* WINPR_RESTRICT pSrc, UINT32 SrcFormat,
1901 const UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[3],
1902 const UINT32 dstStep[3],
const prim_size_t* WINPR_RESTRICT roi)
1907 case PIXEL_FORMAT_BGRA32:
1908 case PIXEL_FORMAT_BGRX32:
1909 return sse41_RGBToI444_32bpp(pSrc, srcStep, pDst, dstStep, roi, 2, 1, 0);
1910 case PIXEL_FORMAT_RGBA32:
1911 case PIXEL_FORMAT_RGBX32:
1912 return sse41_RGBToI444_32bpp(pSrc, srcStep, pDst, dstStep, roi, 0, 1, 2);
1913 case PIXEL_FORMAT_ARGB32:
1914 case PIXEL_FORMAT_XRGB32:
1915 return sse41_RGBToI444_32bpp(pSrc, srcStep, pDst, dstStep, roi, 1, 2, 3);
1916 case PIXEL_FORMAT_ABGR32:
1917 case PIXEL_FORMAT_XBGR32:
1918 return sse41_RGBToI444_32bpp(pSrc, srcStep, pDst, dstStep, roi, 3, 2, 1);
1920 return generic->RGBToI444_8u(pSrc, SrcFormat, srcStep, pDst, dstStep, roi);
1925void primitives_init_YUV_sse41_int(
primitives_t* WINPR_RESTRICT prims)
1927#if defined(SSE_AVX_INTRINSICS_ENABLED)
1928 generic = primitives_get_generic();
1930 WLog_VRB(PRIM_TAG,
"SSE3/sse41 optimizations");
1931 prims->RGBToYUV420_8u_P3AC4R = sse41_RGBToYUV420;
1932 prims->RGBToI444_8u = sse41_RGBToI444_8u;
1933 prims->RGBToAVC444YUV = sse41_RGBToAVC444YUV;
1934 prims->RGBToAVC444YUVv2 = sse41_RGBToAVC444YUVv2;
1935 prims->YUV420ToRGB_8u_P3AC4R = sse41_YUV420ToRGB;
1936 prims->YUV444ToRGB_8u_P3AC4R = sse41_YUV444ToRGB_8u_P3AC4R;
1937 prims->I444ToRGB_8u = sse41_I444ToRGB_8u;
1938 prims->YUV420CombineToYUV444 = sse41_YUV420CombineToYUV444;
1940 WLog_VRB(PRIM_TAG,
"undefined WITH_SIMD or sse41 intrinsics not available");
1941 WINPR_UNUSED(prims);