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);