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,
44 const UINT32 bpp = FreeRDPGetBytesPerPixel(format);
45 BYTE fill = PADDING_FILL_VALUE;
46 if (!FreeRDPColorHasAlpha(format))
49 for (
size_t x = 0; x < size; x++)
51 const LONG maxDiff = 4;
62 sColor = FreeRDPReadColor(src, format);
63 dColor = FreeRDPReadColor(dst, format);
66 FreeRDPSplitColor(sColor, format, &sR, &sG, &sB, &sA, NULL);
67 FreeRDPSplitColor(dColor, format, &dR, &dG, &dB, &dA, NULL);
69 const long diffr = labs(1L * sR - dR);
70 const long diffg = labs(1L * sG - dG);
71 const long diffb = labs(1L * sB - dB);
72 if ((diffr > maxDiff) || (diffg > maxDiff) || (diffb > maxDiff))
80 if (use444 && ((x % 2) == 0) && ((y % 2) == 0))
85 const BYTE sY = RGB2Y(sR, sG, sB);
86 const BYTE sU = RGB2U(sR, sG, sB);
87 const BYTE sV = RGB2V(sR, sG, sB);
88 const BYTE dY = RGB2Y(dR, dG, dB);
89 const BYTE dU = RGB2U(dR, dG, dB);
90 const BYTE dV = RGB2V(dR, dG, dB);
92 "[%s] Color value mismatch R[%02X %02X], G[%02X %02X], B[%02X %02X] at "
93 "position %" PRIuz
"\n",
94 use444 ?
"AVC444" :
"AVC420", sR, dR, sG, dG, sA, dA, x);
96 "[%s] Color value mismatch Y[%02X %02X], U[%02X %02X], V[%02X %02X] at "
97 "position %" PRIuz
"\n",
98 use444 ?
"AVC444" :
"AVC420", sY, dY, sU, dU, sV, dV, x);
106 "[%s] Invalid destination alpha value 0x%02X [expected 0x%02X] at position %" PRIuz
108 use444 ?
"AVC444" :
"AVC420", dA, fill, x);
116static void get_size(BOOL large, UINT32* width, UINT32* height)
118 UINT32 shift = large ? 8 : 1;
119 winpr_RAND(width,
sizeof(*width));
120 winpr_RAND(height,
sizeof(*height));
121 *width = (*width % 64 + 1) << shift;
122 *height = (*height % 64 + 1);
125static BOOL check_padding(
const BYTE* psrc,
size_t size,
size_t padding,
const char* buffer)
128 const BYTE* src = NULL;
129 const BYTE* esrc = NULL;
130 size_t halfPad = (padding + 1) / 2;
135 src = psrc - halfPad;
136 esrc = src + size + halfPad;
138 for (
size_t x = 0; x < halfPad; x++)
140 const BYTE s = *src++;
141 const BYTE d = *esrc++;
147 while ((x < halfPad) && (*esrc++ !=
'A'))
150 (void)fprintf(stderr,
151 "Buffer underflow detected %02" PRIx8
" != %02X %s [%" PRIuz
"-%" PRIuz
153 d,
'A', buffer, start, x);
161 while ((x < halfPad) && (*esrc++ !=
'A'))
164 (void)fprintf(stderr,
165 "Buffer overflow detected %02" PRIx8
" != %02X %s [%" PRIuz
"-%" PRIuz
167 d,
'A', buffer, start, x);
175static void* set_padding(
size_t size,
size_t padding)
177 size_t halfPad = (padding + 1) / 2;
179 BYTE* src = winpr_aligned_malloc(size + 2 * halfPad, 16);
184 memset(&src[0],
'A', halfPad);
185 memset(&src[halfPad], PADDING_FILL_VALUE, size);
186 memset(&src[halfPad + size],
'A', halfPad);
187 psrc = &src[halfPad];
189 if (!check_padding(psrc, size, padding,
"init"))
191 winpr_aligned_free(src);
198static void free_padding(
void* src,
size_t padding)
205 ptr = ((BYTE*)src) - (padding + 1) / 2;
206 winpr_aligned_free(ptr);
221 BYTE* luma[3] = { 0 };
222 BYTE* chroma[3] = { 0 };
223 BYTE* yuv[3] = { 0 };
224 BYTE* pmain[3] = { 0 };
225 BYTE* paux[3] = { 0 };
226 UINT32 lumaStride[3] = { 0 };
227 UINT32 chromaStride[3] = { 0 };
228 UINT32 yuvStride[3] = { 0 };
229 const size_t padding = 10000;
231 PROFILER_DEFINE(yuvCombine)
232 PROFILER_DEFINE(yuvSplit)
238 awidth = roi.width + 16 - roi.width % 16;
239 aheight = roi.height + 16 - roi.height % 16;
240 (void)fprintf(stderr,
241 "Running YUVCombine on frame size %" PRIu32
"x%" PRIu32
" [%" PRIu32
"x%" PRIu32
243 roi.width, roi.height, awidth, aheight);
244 PROFILER_CREATE(yuvCombine,
"YUV420CombineToYUV444")
245 PROFILER_CREATE(yuvSplit, "YUV444SplitToYUV420")
248 rect.right = roi.width;
249 rect.bottom = roi.height;
251 if (!prims || !prims->YUV420CombineToYUV444)
254 for (UINT32 x = 0; x < 3; x++)
256 size_t halfStride = ((x > 0) ? awidth / 2 : awidth);
257 size_t size = aheight * awidth;
258 size_t halfSize = ((x > 0) ? halfStride * aheight / 2 : awidth * aheight);
259 yuvStride[x] = awidth;
261 if (!(yuv[x] = set_padding(size, padding)))
264 lumaStride[x] = halfStride;
266 if (!(luma[x] = set_padding(halfSize, padding)))
269 if (!(pmain[x] = set_padding(halfSize, padding)))
272 chromaStride[x] = halfStride;
274 if (!(chroma[x] = set_padding(halfSize, padding)))
277 if (!(paux[x] = set_padding(halfSize, padding)))
280 memset(luma[x], WINPR_ASSERTING_INT_CAST(
int, 0xAB + 3 * x), halfSize);
281 memset(chroma[x], WINPR_ASSERTING_INT_CAST(
int, 0x80 + 2 * x), halfSize);
283 if (!check_padding(luma[x], halfSize, padding,
"luma"))
286 if (!check_padding(chroma[x], halfSize, padding,
"chroma"))
289 if (!check_padding(pmain[x], halfSize, padding,
"main"))
292 if (!check_padding(paux[x], halfSize, padding,
"aux"))
295 if (!check_padding(yuv[x], size, padding,
"yuv"))
299 PROFILER_ENTER(yuvCombine)
302 if (prims->YUV420CombineToYUV444(AVC444_LUMA, cnv.cpv, lumaStride, roi.width, roi.height, yuv,
303 yuvStride, &rect) != PRIMITIVES_SUCCESS)
305 PROFILER_EXIT(yuvCombine)
310 if (prims->YUV420CombineToYUV444(AVC444_CHROMAv1, cnv.cpv, chromaStride, roi.width, roi.height,
311 yuv, yuvStride, &rect) != PRIMITIVES_SUCCESS)
313 PROFILER_EXIT(yuvCombine)
317 PROFILER_EXIT(yuvCombine)
319 for (
size_t x = 0; x < 3; x++)
321 size_t halfStride = ((x > 0) ? awidth / 2 : awidth);
322 size_t size = 1ULL * aheight * awidth;
323 size_t halfSize = ((x > 0) ? halfStride * aheight / 2 : awidth * aheight);
325 if (!check_padding(luma[x], halfSize, padding,
"luma"))
328 if (!check_padding(chroma[x], halfSize, padding,
"chroma"))
331 if (!check_padding(yuv[x], size, padding,
"yuv"))
335 PROFILER_ENTER(yuvSplit)
338 if (prims->YUV444SplitToYUV420(cnv.cpv, yuvStride, pmain, lumaStride, paux, chromaStride,
339 &roi) != PRIMITIVES_SUCCESS)
341 PROFILER_EXIT(yuvSplit)
345 PROFILER_EXIT(yuvSplit)
347 for (UINT32 x = 0; x < 3; x++)
349 size_t halfStride = ((x > 0) ? awidth / 2 : awidth);
350 size_t size = aheight * awidth;
351 size_t halfSize = ((x > 0) ? halfStride * aheight / 2 : awidth * aheight);
353 if (!check_padding(pmain[x], halfSize, padding,
"main"))
356 if (!check_padding(paux[x], halfSize, padding,
"aux"))
359 if (!check_padding(yuv[x], size, padding,
"yuv"))
363 for (
size_t i = 0; i < 3; i++)
365 for (
size_t y = 0; y < roi.height; y++)
367 UINT32 w = roi.width;
368 UINT32 lstride = lumaStride[i];
369 UINT32 cstride = chromaStride[i];
373 w = (roi.width + 3) / 4;
375 if (roi.height > (roi.height + 1) / 2)
379 if (!similar(luma[i] + y * lstride, pmain[i] + y * lstride, w))
390 UINT32 rem = roi.height % 16;
392 if (y > roi.height - rem)
396 if (!similar(chroma[i] + y * cstride, paux[i] + y * cstride, w))
401 PROFILER_PRINT_HEADER
402 PROFILER_PRINT(yuvSplit)
403 PROFILER_PRINT(yuvCombine)
404 PROFILER_PRINT_FOOTER
407 printf(
"[%s] run %s.\n", __func__, (rc) ?
"SUCCESS" :
"FAILED");
408 PROFILER_FREE(yuvCombine)
409 PROFILER_FREE(yuvSplit)
411 for (UINT32 x = 0; x < 3; x++)
413 free_padding(yuv[x], padding);
414 free_padding(luma[x], padding);
415 free_padding(chroma[x], padding);
416 free_padding(pmain[x], padding);
417 free_padding(paux[x], padding);
433 BYTE* yuv[3] = { 0 };
436 BYTE* rgb_dst = NULL;
440 size_t padding = 100ULL * 16ULL;
442 const UINT32 formats[] = { PIXEL_FORMAT_XRGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_ARGB32,
443 PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_RGBX32,
444 PIXEL_FORMAT_BGRA32, PIXEL_FORMAT_BGRX32 };
445 PROFILER_DEFINE(rgbToYUV420)
446 PROFILER_DEFINE(rgbToYUV444)
447 PROFILER_DEFINE(yuv420ToRGB)
448 PROFILER_DEFINE(yuv444ToRGB)
450 awidth = roi.width + 16 - roi.width % 16;
451 aheight = roi.height + 16 - roi.height % 16;
452 stride = 1ULL * awidth *
sizeof(UINT32);
453 size = 1ULL * awidth * aheight;
460 if (!prims || !prims->RGBToYUV444_8u_P3AC4R || !prims->YUV444ToRGB_8u_P3AC4R)
465 uvwidth = (awidth + 1) / 2;
466 uvsize = (aheight + 1) / 2 * uvwidth;
468 if (!prims || !prims->RGBToYUV420_8u_P3AC4R || !prims->YUV420ToRGB_8u_P3AC4R)
472 (void)fprintf(stderr,
"Running AVC%s on frame size %" PRIu32
"x%" PRIu32
"\n",
473 use444 ?
"444" :
"420", roi.width, roi.height);
476 if (!(rgb = set_padding(size *
sizeof(UINT32), padding)))
479 if (!(rgb_dst = set_padding(size *
sizeof(UINT32), padding)))
482 if (!(yuv[0] = set_padding(size, padding)))
485 if (!(yuv[1] = set_padding(uvsize, padding)))
488 if (!(yuv[2] = set_padding(uvsize, padding)))
491 for (
size_t y = 0; y < roi.height; y++)
493 BYTE* line = &rgb[y * stride];
494 winpr_RAND(line, stride);
497 yuv_step[0] = awidth;
498 yuv_step[1] = uvwidth;
499 yuv_step[2] = uvwidth;
501 for (UINT32 x = 0; x < ARRAYSIZE(formats); x++)
504 const UINT32 DstFormat = formats[x];
505 printf(
"Testing destination color format %s\n", FreeRDPGetColorFormatName(DstFormat));
506 memset(rgb_dst, PADDING_FILL_VALUE, size *
sizeof(UINT32));
508 PROFILER_CREATE(rgbToYUV420,
"RGBToYUV420")
509 PROFILER_CREATE(rgbToYUV444, "RGBToYUV444")
510 PROFILER_CREATE(yuv420ToRGB, "YUV420ToRGB")
511 PROFILER_CREATE(yuv444ToRGB, "YUV444ToRGB")
515 PROFILER_ENTER(rgbToYUV444)
516 rc = prims->RGBToYUV444_8u_P3AC4R(rgb, DstFormat, stride, yuv, yuv_step, &roi);
517 PROFILER_EXIT(rgbToYUV444)
519 if (rc != PRIMITIVES_SUCCESS)
522 PROFILER_PRINT_HEADER
523 PROFILER_PRINT(rgbToYUV444)
524 PROFILER_PRINT_FOOTER
528 PROFILER_ENTER(rgbToYUV420)
529 rc = prims->RGBToYUV420_8u_P3AC4R(rgb, DstFormat, stride, yuv, yuv_step, &roi);
530 PROFILER_EXIT(rgbToYUV420)
532 if (rc != PRIMITIVES_SUCCESS)
535 PROFILER_PRINT_HEADER
536 PROFILER_PRINT(rgbToYUV420)
537 PROFILER_PRINT_FOOTER
540 if (!check_padding(rgb, size *
sizeof(UINT32), padding,
"rgb"))
546 if ((!check_padding(yuv[0], size, padding,
"Y")) ||
547 (!check_padding(yuv[1], uvsize, padding,
"U")) ||
548 (!check_padding(yuv[2], uvsize, padding,
"V")))
557 PROFILER_ENTER(yuv444ToRGB)
558 rc = prims->YUV444ToRGB_8u_P3AC4R(cnv.cpv, yuv_step, rgb_dst, stride, DstFormat, &roi);
559 PROFILER_EXIT(yuv444ToRGB)
561 if (rc != PRIMITIVES_SUCCESS)
565 PROFILER_EXIT(yuv444ToRGB)
566 PROFILER_PRINT_HEADER
567 PROFILER_PRINT(yuv444ToRGB)
568 PROFILER_PRINT_FOOTER
570 if (rc != PRIMITIVES_SUCCESS)
575 PROFILER_ENTER(yuv420ToRGB)
577 if (prims->YUV420ToRGB_8u_P3AC4R(cnv.cpv, yuv_step, rgb_dst, stride, DstFormat, &roi) !=
580 PROFILER_EXIT(yuv420ToRGB)
584 PROFILER_EXIT(yuv420ToRGB)
585 PROFILER_PRINT_HEADER
586 PROFILER_PRINT(yuv420ToRGB)
587 PROFILER_PRINT_FOOTER
590 if (!check_padding(rgb_dst, size *
sizeof(UINT32), padding,
"rgb dst"))
593 if ((!check_padding(yuv[0], size, padding,
"Y")) ||
594 (!check_padding(yuv[1], uvsize, padding,
"U")) ||
595 (!check_padding(yuv[2], uvsize, padding,
"V")))
599 for (
size_t y = 0; y < roi.height; y++)
601 BYTE* srgb = &rgb[y * stride];
602 BYTE* drgb = &rgb_dst[y * stride];
604 if (!similarRGB(y, srgb, drgb, roi.width, DstFormat, use444))
609 PROFILER_FREE(rgbToYUV420)
610 PROFILER_FREE(rgbToYUV444)
611 PROFILER_FREE(yuv420ToRGB)
612 PROFILER_FREE(yuv444ToRGB)
617 printf(
"[%s] run %s.\n", __func__, (res) ?
"SUCCESS" :
"FAILED");
618 free_padding(rgb, padding);
619 free_padding(rgb_dst, padding);
620 free_padding(yuv[0], padding);
621 free_padding(yuv[1], padding);
622 free_padding(yuv[2], padding);
626static BOOL allocate_yuv420(BYTE** planes, UINT32 width, UINT32 height, UINT32 padding)
628 const size_t size = 1ULL * width * height;
629 const size_t uvwidth = (1ULL + width) / 2;
630 const size_t uvsize = (1ULL + height) / 2 * uvwidth;
632 if (!(planes[0] = set_padding(size, padding)))
635 if (!(planes[1] = set_padding(uvsize, padding)))
638 if (!(planes[2] = set_padding(uvsize, padding)))
643 free_padding(planes[0], padding);
644 free_padding(planes[1], padding);
645 free_padding(planes[2], padding);
649static void free_yuv420(BYTE** planes, UINT32 padding)
654 free_padding(planes[0], padding);
655 free_padding(planes[1], padding);
656 free_padding(planes[2], padding);
662static BOOL check_yuv420(BYTE** planes, UINT32 width, UINT32 height, UINT32 padding)
664 const size_t size = 1ULL * width * height;
665 const size_t uvwidth = (width + 1) / 2;
666 const size_t uvsize = (height + 1) / 2 * uvwidth;
667 const BOOL yOk = check_padding(planes[0], size, padding,
"Y");
668 const BOOL uOk = check_padding(planes[1], uvsize, padding,
"U");
669 const BOOL vOk = check_padding(planes[2], uvsize, padding,
"V");
670 return (yOk && uOk && vOk);
673static BOOL check_for_mismatches(
const BYTE* planeA,
const BYTE* planeB, UINT32 size)
677 for (UINT32 x = 0; x < size; x++)
679 const BYTE a = planeA[x];
680 const BYTE b = planeB[x];
682 if (fabsf((
float)a - (
float)b) > 2.0f)
685 (void)fprintf(stderr,
"[%08x] %02x != %02x\n", x, a, b);
692static BOOL compare_yuv420(BYTE** planesA, BYTE** planesB, UINT32 width, UINT32 height,
696 const size_t size = 1ULL * width * height;
697 const size_t uvwidth = (1ULL * width + 1) / 2;
698 const size_t uvsize = (1ULL * height + 1) / 2 * uvwidth;
700 if (check_for_mismatches(planesA[0], planesB[0], size))
702 (void)fprintf(stderr,
"Mismatch in Y planes!\n");
706 if (check_for_mismatches(planesA[1], planesB[1], uvsize))
708 (void)fprintf(stderr,
"Mismatch in U planes!\n");
712 if (check_for_mismatches(planesA[2], planesB[2], uvsize))
714 (void)fprintf(stderr,
"Mismatch in V planes!\n");
721static UINT32 prand(UINT32 max)
726 winpr_RAND(&tmp,
sizeof(tmp));
727 return tmp % (max - 1) + 1;
735 BYTE* luma[3] = { 0 };
736 BYTE* chroma[3] = { 0 };
737 BYTE* lumaGeneric[3] = { 0 };
738 BYTE* chromaGeneric[3] = { 0 };
743 const size_t padding = 0x1000;
745 fn_RGBToAVC444YUV_t fkt = NULL;
746 fn_RGBToAVC444YUV_t gen = NULL;
747 const UINT32 formats[] = { PIXEL_FORMAT_XRGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_ARGB32,
748 PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_RGBX32,
749 PIXEL_FORMAT_BGRA32, PIXEL_FORMAT_BGRX32 };
750 PROFILER_DEFINE(rgbToYUV444)
751 PROFILER_DEFINE(rgbToYUV444opt)
755 if (awidth % 16 != 0)
756 awidth += 16 - roi.width % 16;
758 aheight = roi.height;
760 if (aheight % 16 != 0)
761 aheight += 16 - roi.height % 16;
763 stride = 1ULL * awidth *
sizeof(UINT32);
764 size = 1ULL * awidth * aheight;
765 uvwidth = 1ULL * (awidth + 1) / 2;
767 if (!prims || !generic)
773 fkt = prims->RGBToAVC444YUV;
774 gen =
generic->RGBToAVC444YUV;
778 fkt = prims->RGBToAVC444YUVv2;
779 gen =
generic->RGBToAVC444YUVv2;
789 (void)fprintf(stderr,
"Running AVC444 on frame size %" PRIu32
"x%" PRIu32
"\n", roi.width,
793 if (!(rgb = set_padding(size *
sizeof(UINT32), padding)))
796 if (!allocate_yuv420(luma, awidth, aheight, padding))
799 if (!allocate_yuv420(chroma, awidth, aheight, padding))
802 if (!allocate_yuv420(lumaGeneric, awidth, aheight, padding))
805 if (!allocate_yuv420(chromaGeneric, awidth, aheight, padding))
808 for (
size_t y = 0; y < roi.height; y++)
810 BYTE* line = &rgb[y * stride];
812 winpr_RAND(line, 4ULL * roi.width);
815 yuv_step[0] = awidth;
816 yuv_step[1] = uvwidth;
817 yuv_step[2] = uvwidth;
819 for (UINT32 x = 0; x < ARRAYSIZE(formats); x++)
822 const UINT32 DstFormat = formats[x];
823 printf(
"Testing destination color format %s\n", FreeRDPGetColorFormatName(DstFormat));
824 PROFILER_CREATE(rgbToYUV444,
"RGBToYUV444-generic")
825 PROFILER_CREATE(rgbToYUV444opt, "RGBToYUV444-optimized")
827 for (UINT32 cnt = 0; cnt < 10; cnt++)
829 PROFILER_ENTER(rgbToYUV444opt)
830 rc = fkt(rgb, DstFormat, stride, luma, yuv_step, chroma, yuv_step, &roi);
831 PROFILER_EXIT(rgbToYUV444opt)
833 if (rc != PRIMITIVES_SUCCESS)
837 PROFILER_PRINT_HEADER
838 PROFILER_PRINT(rgbToYUV444opt)
839 PROFILER_PRINT_FOOTER
841 if (!check_padding(rgb, size *
sizeof(UINT32), padding,
"rgb"))
847 if (!check_yuv420(luma, awidth, aheight, padding) ||
848 !check_yuv420(chroma, awidth, aheight, padding))
854 for (UINT32 cnt = 0; cnt < 10; cnt++)
856 PROFILER_ENTER(rgbToYUV444)
857 rc = gen(rgb, DstFormat, stride, lumaGeneric, yuv_step, chromaGeneric, yuv_step, &roi);
858 PROFILER_EXIT(rgbToYUV444)
860 if (rc != PRIMITIVES_SUCCESS)
864 PROFILER_PRINT_HEADER
865 PROFILER_PRINT(rgbToYUV444)
866 PROFILER_PRINT_FOOTER
868 if (!check_padding(rgb, size *
sizeof(UINT32), padding,
"rgb"))
874 if (!check_yuv420(lumaGeneric, awidth, aheight, padding) ||
875 !check_yuv420(chromaGeneric, awidth, aheight, padding))
881 if (!compare_yuv420(luma, lumaGeneric, awidth, aheight, padding) ||
882 !compare_yuv420(chroma, chromaGeneric, awidth, aheight, padding))
889 PROFILER_FREE(rgbToYUV444)
890 PROFILER_FREE(rgbToYUV444opt)
892 if (rc != PRIMITIVES_SUCCESS)
898 printf(
"[%s][version %u] run %s.\n", __func__, (
unsigned)version, (res) ?
"SUCCESS" :
"FAILED");
899 free_padding(rgb, padding);
900 free_yuv420(luma, padding);
901 free_yuv420(chroma, padding);
902 free_yuv420(lumaGeneric, padding);
903 free_yuv420(chromaGeneric, padding);
910 for (UINT32 type = PRIMITIVES_PURE_SOFT; type <= PRIMITIVES_AUTODETECT; type++)
915 printf(
"primitives type %d not supported\n", type);
919 for (UINT32 x = 0; x < 5; x++)
922 printf(
"-------------------- GENERIC ------------------------\n");
924 if (!TestPrimitiveYUV(prims, roi, TRUE))
927 printf(
"---------------------- END --------------------------\n");
928 printf(
"-------------------- GENERIC ------------------------\n");
930 if (!TestPrimitiveYUV(prims, roi, FALSE))
933 printf(
"---------------------- END --------------------------\n");
934 printf(
"-------------------- GENERIC ------------------------\n");
936 if (!TestPrimitiveYUVCombine(prims, roi))
939 printf(
"---------------------- END --------------------------\n");
940 printf(
"-------------------- GENERIC ------------------------\n");
942 if (!TestPrimitiveRgbToLumaChroma(prims, roi, 1))
945 printf(
"---------------------- END --------------------------\n");
946 printf(
"-------------------- GENERIC ------------------------\n");
948 if (!TestPrimitiveRgbToLumaChroma(prims, roi, 2))
951 printf(
"---------------------- END --------------------------\n");
956 printf(
"[%s] run %s.\n", __func__, (rc) ?
"SUCCESS" :
"FAILED");
960static void free_yuv(BYTE* yuv[3])
962 for (
size_t x = 0; x < 3; x++)
969static BOOL allocate_yuv(BYTE* yuv[3],
prim_size_t roi)
971 yuv[0] = calloc(roi.width, roi.height);
972 yuv[1] = calloc(roi.width, roi.height);
973 yuv[2] = calloc(roi.width, roi.height);
975 if (!yuv[0] || !yuv[1] || !yuv[2])
981 winpr_RAND(yuv[0], 1ULL * roi.width * roi.height);
982 winpr_RAND(yuv[1], 1ULL * roi.width * roi.height);
983 winpr_RAND(yuv[2], 1ULL * roi.width * roi.height);
987static BOOL yuv444_to_rgb(BYTE* rgb,
size_t stride,
const BYTE* yuv[3],
const UINT32 yuvStep[3],
990 for (
size_t y = 0; y < roi.height; y++)
992 const BYTE* yline[3] = {
993 yuv[0] + y * roi.width,
994 yuv[1] + y * roi.width,
995 yuv[2] + y * roi.width,
997 BYTE* line = &rgb[y * stride];
999 for (
size_t x = 0; x < roi.width; x++)
1001 const BYTE Y = yline[0][x];
1002 const BYTE U = yline[1][x];
1003 const BYTE V = yline[2][x];
1004 const BYTE r = YUV2R(Y, U, V);
1005 const BYTE g = YUV2G(Y, U, V);
1006 const BYTE b = YUV2B(Y, U, V);
1007 writePixelBGRX(&line[x * 4], 4, PIXEL_FORMAT_BGRX32, r, g, b, 0xFF);
1015static BOOL compare_yuv444_to_rgb(
prim_size_t roi, DWORD type)
1018 const UINT32 format = PIXEL_FORMAT_BGRA32;
1019 BYTE* yuv[3] = { 0 };
1020 const UINT32 yuvStep[3] = { roi.width, roi.width, roi.width };
1021 const size_t stride = 4ULL * roi.width;
1026 printf(
"primitives type %" PRIu32
" not supported, skipping\n", type);
1030 BYTE* rgb1 = calloc(roi.height, stride);
1031 BYTE* rgb2 = calloc(roi.height, stride);
1033 primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
1036 if (!allocate_yuv(yuv, roi) || !rgb1 || !rgb2)
1039 const BYTE* cyuv[] = { yuv[0], yuv[1], yuv[2] };
1040 if (soft->YUV444ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb1, stride, format, &roi) !=
1043 if (prims->YUV444ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb2, stride, format, &roi) !=
1047 for (
size_t y = 0; y < roi.height; y++)
1049 const BYTE* yline[3] = {
1050 yuv[0] + y * roi.width,
1051 yuv[1] + y * roi.width,
1052 yuv[2] + y * roi.width,
1054 const BYTE* line1 = &rgb1[y * stride];
1055 const BYTE* line2 = &rgb2[y * stride];
1057 for (
size_t x = 0; x < roi.width; x++)
1059 const int Y = yline[0][x];
1060 const int U = yline[1][x];
1061 const int V = yline[2][x];
1062 const UINT32 color1 = FreeRDPReadColor(&line1[x * 4], format);
1063 const UINT32 color2 = FreeRDPReadColor(&line2[x * 4], format);
1068 FreeRDPSplitColor(color1, format, &r1, &g1, &b1, NULL, NULL);
1073 FreeRDPSplitColor(color2, format, &r2, &g2, &b2, NULL, NULL);
1075 const int dr12 = abs(r1 - r2);
1076 const int dg12 = abs(g1 - g2);
1077 const int db12 = abs(b1 - b2);
1079 if ((dr12 != 0) || (dg12 != 0) || (db12 != 0))
1082 printf(
"\tdiff 1/2: yuv {%d, %d, %d}, rgb {%d, %d, %d}\n", Y, U, V, dr12, dg12,
1087 if ((dr12 > 0) || (dg12 > 0) || (db12 > 0))
1089 (void)fprintf(stderr,
1090 "[%" PRIuz
"x%" PRIuz
1091 "] generic and optimized data mismatch: r[0x%" PRIx8
"|0x%" PRIx8
1092 "] g[0x%" PRIx8
"|0x%" PRIx8
"] b[0x%" PRIx8
"|0x%" PRIx8
"]\n",
1093 x, y, r1, r2, g1, g2, b1, b2);
1094 (void)fprintf(stderr,
"roi: %dx%d\n", roi.width, roi.height);
1095 winpr_HexDump(
"y0", WLOG_INFO, &yline[0][x], 16);
1096 winpr_HexDump(
"y1", WLOG_INFO, &yline[0][x + roi.width], 16);
1097 winpr_HexDump(
"u0", WLOG_INFO, &yline[1][x], 16);
1098 winpr_HexDump(
"u1", WLOG_INFO, &yline[1][x + roi.width], 16);
1099 winpr_HexDump(
"v0", WLOG_INFO, &yline[2][x], 16);
1100 winpr_HexDump(
"v1", WLOG_INFO, &yline[2][x + roi.width], 16);
1101 winpr_HexDump(
"foo1", WLOG_INFO, &line1[x * 4], 16);
1102 winpr_HexDump(
"foo2", WLOG_INFO, &line2[x * 4], 16);
1110 printf(
"%s finished with %s\n", __func__, rc ?
"SUCCESS" :
"FAILURE");
1121static BOOL compare_rgb_to_yuv444(
prim_size_t roi, DWORD type)
1124 const UINT32 format = PIXEL_FORMAT_BGRA32;
1125 const size_t stride = 4ULL * roi.width;
1126 const UINT32 yuvStep[] = { roi.width, roi.width, roi.width };
1127 BYTE* yuv1[3] = { 0 };
1128 BYTE* yuv2[3] = { 0 };
1133 printf(
"primitives type %" PRIu32
" not supported, skipping\n", type);
1137 BYTE* rgb = calloc(roi.height, stride);
1139 primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
1143 if (!allocate_yuv(yuv1, roi) || !allocate_yuv(yuv2, roi))
1146 if (soft->RGBToYUV444_8u_P3AC4R(rgb, format, stride, yuv1, yuvStep, &roi) != PRIMITIVES_SUCCESS)
1148 if (prims->RGBToYUV444_8u_P3AC4R(rgb, format, stride, yuv2, yuvStep, &roi) !=
1152 for (
size_t y = 0; y < roi.height; y++)
1154 const BYTE* yline1[3] = {
1155 yuv1[0] + y * roi.width,
1156 yuv1[1] + y * roi.width,
1157 yuv1[2] + y * roi.width,
1159 const BYTE* yline2[3] = {
1160 yuv2[0] + y * roi.width,
1161 yuv2[1] + y * roi.width,
1162 yuv2[2] + y * roi.width,
1165 for (
size_t x = 0; x < ARRAYSIZE(yline1); x++)
1167 if (memcmp(yline1[x], yline2[x], yuvStep[x]) != 0)
1169 (void)fprintf(stderr,
"[%s] compare failed in line %" PRIuz, __func__, x);
1177 printf(
"%s finished with %s\n", __func__, rc ?
"SUCCESS" :
"FAILURE");
1188static BOOL compare_yuv420_to_rgb(
prim_size_t roi, DWORD type)
1191 const UINT32 format = PIXEL_FORMAT_BGRA32;
1192 BYTE* yuv[3] = { 0 };
1193 const UINT32 yuvStep[3] = { roi.width, roi.width / 2, roi.width / 2 };
1194 const size_t stride = 4ULL * roi.width;
1199 printf(
"primitives type %" PRIu32
" not supported, skipping\n", type);
1203 BYTE* rgb1 = calloc(roi.height, stride);
1204 BYTE* rgb2 = calloc(roi.height, stride);
1206 primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
1209 if (!allocate_yuv(yuv, roi) || !rgb1 || !rgb2)
1212 const BYTE* cyuv[3] = { yuv[0], yuv[1], yuv[2] };
1213 if (soft->YUV420ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb1, stride, format, &roi) !=
1216 if (prims->YUV420ToRGB_8u_P3AC4R(cyuv, yuvStep, rgb2, stride, format, &roi) !=
1220 for (
size_t y = 0; y < roi.height; y++)
1222 const BYTE* yline[3] = {
1223 yuv[0] + y * yuvStep[0],
1224 yuv[1] + y * yuvStep[1],
1225 yuv[2] + y * yuvStep[2],
1227 const BYTE* line1 = &rgb1[y * stride];
1228 const BYTE* line2 = &rgb2[y * stride];
1230 for (
size_t x = 0; x < roi.width; x++)
1232 const int Y = yline[0][x];
1233 const int U = yline[1][x / 2];
1234 const int V = yline[2][x / 2];
1235 const UINT32 color1 = FreeRDPReadColor(&line1[x * 4], format);
1236 const UINT32 color2 = FreeRDPReadColor(&line2[x * 4], format);
1241 FreeRDPSplitColor(color1, format, &r1, &g1, &b1, NULL, NULL);
1246 FreeRDPSplitColor(color2, format, &r2, &g2, &b2, NULL, NULL);
1248 const int dr12 = abs(r1 - r2);
1249 const int dg12 = abs(g1 - g2);
1250 const int db12 = abs(b1 - b2);
1252 if ((dr12 != 0) || (dg12 != 0) || (db12 != 0))
1255 printf(
"\tdiff 1/2: yuv {%d, %d, %d}, rgb {%d, %d, %d}\n", Y, U, V, dr12, dg12,
1260 if ((dr12 > 0) || (dg12 > 0) || (db12 > 0))
1262 printf(
"[%s] failed: r[%" PRIx8
"|%" PRIx8
"] g[%" PRIx8
"|%" PRIx8
"] b[%" PRIx8
1264 __func__, r1, r2, g1, g2, b1, b2);
1272 printf(
"%s finished with %s\n", __func__, rc ?
"SUCCESS" :
"FAILURE");
1280static BOOL similarYUV(
const BYTE* line1,
const BYTE* line2,
size_t len)
1282 for (
size_t x = 0; x < len; x++)
1284 const int a = line1[x];
1285 const int b = line2[x];
1286 const int diff = abs(a - b);
1294static int similarY(
const BYTE* a,
const BYTE* b,
size_t size,
size_t type)
1301 for (
size_t x = 0; x < size; x++)
1303 const int ba = a[x];
1304 const int bb = b[x];
1305 const int diff = abs(ba - bb);
1312 return memcmp(a, b, size);
1318static BOOL compare_rgb_to_yuv420(
prim_size_t roi, DWORD type)
1321 const UINT32 format = PIXEL_FORMAT_BGRA32;
1322 const size_t stride = 4ULL * roi.width;
1323 const UINT32 yuvStep[] = { roi.width, roi.width / 2, roi.width / 2 };
1324 BYTE* yuv1[3] = { 0 };
1325 BYTE* yuv2[3] = { 0 };
1330 printf(
"primitives type %" PRIu32
" not supported, skipping\n", type);
1334 BYTE* rgb = calloc(roi.height, stride);
1335 BYTE* rgbcopy = calloc(roi.height, stride);
1337 primitives_t* soft = primitives_get_by_type(PRIMITIVES_PURE_SOFT);
1338 if (!soft || !rgb || !rgbcopy)
1341 winpr_RAND(rgb, roi.height * stride);
1342 memcpy(rgbcopy, rgb, roi.height * stride);
1344 if (!allocate_yuv(yuv1, roi) || !allocate_yuv(yuv2, roi))
1347 if (soft->RGBToYUV420_8u_P3AC4R(rgb, format, stride, yuv1, yuvStep, &roi) != PRIMITIVES_SUCCESS)
1349 if (memcmp(rgb, rgbcopy, roi.height * stride) != 0)
1351 if (prims->RGBToYUV420_8u_P3AC4R(rgb, format, stride, yuv2, yuvStep, &roi) !=
1355 for (
size_t y = 0; y < roi.height; y++)
1358 if (((y + 1) >= roi.height) && ((y % 2) == 0))
1361 const BYTE* yline1[3] = {
1362 &yuv1[0][y * yuvStep[0]],
1363 &yuv1[1][(y / 2) * yuvStep[1]],
1364 &yuv1[2][(y / 2) * yuvStep[2]],
1366 const BYTE* yline2[3] = {
1367 &yuv2[0][y * yuvStep[0]],
1368 &yuv2[1][(y / 2) * yuvStep[1]],
1369 &yuv2[2][(y / 2) * yuvStep[2]],
1372 for (
size_t x = 0; x < ARRAYSIZE(yline1); x++)
1374 if (similarY(yline1[x], yline2[x], yuvStep[x], x) != 0)
1376 (void)fprintf(stderr,
1377 "[%s] compare failed in component %" PRIuz
", line %" PRIuz
"\n",
1379 (void)fprintf(stderr,
"[%s] roi %" PRIu32
"x%" PRIu32
"\n", __func__, roi.width,
1381 winpr_HexDump(TAG, WLOG_WARN, yline1[x], yuvStep[x]);
1382 winpr_HexDump(TAG, WLOG_WARN, yline2[x], yuvStep[x]);
1383 winpr_HexDump(TAG, WLOG_WARN, &rgb[y * stride], stride);
1391 printf(
"%s finished with %s\n", __func__, rc ?
"SUCCESS" :
"FAILURE");
1400int TestPrimitivesYUV(
int argc,
char* argv[])
1402 BOOL large = (argc > 1);
1411 int crc = sscanf(argv[1],
"%" PRIu32
"x%" PRIu32, &roi.width, &roi.height);
1420 get_size(large, &roi.width, &roi.height);
1422 prim_test_setup(FALSE);
1424 for (UINT32 type = PRIMITIVES_PURE_SOFT; type <= PRIMITIVES_AUTODETECT; type++)
1426 if (!compare_yuv444_to_rgb(roi, type))
1428 if (!compare_rgb_to_yuv444(roi, type))
1431 if (!compare_yuv420_to_rgb(roi, type))
1433 if (!compare_rgb_to_yuv420(roi, type))
1437 if (!run_tests(roi))
1442 printf(
"[%s] finished, status %s [%d]\n", __func__, (rc == 0) ?
"SUCCESS" :
"FAILURE", rc);