16 #include <freerdp/config.h>
19 #include <freerdp/types.h>
20 #include <freerdp/primitives.h>
21 #include <freerdp/log.h>
23 #include "prim_internal.h"
24 #include "prim_copy.h"
25 #include "../codec/color.h"
27 #include <freerdp/codec/color.h>
33 static BOOL memory_regions_overlap_1d(
const BYTE* p1,
const BYTE* p2,
size_t bytes)
35 const ULONG_PTR p1m = (
const ULONG_PTR)p1;
36 const ULONG_PTR p2m = (
const ULONG_PTR)p2;
40 if (p1m + bytes > p2m)
45 if (p2m + bytes > p1m)
55 static BOOL memory_regions_overlap_2d(
const BYTE* p1,
int p1Step,
int p1Size,
const BYTE* p2,
56 int p2Step,
int p2Size,
int width,
int height)
58 ULONG_PTR p1m = (ULONG_PTR)p1;
59 ULONG_PTR p2m = (ULONG_PTR)p2;
63 ULONG_PTR p1mEnd = p1m + 1ull * (height - 1) * p1Step + 1ull * width * p1Size;
70 ULONG_PTR p2mEnd = p2m + 1ull * (height - 1) * p2Step + 1ull * width * p2Size;
81 static pstatus_t general_copy_8u(
const BYTE* pSrc, BYTE* pDst, INT32 len)
83 if (memory_regions_overlap_1d(pSrc, pDst, (
size_t)len))
85 memmove((
void*)pDst, (
const void*)pSrc, (
size_t)len);
89 memcpy((
void*)pDst, (
const void*)pSrc, (
size_t)len);
92 return PRIMITIVES_SUCCESS;
100 static pstatus_t general_copy_8u_AC4r(
const BYTE* pSrc, INT32 srcStep, BYTE* pDst, INT32 dstStep,
101 INT32 width, INT32 height)
103 const BYTE* src = pSrc;
105 int rowbytes = width *
sizeof(UINT32);
107 if ((width == 0) || (height == 0))
108 return PRIMITIVES_SUCCESS;
110 if (memory_regions_overlap_2d(pSrc, srcStep,
sizeof(UINT32), pDst, dstStep,
sizeof(UINT32),
115 generic->copy(src, dst, rowbytes);
128 memcpy(dst, src, rowbytes);
134 return PRIMITIVES_SUCCESS;
137 static INLINE pstatus_t generic_image_copy_bgr24_bgrx32(BYTE* WINPR_RESTRICT pDstData,
138 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
139 UINT32 nWidth, UINT32 nHeight,
140 const BYTE* WINPR_RESTRICT pSrcData,
141 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
142 SSIZE_T srcVMultiplier, SSIZE_T srcVOffset,
143 SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
146 const SSIZE_T srcByte = 3;
147 const SSIZE_T dstByte = 4;
149 const UINT32 width = nWidth - nWidth % 8;
151 for (SSIZE_T y = 0; y < nHeight; y++)
153 const BYTE* WINPR_RESTRICT srcLine =
154 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
155 BYTE* WINPR_RESTRICT dstLine =
156 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
159 WINPR_PRAGMA_UNROLL_LOOP
160 for (; x < width; x++)
162 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
163 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
164 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
167 for (; x < nWidth; x++)
169 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
170 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
171 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
175 return PRIMITIVES_SUCCESS;
178 static INLINE pstatus_t generic_image_copy_bgrx32_bgrx32(
179 BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
180 UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 nSrcStep, UINT32 nXSrc,
181 UINT32 nYSrc, SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier,
185 const SSIZE_T srcByte = 4;
186 const SSIZE_T dstByte = 4;
188 const UINT32 width = nWidth - nWidth % 8;
190 for (SSIZE_T y = 0; y < nHeight; y++)
192 const BYTE* WINPR_RESTRICT srcLine =
193 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
194 BYTE* WINPR_RESTRICT dstLine =
195 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
198 WINPR_PRAGMA_UNROLL_LOOP
199 for (; x < width; x++)
201 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
202 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
203 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
205 for (; x < nWidth; x++)
207 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
208 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
209 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
213 return PRIMITIVES_SUCCESS;
216 pstatus_t generic_image_copy_no_overlap_convert(
217 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
218 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
219 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette,
220 SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
222 const SSIZE_T srcByte = FreeRDPGetBytesPerPixel(SrcFormat);
223 const SSIZE_T dstByte = FreeRDPGetBytesPerPixel(DstFormat);
225 const UINT32 width = nWidth - nWidth % 8;
226 for (SSIZE_T y = 0; y < nHeight; y++)
228 const BYTE* WINPR_RESTRICT srcLine =
229 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
230 BYTE* WINPR_RESTRICT dstLine =
231 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
234 WINPR_PRAGMA_UNROLL_LOOP
235 for (; x < width; x++)
237 const UINT32 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
238 const UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
239 FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat, dstColor);
241 for (; x < nWidth; x++)
243 const UINT32 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
244 const UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
245 FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat, dstColor);
248 return PRIMITIVES_SUCCESS;
251 pstatus_t generic_image_copy_no_overlap_memcpy(
252 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
253 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
254 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette,
255 SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset,
258 const SSIZE_T dstByte = FreeRDPGetBytesPerPixel(DstFormat);
259 const SSIZE_T srcByte = FreeRDPGetBytesPerPixel(SrcFormat);
260 const SSIZE_T copyDstWidth = nWidth * dstByte;
261 const SSIZE_T xSrcOffset = nXSrc * srcByte;
262 const SSIZE_T xDstOffset = nXDst * dstByte;
264 for (SSIZE_T y = 0; y < nHeight; y++)
266 const BYTE* WINPR_RESTRICT srcLine =
267 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
268 BYTE* WINPR_RESTRICT dstLine =
269 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
270 memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
273 return PRIMITIVES_SUCCESS;
276 static INLINE pstatus_t generic_image_copy_no_overlap_dst_alpha(
277 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
278 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
279 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette,
280 SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset)
282 WINPR_ASSERT(pDstData);
283 WINPR_ASSERT(pSrcData);
287 case PIXEL_FORMAT_BGR24:
290 case PIXEL_FORMAT_BGRX32:
291 case PIXEL_FORMAT_BGRA32:
292 return generic_image_copy_bgr24_bgrx32(
293 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
294 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
299 case PIXEL_FORMAT_BGRX32:
300 case PIXEL_FORMAT_BGRA32:
303 case PIXEL_FORMAT_BGRX32:
304 case PIXEL_FORMAT_BGRA32:
305 return generic_image_copy_bgrx32_bgrx32(
306 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
307 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
312 case PIXEL_FORMAT_RGBX32:
313 case PIXEL_FORMAT_RGBA32:
316 case PIXEL_FORMAT_RGBX32:
317 case PIXEL_FORMAT_RGBA32:
318 return generic_image_copy_bgrx32_bgrx32(
319 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
320 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
321 case PIXEL_FORMAT_RGB24:
322 return generic_image_copy_bgr24_bgrx32(
323 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
324 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
333 return generic_image_copy_no_overlap_convert(
334 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
335 nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
338 static INLINE pstatus_t generic_image_copy_no_overlap_no_alpha(
339 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
340 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
341 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette,
342 SSIZE_T srcVMultiplier, SSIZE_T srcVOffset, SSIZE_T dstVMultiplier, SSIZE_T dstVOffset,
345 if (FreeRDPAreColorFormatsEqualNoAlpha(SrcFormat, DstFormat))
346 return generic_image_copy_no_overlap_memcpy(pDstData, DstFormat, nDstStep, nXDst, nYDst,
347 nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
348 nXSrc, nYSrc, palette, srcVMultiplier,
349 srcVOffset, dstVMultiplier, dstVOffset, flags);
351 return generic_image_copy_no_overlap_convert(pDstData, DstFormat, nDstStep, nXDst, nYDst,
352 nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
353 nXSrc, nYSrc, palette, srcVMultiplier,
354 srcVOffset, dstVMultiplier, dstVOffset);
357 static pstatus_t generic_image_copy_no_overlap(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat,
358 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
359 UINT32 nWidth, UINT32 nHeight,
360 const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
361 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
362 const gdiPalette* WINPR_RESTRICT palette,
365 const BOOL vSrcVFlip = (flags & FREERDP_FLIP_VERTICAL) ? TRUE : FALSE;
366 SSIZE_T srcVOffset = 0;
367 SSIZE_T srcVMultiplier = 1;
368 SSIZE_T dstVOffset = 0;
369 SSIZE_T dstVMultiplier = 1;
371 if ((nWidth == 0) || (nHeight == 0))
372 return PRIMITIVES_SUCCESS;
374 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
377 if (!pDstData || !pSrcData)
381 nDstStep = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
384 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
388 srcVOffset = (nHeight - 1ll) * nSrcStep;
392 if (((flags & FREERDP_KEEP_DST_ALPHA) != 0) && FreeRDPColorHasAlpha(DstFormat))
393 return generic_image_copy_no_overlap_dst_alpha(
394 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat,
395 nSrcStep, nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier,
398 return generic_image_copy_no_overlap_no_alpha(
399 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat,
400 nSrcStep, nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset,
403 return PRIMITIVES_SUCCESS;
407 void primitives_init_copy(
primitives_t* WINPR_RESTRICT prims)
410 prims->copy_8u = general_copy_8u;
411 prims->copy_8u_AC4r = general_copy_8u_AC4r;
412 prims->copy = WINPR_FUNC_PTR_CAST(prims->copy_8u, __copy_t);
413 prims->copy_no_overlap = generic_image_copy_no_overlap;
418 primitives_init_copy_sse41(prims);
419 #if defined(WITH_AVX2)
420 primitives_init_copy_avx2(prims);