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"
25#include "../codec/color.h"
27#include <freerdp/codec/color.h>
33static 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)
55static 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 +
64 1ull * (WINPR_ASSERTING_INT_CAST(uint32_t, height - 1)) *
65 WINPR_ASSERTING_INT_CAST(uint32_t, p1Step) +
66 1ull * WINPR_ASSERTING_INT_CAST(uint32_t, width* p1Size);
73 ULONG_PTR p2mEnd = p2m +
74 1ull * (WINPR_ASSERTING_INT_CAST(uintptr_t, height - 1)) *
75 WINPR_ASSERTING_INT_CAST(uintptr_t, p2Step) +
76 1ull * WINPR_ASSERTING_INT_CAST(uintptr_t, width* p2Size);
87static pstatus_t general_copy_8u(
const BYTE* WINPR_RESTRICT pSrc, BYTE* WINPR_RESTRICT pDst,
90 if (memory_regions_overlap_1d(pSrc, pDst, (
size_t)len))
92 memmove((
void*)pDst, (
const void*)pSrc, (
size_t)len);
96 memcpy((
void*)pDst, (
const void*)pSrc, (
size_t)len);
99 return PRIMITIVES_SUCCESS;
107static pstatus_t general_copy_8u_AC4r(
const BYTE* WINPR_RESTRICT pSrc, INT32 srcStep,
108 BYTE* WINPR_RESTRICT pDst, INT32 dstStep, INT32 width,
111 const BYTE* src = pSrc;
113 const size_t rowbytes = WINPR_ASSERTING_INT_CAST(
size_t, width) *
sizeof(UINT32);
115 if ((width == 0) || (height == 0))
116 return PRIMITIVES_SUCCESS;
118 if (memory_regions_overlap_2d(pSrc, srcStep,
sizeof(UINT32), pDst, dstStep,
sizeof(UINT32),
123 generic->copy(src, dst, WINPR_ASSERTING_INT_CAST(int32_t, rowbytes));
136 memcpy(dst, src, rowbytes);
142 return PRIMITIVES_SUCCESS;
145static inline pstatus_t generic_image_copy_bgr24_bgrx32(BYTE* WINPR_RESTRICT pDstData,
146 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
147 UINT32 nWidth, UINT32 nHeight,
148 const BYTE* WINPR_RESTRICT pSrcData,
149 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
150 int64_t srcVMultiplier, int64_t srcVOffset,
151 int64_t dstVMultiplier, int64_t dstVOffset)
154 const int64_t srcByte = 3;
155 const int64_t dstByte = 4;
157 const UINT32 width = nWidth - nWidth % 8;
159 for (int64_t y = 0; y < nHeight; y++)
161 const BYTE* WINPR_RESTRICT srcLine =
162 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
163 BYTE* WINPR_RESTRICT dstLine =
164 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
167 WINPR_PRAGMA_UNROLL_LOOP
168 for (; x < width; x++)
170 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
171 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
172 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
175 for (; x < nWidth; x++)
177 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
178 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
179 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
183 return PRIMITIVES_SUCCESS;
186static inline pstatus_t
187generic_image_copy_bgrx32_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep, UINT32 nXDst,
188 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
189 const BYTE* WINPR_RESTRICT pSrcData, UINT32 nSrcStep, UINT32 nXSrc,
190 UINT32 nYSrc, int64_t srcVMultiplier, int64_t srcVOffset,
191 int64_t dstVMultiplier, int64_t dstVOffset)
194 const int64_t srcByte = 4;
195 const int64_t dstByte = 4;
197 const UINT32 width = nWidth - nWidth % 8;
199 for (int64_t y = 0; y < nHeight; y++)
201 const BYTE* WINPR_RESTRICT srcLine =
202 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
203 BYTE* WINPR_RESTRICT dstLine =
204 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
207 WINPR_PRAGMA_UNROLL_LOOP
208 for (; x < width; x++)
210 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
211 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
212 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
214 for (; x < nWidth; x++)
216 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
217 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
218 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
222 return PRIMITIVES_SUCCESS;
225pstatus_t generic_image_copy_no_overlap_convert(
226 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
227 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
228 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette,
229 int64_t srcVMultiplier, int64_t srcVOffset, int64_t dstVMultiplier, int64_t dstVOffset)
231 const int64_t srcByte = FreeRDPGetBytesPerPixel(SrcFormat);
232 const int64_t dstByte = FreeRDPGetBytesPerPixel(DstFormat);
234 const UINT32 width = nWidth - nWidth % 8;
235 for (int64_t y = 0; y < nHeight; y++)
237 const BYTE* WINPR_RESTRICT srcLine =
238 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
239 BYTE* WINPR_RESTRICT dstLine =
240 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
244 for (; x < width; x++)
246 const UINT32 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
247 const UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
248 FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat, dstColor);
250 for (; x < nWidth; x++)
252 const UINT32 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
253 const UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
254 FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat, dstColor);
257 return PRIMITIVES_SUCCESS;
260pstatus_t generic_image_copy_no_overlap_memcpy(
261 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
262 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
263 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
264 WINPR_ATTR_UNUSED
const gdiPalette* WINPR_RESTRICT palette, int64_t srcVMultiplier,
265 int64_t srcVOffset, int64_t dstVMultiplier, int64_t dstVOffset, WINPR_ATTR_UNUSED UINT32 flags)
267 const int64_t dstByte = FreeRDPGetBytesPerPixel(DstFormat);
268 const int64_t srcByte = FreeRDPGetBytesPerPixel(SrcFormat);
269 const int64_t copyDstWidth = nWidth * dstByte;
270 const int64_t xSrcOffset = nXSrc * srcByte;
271 const int64_t xDstOffset = nXDst * dstByte;
273 for (int64_t y = 0; y < nHeight; y++)
275 const BYTE* WINPR_RESTRICT srcLine =
276 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
277 BYTE* WINPR_RESTRICT dstLine =
278 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
279 memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset],
280 WINPR_ASSERTING_INT_CAST(
size_t, copyDstWidth));
283 return PRIMITIVES_SUCCESS;
286static inline pstatus_t generic_image_copy_no_overlap_dst_alpha(
287 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
288 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
289 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette,
290 int64_t srcVMultiplier, int64_t srcVOffset, int64_t dstVMultiplier, int64_t dstVOffset)
292 WINPR_ASSERT(pDstData);
293 WINPR_ASSERT(pSrcData);
297 case PIXEL_FORMAT_BGR24:
300 case PIXEL_FORMAT_BGRX32:
301 case PIXEL_FORMAT_BGRA32:
302 return generic_image_copy_bgr24_bgrx32(
303 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
304 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
309 case PIXEL_FORMAT_BGRX32:
310 case PIXEL_FORMAT_BGRA32:
313 case PIXEL_FORMAT_BGRX32:
314 case PIXEL_FORMAT_BGRA32:
315 return generic_image_copy_bgrx32_bgrx32(
316 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
317 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
322 case PIXEL_FORMAT_RGBX32:
323 case PIXEL_FORMAT_RGBA32:
326 case PIXEL_FORMAT_RGBX32:
327 case PIXEL_FORMAT_RGBA32:
328 return generic_image_copy_bgrx32_bgrx32(
329 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
330 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
331 case PIXEL_FORMAT_RGB24:
332 return generic_image_copy_bgr24_bgrx32(
333 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
334 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
343 return generic_image_copy_no_overlap_convert(
344 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
345 nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
348static inline pstatus_t generic_image_copy_no_overlap_no_alpha(
349 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
350 UINT32 nWidth, UINT32 nHeight,
const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
351 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette,
352 int64_t srcVMultiplier, int64_t srcVOffset, int64_t dstVMultiplier, int64_t dstVOffset,
355 if (FreeRDPAreColorFormatsEqualNoAlpha(SrcFormat, DstFormat))
356 return generic_image_copy_no_overlap_memcpy(pDstData, DstFormat, nDstStep, nXDst, nYDst,
357 nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
358 nXSrc, nYSrc, palette, srcVMultiplier,
359 srcVOffset, dstVMultiplier, dstVOffset, flags);
361 return generic_image_copy_no_overlap_convert(pDstData, DstFormat, nDstStep, nXDst, nYDst,
362 nWidth, nHeight, pSrcData, SrcFormat, nSrcStep,
363 nXSrc, nYSrc, palette, srcVMultiplier,
364 srcVOffset, dstVMultiplier, dstVOffset);
367static pstatus_t generic_image_copy_no_overlap(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat,
368 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
369 UINT32 nWidth, UINT32 nHeight,
370 const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
371 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
372 const gdiPalette* WINPR_RESTRICT palette,
375 const BOOL vSrcVFlip = (flags & FREERDP_FLIP_VERTICAL) ? TRUE : FALSE;
376 int64_t srcVOffset = 0;
377 int64_t srcVMultiplier = 1;
378 int64_t dstVOffset = 0;
379 int64_t dstVMultiplier = 1;
381 if ((nWidth == 0) || (nHeight == 0))
382 return PRIMITIVES_SUCCESS;
384 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
387 if (!pDstData || !pSrcData)
391 nDstStep = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
394 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
398 srcVOffset = (nHeight - 1ll) * nSrcStep;
402 if (((flags & FREERDP_KEEP_DST_ALPHA) != 0) && FreeRDPColorHasAlpha(DstFormat))
403 return generic_image_copy_no_overlap_dst_alpha(
404 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat,
405 nSrcStep, nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier,
408 return generic_image_copy_no_overlap_no_alpha(
409 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat,
410 nSrcStep, nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset,
413 return PRIMITIVES_SUCCESS;
417void primitives_init_copy(
primitives_t* WINPR_RESTRICT prims)
420 prims->copy_8u = general_copy_8u;
421 prims->copy_8u_AC4r = general_copy_8u_AC4r;
422 prims->copy = WINPR_FUNC_PTR_CAST(prims->copy_8u, fn_copy_t);
423 prims->copy_no_overlap = generic_image_copy_no_overlap;
426void primitives_init_copy_opt(
primitives_t* WINPR_RESTRICT prims)
428 primitives_init_copy(prims);
429 primitives_init_copy_sse41(prims);
430#if defined(WITH_AVX2)
431 primitives_init_copy_avx2(prims);