FreeRDP
Loading...
Searching...
No Matches
prim_copy_sse4_1.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_avxsse.h"
27#include "prim_copy.h"
28#include "../codec/color.h"
29
30#include <freerdp/codec/color.h>
31
32#if defined(SSE_AVX_INTRINSICS_ENABLED)
33#include <emmintrin.h>
34#include <immintrin.h>
35
36static inline pstatus_t sse_image_copy_bgr24_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
37 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
38 UINT32 nHeight,
39 const BYTE* WINPR_RESTRICT pSrcData,
40 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
41 int64_t srcVMultiplier, int64_t srcVOffset,
42 int64_t dstVMultiplier, int64_t dstVOffset)
43{
44
45 const int64_t srcByte = 3;
46 const int64_t dstByte = 4;
47
48 const __m128i mask = mm_set_epu32(0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000);
49 const __m128i smask = mm_set_epu32(0xff0b0a09, 0xff080706, 0xff050403, 0xff020100);
50 const UINT32 rem = nWidth % 4;
51
52 const int64_t width = nWidth - rem;
53 for (int64_t y = 0; y < nHeight; y++)
54 {
55 const BYTE* WINPR_RESTRICT srcLine =
56 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
57 BYTE* WINPR_RESTRICT dstLine =
58 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
59
60 int64_t x = 0;
61 /* Ensure alignment requirements can be met */
62 for (; x < width; x += 4)
63 {
64 const __m128i* src =
65 WINPR_PACKED_ALIGN_CAST(const __m128i*, &srcLine[(x + nXSrc) * srcByte]);
66 __m128i* dst = WINPR_PACKED_ALIGN_CAST(__m128i*, &dstLine[(x + nXDst) * dstByte]);
67 const __m128i s0 = LOAD_SI128(src);
68 const __m128i s1 = _mm_shuffle_epi8(s0, smask);
69 const __m128i s2 = LOAD_SI128(dst);
70
71 __m128i d0 = _mm_blendv_epi8(s1, s2, mask);
72 STORE_SI128(dst, d0);
73 }
74
75 for (; x < nWidth; x++)
76 {
77 const BYTE* src = &srcLine[(x + nXSrc) * srcByte];
78 BYTE* dst = &dstLine[(x + nXDst) * dstByte];
79 *dst++ = *src++;
80 *dst++ = *src++;
81 *dst++ = *src++;
82 }
83 }
84
85 return PRIMITIVES_SUCCESS;
86}
87
88static inline pstatus_t sse_image_copy_bgrx32_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
89 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
90 UINT32 nHeight,
91 const BYTE* WINPR_RESTRICT pSrcData,
92 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
93 int64_t srcVMultiplier, int64_t srcVOffset,
94 int64_t dstVMultiplier, int64_t dstVOffset)
95{
96
97 const int64_t srcByte = 4;
98 const int64_t dstByte = 4;
99
100 const __m128i mask = _mm_setr_epi8((char)0xFF, (char)0xFF, (char)0xFF, 0x00, (char)0xFF,
101 (char)0xFF, (char)0xFF, 0x00, (char)0xFF, (char)0xFF,
102 (char)0xFF, 0x00, (char)0xFF, (char)0xFF, (char)0xFF, 0x00);
103 const UINT32 rem = nWidth % 4;
104 const int64_t width = nWidth - rem;
105 for (int64_t y = 0; y < nHeight; y++)
106 {
107 const BYTE* WINPR_RESTRICT srcLine =
108 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
109 BYTE* WINPR_RESTRICT dstLine =
110 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
111
112 int64_t x = 0;
113 for (; x < width; x += 4)
114 {
115 const __m128i* src =
116 WINPR_PACKED_ALIGN_CAST(const __m128i*, &srcLine[(x + nXSrc) * srcByte]);
117 __m128i* dst = WINPR_PACKED_ALIGN_CAST(__m128i*, &dstLine[(x + nXDst) * dstByte]);
118 const __m128i s0 = LOAD_SI128(src);
119 const __m128i s1 = LOAD_SI128(dst);
120 __m128i d0 = _mm_blendv_epi8(s1, s0, mask);
121 STORE_SI128(dst, d0);
122 }
123
124 for (; x < nWidth; x++)
125 {
126 const BYTE* src = &srcLine[(x + nXSrc) * srcByte];
127 BYTE* dst = &dstLine[(x + nXDst) * dstByte];
128 *dst++ = *src++;
129 *dst++ = *src++;
130 *dst++ = *src++;
131 }
132 }
133
134 return PRIMITIVES_SUCCESS;
135}
136
137static pstatus_t sse_image_copy_no_overlap_dst_alpha(
138 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
139 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
140 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
141 UINT32 flags, int64_t srcVMultiplier, int64_t srcVOffset, int64_t dstVMultiplier,
142 int64_t dstVOffset)
143{
144 WINPR_ASSERT(pDstData);
145 WINPR_ASSERT(pSrcData);
146
147 switch (SrcFormat)
148 {
149 case PIXEL_FORMAT_BGR24:
150 switch (DstFormat)
151 {
152 case PIXEL_FORMAT_BGRX32:
153 case PIXEL_FORMAT_BGRA32:
154 return sse_image_copy_bgr24_bgrx32(
155 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
156 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
157 default:
158 break;
159 }
160 break;
161 case PIXEL_FORMAT_BGRX32:
162 case PIXEL_FORMAT_BGRA32:
163 switch (DstFormat)
164 {
165 case PIXEL_FORMAT_BGRX32:
166 case PIXEL_FORMAT_BGRA32:
167 return sse_image_copy_bgrx32_bgrx32(
168 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
169 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
170 default:
171 break;
172 }
173 break;
174 case PIXEL_FORMAT_RGBX32:
175 case PIXEL_FORMAT_RGBA32:
176 switch (DstFormat)
177 {
178 case PIXEL_FORMAT_RGBX32:
179 case PIXEL_FORMAT_RGBA32:
180 return sse_image_copy_bgrx32_bgrx32(
181 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
182 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
183 default:
184 break;
185 }
186 break;
187 default:
188 break;
189 }
190
191 primitives_t* gen = primitives_get_generic();
192 return gen->copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
193 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette, flags);
194}
195
196static pstatus_t sse_image_copy_no_overlap(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat,
197 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
198 UINT32 nWidth, UINT32 nHeight,
199 const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
200 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
201 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
202{
203 const BOOL vSrcVFlip = (flags & FREERDP_FLIP_VERTICAL) != 0;
204 int64_t srcVOffset = 0;
205 int64_t srcVMultiplier = 1;
206 int64_t dstVOffset = 0;
207 int64_t dstVMultiplier = 1;
208
209 if ((nWidth == 0) || (nHeight == 0))
210 return PRIMITIVES_SUCCESS;
211
212 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
213 return -1;
214
215 if (!pDstData || !pSrcData)
216 return -1;
217
218 if (nDstStep == 0)
219 nDstStep = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
220
221 if (nSrcStep == 0)
222 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
223
224 if (vSrcVFlip)
225 {
226 srcVOffset = (nHeight - 1ll) * nSrcStep;
227 srcVMultiplier = -1;
228 }
229
230 if (((flags & FREERDP_KEEP_DST_ALPHA) != 0) && FreeRDPColorHasAlpha(DstFormat))
231 return sse_image_copy_no_overlap_dst_alpha(pDstData, DstFormat, nDstStep, nXDst, nYDst,
232 nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
233 nXSrc, nYSrc, palette, flags, srcVMultiplier,
234 srcVOffset, dstVMultiplier, dstVOffset);
235 else if (FreeRDPAreColorFormatsEqualNoAlpha(SrcFormat, DstFormat))
236 return generic_image_copy_no_overlap_memcpy(pDstData, DstFormat, nDstStep, nXDst, nYDst,
237 nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
238 nXSrc, nYSrc, palette, srcVMultiplier,
239 srcVOffset, dstVMultiplier, dstVOffset, flags);
240 else
241 {
242 primitives_t* gen = primitives_get_generic();
243 return gen->copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
244 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette, flags);
245 }
246}
247#endif
248
249/* ------------------------------------------------------------------------- */
250void primitives_init_copy_sse41_int(primitives_t* WINPR_RESTRICT prims)
251{
252#if defined(SSE_AVX_INTRINSICS_ENABLED)
253 WLog_VRB(PRIM_TAG, "SSE4.1 optimizations");
254 prims->copy_no_overlap = sse_image_copy_no_overlap;
255#else
256 WLog_VRB(PRIM_TAG, "undefined WITH_SIMD or SSE4.1 intrinsics not available");
257 WINPR_UNUSED(prims);
258#endif
259}
WINPR_ATTR_NODISCARD fn_copy_no_overlap_t copy_no_overlap
Definition primitives.h:304