2#include <freerdp/config.h>
10#include <winpr/print.h>
12#include <winpr/wlog.h>
13#include <winpr/crypto.h>
14#include <freerdp/primitives.h>
15#include <freerdp/utils/profiler.h>
17#include "../prim_internal.h"
21#define PADDING_FILL_VALUE 0x37
26static BOOL similar(
const BYTE* src,
const BYTE* dst,
size_t size)
28 for (
size_t x = 0; x < size; x++)
30 int diff = src[x] - dst[x];
34 (void)fprintf(stderr,
"%" PRIuz
" %02" PRIX8
" : %02" PRIX8
" diff=%d\n", x, src[x],
44static BOOL similarRGB(
size_t y,
const BYTE* src,
const BYTE* dst,
size_t size, UINT32 format,
52 const UINT32 bpp = FreeRDPGetBytesPerPixel(format);
53 BYTE fill = PADDING_FILL_VALUE;
54 if (!FreeRDPColorHasAlpha(format))
57 for (
size_t x = 0; x < size; x++)
59 const LONG maxDiff = 4;
70 sColor = FreeRDPReadColor(src, format);
71 dColor = FreeRDPReadColor(dst, format);
74 FreeRDPSplitColor(sColor, format, &sR, &sG, &sB, &sA,
nullptr);
75 FreeRDPSplitColor(dColor, format, &dR, &dG, &dB, &dA,
nullptr);
77 const long diffr = labs(1L * sR - dR);
78 const long diffg = labs(1L * sG - dG);
79 const long diffb = labs(1L * sB - dB);
80 if ((diffr > maxDiff) || (diffg > maxDiff) || (diffb > maxDiff))
88 if (use444 && ((x % 2) == 0) && ((y % 2) == 0))
93 const BYTE sY = RGB2Y(sR, sG, sB);
94 const BYTE sU = RGB2U(sR, sG, sB);
95 const BYTE sV = RGB2V(sR, sG, sB);
96 const BYTE dY = RGB2Y(dR, dG, dB);
97 const BYTE dU = RGB2U(dR, dG, dB);
98 const BYTE dV = RGB2V(dR, dG, dB);
100 "[%s] Color value mismatch R[%02X %02X], G[%02X %02X], B[%02X %02X] at "
101 "position %" PRIuz
"x%" PRIuz
"\n",
102 use444 ?
"AVC444" :
"AVC420", sR, dR, sG, dG, sA, dA, x, y);
103 (void)fprintf(stderr,
104 "[%s] Color value mismatch Y[%02X %02X], U[%02X %02X], V[%02X %02X] at "
105 "position %" PRIuz
"x%" PRIuz
"\n",
106 use444 ?
"AVC444" :
"AVC420", sY, dY, sU, dU, sV, dV, x, y);
115 "[%s] Invalid destination alpha value 0x%02X [expected 0x%02X] at position %" PRIuz
117 use444 ?
"AVC444" :
"AVC420", dA, fill, x, y);
127static BOOL get_size(BOOL large, UINT32* width, UINT32* height)
129 UINT32 shift = large ? 8 : 1;
130 if (winpr_RAND(width,
sizeof(*width)) < 0)
132 if (winpr_RAND(height,
sizeof(*height)) < 0)
134 *width = (*width % 64 + 1) << shift;
135 *height = (*height % 64 + 1);
140static BOOL check_padding(
const BYTE* psrc,
size_t size,
size_t padding,
const char* buffer)
143 const BYTE* src =
nullptr;
144 const BYTE* esrc =
nullptr;
145 size_t halfPad = (padding + 1) / 2;
150 src = psrc - halfPad;
151 esrc = src + size + halfPad;
153 for (
size_t x = 0; x < halfPad; x++)
155 const BYTE s = *src++;
156 const BYTE d = *esrc++;
162 while ((x < halfPad) && (*esrc++ !=
'A'))
165 (void)fprintf(stderr,
166 "Buffer underflow detected %02" PRIx8
" != %02X %s [%" PRIuz
"-%" PRIuz
168 d,
'A', buffer, start, x);
176 while ((x < halfPad) && (*esrc++ !=
'A'))
179 (void)fprintf(stderr,
180 "Buffer overflow detected %02" PRIx8
" != %02X %s [%" PRIuz
"-%" PRIuz
182 d,
'A', buffer, start, x);
190static void* set_padding(
size_t size,
size_t padding)
192 size_t halfPad = (padding + 1) / 2;
193 BYTE* psrc =
nullptr;
194 BYTE* src = winpr_aligned_malloc(size + 2 * halfPad, 16);
199 memset(&src[0],
'A', halfPad);
200 memset(&src[halfPad], PADDING_FILL_VALUE, size);
201 memset(&src[halfPad + size],
'A', halfPad);
202 psrc = &src[halfPad];
204 if (!check_padding(psrc, size, padding,
"init"))
206 winpr_aligned_free(src);
213static void free_padding(
void* src,
size_t padding)
220 ptr = ((BYTE*)src) - (padding + 1) / 2;
221 winpr_aligned_free(ptr);
236 BYTE* luma[3] = WINPR_C_ARRAY_INIT;
237 BYTE* chroma[3] = WINPR_C_ARRAY_INIT;
238 BYTE* yuv[3] = WINPR_C_ARRAY_INIT;
239 BYTE* pmain[3] = WINPR_C_ARRAY_INIT;
240 BYTE* paux[3] = WINPR_C_ARRAY_INIT;
241 UINT32 lumaStride[3] = WINPR_C_ARRAY_INIT;
242 UINT32 chromaStride[3] = WINPR_C_ARRAY_INIT;
243 UINT32 yuvStride[3] = WINPR_C_ARRAY_INIT;
244 const size_t padding = 10000;
246 PROFILER_DEFINE(yuvCombine)
247 PROFILER_DEFINE(yuvSplit)
253 awidth = roi.width + 16 - roi.width % 16;
254 aheight = roi.height + 16 - roi.height % 16;
255 (void)fprintf(stderr,
256 "Running YUVCombine on frame size %" PRIu32
"x%" PRIu32
" [%" PRIuz
"x%" PRIuz
258 roi.width, roi.height, awidth, aheight);
259 PROFILER_CREATE(yuvCombine,
"YUV420CombineToYUV444")
260 PROFILER_CREATE(yuvSplit, "YUV444SplitToYUV420")
263 rect.right = roi.width;
264 rect.bottom = roi.height;
266 if (!prims || !prims->YUV420CombineToYUV444)
269 for (UINT32 x = 0; x < 3; x++)
271 size_t halfStride = ((x > 0) ? awidth / 2 : awidth);
272 size_t size = aheight * awidth;
273 size_t halfSize = ((x > 0) ? halfStride * aheight / 2 : awidth * aheight);
274 yuvStride[x] = awidth;
276 if (!(yuv[x] = set_padding(size, padding)))
279 lumaStride[x] = halfStride;
281 if (!(luma[x] = set_padding(halfSize, padding)))
284 if (!(pmain[x] = set_padding(halfSize, padding)))
287 chromaStride[x] = halfStride;
289 if (!(chroma[x] = set_padding(halfSize, padding)))
292 if (!(paux[x] = set_padding(halfSize, padding)))
295 memset(luma[x], WINPR_ASSERTING_INT_CAST(
int, 0xAB + 3 * x), halfSize);
296 memset(chroma[x], WINPR_ASSERTING_INT_CAST(
int, 0x80 + 2 * x), halfSize);
298 if (!check_padding(luma[x], halfSize, padding,
"luma"))
301 if (!check_padding(chroma[x], halfSize, padding,
"chroma"))
304 if (!check_padding(pmain[x], halfSize, padding,
"main"))
307 if (!check_padding(paux[x], halfSize, padding,
"aux"))
310 if (!check_padding(yuv[x], size, padding,
"yuv"))
314 PROFILER_ENTER(yuvCombine)
317 if (prims->YUV420CombineToYUV444(AVC444_LUMA, cnv.cpv, lumaStride, roi.width, roi.height, yuv,
318 yuvStride, &rect) != PRIMITIVES_SUCCESS)
320 PROFILER_EXIT(yuvCombine)
325 if (prims->YUV420CombineToYUV444(AVC444_CHROMAv1, cnv.cpv, chromaStride, roi.width, roi.height,
326 yuv, yuvStride, &rect) != PRIMITIVES_SUCCESS)
328 PROFILER_EXIT(yuvCombine)
332 PROFILER_EXIT(yuvCombine)
334 for (
size_t x = 0; x < 3; x++)
336 size_t halfStride = ((x > 0) ? awidth / 2 : awidth);
337 size_t size = 1ULL * aheight * awidth;
338 size_t halfSize = ((x > 0) ? halfStride * aheight / 2 : awidth * aheight);
340 if (!check_padding(luma[x], halfSize, padding,
"luma"))
343 if (!check_padding(chroma[x], halfSize, padding,
"chroma"))
346 if (!check_padding(yuv[x], size, padding,
"yuv"))
350 PROFILER_ENTER(yuvSplit)
353 if (prims->YUV444SplitToYUV420(cnv.cpv, yuvStride, pmain, lumaStride, paux, chromaStride,
354 &roi) != PRIMITIVES_SUCCESS)
356 PROFILER_EXIT(yuvSplit)
360 PROFILER_EXIT(yuvSplit)
362 for (UINT32 x = 0; x < 3; x++)
364 size_t halfStride = ((x > 0) ? awidth / 2 : awidth);
365 size_t size = aheight * awidth;
366 size_t halfSize = ((x > 0) ? halfStride * aheight / 2 : awidth * aheight);
368 if (!check_padding(pmain[x], halfSize, padding,
"main"))
371 if (!check_padding(paux[x], halfSize, padding,
"aux"))
374 if (!check_padding(yuv[x], size, padding,
"yuv"))
378 for (
size_t i = 0; i < 3; i++)
380 for (
size_t y = 0; y < roi.height; y++)
382 UINT32 w = roi.width;
383 UINT32 lstride = lumaStride[i];
384 UINT32 cstride = chromaStride[i];
388 w = (roi.width + 3) / 4;
390 if (roi.height > (roi.height + 1) / 2)
394 if (!similar(luma[i] + y * lstride, pmain[i] + y * lstride, w))
405 UINT32 rem = roi.height % 16;
407 if (y > roi.height - rem)
411 if (!similar(chroma[i] + y * cstride, paux[i] + y * cstride, w))
416 PROFILER_PRINT_HEADER
417 PROFILER_PRINT(yuvSplit)
418 PROFILER_PRINT(yuvCombine)
419 PROFILER_PRINT_FOOTER
422 printf(
"[%s] run %s.\n", __func__, (rc) ?
"SUCCESS" :
"FAILED");
423 PROFILER_FREE(yuvCombine)
424 PROFILER_FREE(yuvSplit)
426 for (UINT32 x = 0; x < 3; x++)
428 free_padding(yuv[x], padding);
429 free_padding(luma[x], padding);
430 free_padding(chroma[x], padding);
431 free_padding(pmain[x], padding);
432 free_padding(paux[x], padding);
448 BYTE* yuv[3] = WINPR_C_ARRAY_INIT;
449 UINT32 yuv_step[3] = WINPR_C_ARRAY_INIT;
451 BYTE* rgb_dst =
nullptr;
455 size_t padding = 100ULL * 16ULL;
457 const UINT32 formats[] = { PIXEL_FORMAT_XRGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_ARGB32,
458 PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_RGBX32,
459 PIXEL_FORMAT_BGRA32, PIXEL_FORMAT_BGRX32 };
460 PROFILER_DEFINE(rgbToYUV420)
461 PROFILER_DEFINE(rgbToYUV444)
462 PROFILER_DEFINE(yuv420ToRGB)
463 PROFILER_DEFINE(yuv444ToRGB)
465 awidth = roi.width + 16 - roi.width % 16;
466 aheight = roi.height + 16 - roi.height % 16;
467 stride = 1ULL * awidth *
sizeof(UINT32);
468 size = 1ULL * awidth * aheight;
475 if (!prims || !prims->RGBToYUV444_8u_P3AC4R || !prims->YUV444ToRGB_8u_P3AC4R)
480 uvwidth = (awidth + 1) / 2;
481 uvsize = (aheight + 1) / 2 * uvwidth;
483 if (!prims || !prims->RGBToYUV420_8u_P3AC4R || !prims->YUV420ToRGB_8u_P3AC4R)
487 (void)fprintf(stderr,
"Running AVC%s on frame size %" PRIu32
"x%" PRIu32
"\n",
488 use444 ?
"444" :
"420", roi.width, roi.height);
491 if (!(rgb = set_padding(size *
sizeof(UINT32), padding)))
494 if (!(rgb_dst = set_padding(size *
sizeof(UINT32), padding)))
497 if (!(yuv[0] = set_padding(size, padding)))
500 if (!(yuv[1] = set_padding(uvsize, padding)))
503 if (!(yuv[2] = set_padding(uvsize, padding)))
506 for (
size_t y = 0; y < roi.height; y++)
508 BYTE* line = &rgb[y * stride];
509 if (winpr_RAND(line, stride) < 0)
513 yuv_step[0] = awidth;
514 yuv_step[1] = uvwidth;
515 yuv_step[2] = uvwidth;
517 for (UINT32 x = 0; x < ARRAYSIZE(formats); x++)
520 const UINT32 DstFormat = formats[x];
521 printf(
"Testing destination color format %s\n", FreeRDPGetColorFormatName(DstFormat));
522 memset(rgb_dst, PADDING_FILL_VALUE, size *
sizeof(UINT32));
524 PROFILER_CREATE(rgbToYUV420,
"RGBToYUV420")
525 PROFILER_CREATE(rgbToYUV444, "RGBToYUV444")
526 PROFILER_CREATE(yuv420ToRGB, "YUV420ToRGB")
527 PROFILER_CREATE(yuv444ToRGB, "YUV444ToRGB")
531 PROFILER_ENTER(rgbToYUV444)
532 rc = prims->RGBToYUV444_8u_P3AC4R(rgb, DstFormat, stride, yuv, yuv_step, &roi);
533 PROFILER_EXIT(rgbToYUV444)
535 if (rc != PRIMITIVES_SUCCESS)
538 PROFILER_PRINT_HEADER
539 PROFILER_PRINT(rgbToYUV444)
540 PROFILER_PRINT_FOOTER
544 PROFILER_ENTER(rgbToYUV420)
545 rc = prims->RGBToYUV420_8u_P3AC4R(rgb, DstFormat, stride, yuv, yuv_step, &roi);
546 PROFILER_EXIT(rgbToYUV420)
548 if (rc != PRIMITIVES_SUCCESS)
551 PROFILER_PRINT_HEADER
552 PROFILER_PRINT(rgbToYUV420)
553 PROFILER_PRINT_FOOTER
556 if (!check_padding(rgb, size *
sizeof(UINT32), padding,
"rgb"))
562 if ((!check_padding(yuv[0], size, padding,
"Y")) ||
563 (!check_padding(yuv[1], uvsize, padding,
"U")) ||
564 (!check_padding(yuv[2], uvsize, padding,
"V")))
573 PROFILER_ENTER(yuv444ToRGB)
574 rc = prims->YUV444ToRGB_8u_P3AC4R(cnv.cpv, yuv_step, rgb_dst, stride, DstFormat, &roi);
575 PROFILER_EXIT(yuv444ToRGB)
577 if (rc != PRIMITIVES_SUCCESS)
581 PROFILER_EXIT(yuv444ToRGB)
582 PROFILER_PRINT_HEADER
583 PROFILER_PRINT(yuv444ToRGB)
584 PROFILER_PRINT_FOOTER
586 if (rc != PRIMITIVES_SUCCESS)
591 PROFILER_ENTER(yuv420ToRGB)
593 if (prims->YUV420ToRGB_8u_P3AC4R(cnv.cpv, yuv_step, rgb_dst, stride, DstFormat, &roi) !=
596 PROFILER_EXIT(yuv420ToRGB)
600 PROFILER_EXIT(yuv420ToRGB)
601 PROFILER_PRINT_HEADER
602 PROFILER_PRINT(yuv420ToRGB)
603 PROFILER_PRINT_FOOTER
606 if (!check_padding(rgb_dst, size *
sizeof(UINT32), padding,
"rgb dst"))
609 if ((!check_padding(yuv[0], size, padding,
"Y")) ||
610 (!check_padding(yuv[1], uvsize, padding,
"U")) ||
611 (!check_padding(yuv[2], uvsize, padding,
"V")))
615 for (
size_t y = 0; y < roi.height; y++)
617 BYTE* srgb = &rgb[y * stride];
618 BYTE* drgb = &rgb_dst[y * stride];
620 if (!similarRGB(y, srgb, drgb, roi.width, DstFormat, use444))
626 PROFILER_FREE(rgbToYUV420)
627 PROFILER_FREE(rgbToYUV444)
628 PROFILER_FREE(yuv420ToRGB)
629 PROFILER_FREE(yuv444ToRGB)
634 printf(
"[%s] run %s.\n", __func__, (res) ?
"SUCCESS" :
"FAILED");
635 free_padding(rgb, padding);
636 free_padding(rgb_dst, padding);
637 free_padding(yuv[0], padding);
638 free_padding(yuv[1], padding);
639 free_padding(yuv[2], padding);
643static BOOL allocate_yuv420(BYTE** planes, UINT32 width, UINT32 height, UINT32 padding)
645 const size_t size = 1ULL * width * height;
646 const size_t uvwidth = (1ULL + width) / 2;
647 const size_t uvsize = (1ULL + height) / 2 * uvwidth;
649 if (!(planes[0] = set_padding(size, padding)))
652 if (!(planes[1] = set_padding(uvsize, padding)))
655 if (!(planes[2] = set_padding(uvsize, padding)))
660 free_padding(planes[0], padding);
661 free_padding(planes[1], padding);
662 free_padding(planes[2], padding);
666static void free_yuv420(BYTE** planes, UINT32 padding)
671 free_padding(planes[0], padding);
672 free_padding(planes[1], padding);
673 free_padding(planes[2], padding);
679static BOOL check_yuv420(BYTE** planes, UINT32 width, UINT32 height, UINT32 padding)
681 const size_t size = 1ULL * width * height;
682 const size_t uvwidth = (width + 1) / 2;
683 const size_t uvsize = (height + 1) / 2 * uvwidth;
684 const BOOL yOk = check_padding(planes[0], size, padding,
"Y");
685 const BOOL uOk = check_padding(planes[1], uvsize, padding,
"U");
686 const BOOL vOk = check_padding(planes[2], uvsize, padding,
"V");
687 return (yOk && uOk && vOk);
690static BOOL check_for_mismatches(
const BYTE* planeA,
const BYTE* planeB, UINT32 size)
694 for (UINT32 x = 0; x < size; x++)
696 const BYTE a = planeA[x];
697 const BYTE b = planeB[x];
699 if (fabsf((
float)a - (
float)b) > 2.0f)
702 (void)fprintf(stderr,
"[%08x] %02x != %02x\n", x, a, b);
709static BOOL compare_yuv420(BYTE** planesA, BYTE** planesB, UINT32 width, UINT32 height,
713 const size_t size = 1ULL * width * height;
714 const size_t uvwidth = (1ULL * width + 1) / 2;
715 const size_t uvsize = (1ULL * height + 1) / 2 * uvwidth;
717 if (check_for_mismatches(planesA[0], planesB[0], size))
719 (void)fprintf(stderr,
"Mismatch in Y planes!\n");
723 if (check_for_mismatches(planesA[1], planesB[1], uvsize))
725 (void)fprintf(stderr,
"Mismatch in U planes!\n");
729 if (check_for_mismatches(planesA[2], planesB[2], uvsize))
731 (void)fprintf(stderr,
"Mismatch in V planes!\n");
738static UINT32 prand(UINT32 max)
743 if (winpr_RAND(&tmp,
sizeof(tmp)) < 0)
745 (void)fprintf(stderr,
"winpr_RAND failed, retry...\n");
749 return tmp % (max - 1) + 1;
757 BYTE* luma[3] = WINPR_C_ARRAY_INIT;
758 BYTE* chroma[3] = WINPR_C_ARRAY_INIT;
759 BYTE* lumaGeneric[3] = WINPR_C_ARRAY_INIT;
760 BYTE* chromaGeneric[3] = WINPR_C_ARRAY_INIT;
765 const size_t padding = 0x1000;
767 fn_RGBToAVC444YUV_t fkt =
nullptr;
768 fn_RGBToAVC444YUV_t gen =
nullptr;
769 const UINT32 formats[] = { PIXEL_FORMAT_XRGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_ARGB32,
770 PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_RGBX32,
771 PIXEL_FORMAT_BGRA32, PIXEL_FORMAT_BGRX32 };
772 PROFILER_DEFINE(rgbToYUV444)
773 PROFILER_DEFINE(rgbToYUV444opt)
777 if (awidth % 16 != 0)
778 awidth += 16 - roi.width % 16;
780 aheight = roi.height;
782 if (aheight % 16 != 0)
783 aheight += 16 - roi.height % 16;
785 stride = 1ULL * awidth *
sizeof(UINT32);
786 size = 1ULL * awidth * aheight;
787 uvwidth = 1ULL * (awidth + 1) / 2;
789 if (!prims || !generic)
795 fkt = prims->RGBToAVC444YUV;
796 gen =
generic->RGBToAVC444YUV;
800 fkt = prims->RGBToAVC444YUVv2;
801 gen =
generic->RGBToAVC444YUVv2;
811 (void)fprintf(stderr,
"Running AVC444 on frame size %" PRIu32
"x%" PRIu32
"\n", roi.width,
815 if (!(rgb = set_padding(size *
sizeof(UINT32), padding)))
818 if (!allocate_yuv420(luma, awidth, aheight, padding))
821 if (!allocate_yuv420(chroma, awidth, aheight, padding))
824 if (!allocate_yuv420(lumaGeneric, awidth, aheight, padding))
827 if (!allocate_yuv420(chromaGeneric, awidth, aheight, padding))
830 for (
size_t y = 0; y < roi.height; y++)
832 BYTE* line = &rgb[y * stride];
834 if (winpr_RAND(line, 4ULL * roi.width) < 0)
838 yuv_step[0] = awidth;
839 yuv_step[1] = uvwidth;
840 yuv_step[2] = uvwidth;
842 for (UINT32 x = 0; x < ARRAYSIZE(formats); x++)
845 const UINT32 DstFormat = formats[x];
846 printf(
"Testing destination color format %s\n", FreeRDPGetColorFormatName(DstFormat));
847 PROFILER_CREATE(rgbToYUV444,
"RGBToYUV444-generic")
848 PROFILER_CREATE(rgbToYUV444opt, "RGBToYUV444-optimized")
850 for (UINT32 cnt = 0; cnt < 10; cnt++)
852 PROFILER_ENTER(rgbToYUV444opt)
853 rc = fkt(rgb, DstFormat, stride, luma, yuv_step, chroma, yuv_step, &roi);
854 PROFILER_EXIT(rgbToYUV444opt)
856 if (rc != PRIMITIVES_SUCCESS)
860 PROFILER_PRINT_HEADER
861 PROFILER_PRINT(rgbToYUV444opt)
862 PROFILER_PRINT_FOOTER
864 if (!check_padding(rgb, size *
sizeof(UINT32), padding,
"rgb"))
870 if (!check_yuv420(luma, awidth, aheight, padding) ||
871 !check_yuv420(chroma, awidth, aheight, padding))
877 for (UINT32 cnt = 0; cnt < 10; cnt++)
879 PROFILER_ENTER(rgbToYUV444)
880 rc = gen(rgb, DstFormat, stride, lumaGeneric, yuv_step, chromaGeneric, yuv_step, &roi);
881 PROFILER_EXIT(rgbToYUV444)
883 if (rc != PRIMITIVES_SUCCESS)
887 PROFILER_PRINT_HEADER
888 PROFILER_PRINT(rgbToYUV444)
889 PROFILER_PRINT_FOOTER
891 if (!check_padding(rgb, size *
sizeof(UINT32), padding,
"rgb"))
897 if (!check_yuv420(lumaGeneric, awidth, aheight, padding) ||
898 !check_yuv420(chromaGeneric, awidth, aheight, padding))
904 if (!compare_yuv420(luma, lumaGeneric, awidth, aheight, padding) ||
905 !compare_yuv420(chroma, chromaGeneric, awidth, aheight, padding))
912 PROFILER_FREE(rgbToYUV444)
913 PROFILER_FREE(rgbToYUV444opt)
915 if (rc != PRIMITIVES_SUCCESS)
921 printf(
"[%s][version %u] run %s.\n", __func__, (
unsigned)version, (res) ?
"SUCCESS" :
"FAILED");
922 free_padding(rgb, padding);
923 free_yuv420(luma, padding);
924 free_yuv420(chroma, padding);
925 free_yuv420(lumaGeneric, padding);
926 free_yuv420(chromaGeneric, padding);
933 for (UINT32 type = PRIMITIVES_PURE_SOFT; type <= PRIMITIVES_AUTODETECT; type++)
938 printf(
"primitives type %d not supported\n", type);
942 for (UINT32 x = 0; x < 5; x++)
945 printf(
"-------------------- GENERIC ------------------------\n");
947 if (!TestPrimitiveYUV(prims, roi, TRUE))
950 printf(
"---------------------- END --------------------------\n");
951 printf(
"-------------------- GENERIC ------------------------\n");
953 if (!TestPrimitiveYUV(prims, roi, FALSE))
956 printf(
"---------------------- END --------------------------\n");
957 printf(
"-------------------- GENERIC ------------------------\n");
959 if (!TestPrimitiveYUVCombine(prims, roi))
962 printf(
"---------------------- END --------------------------\n");
963 printf(
"-------------------- GENERIC ------------------------\n");
965 if (!TestPrimitiveRgbToLumaChroma(prims, roi, 1))
968 printf(
"---------------------- END --------------------------\n");
969 printf(
"-------------------- GENERIC ------------------------\n");
971 if (!TestPrimitiveRgbToLumaChroma(prims, roi, 2))
974 printf(
"---------------------- END --------------------------\n");
979 printf(
"[%s] run %s.\n", __func__, (rc) ?
"SUCCESS" :
"FAILED");
983static void free_yuv(BYTE* yuv[3])
985 for (
size_t x = 0; x < 3; x++)
992static BOOL allocate_yuv(BYTE* yuv[3],
prim_size_t roi)
994 yuv[0] = calloc(roi.width, roi.height);
995 yuv[1] = calloc(roi.width, roi.height);
996 yuv[2] = calloc(roi.width, roi.height);
998 if (!yuv[0] || !yuv[1] || !yuv[2])
1004 if (winpr_RAND(yuv[0], 1ULL * roi.width * roi.height) < 0)
1006 if (winpr_RAND(yuv[1], 1ULL * roi.width * roi.height) < 0)
1008 if (winpr_RAND(yuv[2], 1ULL * roi.width * roi.height) < 0)
1013static BOOL yuv444_to_rgb(BYTE* rgb,
size_t stride,
const BYTE* yuv[3],
const UINT32 yuvStep[3],
1016 for (
size_t y = 0; y < roi.height; y++)
1018 const BYTE* yline[3] = {
1019 yuv[0] + y * roi.width,
1020 yuv[1] + y * roi.width,
1021 yuv[2] + y * roi.width,
1023 BYTE* line = &rgb[y * stride];
1025 for (
size_t x = 0; x < roi.width; x++)
1027 const BYTE Y = yline[0][x];
1028 const BYTE U = yline[1][x];
1029 const BYTE V = yline[2][x];
1031 writeYUVPixel(&line[x * 4], PIXEL_FORMAT_BGRX32, Y, U, V, writePixelBGRX);
1039static BOOL compare_yuv444_to_rgb(
prim_size_t roi, DWORD type)
1042 const UINT32 format = PIXEL_FORMAT_BGRA32;
1043 BYTE* yuv[3] = WINPR_C_ARRAY_INIT;
1044 const UINT32 yuvStep[3] = { roi.width, roi.width, roi.width };
1045 const size_t stride = 4ULL * roi.width;
1050 printf(
"primitives type %" PRIu32
" not supported, skipping\n", type);
1054 BYTE* rgb1 = calloc(roi.height, stride);
1055 BYTE* rgb2 = calloc(roi.height, stride);
1057 primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
1060 if (!allocate_yuv(yuv, roi) || !rgb1 || !rgb2)
1063 const BYTE* cyuv[] = { yuv[0], yuv[1], yuv[2] };
1064 if (soft->YUV444ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb1, stride, format, &roi) !=
1067 if (prims->YUV444ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb2, stride, format, &roi) !=
1071 for (
size_t y = 0; y < roi.height; y++)
1073 const BYTE* yline[3] = {
1074 yuv[0] + y * roi.width,
1075 yuv[1] + y * roi.width,
1076 yuv[2] + y * roi.width,
1078 const BYTE* line1 = &rgb1[y * stride];
1079 const BYTE* line2 = &rgb2[y * stride];
1081 for (
size_t x = 0; x < roi.width; x++)
1083 const int Y = yline[0][x];
1084 const int U = yline[1][x];
1085 const int V = yline[2][x];
1086 const UINT32 color1 = FreeRDPReadColor(&line1[x * 4], format);
1087 const UINT32 color2 = FreeRDPReadColor(&line2[x * 4], format);
1092 FreeRDPSplitColor(color1, format, &r1, &g1, &b1,
nullptr,
nullptr);
1097 FreeRDPSplitColor(color2, format, &r2, &g2, &b2,
nullptr,
nullptr);
1099 const int dr12 = abs(r1 - r2);
1100 const int dg12 = abs(g1 - g2);
1101 const int db12 = abs(b1 - b2);
1103 if ((dr12 != 0) || (dg12 != 0) || (db12 != 0))
1106 printf(
"\tdiff 1/2: yuv {%d, %d, %d}, rgb {%d, %d, %d}\n", Y, U, V, dr12, dg12,
1111 if ((dr12 > 0) || (dg12 > 0) || (db12 > 0))
1113 (void)fprintf(stderr,
1114 "[%" PRIuz
"x%" PRIuz
1115 "] generic and optimized data mismatch: r[0x%" PRIx8
"|0x%" PRIx8
1116 "] g[0x%" PRIx8
"|0x%" PRIx8
"] b[0x%" PRIx8
"|0x%" PRIx8
"]\n",
1117 x, y, r1, r2, g1, g2, b1, b2);
1118 (void)fprintf(stderr,
"roi: %dx%d\n", roi.width, roi.height);
1119 winpr_HexDump(
"y0", WLOG_INFO, &yline[0][x], 16);
1120 winpr_HexDump(
"y1", WLOG_INFO, &yline[0][x + roi.width], 16);
1121 winpr_HexDump(
"u0", WLOG_INFO, &yline[1][x], 16);
1122 winpr_HexDump(
"u1", WLOG_INFO, &yline[1][x + roi.width], 16);
1123 winpr_HexDump(
"v0", WLOG_INFO, &yline[2][x], 16);
1124 winpr_HexDump(
"v1", WLOG_INFO, &yline[2][x + roi.width], 16);
1125 winpr_HexDump(
"foo1", WLOG_INFO, &line1[x * 4], 16);
1126 winpr_HexDump(
"foo2", WLOG_INFO, &line2[x * 4], 16);
1134 printf(
"%s finished with %s\n", __func__, rc ?
"SUCCESS" :
"FAILURE");
1145static BOOL compare_rgb_to_yuv444(
prim_size_t roi, DWORD type)
1148 const UINT32 format = PIXEL_FORMAT_BGRA32;
1149 const size_t stride = 4ULL * roi.width;
1150 const UINT32 yuvStep[] = { roi.width, roi.width, roi.width };
1151 BYTE* yuv1[3] = WINPR_C_ARRAY_INIT;
1152 BYTE* yuv2[3] = WINPR_C_ARRAY_INIT;
1157 printf(
"primitives type %" PRIu32
" not supported, skipping\n", type);
1161 BYTE* rgb = calloc(roi.height, stride);
1163 primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
1167 if (!allocate_yuv(yuv1, roi) || !allocate_yuv(yuv2, roi))
1170 if (soft->RGBToYUV444_8u_P3AC4R(rgb, format, stride, yuv1, yuvStep, &roi) != PRIMITIVES_SUCCESS)
1172 if (prims->RGBToYUV444_8u_P3AC4R(rgb, format, stride, yuv2, yuvStep, &roi) !=
1176 for (
size_t y = 0; y < roi.height; y++)
1178 const BYTE* yline1[3] = {
1179 yuv1[0] + y * roi.width,
1180 yuv1[1] + y * roi.width,
1181 yuv1[2] + y * roi.width,
1183 const BYTE* yline2[3] = {
1184 yuv2[0] + y * roi.width,
1185 yuv2[1] + y * roi.width,
1186 yuv2[2] + y * roi.width,
1189 for (
size_t x = 0; x < ARRAYSIZE(yline1); x++)
1191 if (memcmp(yline1[x], yline2[x], yuvStep[x]) != 0)
1193 (void)fprintf(stderr,
"[%s] compare failed in line %" PRIuz, __func__, x);
1201 printf(
"%s finished with %s\n", __func__, rc ?
"SUCCESS" :
"FAILURE");
1212static BOOL compare_yuv420_to_rgb(
prim_size_t roi, DWORD type)
1215 const UINT32 format = PIXEL_FORMAT_BGRA32;
1216 BYTE* yuv[3] = WINPR_C_ARRAY_INIT;
1217 const UINT32 yuvStep[3] = { roi.width, roi.width / 2, roi.width / 2 };
1218 const size_t stride = 4ULL * roi.width;
1223 printf(
"primitives type %" PRIu32
" not supported, skipping\n", type);
1227 BYTE* rgb1 = calloc(roi.height, stride);
1228 BYTE* rgb2 = calloc(roi.height, stride);
1230 primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
1233 if (!allocate_yuv(yuv, roi) || !rgb1 || !rgb2)
1236 const BYTE* cyuv[3] = { yuv[0], yuv[1], yuv[2] };
1237 if (soft->YUV420ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb1, stride, format, &roi) !=
1240 if (prims->YUV420ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb2, stride, format, &roi) !=
1244 for (
size_t y = 0; y < roi.height; y++)
1246 const BYTE* yline[3] = {
1247 yuv[0] + y * yuvStep[0],
1248 yuv[1] + y * yuvStep[1],
1249 yuv[2] + y * yuvStep[2],
1251 const BYTE* line1 = &rgb1[y * stride];
1252 const BYTE* line2 = &rgb2[y * stride];
1254 for (
size_t x = 0; x < roi.width; x++)
1256 const int Y = yline[0][x];
1257 const int U = yline[1][x / 2];
1258 const int V = yline[2][x / 2];
1259 const UINT32 color1 = FreeRDPReadColor(&line1[x * 4], format);
1260 const UINT32 color2 = FreeRDPReadColor(&line2[x * 4], format);
1265 FreeRDPSplitColor(color1, format, &r1, &g1, &b1,
nullptr,
nullptr);
1270 FreeRDPSplitColor(color2, format, &r2, &g2, &b2,
nullptr,
nullptr);
1272 const int dr12 = abs(r1 - r2);
1273 const int dg12 = abs(g1 - g2);
1274 const int db12 = abs(b1 - b2);
1276 if ((dr12 != 0) || (dg12 != 0) || (db12 != 0))
1279 printf(
"\tdiff 1/2: yuv {%d, %d, %d}, rgb {%d, %d, %d}\n", Y, U, V, dr12, dg12,
1284 if ((dr12 > 0) || (dg12 > 0) || (db12 > 0))
1286 printf(
"[%s] failed: r[%" PRIx8
"|%" PRIx8
"] g[%" PRIx8
"|%" PRIx8
"] b[%" PRIx8
1288 __func__, r1, r2, g1, g2, b1, b2);
1296 printf(
"%s finished with %s\n", __func__, rc ?
"SUCCESS" :
"FAILURE");
1304static BOOL similarYUV(
const BYTE* line1,
const BYTE* line2,
size_t len)
1306 for (
size_t x = 0; x < len; x++)
1308 const int a = line1[x];
1309 const int b = line2[x];
1310 const int diff = abs(a - b);
1316static int similarY(
const BYTE* a,
const BYTE* b,
size_t size,
size_t type)
1323 for (
size_t x = 0; x < size; x++)
1325 const int ba = a[x];
1326 const int bb = b[x];
1327 const int diff = abs(ba - bb);
1334 return memcmp(a, b, size);
1340static BOOL compare_rgb_to_yuv420(
prim_size_t roi, DWORD type)
1343 const UINT32 format = PIXEL_FORMAT_BGRA32;
1344 const size_t stride = 4ULL * roi.width;
1345 const UINT32 yuvStep[] = { roi.width, roi.width / 2, roi.width / 2 };
1346 BYTE* yuv1[3] = WINPR_C_ARRAY_INIT;
1347 BYTE* yuv2[3] = WINPR_C_ARRAY_INIT;
1352 printf(
"primitives type %" PRIu32
" not supported, skipping\n", type);
1356 BYTE* rgb = calloc(roi.height, stride);
1357 BYTE* rgbcopy = calloc(roi.height, stride);
1359 primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
1360 if (!soft || !rgb || !rgbcopy)
1363 if (winpr_RAND(rgb, roi.height * stride) < 0)
1365 memcpy(rgbcopy, rgb, roi.height * stride);
1367 if (!allocate_yuv(yuv1, roi) || !allocate_yuv(yuv2, roi))
1370 if (soft->RGBToYUV420_8u_P3AC4R(rgb, format, stride, yuv1, yuvStep, &roi) != PRIMITIVES_SUCCESS)
1372 if (memcmp(rgb, rgbcopy, roi.height * stride) != 0)
1374 if (prims->RGBToYUV420_8u_P3AC4R(rgb, format, stride, yuv2, yuvStep, &roi) !=
1378 for (
size_t y = 0; y < roi.height; y++)
1381 if (((y + 1) >= roi.height) && ((y % 2) == 0))
1384 const BYTE* yline1[3] = {
1385 &yuv1[0][y * yuvStep[0]],
1386 &yuv1[1][(y / 2) * yuvStep[1]],
1387 &yuv1[2][(y / 2) * yuvStep[2]],
1389 const BYTE* yline2[3] = {
1390 &yuv2[0][y * yuvStep[0]],
1391 &yuv2[1][(y / 2) * yuvStep[1]],
1392 &yuv2[2][(y / 2) * yuvStep[2]],
1395 for (
size_t x = 0; x < ARRAYSIZE(yline1); x++)
1397 if (similarY(yline1[x], yline2[x], yuvStep[x], x) != 0)
1399 (void)fprintf(stderr,
1400 "[%s] compare failed in component %" PRIuz
", line %" PRIuz
"\n",
1402 (void)fprintf(stderr,
"[%s] roi %" PRIu32
"x%" PRIu32
"\n", __func__, roi.width,
1404 winpr_HexDump(TAG, WLOG_WARN, yline1[x], yuvStep[x]);
1405 winpr_HexDump(TAG, WLOG_WARN, yline2[x], yuvStep[x]);
1406 winpr_HexDump(TAG, WLOG_WARN, &rgb[y * stride], stride);
1414 printf(
"%s finished with %s\n", __func__, rc ?
"SUCCESS" :
"FAILURE");
1423int TestPrimitivesYUV(
int argc,
char* argv[])
1425 BOOL large = (argc > 1);
1434 char* str = argv[1];
1435 char* ptr = strchr(str,
'x');
1441 roi.width = strtoul(str,
nullptr, 0);
1443 roi.height = strtoul(str,
nullptr, 0);
1454 get_size(large, &roi.width, &roi.height);
1456 prim_test_setup(FALSE);
1458 for (UINT32 type = PRIMITIVES_PURE_SOFT; type <= PRIMITIVES_AUTODETECT; type++)
1460 if (!compare_yuv444_to_rgb(roi, type))
1462 if (!compare_rgb_to_yuv444(roi, type))
1465 if (!compare_yuv420_to_rgb(roi, type))
1467 if (!compare_rgb_to_yuv420(roi, type))
1471 if (!run_tests(roi))
1476 printf(
"[%s] finished, status %s [%d]\n", __func__, (rc == 0) ?
"SUCCESS" :
"FAILURE", rc);