18#include <winpr/sysinfo.h>
20#include <freerdp/config.h>
23#include <freerdp/types.h>
24#include <freerdp/primitives.h>
25#include <freerdp/log.h>
27#include "prim_internal.h"
30#if defined(SSE_AVX_INTRINSICS_ENABLED)
42static inline __m256i avx2_I444_mask(
size_t off,
size_t first)
45 memset(m, 0x80,
sizeof(m));
46 for (
size_t x = 0; x < 4; x++)
47 m[2 * (first + x)] = (BYTE)(4 * x + off);
48 const __m128i half = _mm_loadu_si128((
const __m128i*)m);
49 return _mm256_broadcastsi128_si256(half);
53static inline void avx2_I444_YUV(__m256i r, __m256i g, __m256i b, __m256i* WINPR_RESTRICT y,
54 __m256i* WINPR_RESTRICT u, __m256i* WINPR_RESTRICT v)
56 const __m256i c128 = _mm256_set1_epi16(128);
59 __m256i t = _mm256_add_epi16(_mm256_mullo_epi16(r, _mm256_set1_epi16(54)),
60 _mm256_mullo_epi16(g, _mm256_set1_epi16(183)));
61 t = _mm256_add_epi16(t, _mm256_mullo_epi16(b, _mm256_set1_epi16(18)));
62 *y = _mm256_srli_epi16(t, 8);
65 t = _mm256_add_epi16(_mm256_mullo_epi16(r, _mm256_set1_epi16(29)),
66 _mm256_mullo_epi16(g, _mm256_set1_epi16(99)));
67 t = _mm256_sub_epi16(_mm256_slli_epi16(b, 7), t);
68 *u = _mm256_add_epi16(_mm256_srai_epi16(t, 8), c128);
71 t = _mm256_add_epi16(_mm256_mullo_epi16(g, _mm256_set1_epi16(116)),
72 _mm256_mullo_epi16(b, _mm256_set1_epi16(12)));
73 t = _mm256_sub_epi16(_mm256_slli_epi16(r, 7), t);
74 *v = _mm256_add_epi16(_mm256_srai_epi16(t, 8), c128);
79static inline void avx2_I444_16px(
const BYTE* WINPR_RESTRICT src,
const __m256i masks[6],
80 __m256i* WINPR_RESTRICT y, __m256i* WINPR_RESTRICT u,
81 __m256i* WINPR_RESTRICT v)
83 const __m256i p0 = _mm256_loadu_si256(WINPR_PACKED_ALIGN_CAST(
const __m256i*, src));
84 const __m256i p1 = _mm256_loadu_si256(WINPR_PACKED_ALIGN_CAST(
const __m256i*, &src[32]));
86 _mm256_or_si256(_mm256_shuffle_epi8(p0, masks[0]), _mm256_shuffle_epi8(p1, masks[1]));
88 _mm256_or_si256(_mm256_shuffle_epi8(p0, masks[2]), _mm256_shuffle_epi8(p1, masks[3]));
90 _mm256_or_si256(_mm256_shuffle_epi8(p0, masks[4]), _mm256_shuffle_epi8(p1, masks[5]));
91 avx2_I444_YUV(r, g, b, y, u, v);
97static inline __m256i avx2_I444_pack(__m256i a, __m256i b)
99 const __m256i order = _mm256_setr_epi32(0, 4, 1, 5, 2, 6, 3, 7);
100 return _mm256_permutevar8x32_epi32(_mm256_packus_epi16(a, b), order);
103static pstatus_t avx2_RGBToI444_32bpp(
const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
104 BYTE* WINPR_RESTRICT pDst[3],
const UINT32 dstStep[3],
105 const prim_size_t* WINPR_RESTRICT roi,
size_t rOff,
106 size_t gOff,
size_t bOff)
108 const __m256i masks[6] = { avx2_I444_mask(rOff, 0), avx2_I444_mask(rOff, 4),
109 avx2_I444_mask(gOff, 0), avx2_I444_mask(gOff, 4),
110 avx2_I444_mask(bOff, 0), avx2_I444_mask(bOff, 4) };
111 const size_t width = roi->width;
113 for (
size_t row = 0; row < roi->height; row++)
115 const BYTE* src = &pSrc[row * srcStep];
116 BYTE* yd = &pDst[0][row * dstStep[0]];
117 BYTE* ud = &pDst[1][row * dstStep[1]];
118 BYTE* vd = &pDst[2][row * dstStep[2]];
121 for (; x + 32 <= width; x += 32)
123 __m256i y0 = _mm256_setzero_si256();
124 __m256i u0 = _mm256_setzero_si256();
125 __m256i v0 = _mm256_setzero_si256();
126 __m256i y1 = _mm256_setzero_si256();
127 __m256i u1 = _mm256_setzero_si256();
128 __m256i v1 = _mm256_setzero_si256();
129 avx2_I444_16px(&src[4 * x], masks, &y0, &u0, &v0);
130 avx2_I444_16px(&src[4 * x + 64], masks, &y1, &u1, &v1);
132 __m256i* cyd = WINPR_PACKED_ALIGN_CAST(__m256i*, &yd[x]);
133 __m256i* cud = WINPR_PACKED_ALIGN_CAST(__m256i*, &ud[x]);
134 __m256i* cvd = WINPR_PACKED_ALIGN_CAST(__m256i*, &vd[x]);
135 _mm256_storeu_si256(cyd, avx2_I444_pack(y0, y1));
136 _mm256_storeu_si256(cud, avx2_I444_pack(u0, u1));
137 _mm256_storeu_si256(cvd, avx2_I444_pack(v0, v1));
140 for (; x < width; x++)
142 const BYTE* px = &src[4 * x];
143 const BYTE R = px[rOff];
144 const BYTE G = px[gOff];
145 const BYTE B = px[bOff];
146 yd[x] = RGB2Y(R, G, B);
147 ud[x] = RGB2U(R, G, B);
148 vd[x] = RGB2V(R, G, B);
152 return PRIMITIVES_SUCCESS;
155static pstatus_t avx2_RGBToI444_8u(
const BYTE* WINPR_RESTRICT pSrc, UINT32 SrcFormat,
156 const UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[3],
157 const UINT32 dstStep[3],
const prim_size_t* WINPR_RESTRICT roi)
162 case PIXEL_FORMAT_BGRA32:
163 case PIXEL_FORMAT_BGRX32:
164 return avx2_RGBToI444_32bpp(pSrc, srcStep, pDst, dstStep, roi, 2, 1, 0);
165 case PIXEL_FORMAT_RGBA32:
166 case PIXEL_FORMAT_RGBX32:
167 return avx2_RGBToI444_32bpp(pSrc, srcStep, pDst, dstStep, roi, 0, 1, 2);
168 case PIXEL_FORMAT_ARGB32:
169 case PIXEL_FORMAT_XRGB32:
170 return avx2_RGBToI444_32bpp(pSrc, srcStep, pDst, dstStep, roi, 1, 2, 3);
171 case PIXEL_FORMAT_ABGR32:
172 case PIXEL_FORMAT_XBGR32:
173 return avx2_RGBToI444_32bpp(pSrc, srcStep, pDst, dstStep, roi, 3, 2, 1);
175 return generic->RGBToI444_8u(pSrc, SrcFormat, srcStep, pDst, dstStep, roi);
180void primitives_init_YUV_avx2_int(
primitives_t* WINPR_RESTRICT prims)
182#if defined(SSE_AVX_INTRINSICS_ENABLED)
183 generic = primitives_get_generic();
185 WLog_VRB(PRIM_TAG,
"AVX2 optimizations");
186 prims->RGBToI444_8u = avx2_RGBToI444_8u;
188 WLog_VRB(PRIM_TAG,
"undefined WITH_SIMD or WITH_AVX2 or AVX2 intrinsics not available");