2#include <freerdp/config.h> 
    9#include <winpr/print.h> 
   11#include <winpr/wlog.h> 
   12#include <winpr/crypto.h> 
   13#include <freerdp/primitives.h> 
   14#include <freerdp/utils/profiler.h> 
   16#include "../prim_internal.h" 
   20#define PADDING_FILL_VALUE 0x37 
   24static BOOL similar(
const BYTE* src, 
const BYTE* dst, 
size_t size)
 
   26  for (
size_t x = 0; x < size; x++)
 
   28    int diff = src[x] - dst[x];
 
   32      (void)fprintf(stderr, 
"%" PRIuz 
" %02" PRIX8 
" : %02" PRIX8 
" diff=%d\n", x, src[x],
 
   41static BOOL similarRGB(
size_t y, 
const BYTE* src, 
const BYTE* dst, 
size_t size, UINT32 format,
 
   49  const UINT32 bpp = FreeRDPGetBytesPerPixel(format);
 
   50  BYTE fill = PADDING_FILL_VALUE;
 
   51  if (!FreeRDPColorHasAlpha(format))
 
   54  for (
size_t x = 0; x < size; x++)
 
   56    const LONG maxDiff = 4;
 
   67    sColor = FreeRDPReadColor(src, format);
 
   68    dColor = FreeRDPReadColor(dst, format);
 
   71    FreeRDPSplitColor(sColor, format, &sR, &sG, &sB, &sA, NULL);
 
   72    FreeRDPSplitColor(dColor, format, &dR, &dG, &dB, &dA, NULL);
 
   74    const long diffr = labs(1L * sR - dR);
 
   75    const long diffg = labs(1L * sG - dG);
 
   76    const long diffb = labs(1L * sB - dB);
 
   77    if ((diffr > maxDiff) || (diffg > maxDiff) || (diffb > maxDiff))
 
   85      if (use444 && ((x % 2) == 0) && ((y % 2) == 0))
 
   90      const BYTE sY = RGB2Y(sR, sG, sB);
 
   91      const BYTE sU = RGB2U(sR, sG, sB);
 
   92      const BYTE sV = RGB2V(sR, sG, sB);
 
   93      const BYTE dY = RGB2Y(dR, dG, dB);
 
   94      const BYTE dU = RGB2U(dR, dG, dB);
 
   95      const BYTE dV = RGB2V(dR, dG, dB);
 
   97                    "[%s] Color value  mismatch R[%02X %02X], G[%02X %02X], B[%02X %02X] at " 
   98                    "position %" PRIuz 
"x%" PRIuz 
"\n",
 
   99                    use444 ? 
"AVC444" : 
"AVC420", sR, dR, sG, dG, sA, dA, x, y);
 
  100      (void)fprintf(stderr,
 
  101                    "[%s] Color value  mismatch Y[%02X %02X], U[%02X %02X], V[%02X %02X] at " 
  102                    "position %" PRIuz 
"x%" PRIuz 
"\n",
 
  103                    use444 ? 
"AVC444" : 
"AVC420", sY, dY, sU, dU, sV, dV, x, y);
 
  112          "[%s] Invalid destination alpha value 0x%02X [expected 0x%02X] at position %" PRIuz
 
  114          use444 ? 
"AVC444" : 
"AVC420", dA, fill, x, y);
 
  123static void get_size(BOOL large, UINT32* width, UINT32* height)
 
  125  UINT32 shift = large ? 8 : 1;
 
  126  winpr_RAND(width, 
sizeof(*width));
 
  127  winpr_RAND(height, 
sizeof(*height));
 
  128  *width = (*width % 64 + 1) << shift;
 
  129  *height = (*height % 64 + 1);
 
  132static BOOL check_padding(
const BYTE* psrc, 
size_t size, 
size_t padding, 
const char* buffer)
 
  135  const BYTE* src = NULL;
 
  136  const BYTE* esrc = NULL;
 
  137  size_t halfPad = (padding + 1) / 2;
 
  142  src = psrc - halfPad;
 
  143  esrc = src + size + halfPad;
 
  145  for (
size_t x = 0; x < halfPad; x++)
 
  147    const BYTE s = *src++;
 
  148    const BYTE d = *esrc++;
 
  154      while ((x < halfPad) && (*esrc++ != 
'A'))
 
  157      (void)fprintf(stderr,
 
  158                    "Buffer underflow detected %02" PRIx8 
" != %02X %s [%" PRIuz 
"-%" PRIuz
 
  160                    d, 
'A', buffer, start, x);
 
  168      while ((x < halfPad) && (*esrc++ != 
'A'))
 
  171      (void)fprintf(stderr,
 
  172                    "Buffer overflow detected %02" PRIx8 
" != %02X %s [%" PRIuz 
"-%" PRIuz
 
  174                    d, 
'A', buffer, start, x);
 
  182static void* set_padding(
size_t size, 
size_t padding)
 
  184  size_t halfPad = (padding + 1) / 2;
 
  186  BYTE* src = winpr_aligned_malloc(size + 2 * halfPad, 16);
 
  191  memset(&src[0], 
'A', halfPad);
 
  192  memset(&src[halfPad], PADDING_FILL_VALUE, size);
 
  193  memset(&src[halfPad + size], 
'A', halfPad);
 
  194  psrc = &src[halfPad];
 
  196  if (!check_padding(psrc, size, padding, 
"init"))
 
  198    winpr_aligned_free(src);
 
  205static void free_padding(
void* src, 
size_t padding)
 
  212  ptr = ((BYTE*)src) - (padding + 1) / 2;
 
  213  winpr_aligned_free(ptr);
 
  228  BYTE* luma[3] = { 0 };
 
  229  BYTE* chroma[3] = { 0 };
 
  230  BYTE* yuv[3] = { 0 };
 
  231  BYTE* pmain[3] = { 0 };
 
  232  BYTE* paux[3] = { 0 };
 
  233  UINT32 lumaStride[3] = { 0 };
 
  234  UINT32 chromaStride[3] = { 0 };
 
  235  UINT32 yuvStride[3] = { 0 };
 
  236  const size_t padding = 10000;
 
  238  PROFILER_DEFINE(yuvCombine)
 
  239  PROFILER_DEFINE(yuvSplit)
 
  245  awidth = roi.width + 16 - roi.width % 16;
 
  246  aheight = roi.height + 16 - roi.height % 16;
 
  247  (void)fprintf(stderr,
 
  248                "Running YUVCombine on frame size %" PRIu32 
"x%" PRIu32 
" [%" PRIuz 
"x%" PRIuz
 
  250                roi.width, roi.height, awidth, aheight);
 
  251  PROFILER_CREATE(yuvCombine, 
"YUV420CombineToYUV444")
 
  252  PROFILER_CREATE(yuvSplit, "YUV444SplitToYUV420")
 
  255  rect.right = roi.width;
 
  256  rect.bottom = roi.height;
 
  258  if (!prims || !prims->YUV420CombineToYUV444)
 
  261  for (UINT32 x = 0; x < 3; x++)
 
  263    size_t halfStride = ((x > 0) ? awidth / 2 : awidth);
 
  264    size_t size = aheight * awidth;
 
  265    size_t halfSize = ((x > 0) ? halfStride * aheight / 2 : awidth * aheight);
 
  266    yuvStride[x] = awidth;
 
  268    if (!(yuv[x] = set_padding(size, padding)))
 
  271    lumaStride[x] = halfStride;
 
  273    if (!(luma[x] = set_padding(halfSize, padding)))
 
  276    if (!(pmain[x] = set_padding(halfSize, padding)))
 
  279    chromaStride[x] = halfStride;
 
  281    if (!(chroma[x] = set_padding(halfSize, padding)))
 
  284    if (!(paux[x] = set_padding(halfSize, padding)))
 
  287    memset(luma[x], WINPR_ASSERTING_INT_CAST(
int, 0xAB + 3 * x), halfSize);
 
  288    memset(chroma[x], WINPR_ASSERTING_INT_CAST(
int, 0x80 + 2 * x), halfSize);
 
  290    if (!check_padding(luma[x], halfSize, padding, 
"luma"))
 
  293    if (!check_padding(chroma[x], halfSize, padding, 
"chroma"))
 
  296    if (!check_padding(pmain[x], halfSize, padding, 
"main"))
 
  299    if (!check_padding(paux[x], halfSize, padding, 
"aux"))
 
  302    if (!check_padding(yuv[x], size, padding, 
"yuv"))
 
  306  PROFILER_ENTER(yuvCombine)
 
  309  if (prims->YUV420CombineToYUV444(AVC444_LUMA, cnv.cpv, lumaStride, roi.width, roi.height, yuv,
 
  310                                   yuvStride, &rect) != PRIMITIVES_SUCCESS)
 
  312    PROFILER_EXIT(yuvCombine)
 
  317  if (prims->YUV420CombineToYUV444(AVC444_CHROMAv1, cnv.cpv, chromaStride, roi.width, roi.height,
 
  318                                   yuv, yuvStride, &rect) != PRIMITIVES_SUCCESS)
 
  320    PROFILER_EXIT(yuvCombine)
 
  324  PROFILER_EXIT(yuvCombine)
 
  326  for (
size_t x = 0; x < 3; x++)
 
  328    size_t halfStride = ((x > 0) ? awidth / 2 : awidth);
 
  329    size_t size = 1ULL * aheight * awidth;
 
  330    size_t halfSize = ((x > 0) ? halfStride * aheight / 2 : awidth * aheight);
 
  332    if (!check_padding(luma[x], halfSize, padding, 
"luma"))
 
  335    if (!check_padding(chroma[x], halfSize, padding, 
"chroma"))
 
  338    if (!check_padding(yuv[x], size, padding, 
"yuv"))
 
  342  PROFILER_ENTER(yuvSplit)
 
  345  if (prims->YUV444SplitToYUV420(cnv.cpv, yuvStride, pmain, lumaStride, paux, chromaStride,
 
  346                                 &roi) != PRIMITIVES_SUCCESS)
 
  348    PROFILER_EXIT(yuvSplit)
 
  352  PROFILER_EXIT(yuvSplit)
 
  354  for (UINT32 x = 0; x < 3; x++)
 
  356    size_t halfStride = ((x > 0) ? awidth / 2 : awidth);
 
  357    size_t size = aheight * awidth;
 
  358    size_t halfSize = ((x > 0) ? halfStride * aheight / 2 : awidth * aheight);
 
  360    if (!check_padding(pmain[x], halfSize, padding, 
"main"))
 
  363    if (!check_padding(paux[x], halfSize, padding, 
"aux"))
 
  366    if (!check_padding(yuv[x], size, padding, 
"yuv"))
 
  370  for (
size_t i = 0; i < 3; i++)
 
  372    for (
size_t y = 0; y < roi.height; y++)
 
  374      UINT32 w = roi.width;
 
  375      UINT32 lstride = lumaStride[i];
 
  376      UINT32 cstride = chromaStride[i];
 
  380        w = (roi.width + 3) / 4;
 
  382        if (roi.height > (roi.height + 1) / 2)
 
  386      if (!similar(luma[i] + y * lstride, pmain[i] + y * lstride, w))
 
  397        UINT32 rem = roi.height % 16;
 
  399        if (y > roi.height - rem)
 
  403      if (!similar(chroma[i] + y * cstride, paux[i] + y * cstride, w))
 
  408  PROFILER_PRINT_HEADER
 
  409  PROFILER_PRINT(yuvSplit)
 
  410  PROFILER_PRINT(yuvCombine)
 
  411  PROFILER_PRINT_FOOTER
 
  414  printf(
"[%s] run %s.\n", __func__, (rc) ? 
"SUCCESS" : 
"FAILED");
 
  415  PROFILER_FREE(yuvCombine)
 
  416  PROFILER_FREE(yuvSplit)
 
  418  for (UINT32 x = 0; x < 3; x++)
 
  420    free_padding(yuv[x], padding);
 
  421    free_padding(luma[x], padding);
 
  422    free_padding(chroma[x], padding);
 
  423    free_padding(pmain[x], padding);
 
  424    free_padding(paux[x], padding);
 
  440  BYTE* yuv[3] = { 0 };
 
  441  UINT32 yuv_step[3] = { 0 };
 
  443  BYTE* rgb_dst = NULL;
 
  447  size_t padding = 100ULL * 16ULL;
 
  449  const UINT32 formats[] = { PIXEL_FORMAT_XRGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_ARGB32,
 
  450                           PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_RGBX32,
 
  451                           PIXEL_FORMAT_BGRA32, PIXEL_FORMAT_BGRX32 };
 
  452  PROFILER_DEFINE(rgbToYUV420)
 
  453  PROFILER_DEFINE(rgbToYUV444)
 
  454  PROFILER_DEFINE(yuv420ToRGB)
 
  455  PROFILER_DEFINE(yuv444ToRGB)
 
  457  awidth = roi.width + 16 - roi.width % 16;
 
  458  aheight = roi.height + 16 - roi.height % 16;
 
  459  stride = 1ULL * awidth * 
