16#include <winpr/sysinfo.h>
18#include <freerdp/config.h>
21#include <freerdp/types.h>
22#include <freerdp/primitives.h>
23#include <freerdp/log.h>
25#include "prim_internal.h"
27#include "../codec/color.h"
29#include <freerdp/codec/color.h>
31#if defined(SSE_AVX_INTRINSICS_ENABLED)
35static inline __m256i mm256_set_epu32(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3,
36 uint32_t i4, uint32_t i5, uint32_t i6, uint32_t i7)
38 return _mm256_set_epi32((int32_t)i0, (int32_t)i1, (int32_t)i2, (int32_t)i3, (int32_t)i4,
39 (int32_t)i5, (int32_t)i6, (int32_t)i7);
42static inline pstatus_t avx2_image_copy_bgr24_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
43 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
45 const BYTE* WINPR_RESTRICT pSrcData,
46 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
47 int64_t srcVMultiplier, int64_t srcVOffset,
48 int64_t dstVMultiplier, int64_t dstVOffset)
51 const int64_t srcByte = 3;
52 const int64_t dstByte = 4;
54 const __m256i mask = mm256_set_epu32(0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000,
55 0xFF000000, 0xFF000000, 0xFF000000);
56 const __m256i smask = mm256_set_epu32(0xff171615, 0xff141312, 0xff1110ff, 0xffffffff,
57 0xff0b0a09, 0xff080706, 0xff050403, 0xff020100);
58 const __m256i shelpmask = mm256_set_epu32(0xffffffff, 0xffffffff, 0xffffff1f, 0xff1e1d1c,
59 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
60 const UINT32 rem = nWidth % 8;
61 const int64_t width = nWidth - rem;
63 for (int64_t y = 0; y < nHeight; y++)
65 const BYTE* WINPR_RESTRICT srcLine =
66 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
67 BYTE* WINPR_RESTRICT dstLine =
68 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
73 for (; x < width; x += 8)
76 WINPR_PACKED_ALIGN_CAST(
const __m256i*, &srcLine[(x + nXSrc) * srcByte]);
77 __m256i* dst = WINPR_PACKED_ALIGN_CAST(__m256i*, &dstLine[(x + nXDst) * dstByte]);
78 const __m256i s0 = _mm256_loadu_si256(src);
79 __m256i s1 = _mm256_shuffle_epi8(s0, smask);
83 const __m256i sx = _mm256_broadcastsi128_si256(_mm256_extractf128_si256(s0, 0));
84 const __m256i sxx = _mm256_shuffle_epi8(sx, shelpmask);
85 const __m256i bmask = _mm256_set_epi32(0x00000000, 0x00000000, 0x000000FF, 0x00FFFFFF,
86 0x00000000, 0x00000000, 0x00000000, 0x00000000);
87 const __m256i merged = _mm256_blendv_epi8(s1, sxx, bmask);
89 const __m256i s2 = _mm256_loadu_si256(dst);
90 __m256i d0 = _mm256_blendv_epi8(merged, s2, mask);
91 _mm256_storeu_si256(dst, d0);
94 for (; x < nWidth; x++)
96 const BYTE* src = &srcLine[(x + nXSrc) * srcByte];
97 BYTE* dst = &dstLine[(x + nXDst) * dstByte];
104 return PRIMITIVES_SUCCESS;
107static inline pstatus_t avx2_image_copy_bgrx32_bgrx32(BYTE* WINPR_RESTRICT pDstData,
108 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
109 UINT32 nWidth, UINT32 nHeight,
110 const BYTE* WINPR_RESTRICT pSrcData,
111 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
112 int64_t srcVMultiplier, int64_t srcVOffset,
113 int64_t dstVMultiplier, int64_t dstVOffset)
116 const int64_t srcByte = 4;
117 const int64_t dstByte = 4;
119 const __m256i mask = _mm256_setr_epi8(
120 (
char)0xFF, (
char)0xFF, (
char)0xFF, 0x00, (
char)0xFF, (
char)0xFF, (
char)0xFF, 0x00,
121 (
char)0xFF, (
char)0xFF, (
char)0xFF, 0x00, (
char)0xFF, (
char)0xFF, (
char)0xFF, 0x00,
122 (
char)0xFF, (
char)0xFF, (
char)0xFF, 0x00, (
char)0xFF, (
char)0xFF, (
char)0xFF, 0x00,
123 (
char)0xFF, (
char)0xFF, (
char)0xFF, 0x00, (
char)0xFF, (
char)0xFF, (
char)0xFF, 0x00);
124 const UINT32 rem = nWidth % 8;
125 const int64_t width = nWidth - rem;
126 for (int64_t y = 0; y < nHeight; y++)
128 const BYTE* WINPR_RESTRICT srcLine =
129 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
130 BYTE* WINPR_RESTRICT dstLine =
131 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
134 for (; x < width; x += 8)
137 WINPR_PACKED_ALIGN_CAST(
const __m256i*, &srcLine[(x + nXSrc) * srcByte]);
138 __m256i* dst = WINPR_PACKED_ALIGN_CAST(__m256i*, &dstLine[(x + nXDst) * dstByte]);
139 const __m256i s0 = _mm256_loadu_si256(src);
140 const __m256i s1 = _mm256_loadu_si256(dst);
141 __m256i d0 = _mm256_blendv_epi8(s1, s0, mask);
142 _mm256_storeu_si256(dst, d0);
145 for (; x < nWidth; x++)
147 const BYTE* src = &srcLine[(x + nXSrc) * srcByte];
148 BYTE* dst = &dstLine[(x + nXDst) * dstByte];
155 return PRIMITIVES_SUCCESS;
158static pstatus_t avx2_image_copy_no_overlap_dst_alpha(
159 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
160 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
161 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette,
162 UINT32 flags, int64_t srcVMultiplier, int64_t srcVOffset, int64_t dstVMultiplier,
165 WINPR_ASSERT(pDstData);
166 WINPR_ASSERT(pSrcData);
170 case PIXEL_FORMAT_BGR24:
173 case PIXEL_FORMAT_BGRX32:
174 case PIXEL_FORMAT_BGRA32:
175 return avx2_image_copy_bgr24_bgrx32(
176 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
177 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
182 case PIXEL_FORMAT_BGRX32:
183 case PIXEL_FORMAT_BGRA32:
186 case PIXEL_FORMAT_BGRX32:
187 case PIXEL_FORMAT_BGRA32:
188 return avx2_image_copy_bgrx32_bgrx32(
189 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
190 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
195 case PIXEL_FORMAT_RGBX32:
196 case PIXEL_FORMAT_RGBA32:
199 case PIXEL_FORMAT_RGBX32:
200 case PIXEL_FORMAT_RGBA32:
201 return avx2_image_copy_bgrx32_bgrx32(
202 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
203 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
213 return gen->
copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
214 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette, flags);
217static pstatus_t avx2_image_copy_no_overlap(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat,
218 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
219 UINT32 nWidth, UINT32 nHeight,
220 const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
221 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
222 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
224 const BOOL vSrcVFlip = (flags & FREERDP_FLIP_VERTICAL) != 0;
225 int64_t srcVOffset = 0;
226 int64_t srcVMultiplier = 1;
227 int64_t dstVOffset = 0;
228 int64_t dstVMultiplier = 1;
230 if ((nWidth == 0) || (nHeight == 0))
231 return PRIMITIVES_SUCCESS;
233 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
236 if (!pDstData || !pSrcData)
240 nDstStep = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
243 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
247 srcVOffset = (nHeight - 1ll) * nSrcStep;
251 if (((flags & FREERDP_KEEP_DST_ALPHA) != 0) && FreeRDPColorHasAlpha(DstFormat))
252 return avx2_image_copy_no_overlap_dst_alpha(pDstData, DstFormat, nDstStep, nXDst, nYDst,
253 nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
254 nXSrc, nYSrc, palette, flags, srcVMultiplier,
255 srcVOffset, dstVMultiplier, dstVOffset);
256 else if (FreeRDPAreColorFormatsEqualNoAlpha(SrcFormat, DstFormat))
257 return generic_image_copy_no_overlap_memcpy(pDstData, DstFormat, nDstStep, nXDst, nYDst,
258 nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
259 nXSrc, nYSrc, palette, srcVMultiplier,
260 srcVOffset, dstVMultiplier, dstVOffset, flags);
264 return gen->
copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
265 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette, flags);
271void primitives_init_copy_avx2_int(
primitives_t* WINPR_RESTRICT prims)
273#if defined(SSE_AVX_INTRINSICS_ENABLED)
274 WLog_VRB(PRIM_TAG,
"AVX2 optimizations");
275 prims->copy_no_overlap = avx2_image_copy_no_overlap;
277 WLog_VRB(PRIM_TAG,
"undefined WITH_SIMD or WITH_AVX2 or AVX2 intrinsics not available");
WINPR_ATTR_NODISCARD fn_copy_no_overlap_t copy_no_overlap