FreeRDP
Loading...
Searching...
No Matches
prim_copy_avx2.c
1/* FreeRDP: A Remote Desktop Protocol Client
2 * Copy operations.
3 * vi:ts=4 sw=4:
4 *
5 * (c) Copyright 2012 Hewlett-Packard Development Company, L.P.
6 * Licensed under the Apache License, Version 2.0 (the "License"); you may
7 * not use this file except in compliance with the License. You may obtain
8 * a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12 * or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15
16#include <winpr/sysinfo.h>
17
18#include <freerdp/config.h>
19
20#include <string.h>
21#include <freerdp/types.h>
22#include <freerdp/primitives.h>
23#include <freerdp/log.h>
24
25#include "prim_internal.h"
26#include "prim_copy.h"
27#include "../codec/color.h"
28
29#include <freerdp/codec/color.h>
30
31#if defined(SSE_AVX_INTRINSICS_ENABLED)
32#include <emmintrin.h>
33#include <immintrin.h>
34
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)
37{
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);
40}
41
42static inline pstatus_t avx2_image_copy_bgr24_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
43 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
44 UINT32 nHeight,
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)
49{
50
51 const int64_t srcByte = 3;
52 const int64_t dstByte = 4;
53
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;
62
63 for (int64_t y = 0; y < nHeight; y++)
64 {
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];
69
70 int64_t x = 0;
71
72 /* Ensure alignment requirements can be met */
73 for (; x < width; x += 8)
74 {
75 const __m256i* src =
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);
80
81 /* _mm256_shuffle_epi8 can not cross 128bit lanes.
82 * manually copy these bytes with extract/insert */
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);
88
89 const __m256i s2 = _mm256_loadu_si256(dst);
90 __m256i d0 = _mm256_blendv_epi8(merged, s2, mask);
91 _mm256_storeu_si256(dst, d0);
92 }
93
94 for (; x < nWidth; x++)
95 {
96 const BYTE* src = &srcLine[(x + nXSrc) * srcByte];
97 BYTE* dst = &dstLine[(x + nXDst) * dstByte];
98 *dst++ = *src++;
99 *dst++ = *src++;
100 *dst++ = *src++;
101 }
102 }
103
104 return PRIMITIVES_SUCCESS;
105}
106
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)
114{
115
116 const int64_t srcByte = 4;
117 const int64_t dstByte = 4;
118
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++)
127 {
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];
132
133 int64_t x = 0;
134 for (; x < width; x += 8)
135 {
136 const __m256i* src =
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);
143 }
144
145 for (; x < nWidth; x++)
146 {
147 const BYTE* src = &srcLine[(x + nXSrc) * srcByte];
148 BYTE* dst = &dstLine[(x + nXDst) * dstByte];
149 *dst++ = *src++;
150 *dst++ = *src++;
151 *dst++ = *src++;
152 }
153 }
154
155 return PRIMITIVES_SUCCESS;
156}
157
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,
163 int64_t dstVOffset)
164{
165 WINPR_ASSERT(pDstData);
166 WINPR_ASSERT(pSrcData);
167
168 switch (SrcFormat)
169 {
170 case PIXEL_FORMAT_BGR24:
171 switch (DstFormat)
172 {
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);
178 default:
179 break;
180 }
181 break;
182 case PIXEL_FORMAT_BGRX32:
183 case PIXEL_FORMAT_BGRA32:
184 switch (DstFormat)
185 {
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);
191 default:
192 break;
193 }
194 break;
195 case PIXEL_FORMAT_RGBX32:
196 case PIXEL_FORMAT_RGBA32:
197 switch (DstFormat)
198 {
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);
204 default:
205 break;
206 }
207 break;
208 default:
209 break;
210 }
211
212 primitives_t* gen = primitives_get_generic();
213 return gen->copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
214 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette, flags);
215}
216
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)
223{
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;
229
230 if ((nWidth == 0) || (nHeight == 0))
231 return PRIMITIVES_SUCCESS;
232
233 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
234 return -1;
235
236 if (!pDstData || !pSrcData)
237 return -1;
238
239 if (nDstStep == 0)
240 nDstStep = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
241
242 if (nSrcStep == 0)
243 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
244
245 if (vSrcVFlip)
246 {
247 srcVOffset = (nHeight - 1ll) * nSrcStep;
248 srcVMultiplier = -1;
249 }
250
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);
261 else
262 {
263 primitives_t* gen = primitives_get_generic();
264 return gen->copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
265 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette, flags);
266 }
267}
268#endif
269
270/* ------------------------------------------------------------------------- */
271void primitives_init_copy_avx2_int(primitives_t* WINPR_RESTRICT prims)
272{
273#if defined(SSE_AVX_INTRINSICS_ENABLED)
274 WLog_VRB(PRIM_TAG, "AVX2 optimizations");
275 prims->copy_no_overlap = avx2_image_copy_no_overlap;
276#else
277 WLog_VRB(PRIM_TAG, "undefined WITH_SIMD or WITH_AVX2 or AVX2 intrinsics not available");
278 WINPR_UNUSED(prims);
279#endif
280}
WINPR_ATTR_NODISCARD fn_copy_no_overlap_t copy_no_overlap
Definition primitives.h:304