sizeof(UINT32);
 
  460  size = 1ULL * awidth * aheight;
 
  467    if (!prims || !prims->RGBToYUV444_8u_P3AC4R || !prims->YUV444ToRGB_8u_P3AC4R)
 
  472    uvwidth = (awidth + 1) / 2;
 
  473    uvsize = (aheight + 1) / 2 * uvwidth;
 
  475    if (!prims || !prims->RGBToYUV420_8u_P3AC4R || !prims->YUV420ToRGB_8u_P3AC4R)
 
  479  (void)fprintf(stderr, 
"Running AVC%s on frame size %" PRIu32 
"x%" PRIu32 
"\n",
 
  480                use444 ? 
"444" : 
"420", roi.width, roi.height);
 
  483  if (!(rgb = set_padding(size * 
sizeof(UINT32), padding)))
 
  486  if (!(rgb_dst = set_padding(size * 
sizeof(UINT32), padding)))
 
  489  if (!(yuv[0] = set_padding(size, padding)))
 
  492  if (!(yuv[1] = set_padding(uvsize, padding)))
 
  495  if (!(yuv[2] = set_padding(uvsize, padding)))
 
  498  for (
size_t y = 0; y < roi.height; y++)
 
  500    BYTE* line = &rgb[y * stride];
 
  501    winpr_RAND(line, stride);
 
  504  yuv_step[0] = awidth;
 
  505  yuv_step[1] = uvwidth;
 
  506  yuv_step[2] = uvwidth;
 
  508  for (UINT32 x = 0; x < ARRAYSIZE(formats); x++)
 
  511    const UINT32 DstFormat = formats[x];
 
  512    printf(
"Testing destination color format %s\n", FreeRDPGetColorFormatName(DstFormat));
 
  513    memset(rgb_dst, PADDING_FILL_VALUE, size * 
sizeof(UINT32));
 
  515    PROFILER_CREATE(rgbToYUV420, 
"RGBToYUV420")
 
  516    PROFILER_CREATE(rgbToYUV444, "RGBToYUV444")
 
  517    PROFILER_CREATE(yuv420ToRGB, "YUV420ToRGB")
 
  518    PROFILER_CREATE(yuv444ToRGB, "YUV444ToRGB")
 
  522      PROFILER_ENTER(rgbToYUV444)
 
  523      rc = prims->RGBToYUV444_8u_P3AC4R(rgb, DstFormat, stride, yuv, yuv_step, &roi);
 
  524      PROFILER_EXIT(rgbToYUV444)
 
  526      if (rc != PRIMITIVES_SUCCESS)
 
  529      PROFILER_PRINT_HEADER
 
  530      PROFILER_PRINT(rgbToYUV444)
 
  531      PROFILER_PRINT_FOOTER
 
  535      PROFILER_ENTER(rgbToYUV420)
 
  536      rc = prims->RGBToYUV420_8u_P3AC4R(rgb, DstFormat, stride, yuv, yuv_step, &roi);
 
  537      PROFILER_EXIT(rgbToYUV420)
 
  539      if (rc != PRIMITIVES_SUCCESS)
 
  542      PROFILER_PRINT_HEADER
 
  543      PROFILER_PRINT(rgbToYUV420)
 
  544      PROFILER_PRINT_FOOTER
 
  547    if (!check_padding(rgb, size * 
sizeof(UINT32), padding, 
"rgb"))
 
  553    if ((!check_padding(yuv[0], size, padding, 
"Y")) ||
 
  554        (!check_padding(yuv[1], uvsize, padding, 
"U")) ||
 
  555        (!check_padding(yuv[2], uvsize, padding, 
"V")))
 
  564      PROFILER_ENTER(yuv444ToRGB)
 
  565      rc = prims->YUV444ToRGB_8u_P3AC4R(cnv.cpv, yuv_step, rgb_dst, stride, DstFormat, &roi);
 
  566      PROFILER_EXIT(yuv444ToRGB)
 
  568      if (rc != PRIMITIVES_SUCCESS)
 
  572      PROFILER_EXIT(yuv444ToRGB)
 
  573      PROFILER_PRINT_HEADER
 
  574      PROFILER_PRINT(yuv444ToRGB)
 
  575      PROFILER_PRINT_FOOTER
 
  577      if (rc != PRIMITIVES_SUCCESS)
 
  582      PROFILER_ENTER(yuv420ToRGB)
 
  584      if (prims->YUV420ToRGB_8u_P3AC4R(cnv.cpv, yuv_step, rgb_dst, stride, DstFormat, &roi) !=
 
  587        PROFILER_EXIT(yuv420ToRGB)
 
  591      PROFILER_EXIT(yuv420ToRGB)
 
  592      PROFILER_PRINT_HEADER
 
  593      PROFILER_PRINT(yuv420ToRGB)
 
  594      PROFILER_PRINT_FOOTER
 
  597    if (!check_padding(rgb_dst, size * 
sizeof(UINT32), padding, 
"rgb dst"))
 
  600    if ((!check_padding(yuv[0], size, padding, 
"Y")) ||
 
  601        (!check_padding(yuv[1], uvsize, padding, 
"U")) ||
 
  602        (!check_padding(yuv[2], uvsize, padding, 
"V")))
 
  606    for (
size_t y = 0; y < roi.height; y++)
 
  608      BYTE* srgb = &rgb[y * stride];
 
  609      BYTE* drgb = &rgb_dst[y * stride];
 
  611      if (!similarRGB(y, srgb, drgb, roi.width, DstFormat, use444))
 
  617    PROFILER_FREE(rgbToYUV420)
 
  618    PROFILER_FREE(rgbToYUV444)
 
  619    PROFILER_FREE(yuv420ToRGB)
 
  620    PROFILER_FREE(yuv444ToRGB)
 
  625  printf(
"[%s] run %s.\n", __func__, (res) ? 
"SUCCESS" : 
"FAILED");
 
  626  free_padding(rgb, padding);
 
  627  free_padding(rgb_dst, padding);
 
  628  free_padding(yuv[0], padding);
 
  629  free_padding(yuv[1], padding);
 
  630  free_padding(yuv[2], padding);
 
  634static BOOL allocate_yuv420(BYTE** planes, UINT32 width, UINT32 height, UINT32 padding)
 
  636  const size_t size = 1ULL * width * height;
 
  637  const size_t uvwidth = (1ULL + width) / 2;
 
  638  const size_t uvsize = (1ULL + height) / 2 * uvwidth;
 
  640  if (!(planes[0] = set_padding(size, padding)))
 
  643  if (!(planes[1] = set_padding(uvsize, padding)))
 
  646  if (!(planes[2] = set_padding(uvsize, padding)))
 
  651  free_padding(planes[0], padding);
 
  652  free_padding(planes[1], padding);
 
  653  free_padding(planes[2], padding);
 
  657static void free_yuv420(BYTE** planes, UINT32 padding)
 
  662  free_padding(planes[0], padding);
 
  663  free_padding(planes[1], padding);
 
  664  free_padding(planes[2], padding);
 
  670static BOOL check_yuv420(BYTE** planes, UINT32 width, UINT32 height, UINT32 padding)
 
  672  const size_t size = 1ULL * width * height;
 
  673  const size_t uvwidth = (width + 1) / 2;
 
  674  const size_t uvsize = (height + 1) / 2 * uvwidth;
 
  675  const BOOL yOk = check_padding(planes[0], size, padding, 
"Y");
 
  676  const BOOL uOk = check_padding(planes[1], uvsize, padding, 
"U");
 
  677  const BOOL vOk = check_padding(planes[2], uvsize, padding, 
"V");
 
  678  return (yOk && uOk && vOk);
 
  681static BOOL check_for_mismatches(
const BYTE* planeA, 
const BYTE* planeB, UINT32 size)
 
  685  for (UINT32 x = 0; x < size; x++)
 
  687    const BYTE a = planeA[x];
 
  688    const BYTE b = planeB[x];
 
  690    if (fabsf((
float)a - (
float)b) > 2.0f)
 
  693      (void)fprintf(stderr, 
"[%08x] %02x != %02x\n", x, a, b);
 
  700static BOOL compare_yuv420(BYTE** planesA, BYTE** planesB, UINT32 width, UINT32 height,
 
  704  const size_t size = 1ULL * width * height;
 
  705  const size_t uvwidth = (1ULL * width + 1) / 2;
 
  706  const size_t uvsize = (1ULL * height + 1) / 2 * uvwidth;
 
  708  if (check_for_mismatches(planesA[0], planesB[0], size))
 
  710    (void)fprintf(stderr, 
"Mismatch in Y planes!\n");
 
  714  if (check_for_mismatches(planesA[1], planesB[1], uvsize))
 
  716    (void)fprintf(stderr, 
"Mismatch in U planes!\n");
 
  720  if (check_for_mismatches(planesA[2], planesB[2], uvsize))
 
  722    (void)fprintf(stderr, 
"Mismatch in V planes!\n");
 
  729static UINT32 prand(UINT32 max)
 
  734  winpr_RAND(&tmp, 
sizeof(tmp));
 
  735  return tmp % (max - 1) + 1;
 
  743  BYTE* luma[3] = { 0 };
 
  744  BYTE* chroma[3] = { 0 };
 
  745  BYTE* lumaGeneric[3] = { 0 };
 
  746  BYTE* chromaGeneric[3] = { 0 };
 
  751  const size_t padding = 0x1000;
 
  753  fn_RGBToAVC444YUV_t fkt = NULL;
 
  754  fn_RGBToAVC444YUV_t gen = NULL;
 
  755  const UINT32 formats[] = { PIXEL_FORMAT_XRGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_ARGB32,
 
  756                           PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_RGBX32,
 
  757                           PIXEL_FORMAT_BGRA32, PIXEL_FORMAT_BGRX32 };
 
  758  PROFILER_DEFINE(rgbToYUV444)
 
  759  PROFILER_DEFINE(rgbToYUV444opt)
 
  763  if (awidth % 16 != 0)
 
  764    awidth += 16 - roi.width % 16;
 
  766  aheight = roi.height;
 
  768  if (aheight % 16 != 0)
 
  769    aheight += 16 - roi.height % 16;
 
  771  stride = 1ULL * awidth * 
sizeof(UINT32);
 
  772  size = 1ULL * awidth * aheight;
 
  773  uvwidth = 1ULL * (awidth + 1) / 2;
 
  775  if (!prims || !generic)
 
  781      fkt = prims->RGBToAVC444YUV;
 
  782      gen = 
generic->RGBToAVC444YUV;
 
  786      fkt = prims->RGBToAVC444YUVv2;
 
  787      gen = 
generic->RGBToAVC444YUVv2;
 
  797  (void)fprintf(stderr, 
"Running AVC444 on frame size %" PRIu32 
"x%" PRIu32 
"\n", roi.width,
 
  801  if (!(rgb = set_padding(size * 
sizeof(UINT32), padding)))
 
  804  if (!allocate_yuv420(luma, awidth, aheight, padding))
 
  807  if (!allocate_yuv420(chroma, awidth, aheight, padding))
 
  810  if (!allocate_yuv420(lumaGeneric, awidth, aheight, padding))
 
  813  if (!allocate_yuv420(chromaGeneric, awidth, aheight, padding))
 
  816  for (
size_t y = 0; y < roi.height; y++)
 
  818    BYTE* line = &rgb[y * stride];
 
  820    winpr_RAND(line, 4ULL * roi.width);
 
  823  yuv_step[0] = awidth;
 
  824  yuv_step[1] = uvwidth;
 
  825  yuv_step[2] = uvwidth;
 
  827  for (UINT32 x = 0; x < ARRAYSIZE(formats); x++)
 
  830    const UINT32 DstFormat = formats[x];
 
  831    printf(
"Testing destination color format %s\n", FreeRDPGetColorFormatName(DstFormat));
 
  832    PROFILER_CREATE(rgbToYUV444, 
"RGBToYUV444-generic")
 
  833    PROFILER_CREATE(rgbToYUV444opt, "RGBToYUV444-optimized")
 
  835    for (UINT32 cnt = 0; cnt < 10; cnt++)
 
  837      PROFILER_ENTER(rgbToYUV444opt)
 
  838      rc = fkt(rgb, DstFormat, stride, luma, yuv_step, chroma, yuv_step, &roi);
 
  839      PROFILER_EXIT(rgbToYUV444opt)
 
  841      if (rc != PRIMITIVES_SUCCESS)
 
  845    PROFILER_PRINT_HEADER
 
  846    PROFILER_PRINT(rgbToYUV444opt)
 
  847    PROFILER_PRINT_FOOTER
 
  849    if (!check_padding(rgb, size * 
sizeof(UINT32), padding, 
"rgb"))
 
  855    if (!check_yuv420(luma, awidth, aheight, padding) ||
 
  856        !check_yuv420(chroma, awidth, aheight, padding))
 
  862    for (UINT32 cnt = 0; cnt < 10; cnt++)
 
  864      PROFILER_ENTER(rgbToYUV444)
 
  865      rc = gen(rgb, DstFormat, stride, lumaGeneric, yuv_step, chromaGeneric, yuv_step, &roi);
 
  866      PROFILER_EXIT(rgbToYUV444)
 
  868      if (rc != PRIMITIVES_SUCCESS)
 
  872    PROFILER_PRINT_HEADER
 
  873    PROFILER_PRINT(rgbToYUV444)
 
  874    PROFILER_PRINT_FOOTER
 
  876    if (!check_padding(rgb, size * 
sizeof(UINT32), padding, 
"rgb"))
 
  882    if (!check_yuv420(lumaGeneric, awidth, aheight, padding) ||
 
  883        !check_yuv420(chromaGeneric, awidth, aheight, padding))
 
  889    if (!compare_yuv420(luma, lumaGeneric, awidth, aheight, padding) ||
 
  890        !compare_yuv420(chroma, chromaGeneric, awidth, aheight, padding))
 
  897    PROFILER_FREE(rgbToYUV444)
 
  898    PROFILER_FREE(rgbToYUV444opt)
 
  900    if (rc != PRIMITIVES_SUCCESS)
 
  906  printf(
"[%s][version %u] run %s.\n", __func__, (
unsigned)version, (res) ? 
"SUCCESS" : 
"FAILED");
 
  907  free_padding(rgb, padding);
 
  908  free_yuv420(luma, padding);
 
  909  free_yuv420(chroma, padding);
 
  910  free_yuv420(lumaGeneric, padding);
 
  911  free_yuv420(chromaGeneric, padding);
 
  918  for (UINT32 type = PRIMITIVES_PURE_SOFT; type <= PRIMITIVES_AUTODETECT; type++)
 
  923      printf(
"primitives type %d not supported\n", type);
 
  927    for (UINT32 x = 0; x < 5; x++)
 
  930      printf(
"-------------------- GENERIC ------------------------\n");
 
  932      if (!TestPrimitiveYUV(prims, roi, TRUE))
 
  935      printf(
"---------------------- END --------------------------\n");
 
  936      printf(
"-------------------- GENERIC ------------------------\n");
 
  938      if (!TestPrimitiveYUV(prims, roi, FALSE))
 
  941      printf(
"---------------------- END --------------------------\n");
 
  942      printf(
"-------------------- GENERIC ------------------------\n");
 
  944      if (!TestPrimitiveYUVCombine(prims, roi))
 
  947      printf(
"---------------------- END --------------------------\n");
 
  948      printf(
"-------------------- GENERIC ------------------------\n");
 
  950      if (!TestPrimitiveRgbToLumaChroma(prims, roi, 1))
 
  953      printf(
"---------------------- END --------------------------\n");
 
  954      printf(
"-------------------- GENERIC ------------------------\n");
 
  956      if (!TestPrimitiveRgbToLumaChroma(prims, roi, 2))
 
  959      printf(
"---------------------- END --------------------------\n");
 
  964  printf(
"[%s] run %s.\n", __func__, (rc) ? 
"SUCCESS" : 
"FAILED");
 
  968static void free_yuv(BYTE* yuv[3])
 
  970  for (
size_t x = 0; x < 3; x++)
 
  977static BOOL allocate_yuv(BYTE* yuv[3], 
prim_size_t roi)
 
  979  yuv[0] = calloc(roi.width, roi.height);
 
  980  yuv[1] = calloc(roi.width, roi.height);
 
  981  yuv[2] = calloc(roi.width, roi.height);
 
  983  if (!yuv[0] || !yuv[1] || !yuv[2])
 
  989  winpr_RAND(yuv[0], 1ULL * roi.width * roi.height);
 
  990  winpr_RAND(yuv[1], 1ULL * roi.width * roi.height);
 
  991  winpr_RAND(yuv[2], 1ULL * roi.width * roi.height);
 
  995static BOOL yuv444_to_rgb(BYTE* rgb, 
size_t stride, 
const BYTE* yuv[3], 
const UINT32 yuvStep[3],
 
  998  for (
size_t y = 0; y < roi.height; y++)
 
 1000    const BYTE* yline[3] = {
 
 1001      yuv[0] + y * roi.width,
 
 1002      yuv[1] + y * roi.width,
 
 1003      yuv[2] + y * roi.width,
 
 1005    BYTE* line = &rgb[y * stride];
 
 1007    for (
size_t x = 0; x < roi.width; x++)
 
 1009      const BYTE Y = yline[0][x];
 
 1010      const BYTE U = yline[1][x];
 
 1011      const BYTE V = yline[2][x];
 
 1013      writeYUVPixel(&line[x * 4], PIXEL_FORMAT_BGRX32, Y, U, V, writePixelBGRX);
 
 1021static BOOL compare_yuv444_to_rgb(
prim_size_t roi, DWORD type)
 
 1024  const UINT32 format = PIXEL_FORMAT_BGRA32;
 
 1025  BYTE* yuv[3] = { 0 };
 
 1026  const UINT32 yuvStep[3] = { roi.width, roi.width, roi.width };
 
 1027  const size_t stride = 4ULL * roi.width;
 
 1032    printf(
"primitives type %" PRIu32 
" not supported, skipping\n", type);
 
 1036  BYTE* rgb1 = calloc(roi.height, stride);
 
 1037  BYTE* rgb2 = calloc(roi.height, stride);
 
 1039  primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
 
 1042  if (!allocate_yuv(yuv, roi) || !rgb1 || !rgb2)
 
 1045  const BYTE* cyuv[] = { yuv[0], yuv[1], yuv[2] };
 
 1046  if (soft->YUV444ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb1, stride, format, &roi) !=
 
 1049  if (prims->YUV444ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb2, stride, format, &roi) !=
 
 1053  for (
size_t y = 0; y < roi.height; y++)
 
 1055    const BYTE* yline[3] = {
 
 1056      yuv[0] + y * roi.width,
 
 1057      yuv[1] + y * roi.width,
 
 1058      yuv[2] + y * roi.width,
 
 1060    const BYTE* line1 = &rgb1[y * stride];
 
 1061    const BYTE* line2 = &rgb2[y * stride];
 
 1063    for (
size_t x = 0; x < roi.width; x++)
 
 1065      const int Y = yline[0][x];
 
 1066      const int U = yline[1][x];
 
 1067      const int V = yline[2][x];
 
 1068      const UINT32 color1 = FreeRDPReadColor(&line1[x * 4], format);
 
 1069      const UINT32 color2 = FreeRDPReadColor(&line2[x * 4], format);
 
 1074      FreeRDPSplitColor(color1, format, &r1, &g1, &b1, NULL, NULL);
 
 1079      FreeRDPSplitColor(color2, format, &r2, &g2, &b2, NULL, NULL);
 
 1081      const int dr12 = abs(r1 - r2);
 
 1082      const int dg12 = abs(g1 - g2);
 
 1083      const int db12 = abs(b1 - b2);
 
 1085      if ((dr12 != 0) || (dg12 != 0) || (db12 != 0))
 
 1088        printf(
"\tdiff 1/2: yuv {%d, %d, %d}, rgb {%d, %d, %d}\n", Y, U, V, dr12, dg12,
 
 1093      if ((dr12 > 0) || (dg12 > 0) || (db12 > 0))
 
 1095        (void)fprintf(stderr,
 
 1096                      "[%" PRIuz 
"x%" PRIuz
 
 1097                      "] generic and optimized data mismatch: r[0x%" PRIx8 
"|0x%" PRIx8
 
 1098                      "] g[0x%" PRIx8 
"|0x%" PRIx8 
"] b[0x%" PRIx8 
"|0x%" PRIx8 
"]\n",
 
 1099                      x, y, r1, r2, g1, g2, b1, b2);
 
 1100        (void)fprintf(stderr, 
"roi: %dx%d\n", roi.width, roi.height);
 
 1101        winpr_HexDump(
"y0", WLOG_INFO, &yline[0][x], 16);
 
 1102        winpr_HexDump(
"y1", WLOG_INFO, &yline[0][x + roi.width], 16);
 
 1103        winpr_HexDump(
"u0", WLOG_INFO, &yline[1][x], 16);
 
 1104        winpr_HexDump(
"u1", WLOG_INFO, &yline[1][x + roi.width], 16);
 
 1105        winpr_HexDump(
"v0", WLOG_INFO, &yline[2][x], 16);
 
 1106        winpr_HexDump(
"v1", WLOG_INFO, &yline[2][x + roi.width], 16);
 
 1107        winpr_HexDump(
"foo1", WLOG_INFO, &line1[x * 4], 16);
 
 1108        winpr_HexDump(
"foo2", WLOG_INFO, &line2[x * 4], 16);
 
 1116  printf(
"%s finished with %s\n", __func__, rc ? 
"SUCCESS" : 
"FAILURE");
 
 1127static BOOL compare_rgb_to_yuv444(
prim_size_t roi, DWORD type)
 
 1130  const UINT32 format = PIXEL_FORMAT_BGRA32;
 
 1131  const size_t stride = 4ULL * roi.width;
 
 1132  const UINT32 yuvStep[] = { roi.width, roi.width, roi.width };
 
 1133  BYTE* yuv1[3] = { 0 };
 
 1134  BYTE* yuv2[3] = { 0 };
 
 1139    printf(
"primitives type %" PRIu32 
" not supported, skipping\n", type);
 
 1143  BYTE* rgb = calloc(roi.height, stride);
 
 1145  primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
 
 1149  if (!allocate_yuv(yuv1, roi) || !allocate_yuv(yuv2, roi))
 
 1152  if (soft->RGBToYUV444_8u_P3AC4R(rgb, format, stride, yuv1, yuvStep, &roi) != PRIMITIVES_SUCCESS)
 
 1154  if (prims->RGBToYUV444_8u_P3AC4R(rgb, format, stride, yuv2, yuvStep, &roi) !=
 
 1158  for (
size_t y = 0; y < roi.height; y++)
 
 1160    const BYTE* yline1[3] = {
 
 1161      yuv1[0] + y * roi.width,
 
 1162      yuv1[1] + y * roi.width,
 
 1163      yuv1[2] + y * roi.width,
 
 1165    const BYTE* yline2[3] = {
 
 1166      yuv2[0] + y * roi.width,
 
 1167      yuv2[1] + y * roi.width,
 
 1168      yuv2[2] + y * roi.width,
 
 1171    for (
size_t x = 0; x < ARRAYSIZE(yline1); x++)
 
 1173      if (memcmp(yline1[x], yline2[x], yuvStep[x]) != 0)
 
 1175        (void)fprintf(stderr, 
"[%s] compare failed in line %" PRIuz, __func__, x);
 
 1183  printf(
"%s finished with %s\n", __func__, rc ? 
"SUCCESS" : 
"FAILURE");
 
 1194static BOOL compare_yuv420_to_rgb(
prim_size_t roi, DWORD type)
 
 1197  const UINT32 format = PIXEL_FORMAT_BGRA32;
 
 1198  BYTE* yuv[3] = { 0 };
 
 1199  const UINT32 yuvStep[3] = { roi.width, roi.width / 2, roi.width / 2 };
 
 1200  const size_t stride = 4ULL * roi.width;
 
 1205    printf(
"primitives type %" PRIu32 
" not supported, skipping\n", type);
 
 1209  BYTE* rgb1 = calloc(roi.height, stride);
 
 1210  BYTE* rgb2 = calloc(roi.height, stride);
 
 1212  primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
 
 1215  if (!allocate_yuv(yuv, roi) || !rgb1 || !rgb2)
 
 1218  const BYTE* cyuv[3] = { yuv[0], yuv[1], yuv[2] };
 
 1219  if (soft->YUV420ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb1, stride, format, &roi) !=
 
 1222  if (prims->YUV420ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb2, stride, format, &roi) !=
 
 1226  for (
size_t y = 0; y < roi.height; y++)
 
 1228    const BYTE* yline[3] = {
 
 1229      yuv[0] + y * yuvStep[0],
 
 1230      yuv[1] + y * yuvStep[1],
 
 1231      yuv[2] + y * yuvStep[2],
 
 1233    const BYTE* line1 = &rgb1[y * stride];
 
 1234    const BYTE* line2 = &rgb2[y * stride];
 
 1236    for (
size_t x = 0; x < roi.width; x++)
 
 1238      const int Y = yline[0][x];
 
 1239      const int U = yline[1][x / 2];
 
 1240      const int V = yline[2][x / 2];
 
 1241      const UINT32 color1 = FreeRDPReadColor(&line1[x * 4], format);
 
 1242      const UINT32 color2 = FreeRDPReadColor(&line2[x * 4], format);
 
 1247      FreeRDPSplitColor(color1, format, &r1, &g1, &b1, NULL, NULL);
 
 1252      FreeRDPSplitColor(color2, format, &r2, &g2, &b2, NULL, NULL);
 
 1254      const int dr12 = abs(r1 - r2);
 
 1255      const int dg12 = abs(g1 - g2);
 
 1256      const int db12 = abs(b1 - b2);
 
 1258      if ((dr12 != 0) || (dg12 != 0) || (db12 != 0))
 
 1261        printf(
"\tdiff 1/2: yuv {%d, %d, %d}, rgb {%d, %d, %d}\n", Y, U, V, dr12, dg12,
 
 1266      if ((dr12 > 0) || (dg12 > 0) || (db12 > 0))
 
 1268        printf(
"[%s] failed: r[%" PRIx8 
"|%" PRIx8 
"] g[%" PRIx8 
"|%" PRIx8 
"] b[%" PRIx8
 
 1270               __func__, r1, r2, g1, g2, b1, b2);
 
 1278  printf(
"%s finished with %s\n", __func__, rc ? 
"SUCCESS" : 
"FAILURE");
 
 1286static BOOL similarYUV(
const BYTE* line1, 
const BYTE* line2, 
size_t len)
 
 1288  for (
size_t x = 0; x < len; x++)
 
 1290    const int a = line1[x];
 
 1291    const int b = line2[x];
 
 1292    const int diff = abs(a - b);
 
 1300static int similarY(
const BYTE* a, 
const BYTE* b, 
size_t size, 
size_t type)
 
 1307      for (
size_t x = 0; x < size; x++)
 
 1309        const int ba = a[x];
 
 1310        const int bb = b[x];
 
 1311        const int diff = abs(ba - bb);
 
 1318      return memcmp(a, b, size);
 
 1324static BOOL compare_rgb_to_yuv420(
prim_size_t roi, DWORD type)
 
 1327  const UINT32 format = PIXEL_FORMAT_BGRA32;
 
 1328  const size_t stride = 4ULL * roi.width;
 
 1329  const UINT32 yuvStep[] = { roi.width, roi.width / 2, roi.width / 2 };
 
 1330  BYTE* yuv1[3] = { 0 };
 
 1331  BYTE* yuv2[3] = { 0 };
 
 1336    printf(
"primitives type %" PRIu32 
" not supported, skipping\n", type);
 
 1340  BYTE* rgb = calloc(roi.height, stride);
 
 1341  BYTE* rgbcopy = calloc(roi.height, stride);
 
 1343  primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
 
 1344  if (!soft || !rgb || !rgbcopy)
 
 1347  winpr_RAND(rgb, roi.height * stride);
 
 1348  memcpy(rgbcopy, rgb, roi.height * stride);
 
 1350  if (!allocate_yuv(yuv1, roi) || !allocate_yuv(yuv2, roi))
 
 1353  if (soft->RGBToYUV420_8u_P3AC4R(rgb, format, stride, yuv1, yuvStep, &roi) != PRIMITIVES_SUCCESS)
 
 1355  if (memcmp(rgb, rgbcopy, roi.height * stride) != 0)
 
 1357  if (prims->RGBToYUV420_8u_P3AC4R(rgb, format, stride, yuv2, yuvStep, &roi) !=
 
 1361  for (
size_t y = 0; y < roi.height; y++)
 
 1364    if (((y + 1) >= roi.height) && ((y % 2) == 0))
 
 1367    const BYTE* yline1[3] = {
 
 1368      &yuv1[0][y * yuvStep[0]],
 
 1369      &yuv1[1][(y / 2) * yuvStep[1]],
 
 1370      &yuv1[2][(y / 2) * yuvStep[2]],
 
 1372    const BYTE* yline2[3] = {
 
 1373      &yuv2[0][y * yuvStep[0]],
 
 1374      &yuv2[1][(y / 2) * yuvStep[1]],
 
 1375      &yuv2[2][(y / 2) * yuvStep[2]],
 
 1378    for (
size_t x = 0; x < ARRAYSIZE(yline1); x++)
 
 1380      if (similarY(yline1[x], yline2[x], yuvStep[x], x) != 0)
 
 1382        (void)fprintf(stderr,
 
 1383                      "[%s] compare failed in component %" PRIuz 
", line %" PRIuz 
"\n",
 
 1385        (void)fprintf(stderr, 
"[%s] roi %" PRIu32 
"x%" PRIu32 
"\n", __func__, roi.width,
 
 1387        winpr_HexDump(TAG, WLOG_WARN, yline1[x], yuvStep[x]);
 
 1388        winpr_HexDump(TAG, WLOG_WARN, yline2[x], yuvStep[x]);
 
 1389        winpr_HexDump(TAG, WLOG_WARN, &rgb[y * stride], stride);
 
 1397  printf(
"%s finished with %s\n", __func__, rc ? 
"SUCCESS" : 
"FAILURE");
 
 1406int TestPrimitivesYUV(
int argc, 
char* argv[])
 
 1408  BOOL large = (argc > 1);
 
 1417    int crc = sscanf(argv[1], 
"%" PRIu32 
"x%" PRIu32, &roi.width, &roi.height);
 
 1426    get_size(large, &roi.width, &roi.height);
 
 1428  prim_test_setup(FALSE);
 
 1430  for (UINT32 type = PRIMITIVES_PURE_SOFT; type <= PRIMITIVES_AUTODETECT; type++)
 
 1432    if (!compare_yuv444_to_rgb(roi, type))
 
 1434    if (!compare_rgb_to_yuv444(roi, type))
 
 1437    if (!compare_yuv420_to_rgb(roi, type))
 
 1439    if (!compare_rgb_to_yuv420(roi, type))
 
 1443  if (!run_tests(roi))
 
 1448  printf(
"[%s] finished, status %s [%d]\n", __func__, (rc == 0) ? 
"SUCCESS" : 
"FAILURE", rc);