2 * Copyright © 2005 Eric Anholt
3 * Copyright © 2009 Chris Wilson
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of Eric Anholt not be used in
10 * advertising or publicity pertaining to distribution of the software without
11 * specific, written prior permission. Eric Anholt makes no
12 * representations about the suitability of this software for any purpose. It
13 * is provided "as is" without express or implied warranty.
15 * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21 * PERFORMANCE OF THIS SOFTWARE.
26 #include <stdlib.h> /* abort() */
33 #define ARRAY_LENGTH(A) ((int) (sizeof (A) / sizeof ((A) [0])))
34 #define min(a,b) ((a) <= (b) ? (a) : (b))
35 #define max(a,b) ((a) >= (b) ? (a) : (b))
37 typedef struct color_t color_t;
38 typedef struct format_t format_t;
39 typedef struct image_t image_t;
40 typedef struct operator_t operator_t;
49 pixman_format_code_t format;
53 static color_t colors[] =
55 /* these are premultiplied in main() */
56 { 1.0, 1.0, 1.0, 1.0 },
57 { 1.0, 0.0, 0.0, 1.0 },
58 { 0.0, 1.0, 0.0, 1.0 },
59 { 0.0, 0.0, 1.0, 1.0 },
60 { 0.0, 0.0, 0.0, 1.0 },
61 { 0.5, 0.0, 0.0, 0.5 },
65 _color_double_to_short (double d)
69 i = (uint32_t) (d * 65536);
76 compute_pixman_color (const color_t *color,
79 out->red = _color_double_to_short (color->r);
80 out->green = _color_double_to_short (color->g);
81 out->blue = _color_double_to_short (color->b);
82 out->alpha = _color_double_to_short (color->a);
85 static const format_t formats[] =
87 #define P(x) { PIXMAN_##x, #x }
98 /* XXX: and here the errors begin! */
146 pixman_image_t *image;
147 const format_t *format;
148 const color_t *color;
149 pixman_repeat_t repeat;
159 static const operator_t operators[] =
161 #define P(x) { PIXMAN_OP_##x, #x }
181 P(DISJOINT_OVER_REVERSE),
183 P(DISJOINT_IN_REVERSE),
185 P(DISJOINT_OUT_REVERSE),
187 P(DISJOINT_ATOP_REVERSE),
194 P(CONJOINT_OVER_REVERSE),
196 P(CONJOINT_IN_REVERSE),
198 P(CONJOINT_OUT_REVERSE),
200 P(CONJOINT_ATOP_REVERSE),
206 calc_op (pixman_op_t op, double src, double dst, double srca, double dsta)
208 #define mult_chan(src, dst, Fa, Fb) min ((src) * (Fa) + (dst) * (Fb), 1.0)
214 case PIXMAN_OP_CLEAR:
215 case PIXMAN_OP_DISJOINT_CLEAR:
216 case PIXMAN_OP_CONJOINT_CLEAR:
217 return mult_chan (src, dst, 0.0, 0.0);
220 case PIXMAN_OP_DISJOINT_SRC:
221 case PIXMAN_OP_CONJOINT_SRC:
222 return mult_chan (src, dst, 1.0, 0.0);
225 case PIXMAN_OP_DISJOINT_DST:
226 case PIXMAN_OP_CONJOINT_DST:
227 return mult_chan (src, dst, 0.0, 1.0);
230 return mult_chan (src, dst, 1.0, 1.0 - srca);
232 case PIXMAN_OP_OVER_REVERSE:
233 return mult_chan (src, dst, 1.0 - dsta, 1.0);
236 return mult_chan (src, dst, dsta, 0.0);
238 case PIXMAN_OP_IN_REVERSE:
239 return mult_chan (src, dst, 0.0, srca);
242 return mult_chan (src, dst, 1.0 - dsta, 0.0);
244 case PIXMAN_OP_OUT_REVERSE:
245 return mult_chan (src, dst, 0.0, 1.0 - srca);
248 return mult_chan (src, dst, dsta, 1.0 - srca);
250 case PIXMAN_OP_ATOP_REVERSE:
251 return mult_chan (src, dst, 1.0 - dsta, srca);
254 return mult_chan (src, dst, 1.0 - dsta, 1.0 - srca);
257 return mult_chan (src, dst, 1.0, 1.0);
259 case PIXMAN_OP_SATURATE:
260 case PIXMAN_OP_DISJOINT_OVER_REVERSE:
264 Fa = min (1.0, (1.0 - dsta) / srca);
265 return mult_chan (src, dst, Fa, 1.0);
267 case PIXMAN_OP_DISJOINT_OVER:
271 Fb = min (1.0, (1.0 - srca) / dsta);
272 return mult_chan (src, dst, 1.0, Fb);
274 case PIXMAN_OP_DISJOINT_IN:
278 Fa = max (0.0, 1.0 - (1.0 - dsta) / srca);
279 return mult_chan (src, dst, Fa, 0.0);
281 case PIXMAN_OP_DISJOINT_IN_REVERSE:
285 Fb = max (0.0, 1.0 - (1.0 - srca) / dsta);
286 return mult_chan (src, dst, 0.0, Fb);
288 case PIXMAN_OP_DISJOINT_OUT:
292 Fa = min (1.0, (1.0 - dsta) / srca);
293 return mult_chan (src, dst, Fa, 0.0);
295 case PIXMAN_OP_DISJOINT_OUT_REVERSE:
299 Fb = min (1.0, (1.0 - srca) / dsta);
300 return mult_chan (src, dst, 0.0, Fb);
302 case PIXMAN_OP_DISJOINT_ATOP:
306 Fa = max (0.0, 1.0 - (1.0 - dsta) / srca);
310 Fb = min (1.0, (1.0 - srca) / dsta);
311 return mult_chan (src, dst, Fa, Fb);
313 case PIXMAN_OP_DISJOINT_ATOP_REVERSE:
317 Fa = min (1.0, (1.0 - dsta) / srca);
321 Fb = max (0.0, 1.0 - (1.0 - srca) / dsta);
322 return mult_chan (src, dst, Fa, Fb);
324 case PIXMAN_OP_DISJOINT_XOR:
328 Fa = min (1.0, (1.0 - dsta) / srca);
332 Fb = min (1.0, (1.0 - srca) / dsta);
333 return mult_chan (src, dst, Fa, Fb);
335 case PIXMAN_OP_CONJOINT_OVER:
339 Fb = max (0.0, 1.0 - srca / dsta);
340 return mult_chan (src, dst, 1.0, Fb);
342 case PIXMAN_OP_CONJOINT_OVER_REVERSE:
346 Fa = max (0.0, 1.0 - dsta / srca);
347 return mult_chan (src, dst, Fa, 1.0);
349 case PIXMAN_OP_CONJOINT_IN:
353 Fa = min (1.0, dsta / srca);
354 return mult_chan (src, dst, Fa, 0.0);
356 case PIXMAN_OP_CONJOINT_IN_REVERSE:
360 Fb = min (1.0, srca / dsta);
361 return mult_chan (src, dst, 0.0, Fb);
363 case PIXMAN_OP_CONJOINT_OUT:
367 Fa = max (0.0, 1.0 - dsta / srca);
368 return mult_chan (src, dst, Fa, 0.0);
370 case PIXMAN_OP_CONJOINT_OUT_REVERSE:
374 Fb = max (0.0, 1.0 - srca / dsta);
375 return mult_chan (src, dst, 0.0, Fb);
377 case PIXMAN_OP_CONJOINT_ATOP:
381 Fa = min (1.0, dsta / srca);
385 Fb = max (0.0, 1.0 - srca / dsta);
386 return mult_chan (src, dst, Fa, Fb);
388 case PIXMAN_OP_CONJOINT_ATOP_REVERSE:
392 Fa = max (0.0, 1.0 - dsta / srca);
396 Fb = min (1.0, srca / dsta);
397 return mult_chan (src, dst, Fa, Fb);
399 case PIXMAN_OP_CONJOINT_XOR:
403 Fa = max (0.0, 1.0 - dsta / srca);
407 Fb = max (0.0, 1.0 - srca / dsta);
408 return mult_chan (src, dst, Fa, Fb);
410 case PIXMAN_OP_MULTIPLY:
411 case PIXMAN_OP_SCREEN:
412 case PIXMAN_OP_OVERLAY:
413 case PIXMAN_OP_DARKEN:
414 case PIXMAN_OP_LIGHTEN:
415 case PIXMAN_OP_COLOR_DODGE:
416 case PIXMAN_OP_COLOR_BURN:
417 case PIXMAN_OP_HARD_LIGHT:
418 case PIXMAN_OP_SOFT_LIGHT:
419 case PIXMAN_OP_DIFFERENCE:
420 case PIXMAN_OP_EXCLUSION:
421 case PIXMAN_OP_HSL_HUE:
422 case PIXMAN_OP_HSL_SATURATION:
423 case PIXMAN_OP_HSL_COLOR:
424 case PIXMAN_OP_HSL_LUMINOSITY:
432 do_composite (pixman_op_t op,
437 pixman_bool_t component_alpha)
439 color_t srcval, srcalpha;
450 else if (component_alpha)
452 srcval.r = src->r * mask->r;
453 srcval.g = src->g * mask->g;
454 srcval.b = src->b * mask->b;
455 srcval.a = src->a * mask->a;
457 srcalpha.r = src->a * mask->r;
458 srcalpha.g = src->a * mask->g;
459 srcalpha.b = src->a * mask->b;
460 srcalpha.a = src->a * mask->a;
464 srcval.r = src->r * mask->a;
465 srcval.g = src->g * mask->a;
466 srcval.b = src->b * mask->a;
467 srcval.a = src->a * mask->a;
469 srcalpha.r = src->a * mask->a;
470 srcalpha.g = src->a * mask->a;
471 srcalpha.b = src->a * mask->a;
472 srcalpha.a = src->a * mask->a;
475 result->r = calc_op (op, srcval.r, dst->r, srcalpha.r, dst->a);
476 result->g = calc_op (op, srcval.g, dst->g, srcalpha.g, dst->a);
477 result->b = calc_op (op, srcval.b, dst->b, srcalpha.b, dst->a);
478 result->a = calc_op (op, srcval.a, dst->a, srcalpha.a, dst->a);
482 color_correct (pixman_format_code_t format,
485 #define round_pix(pix, mask) \
486 ((int)((pix) * (mask) + .5) / (double) (mask))
488 if (PIXMAN_FORMAT_R (format) == 0)
496 color->r = round_pix (color->r, PIXMAN_FORMAT_R (format));
497 color->g = round_pix (color->g, PIXMAN_FORMAT_G (format));
498 color->b = round_pix (color->b, PIXMAN_FORMAT_B (format));
501 if (PIXMAN_FORMAT_A (format) == 0)
504 color->a = round_pix (color->a, PIXMAN_FORMAT_A (format));
510 get_pixel (pixman_image_t *image,
511 pixman_format_code_t format,
514 #define MASK(N) ((1UL << (N))-1)
516 unsigned long rs, gs, bs, as;
520 val = *(unsigned long *) pixman_image_get_data (image);
521 #ifdef WORDS_BIGENDIAN
522 val >>= 8 * sizeof(val) - PIXMAN_FORMAT_BPP (format);
525 /* Number of bits in each channel */
526 a = PIXMAN_FORMAT_A (format);
527 r = PIXMAN_FORMAT_R (format);
528 g = PIXMAN_FORMAT_G (format);
529 b = PIXMAN_FORMAT_B (format);
531 switch (PIXMAN_FORMAT_TYPE (format))
533 case PIXMAN_TYPE_ARGB:
540 case PIXMAN_TYPE_ABGR:
547 case PIXMAN_TYPE_BGRA:
549 rs = PIXMAN_FORMAT_BPP (format) - (b + g + r);
561 case PIXMAN_TYPE_OTHER:
562 case PIXMAN_TYPE_COLOR:
563 case PIXMAN_TYPE_GRAY:
564 case PIXMAN_TYPE_YUY2:
565 case PIXMAN_TYPE_YV12:
576 color->a = ((val >> as) & MASK (a)) / (double) MASK (a);
582 color->r = ((val >> rs) & MASK (r)) / (double) MASK (r);
583 color->g = ((val >> gs) & MASK (g)) / (double) MASK (g);
584 color->b = ((val >> bs) & MASK (b)) / (double) MASK (b);
597 eval_diff (color_t *expected, color_t *test)
599 double rscale, gscale, bscale, ascale;
600 double rdiff, gdiff, bdiff, adiff;
602 /* XXX: Need to be provided mask shifts so we can produce useful error
605 rscale = 1.0 * (1 << 5);
606 gscale = 1.0 * (1 << 6);
607 bscale = 1.0 * (1 << 5);
610 rdiff = fabs (test->r - expected->r) * rscale;
611 bdiff = fabs (test->g - expected->g) * gscale;
612 gdiff = fabs (test->b - expected->b) * bscale;
613 adiff = fabs (test->a - expected->a) * ascale;
615 return max (max (max (rdiff, gdiff), bdiff), adiff);
619 describe_image (image_t *info, char *buf, int buflen)
623 snprintf (buf, buflen, "%s %dx%d%s",
625 info->size, info->size,
626 info->repeat ? "R" :"");
630 snprintf (buf, buflen, "solid");
636 /* Test a composite of a given operation, source, mask, and destination
638 * Fills the window, and samples from the 0,0 pixel corner.
641 composite_test (image_t *dst,
642 const operator_t *op,
645 pixman_bool_t component_alpha)
648 pixman_rectangle16_t rect;
649 color_t expected, result, tdst, tsrc, tmsk;
651 pixman_bool_t success = TRUE;
653 compute_pixman_color (dst->color, &fill);
655 rect.width = rect.height = dst->size;
656 pixman_image_fill_rectangles (PIXMAN_OP_SRC, dst->image,
661 pixman_image_set_component_alpha (mask->image, component_alpha);
662 pixman_image_composite (op->op, src->image, mask->image, dst->image,
666 dst->size, dst->size);
671 color_correct (mask->format->format, &tmsk);
673 if (component_alpha &&
674 PIXMAN_FORMAT_R (mask->format->format) == 0)
676 /* Ax component-alpha masks expand alpha into
677 * all color channels.
679 tmsk.r = tmsk.g = tmsk.b = tmsk.a;
685 pixman_image_composite (op->op, src->image, NULL, dst->image,
689 dst->size, dst->size);
691 get_pixel (dst->image, dst->format->format, &result);
694 color_correct (dst->format->format, &tdst);
697 color_correct (src->format->format, &tsrc);
698 do_composite (op->op, &tsrc, mask ? &tmsk : NULL, &tdst,
699 &expected, component_alpha);
700 color_correct (dst->format->format, &expected);
702 diff = eval_diff (&expected, &result);
707 snprintf (buf, sizeof (buf),
710 component_alpha ? "CA " : "");
712 printf ("%s test error of %.4f --\n"
714 "got: %.2f %.2f %.2f %.2f [%08lx]\n"
715 "expected: %.2f %.2f %.2f %.2f\n",
717 result.r, result.g, result.b, result.a,
718 *(unsigned long *) pixman_image_get_data (dst->image),
719 expected.r, expected.g, expected.b, expected.a);
723 printf ("src color: %.2f %.2f %.2f %.2f\n"
724 "msk color: %.2f %.2f %.2f %.2f\n"
725 "dst color: %.2f %.2f %.2f %.2f\n",
726 src->color->r, src->color->g,
727 src->color->b, src->color->a,
728 mask->color->r, mask->color->g,
729 mask->color->b, mask->color->a,
730 dst->color->r, dst->color->g,
731 dst->color->b, dst->color->a);
732 printf ("src: %s, ", describe_image (src, buf, sizeof (buf)));
733 printf ("mask: %s, ", describe_image (mask, buf, sizeof (buf)));
734 printf ("dst: %s\n\n", describe_image (dst, buf, sizeof (buf)));
738 printf ("src color: %.2f %.2f %.2f %.2f\n"
739 "dst color: %.2f %.2f %.2f %.2f\n",
740 src->color->r, src->color->g,
741 src->color->b, src->color->a,
742 dst->color->r, dst->color->g,
743 dst->color->b, dst->color->a);
744 printf ("src: %s, ", describe_image (src, buf, sizeof (buf)));
745 printf ("dst: %s\n\n", describe_image (dst, buf, sizeof (buf)));
754 #define REPEAT 0x01000000
755 #define FLAGS 0xff000000
758 image_init (image_t *info,
765 info->color = &colors[color];
766 compute_pixman_color (info->color, &fill);
768 info->format = &formats[format];
769 info->size = size & ~FLAGS;
770 info->repeat = PIXMAN_REPEAT_NONE;
774 pixman_rectangle16_t rect;
776 info->image = pixman_image_create_bits (info->format->format,
777 info->size, info->size,
781 rect.width = rect.height = info->size;
782 pixman_image_fill_rectangles (PIXMAN_OP_SRC, info->image, &fill,
787 pixman_image_set_repeat (info->image, PIXMAN_REPEAT_NORMAL);
788 info->repeat = PIXMAN_REPEAT_NORMAL;
793 info->image = pixman_image_create_solid_fill (&fill);
798 image_fini (image_t *info)
800 pixman_image_unref (info->image);
806 pixman_bool_t ok, group_ok = TRUE, ca;
808 int tests_passed = 0, tests_total = 0;
809 int sizes[] = { 1, 1 | REPEAT, 10 };
812 for (i = 0; i < ARRAY_LENGTH (colors); i++)
814 colors[i].r *= colors[i].a;
815 colors[i].g *= colors[i].a;
816 colors[i].b *= colors[i].a;
819 num_tests = ARRAY_LENGTH (colors) * ARRAY_LENGTH (formats);
821 for (d = 0; d < num_tests; d++)
826 &dst, d / ARRAY_LENGTH (formats), d % ARRAY_LENGTH (formats), 1);
829 for (s = -ARRAY_LENGTH (colors);
830 s < ARRAY_LENGTH (sizes) * num_tests;
837 image_init (&src, -s - 1, 0, 0);
842 s / ARRAY_LENGTH (sizes) / ARRAY_LENGTH (formats),
843 s / ARRAY_LENGTH (sizes) % ARRAY_LENGTH (formats),
844 sizes[s % ARRAY_LENGTH (sizes)]);
847 for (m = -ARRAY_LENGTH (colors);
848 m < ARRAY_LENGTH (sizes) * num_tests;
855 image_init (&mask, -m - 1, 0, 0);
861 m / ARRAY_LENGTH (sizes) / ARRAY_LENGTH (formats),
862 m / ARRAY_LENGTH (sizes) % ARRAY_LENGTH (formats),
863 sizes[m % ARRAY_LENGTH (sizes)]);
866 for (ca = -1; ca <= 1; ca++)
868 for (i = 0; i < ARRAY_LENGTH (operators); i++)
870 const operator_t *op = &operators[i];
875 ok = composite_test (&dst, op, &src, NULL, FALSE);
878 ok = composite_test (&dst, op, &src, &mask, FALSE);
881 ok = composite_test (&dst, op, &src, &mask,
882 mask.size? TRUE : FALSE);
887 group_ok = group_ok && ok;
900 return group_ok == FALSE;