| File: | test/composite.c |
| Location: | line 539, column 14 |
| Description: | The right operand to '+' is always 0 |
| 1 | /* | ||
| 2 | * Copyright © 2005 Eric Anholt | ||
| 3 | * Copyright © 2009 Chris Wilson | ||
| 4 | * Copyright © 2010 Soeren Sandmann | ||
| 5 | * Copyright © 2010 Red Hat, Inc. | ||
| 6 | * | ||
| 7 | * Permission to use, copy, modify, distribute, and sell this software and its | ||
| 8 | * documentation for any purpose is hereby granted without fee, provided that | ||
| 9 | * the above copyright notice appear in all copies and that both that | ||
| 10 | * copyright notice and this permission notice appear in supporting | ||
| 11 | * documentation, and that the name of Eric Anholt not be used in | ||
| 12 | * advertising or publicity pertaining to distribution of the software without | ||
| 13 | * specific, written prior permission. Eric Anholt makes no | ||
| 14 | * representations about the suitability of this software for any purpose. It | ||
| 15 | * is provided "as is" without express or implied warranty. | ||
| 16 | * | ||
| 17 | * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | ||
| 18 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO | ||
| 19 | * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR | ||
| 20 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, | ||
| 21 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER | ||
| 22 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
| 23 | * PERFORMANCE OF THIS SOFTWARE. | ||
| 24 | */ | ||
| 25 | #define PIXMAN_USE_INTERNAL_API | ||
| 26 | #include <pixman.h> | ||
| 27 | #include <stdio.h> | ||
| 28 | #include <stdlib.h> /* abort() */ | ||
| 29 | #include <math.h> | ||
| 30 | #include <config.h> | ||
| 31 | #include <time.h> | ||
| 32 | #include "utils.h" | ||
| 33 | |||
| 34 | typedef struct color_t color_t; | ||
| 35 | typedef struct format_t format_t; | ||
| 36 | typedef struct image_t image_t; | ||
| 37 | typedef struct operator_t operator_t; | ||
| 38 | |||
| 39 | struct color_t | ||
| 40 | { | ||
| 41 | double r, g, b, a; | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct format_t | ||
| 45 | { | ||
| 46 | pixman_format_code_t format; | ||
| 47 | const char *name; | ||
| 48 | }; | ||
| 49 | |||
| 50 | static const color_t colors[] = | ||
| 51 | { | ||
| 52 | { 1.0, 1.0, 1.0, 1.0 }, | ||
| 53 | { 1.0, 1.0, 1.0, 0.0 }, | ||
| 54 | { 0.0, 0.0, 0.0, 1.0 }, | ||
| 55 | { 0.0, 0.0, 0.0, 0.0 }, | ||
| 56 | { 1.0, 0.0, 0.0, 1.0 }, | ||
| 57 | { 0.0, 1.0, 0.0, 1.0 }, | ||
| 58 | { 0.0, 0.0, 1.0, 1.0 }, | ||
| 59 | { 0.5, 0.0, 0.0, 0.5 }, | ||
| 60 | }; | ||
| 61 | |||
| 62 | static uint16_t | ||
| 63 | _color_double_to_short (double d) | ||
| 64 | { | ||
| 65 | uint32_t i; | ||
| 66 | |||
| 67 | i = (uint32_t) (d * 65536); | ||
| 68 | i -= (i >> 16); | ||
| 69 | |||
| 70 | return i; | ||
| 71 | } | ||
| 72 | |||
| 73 | static void | ||
| 74 | compute_pixman_color (const color_t *color, | ||
| 75 | pixman_color_t *out) | ||
| 76 | { | ||
| 77 | out->red = _color_double_to_short (color->r); | ||
| 78 | out->green = _color_double_to_short (color->g); | ||
| 79 | out->blue = _color_double_to_short (color->b); | ||
| 80 | out->alpha = _color_double_to_short (color->a); | ||
| 81 | } | ||
| 82 | |||
| 83 | #define REPEAT0x01000000 0x01000000 | ||
| 84 | #define FLAGS0xff000000 0xff000000 | ||
| 85 | |||
| 86 | static const int sizes[] = | ||
| 87 | { | ||
| 88 | 0, | ||
| 89 | 1, | ||
| 90 | 1 | REPEAT0x01000000, | ||
| 91 | 10 | ||
| 92 | }; | ||
| 93 | |||
| 94 | static const format_t formats[] = | ||
| 95 | { | ||
| 96 | #define P(x) { PIXMAN_##x, #x } | ||
| 97 | |||
| 98 | /* 32 bpp formats */ | ||
| 99 | P(a8r8g8b8), | ||
| 100 | P(x8r8g8b8), | ||
| 101 | P(a8b8g8r8), | ||
| 102 | P(x8b8g8r8), | ||
| 103 | P(b8g8r8a8), | ||
| 104 | P(b8g8r8x8), | ||
| 105 | P(x2r10g10b10), | ||
| 106 | P(x2b10g10r10), | ||
| 107 | P(a2r10g10b10), | ||
| 108 | P(a2b10g10r10), | ||
| 109 | |||
| 110 | /* 24 bpp formats */ | ||
| 111 | P(r8g8b8), | ||
| 112 | P(b8g8r8), | ||
| 113 | P(r5g6b5), | ||
| 114 | P(b5g6r5), | ||
| 115 | |||
| 116 | /* 16 bpp formats */ | ||
| 117 | P(x1r5g5b5), | ||
| 118 | P(x1b5g5r5), | ||
| 119 | P(a1r5g5b5), | ||
| 120 | P(a1b5g5r5), | ||
| 121 | P(a4b4g4r4), | ||
| 122 | P(x4b4g4r4), | ||
| 123 | P(a4r4g4b4), | ||
| 124 | P(x4r4g4b4), | ||
| 125 | |||
| 126 | /* 8 bpp formats */ | ||
| 127 | P(a8), | ||
| 128 | P(r3g3b2), | ||
| 129 | P(b2g3r3), | ||
| 130 | P(a2r2g2b2), | ||
| 131 | P(a2b2g2r2), | ||
| 132 | P(x4a4), | ||
| 133 | |||
| 134 | /* 4 bpp formats */ | ||
| 135 | P(a4), | ||
| 136 | P(r1g2b1), | ||
| 137 | P(b1g2r1), | ||
| 138 | P(a1r1g1b1), | ||
| 139 | P(a1b1g1r1), | ||
| 140 | |||
| 141 | /* 1 bpp formats */ | ||
| 142 | P(a1) | ||
| 143 | #undef P | ||
| 144 | }; | ||
| 145 | |||
| 146 | struct image_t | ||
| 147 | { | ||
| 148 | pixman_image_t *image; | ||
| 149 | const format_t *format; | ||
| 150 | const color_t *color; | ||
| 151 | pixman_repeat_t repeat; | ||
| 152 | int size; | ||
| 153 | }; | ||
| 154 | |||
| 155 | struct operator_t | ||
| 156 | { | ||
| 157 | pixman_op_t op; | ||
| 158 | const char *name; | ||
| 159 | }; | ||
| 160 | |||
| 161 | static const operator_t operators[] = | ||
| 162 | { | ||
| 163 | #define P(x) { PIXMAN_OP_##x, #x } | ||
| 164 | P(CLEAR), | ||
| 165 | P(SRC), | ||
| 166 | P(DST), | ||
| 167 | P(OVER), | ||
| 168 | P(OVER_REVERSE), | ||
| 169 | P(IN), | ||
| 170 | P(IN_REVERSE), | ||
| 171 | P(OUT), | ||
| 172 | P(OUT_REVERSE), | ||
| 173 | P(ATOP), | ||
| 174 | P(ATOP_REVERSE), | ||
| 175 | P(XOR), | ||
| 176 | P(ADD), | ||
| 177 | P(SATURATE), | ||
| 178 | |||
| 179 | P(DISJOINT_CLEAR), | ||
| 180 | P(DISJOINT_SRC), | ||
| 181 | P(DISJOINT_DST), | ||
| 182 | P(DISJOINT_OVER), | ||
| 183 | P(DISJOINT_OVER_REVERSE), | ||
| 184 | P(DISJOINT_IN), | ||
| 185 | P(DISJOINT_IN_REVERSE), | ||
| 186 | P(DISJOINT_OUT), | ||
| 187 | P(DISJOINT_OUT_REVERSE), | ||
| 188 | P(DISJOINT_ATOP), | ||
| 189 | P(DISJOINT_ATOP_REVERSE), | ||
| 190 | P(DISJOINT_XOR), | ||
| 191 | |||
| 192 | P(CONJOINT_CLEAR), | ||
| 193 | P(CONJOINT_SRC), | ||
| 194 | P(CONJOINT_DST), | ||
| 195 | P(CONJOINT_OVER), | ||
| 196 | P(CONJOINT_OVER_REVERSE), | ||
| 197 | P(CONJOINT_IN), | ||
| 198 | P(CONJOINT_IN_REVERSE), | ||
| 199 | P(CONJOINT_OUT), | ||
| 200 | P(CONJOINT_OUT_REVERSE), | ||
| 201 | P(CONJOINT_ATOP), | ||
| 202 | P(CONJOINT_ATOP_REVERSE), | ||
| 203 | P(CONJOINT_XOR), | ||
| 204 | #undef P | ||
| 205 | }; | ||
| 206 | |||
| 207 | static double | ||
| 208 | calc_op (pixman_op_t op, double src, double dst, double srca, double dsta) | ||
| 209 | { | ||
| 210 | #define mult_chan(src, dst, Fa, Fb) MIN ((src) * (Fa) + (dst) * (Fb), 1.0)(((src) * (Fa) + (dst) * (Fb) < 1.0) ? (src) * (Fa) + (dst ) * (Fb) : 1.0) | ||
| 211 | |||
| 212 | double Fa, Fb; | ||
| 213 | |||
| 214 | switch (op) | ||
| 215 | { | ||
| 216 | case PIXMAN_OP_CLEAR: | ||
| 217 | case PIXMAN_OP_DISJOINT_CLEAR: | ||
| 218 | case PIXMAN_OP_CONJOINT_CLEAR: | ||
| 219 | return mult_chan (src, dst, 0.0, 0.0); | ||
| 220 | |||
| 221 | case PIXMAN_OP_SRC: | ||
| 222 | case PIXMAN_OP_DISJOINT_SRC: | ||
| 223 | case PIXMAN_OP_CONJOINT_SRC: | ||
| 224 | return mult_chan (src, dst, 1.0, 0.0); | ||
| 225 | |||
| 226 | case PIXMAN_OP_DST: | ||
| 227 | case PIXMAN_OP_DISJOINT_DST: | ||
| 228 | case PIXMAN_OP_CONJOINT_DST: | ||
| 229 | return mult_chan (src, dst, 0.0, 1.0); | ||
| 230 | |||
| 231 | case PIXMAN_OP_OVER: | ||
| 232 | return mult_chan (src, dst, 1.0, 1.0 - srca); | ||
| 233 | |||
| 234 | case PIXMAN_OP_OVER_REVERSE: | ||
| 235 | return mult_chan (src, dst, 1.0 - dsta, 1.0); | ||
| 236 | |||
| 237 | case PIXMAN_OP_IN: | ||
| 238 | return mult_chan (src, dst, dsta, 0.0); | ||
| 239 | |||
| 240 | case PIXMAN_OP_IN_REVERSE: | ||
| 241 | return mult_chan (src, dst, 0.0, srca); | ||
| 242 | |||
| 243 | case PIXMAN_OP_OUT: | ||
| 244 | return mult_chan (src, dst, 1.0 - dsta, 0.0); | ||
| 245 | |||
| 246 | case PIXMAN_OP_OUT_REVERSE: | ||
| 247 | return mult_chan (src, dst, 0.0, 1.0 - srca); | ||
| 248 | |||
| 249 | case PIXMAN_OP_ATOP: | ||
| 250 | return mult_chan (src, dst, dsta, 1.0 - srca); | ||
| 251 | |||
| 252 | case PIXMAN_OP_ATOP_REVERSE: | ||
| 253 | return mult_chan (src, dst, 1.0 - dsta, srca); | ||
| 254 | |||
| 255 | case PIXMAN_OP_XOR: | ||
| 256 | return mult_chan (src, dst, 1.0 - dsta, 1.0 - srca); | ||
| 257 | |||
| 258 | case PIXMAN_OP_ADD: | ||
| 259 | return mult_chan (src, dst, 1.0, 1.0); | ||
| 260 | |||
| 261 | case PIXMAN_OP_SATURATE: | ||
| 262 | case PIXMAN_OP_DISJOINT_OVER_REVERSE: | ||
| 263 | if (srca == 0.0) | ||
| 264 | Fa = 1.0; | ||
| 265 | else | ||
| 266 | Fa = MIN (1.0, (1.0 - dsta) / srca)((1.0 < (1.0 - dsta) / srca) ? 1.0 : (1.0 - dsta) / srca); | ||
| 267 | return mult_chan (src, dst, Fa, 1.0); | ||
| 268 | |||
| 269 | case PIXMAN_OP_DISJOINT_OVER: | ||
| 270 | if (dsta == 0.0) | ||
| 271 | Fb = 1.0; | ||
| 272 | else | ||
| 273 | Fb = MIN (1.0, (1.0 - srca) / dsta)((1.0 < (1.0 - srca) / dsta) ? 1.0 : (1.0 - srca) / dsta); | ||
| 274 | return mult_chan (src, dst, 1.0, Fb); | ||
| 275 | |||
| 276 | case PIXMAN_OP_DISJOINT_IN: | ||
| 277 | if (srca == 0.0) | ||
| 278 | Fa = 0.0; | ||
| 279 | else | ||
| 280 | Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca)((0.0 > 1.0 - (1.0 - dsta) / srca) ? 0.0 : 1.0 - (1.0 - dsta ) / srca); | ||
| 281 | return mult_chan (src, dst, Fa, 0.0); | ||
| 282 | |||
| 283 | case PIXMAN_OP_DISJOINT_IN_REVERSE: | ||
| 284 | if (dsta == 0.0) | ||
| 285 | Fb = 0.0; | ||
| 286 | else | ||
| 287 | Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta)((0.0 > 1.0 - (1.0 - srca) / dsta) ? 0.0 : 1.0 - (1.0 - srca ) / dsta); | ||
| 288 | return mult_chan (src, dst, 0.0, Fb); | ||
| 289 | |||
| 290 | case PIXMAN_OP_DISJOINT_OUT: | ||
| 291 | if (srca == 0.0) | ||
| 292 | Fa = 1.0; | ||
| 293 | else | ||
| 294 | Fa = MIN (1.0, (1.0 - dsta) / srca)((1.0 < (1.0 - dsta) / srca) ? 1.0 : (1.0 - dsta) / srca); | ||
| 295 | return mult_chan (src, dst, Fa, 0.0); | ||
| 296 | |||
| 297 | case PIXMAN_OP_DISJOINT_OUT_REVERSE: | ||
| 298 | if (dsta == 0.0) | ||
| 299 | Fb = 1.0; | ||
| 300 | else | ||
| 301 | Fb = MIN (1.0, (1.0 - srca) / dsta)((1.0 < (1.0 - srca) / dsta) ? 1.0 : (1.0 - srca) / dsta); | ||
| 302 | return mult_chan (src, dst, 0.0, Fb); | ||
| 303 | |||
| 304 | case PIXMAN_OP_DISJOINT_ATOP: | ||
| 305 | if (srca == 0.0) | ||
| 306 | Fa = 0.0; | ||
| 307 | else | ||
| 308 | Fa = MAX (0.0, 1.0 - (1.0 - dsta) / srca)((0.0 > 1.0 - (1.0 - dsta) / srca) ? 0.0 : 1.0 - (1.0 - dsta ) / srca); | ||
| 309 | if (dsta == 0.0) | ||
| 310 | Fb = 1.0; | ||
| 311 | else | ||
| 312 | Fb = MIN (1.0, (1.0 - srca) / dsta)((1.0 < (1.0 - srca) / dsta) ? 1.0 : (1.0 - srca) / dsta); | ||
| 313 | return mult_chan (src, dst, Fa, Fb); | ||
| 314 | |||
| 315 | case PIXMAN_OP_DISJOINT_ATOP_REVERSE: | ||
| 316 | if (srca == 0.0) | ||
| 317 | Fa = 1.0; | ||
| 318 | else | ||
| 319 | Fa = MIN (1.0, (1.0 - dsta) / srca)((1.0 < (1.0 - dsta) / srca) ? 1.0 : (1.0 - dsta) / srca); | ||
| 320 | if (dsta == 0.0) | ||
| 321 | Fb = 0.0; | ||
| 322 | else | ||
| 323 | Fb = MAX (0.0, 1.0 - (1.0 - srca) / dsta)((0.0 > 1.0 - (1.0 - srca) / dsta) ? 0.0 : 1.0 - (1.0 - srca ) / dsta); | ||
| 324 | return mult_chan (src, dst, Fa, Fb); | ||
| 325 | |||
| 326 | case PIXMAN_OP_DISJOINT_XOR: | ||
| 327 | if (srca == 0.0) | ||
| 328 | Fa = 1.0; | ||
| 329 | else | ||
| 330 | Fa = MIN (1.0, (1.0 - dsta) / srca)((1.0 < (1.0 - dsta) / srca) ? 1.0 : (1.0 - dsta) / srca); | ||
| 331 | if (dsta == 0.0) | ||
| 332 | Fb = 1.0; | ||
| 333 | else | ||
| 334 | Fb = MIN (1.0, (1.0 - srca) / dsta)((1.0 < (1.0 - srca) / dsta) ? 1.0 : (1.0 - srca) / dsta); | ||
| 335 | return mult_chan (src, dst, Fa, Fb); | ||
| 336 | |||
| 337 | case PIXMAN_OP_CONJOINT_OVER: | ||
| 338 | if (dsta == 0.0) | ||
| 339 | Fb = 0.0; | ||
| 340 | else | ||
| 341 | Fb = MAX (0.0, 1.0 - srca / dsta)((0.0 > 1.0 - srca / dsta) ? 0.0 : 1.0 - srca / dsta); | ||
| 342 | return mult_chan (src, dst, 1.0, Fb); | ||
| 343 | |||
| 344 | case PIXMAN_OP_CONJOINT_OVER_REVERSE: | ||
| 345 | if (srca == 0.0) | ||
| 346 | Fa = 0.0; | ||
| 347 | else | ||
| 348 | Fa = MAX (0.0, 1.0 - dsta / srca)((0.0 > 1.0 - dsta / srca) ? 0.0 : 1.0 - dsta / srca); | ||
| 349 | return mult_chan (src, dst, Fa, 1.0); | ||
| 350 | |||
| 351 | case PIXMAN_OP_CONJOINT_IN: | ||
| 352 | if (srca == 0.0) | ||
| 353 | Fa = 1.0; | ||
| 354 | else | ||
| 355 | Fa = MIN (1.0, dsta / srca)((1.0 < dsta / srca) ? 1.0 : dsta / srca); | ||
| 356 | return mult_chan (src, dst, Fa, 0.0); | ||
| 357 | |||
| 358 | case PIXMAN_OP_CONJOINT_IN_REVERSE: | ||
| 359 | if (dsta == 0.0) | ||
| 360 | Fb = 1.0; | ||
| 361 | else | ||
| 362 | Fb = MIN (1.0, srca / dsta)((1.0 < srca / dsta) ? 1.0 : srca / dsta); | ||
| 363 | return mult_chan (src, dst, 0.0, Fb); | ||
| 364 | |||
| 365 | case PIXMAN_OP_CONJOINT_OUT: | ||
| 366 | if (srca == 0.0) | ||
| 367 | Fa = 0.0; | ||
| 368 | else | ||
| 369 | Fa = MAX (0.0, 1.0 - dsta / srca)((0.0 > 1.0 - dsta / srca) ? 0.0 : 1.0 - dsta / srca); | ||
| 370 | return mult_chan (src, dst, Fa, 0.0); | ||
| 371 | |||
| 372 | case PIXMAN_OP_CONJOINT_OUT_REVERSE: | ||
| 373 | if (dsta == 0.0) | ||
| 374 | Fb = 0.0; | ||
| 375 | else | ||
| 376 | Fb = MAX (0.0, 1.0 - srca / dsta)((0.0 > 1.0 - srca / dsta) ? 0.0 : 1.0 - srca / dsta); | ||
| 377 | return mult_chan (src, dst, 0.0, Fb); | ||
| 378 | |||
| 379 | case PIXMAN_OP_CONJOINT_ATOP: | ||
| 380 | if (srca == 0.0) | ||
| 381 | Fa = 1.0; | ||
| 382 | else | ||
| 383 | Fa = MIN (1.0, dsta / srca)((1.0 < dsta / srca) ? 1.0 : dsta / srca); | ||
| 384 | if (dsta == 0.0) | ||
| 385 | Fb = 0.0; | ||
| 386 | else | ||
| 387 | Fb = MAX (0.0, 1.0 - srca / dsta)((0.0 > 1.0 - srca / dsta) ? 0.0 : 1.0 - srca / dsta); | ||
| 388 | return mult_chan (src, dst, Fa, Fb); | ||
| 389 | |||
| 390 | case PIXMAN_OP_CONJOINT_ATOP_REVERSE: | ||
| 391 | if (srca == 0.0) | ||
| 392 | Fa = 0.0; | ||
| 393 | else | ||
| 394 | Fa = MAX (0.0, 1.0 - dsta / srca)((0.0 > 1.0 - dsta / srca) ? 0.0 : 1.0 - dsta / srca); | ||
| 395 | if (dsta == 0.0) | ||
| 396 | Fb = 1.0; | ||
| 397 | else | ||
| 398 | Fb = MIN (1.0, srca / dsta)((1.0 < srca / dsta) ? 1.0 : srca / dsta); | ||
| 399 | return mult_chan (src, dst, Fa, Fb); | ||
| 400 | |||
| 401 | case PIXMAN_OP_CONJOINT_XOR: | ||
| 402 | if (srca == 0.0) | ||
| 403 | Fa = 0.0; | ||
| 404 | else | ||
| 405 | Fa = MAX (0.0, 1.0 - dsta / srca)((0.0 > 1.0 - dsta / srca) ? 0.0 : 1.0 - dsta / srca); | ||
| 406 | if (dsta == 0.0) | ||
| 407 | Fb = 0.0; | ||
| 408 | else | ||
| 409 | Fb = MAX (0.0, 1.0 - srca / dsta)((0.0 > 1.0 - srca / dsta) ? 0.0 : 1.0 - srca / dsta); | ||
| 410 | return mult_chan (src, dst, Fa, Fb); | ||
| 411 | |||
| 412 | case PIXMAN_OP_MULTIPLY: | ||
| 413 | case PIXMAN_OP_SCREEN: | ||
| 414 | case PIXMAN_OP_OVERLAY: | ||
| 415 | case PIXMAN_OP_DARKEN: | ||
| 416 | case PIXMAN_OP_LIGHTEN: | ||
| 417 | case PIXMAN_OP_COLOR_DODGE: | ||
| 418 | case PIXMAN_OP_COLOR_BURN: | ||
| 419 | case PIXMAN_OP_HARD_LIGHT: | ||
| 420 | case PIXMAN_OP_SOFT_LIGHT: | ||
| 421 | case PIXMAN_OP_DIFFERENCE: | ||
| 422 | case PIXMAN_OP_EXCLUSION: | ||
| 423 | case PIXMAN_OP_HSL_HUE: | ||
| 424 | case PIXMAN_OP_HSL_SATURATION: | ||
| 425 | case PIXMAN_OP_HSL_COLOR: | ||
| 426 | case PIXMAN_OP_HSL_LUMINOSITY: | ||
| 427 | default: | ||
| 428 | abort(); | ||
| 429 | } | ||
| 430 | #undef mult_chan | ||
| 431 | } | ||
| 432 | |||
| 433 | static void | ||
| 434 | do_composite (pixman_op_t op, | ||
| 435 | const color_t *src, | ||
| 436 | const color_t *mask, | ||
| 437 | const color_t *dst, | ||
| 438 | color_t *result, | ||
| 439 | pixman_bool_t component_alpha) | ||
| 440 | { | ||
| 441 | color_t srcval, srcalpha; | ||
| 442 | |||
| 443 | if (mask == NULL((void*)0)) | ||
| 444 | { | ||
| 445 | srcval = *src; | ||
| 446 | |||
| 447 | srcalpha.r = src->a; | ||
| 448 | srcalpha.g = src->a; | ||
| 449 | srcalpha.b = src->a; | ||
| 450 | srcalpha.a = src->a; | ||
| 451 | } | ||
| 452 | else if (component_alpha) | ||
| 453 | { | ||
| 454 | srcval.r = src->r * mask->r; | ||
| 455 | srcval.g = src->g * mask->g; | ||
| 456 | srcval.b = src->b * mask->b; | ||
| 457 | srcval.a = src->a * mask->a; | ||
| 458 | |||
| 459 | srcalpha.r = src->a * mask->r; | ||
| 460 | srcalpha.g = src->a * mask->g; | ||
| 461 | srcalpha.b = src->a * mask->b; | ||
| 462 | srcalpha.a = src->a * mask->a; | ||
| 463 | } | ||
| 464 | else | ||
| 465 | { | ||
| 466 | srcval.r = src->r * mask->a; | ||
| 467 | srcval.g = src->g * mask->a; | ||
| 468 | srcval.b = src->b * mask->a; | ||
| 469 | srcval.a = src->a * mask->a; | ||
| 470 | |||
| 471 | srcalpha.r = src->a * mask->a; | ||
| 472 | srcalpha.g = src->a * mask->a; | ||
| 473 | srcalpha.b = src->a * mask->a; | ||
| 474 | srcalpha.a = src->a * mask->a; | ||
| 475 | } | ||
| 476 | |||
| 477 | result->r = calc_op (op, srcval.r, dst->r, srcalpha.r, dst->a); | ||
| 478 | result->g = calc_op (op, srcval.g, dst->g, srcalpha.g, dst->a); | ||
| 479 | result->b = calc_op (op, srcval.b, dst->b, srcalpha.b, dst->a); | ||
| 480 | result->a = calc_op (op, srcval.a, dst->a, srcalpha.a, dst->a); | ||
| 481 | } | ||
| 482 | |||
| 483 | static void | ||
| 484 | color_correct (pixman_format_code_t format, | ||
| 485 | color_t *color) | ||
| 486 | { | ||
| 487 | #define MASK(x) ((1 << (x)) - 1) | ||
| 488 | #define round_pix(pix, m) \ | ||
| 489 | ((int)((pix) * (MASK(m)) + .5) / (double) (MASK(m))) | ||
| 490 | |||
| 491 | if (PIXMAN_FORMAT_R (format)(((format) >> 8) & 0x0f) == 0) | ||
| 492 | { | ||
| 493 | color->r = 0.0; | ||
| 494 | color->g = 0.0; | ||
| 495 | color->b = 0.0; | ||
| 496 | } | ||
| 497 | else | ||
| 498 | { | ||
| 499 | color->r = round_pix (color->r, PIXMAN_FORMAT_R (format)(((format) >> 8) & 0x0f)); | ||
| 500 | color->g = round_pix (color->g, PIXMAN_FORMAT_G (format)(((format) >> 4) & 0x0f)); | ||
| 501 | color->b = round_pix (color->b, PIXMAN_FORMAT_B (format)(((format) ) & 0x0f)); | ||
| 502 | } | ||
| 503 | |||
| 504 | if (PIXMAN_FORMAT_A (format)(((format) >> 12) & 0x0f) == 0) | ||
| 505 | color->a = 1.0; | ||
| 506 | else | ||
| 507 | color->a = round_pix (color->a, PIXMAN_FORMAT_A (format)(((format) >> 12) & 0x0f)); | ||
| 508 | |||
| 509 | #undef round_pix | ||
| 510 | #undef MASK | ||
| 511 | } | ||
| 512 | |||
| 513 | static void | ||
| 514 | get_pixel (pixman_image_t *image, | ||
| 515 | pixman_format_code_t format, | ||
| 516 | color_t *color) | ||
| 517 | { | ||
| 518 | #define MASK(N) ((1UL << (N))-1) | ||
| 519 | |||
| 520 | unsigned long rs, gs, bs, as; | ||
| 521 | int a, r, g, b; | ||
| 522 | unsigned long val; | ||
| 523 | |||
| 524 | val = *(unsigned long *) pixman_image_get_data (image); | ||
| 525 | #ifdef WORDS_BIGENDIAN | ||
| 526 | val >>= 8 * sizeof(val) - PIXMAN_FORMAT_BPP (format)(((format) >> 24) ); | ||
| 527 | #endif | ||
| 528 | |||
| 529 | /* Number of bits in each channel */ | ||
| 530 | a = PIXMAN_FORMAT_A (format)(((format) >> 12) & 0x0f); | ||
| 531 | r = PIXMAN_FORMAT_R (format)(((format) >> 8) & 0x0f); | ||
| 532 | g = PIXMAN_FORMAT_G (format)(((format) >> 4) & 0x0f); | ||
| 533 | b = PIXMAN_FORMAT_B (format)(((format) ) & 0x0f); | ||
| 534 | |||
| 535 | switch (PIXMAN_FORMAT_TYPE (format)(((format) >> 16) & 0xff)) | ||
| |||
| 536 | { | ||
| 537 | case PIXMAN_TYPE_ARGB2: | ||
| 538 | bs = 0; | ||
| |||
| 539 | gs = b + bs; | ||
| |||
| 540 | rs = g + gs; | ||
| 541 | as = r + rs; | ||
| 542 | break; | ||
| 543 | |||
| 544 | case PIXMAN_TYPE_ABGR3: | ||
| 545 | rs = 0; | ||
| 546 | gs = r + rs; | ||
| 547 | bs = g + gs; | ||
| 548 | as = b + bs; | ||
| 549 | break; | ||
| 550 | |||
| 551 | case PIXMAN_TYPE_BGRA8: | ||
| 552 | as = 0; | ||
| 553 | rs = PIXMAN_FORMAT_BPP (format)(((format) >> 24) ) - (b + g + r); | ||
| 554 | gs = r + rs; | ||
| 555 | bs = g + gs; | ||
| 556 | break; | ||
| 557 | |||
| 558 | case PIXMAN_TYPE_A1: | ||
| 559 | as = 0; | ||
| 560 | rs = 0; | ||
| 561 | gs = 0; | ||
| 562 | bs = 0; | ||
| 563 | break; | ||
| 564 | |||
| 565 | case PIXMAN_TYPE_OTHER0: | ||
| 566 | case PIXMAN_TYPE_COLOR4: | ||
| 567 | case PIXMAN_TYPE_GRAY5: | ||
| 568 | case PIXMAN_TYPE_YUY26: | ||
| 569 | case PIXMAN_TYPE_YV127: | ||
| 570 | default: | ||
| 571 | abort (); | ||
| 572 | as = 0; | ||
| 573 | rs = 0; | ||
| 574 | gs = 0; | ||
| 575 | bs = 0; | ||
| 576 | break; | ||
| 577 | } | ||
| 578 | |||
| 579 | if (MASK (a) != 0) | ||
| 580 | color->a = ((val >> as) & MASK (a)) / (double) MASK (a); | ||
| 581 | else | ||
| 582 | color->a = 1.0; | ||
| 583 | |||
| 584 | if (MASK (r) != 0) | ||
| 585 | { | ||
| 586 | color->r = ((val >> rs) & MASK (r)) / (double) MASK (r); | ||
| 587 | color->g = ((val >> gs) & MASK (g)) / (double) MASK (g); | ||
| 588 | color->b = ((val >> bs) & MASK (b)) / (double) MASK (b); | ||
| 589 | } | ||
| 590 | else | ||
| 591 | { | ||
| 592 | color->r = 0.0; | ||
| 593 | color->g = 0.0; | ||
| 594 | color->b = 0.0; | ||
| 595 | } | ||
| 596 | |||
| 597 | #undef MASK | ||
| 598 | } | ||
| 599 | |||
| 600 | static double | ||
| 601 | eval_diff (color_t *expected, color_t *test, pixman_format_code_t format) | ||
| 602 | { | ||
| 603 | double rscale, gscale, bscale, ascale; | ||
| 604 | double rdiff, gdiff, bdiff, adiff; | ||
| 605 | |||
| 606 | rscale = 1.0 * ((1 << PIXMAN_FORMAT_R (format)(((format) >> 8) & 0x0f)) - 1); | ||
| 607 | gscale = 1.0 * ((1 << PIXMAN_FORMAT_G (format)(((format) >> 4) & 0x0f)) - 1); | ||
| 608 | bscale = 1.0 * ((1 << PIXMAN_FORMAT_B (format)(((format) ) & 0x0f)) - 1); | ||
| 609 | ascale = 1.0 * ((1 << PIXMAN_FORMAT_A (format)(((format) >> 12) & 0x0f)) - 1); | ||
| 610 | |||
| 611 | rdiff = fabs (test->r - expected->r) * rscale; | ||
| 612 | bdiff = fabs (test->g - expected->g) * gscale; | ||
| 613 | gdiff = fabs (test->b - expected->b) * bscale; | ||
| 614 | adiff = fabs (test->a - expected->a) * ascale; | ||
| 615 | |||
| 616 | return MAX (MAX (MAX (rdiff, gdiff), bdiff), adiff)((((((rdiff > gdiff) ? rdiff : gdiff) > bdiff) ? ((rdiff > gdiff) ? rdiff : gdiff) : bdiff) > adiff) ? ((((rdiff > gdiff) ? rdiff : gdiff) > bdiff) ? ((rdiff > gdiff ) ? rdiff : gdiff) : bdiff) : adiff); | ||
| 617 | } | ||
| 618 | |||
| 619 | static char * | ||
| 620 | describe_image (image_t *info, char *buf, int buflen) | ||
| 621 | { | ||
| 622 | if (info->size) | ||
| 623 | { | ||
| 624 | snprintf (buf, buflen, "%s %dx%d%s", | ||
| 625 | info->format->name, | ||
| 626 | info->size, info->size, | ||
| 627 | info->repeat ? "R" :""); | ||
| 628 | } | ||
| 629 | else | ||
| 630 | { | ||
| 631 | snprintf (buf, buflen, "solid"); | ||
| 632 | } | ||
| 633 | |||
| 634 | return buf; | ||
| 635 | } | ||
| 636 | |||
| 637 | /* Test a composite of a given operation, source, mask, and destination | ||
| 638 | * picture. | ||
| 639 | * Fills the window, and samples from the 0,0 pixel corner. | ||
| 640 | */ | ||
| 641 | static pixman_bool_t | ||
| 642 | composite_test (image_t *dst, | ||
| 643 | const operator_t *op, | ||
| 644 | image_t *src, | ||
| 645 | image_t *mask, | ||
| 646 | pixman_bool_t component_alpha) | ||
| 647 | { | ||
| 648 | pixman_color_t fill; | ||
| 649 | pixman_rectangle16_t rect; | ||
| 650 | color_t expected, result, tdst, tsrc, tmsk; | ||
| 651 | double diff; | ||
| 652 | pixman_bool_t success = TRUE1; | ||
| 653 | |||
| 654 | compute_pixman_color (dst->color, &fill); | ||
| 655 | rect.x = rect.y = 0; | ||
| 656 | rect.width = rect.height = dst->size; | ||
| 657 | pixman_image_fill_rectangles (PIXMAN_OP_SRC, dst->image, | ||
| 658 | &fill, 1, &rect); | ||
| 659 | |||
| 660 | if (mask != NULL((void*)0)) | ||
| 661 | { | ||
| 662 | pixman_image_set_component_alpha (mask->image, component_alpha); | ||
| 663 | pixman_image_composite (op->op, src->image, mask->image, dst->image, | ||
| 664 | 0, 0, | ||
| 665 | 0, 0, | ||
| 666 | 0, 0, | ||
| 667 | dst->size, dst->size); | ||
| 668 | |||
| 669 | tmsk = *mask->color; | ||
| 670 | if (mask->size) | ||
| 671 | { | ||
| 672 | color_correct (mask->format->format, &tmsk); | ||
| 673 | |||
| 674 | if (component_alpha && | ||
| 675 | PIXMAN_FORMAT_R (mask->format->format)(((mask->format->format) >> 8) & 0x0f) == 0) | ||
| 676 | { | ||
| 677 | /* Ax component-alpha masks expand alpha into | ||
| 678 | * all color channels. | ||
| 679 | */ | ||
| 680 | tmsk.r = tmsk.g = tmsk.b = tmsk.a; | ||
| 681 | } | ||
| 682 | } | ||
| 683 | } | ||
| 684 | else | ||
| 685 | { | ||
| 686 | pixman_image_composite (op->op, src->image, NULL((void*)0), dst->image, | ||
| 687 | 0, 0, | ||
| 688 | 0, 0, | ||
| 689 | 0, 0, | ||
| 690 | dst->size, dst->size); | ||
| 691 | } | ||
| 692 | get_pixel (dst->image, dst->format->format, &result); | ||
| 693 | |||
| 694 | tdst = *dst->color; | ||
| 695 | color_correct (dst->format->format, &tdst); | ||
| 696 | tsrc = *src->color; | ||
| 697 | if (src->size) | ||
| 698 | color_correct (src->format->format, &tsrc); | ||
| 699 | do_composite (op->op, &tsrc, mask ? &tmsk : NULL((void*)0), &tdst, | ||
| 700 | &expected, component_alpha); | ||
| 701 | color_correct (dst->format->format, &expected); | ||
| 702 | |||
| 703 | diff = eval_diff (&expected, &result, dst->format->format); | ||
| 704 | |||
| 705 | /* FIXME: We should find out what deviation is acceptable. 3.0 | ||
| 706 | * is clearly absurd for 2 bit formats for example. On the other | ||
| 707 | * hand currently 1.0 does not work. | ||
| 708 | */ | ||
| 709 | if (diff > 3.0) | ||
| 710 | { | ||
| 711 | char buf[40]; | ||
| 712 | |||
| 713 | snprintf (buf, sizeof (buf), | ||
| 714 | "%s %scomposite", | ||
| 715 | op->name, | ||
| 716 | component_alpha ? "CA " : ""); | ||
| 717 | |||
| 718 | printf ("%s test error of %.4f --\n" | ||
| 719 | " R G B A\n" | ||
| 720 | "got: %.2f %.2f %.2f %.2f [%08lx]\n" | ||
| 721 | "expected: %.2f %.2f %.2f %.2f\n", | ||
| 722 | buf, diff, | ||
| 723 | result.r, result.g, result.b, result.a, | ||
| 724 | *(unsigned long *) pixman_image_get_data (dst->image), | ||
| 725 | expected.r, expected.g, expected.b, expected.a); | ||
| 726 | |||
| 727 | if (mask != NULL((void*)0)) | ||
| 728 | { | ||
| 729 | printf ("src color: %.2f %.2f %.2f %.2f\n" | ||
| 730 | "msk color: %.2f %.2f %.2f %.2f\n" | ||
| 731 | "dst color: %.2f %.2f %.2f %.2f\n", | ||
| 732 | src->color->r, src->color->g, | ||
| 733 | src->color->b, src->color->a, | ||
| 734 | mask->color->r, mask->color->g, | ||
| 735 | mask->color->b, mask->color->a, | ||
| 736 | dst->color->r, dst->color->g, | ||
| 737 | dst->color->b, dst->color->a); | ||
| 738 | printf ("src: %s, ", describe_image (src, buf, sizeof (buf))); | ||
| 739 | printf ("mask: %s, ", describe_image (mask, buf, sizeof (buf))); | ||
| 740 | printf ("dst: %s\n\n", describe_image (dst, buf, sizeof (buf))); | ||
| 741 | } | ||
| 742 | else | ||
| 743 | { | ||
| 744 | printf ("src color: %.2f %.2f %.2f %.2f\n" | ||
| 745 | "dst color: %.2f %.2f %.2f %.2f\n", | ||
| 746 | src->color->r, src->color->g, | ||
| 747 | src->color->b, src->color->a, | ||
| 748 | dst->color->r, dst->color->g, | ||
| 749 | dst->color->b, dst->color->a); | ||
| 750 | printf ("src: %s, ", describe_image (src, buf, sizeof (buf))); | ||
| 751 | printf ("dst: %s\n\n", describe_image (dst, buf, sizeof (buf))); | ||
| 752 | } | ||
| 753 | |||
| 754 | success = FALSE0; | ||
| 755 | } | ||
| 756 | |||
| 757 | return success; | ||
| 758 | } | ||
| 759 | |||
| 760 | static void | ||
| 761 | image_init (image_t *info, | ||
| 762 | int color, | ||
| 763 | int format, | ||
| 764 | int size) | ||
| 765 | { | ||
| 766 | pixman_color_t fill; | ||
| 767 | |||
| 768 | info->color = &colors[color]; | ||
| 769 | compute_pixman_color (info->color, &fill); | ||
| 770 | |||
| 771 | info->format = &formats[format]; | ||
| 772 | info->size = sizes[size] & ~FLAGS0xff000000; | ||
| 773 | info->repeat = PIXMAN_REPEAT_NONE; | ||
| 774 | |||
| 775 | if (info->size) | ||
| 776 | { | ||
| 777 | pixman_rectangle16_t rect; | ||
| 778 | |||
| 779 | info->image = pixman_image_create_bits (info->format->format, | ||
| 780 | info->size, info->size, | ||
| 781 | NULL((void*)0), 0); | ||
| 782 | |||
| 783 | rect.x = rect.y = 0; | ||
| 784 | rect.width = rect.height = info->size; | ||
| 785 | pixman_image_fill_rectangles (PIXMAN_OP_SRC, info->image, &fill, | ||
| 786 | 1, &rect); | ||
| 787 | |||
| 788 | if (size & REPEAT0x01000000) | ||
| 789 | { | ||
| 790 | pixman_image_set_repeat (info->image, PIXMAN_REPEAT_NORMAL); | ||
| 791 | info->repeat = PIXMAN_REPEAT_NORMAL; | ||
| 792 | } | ||
| 793 | } | ||
| 794 | else | ||
| 795 | { | ||
| 796 | info->image = pixman_image_create_solid_fill (&fill); | ||
| 797 | } | ||
| 798 | } | ||
| 799 | |||
| 800 | static void | ||
| 801 | image_fini (image_t *info) | ||
| 802 | { | ||
| 803 | pixman_image_unref (info->image); | ||
| 804 | } | ||
| 805 | |||
| 806 | static int | ||
| 807 | random_size (void) | ||
| 808 | { | ||
| 809 | return lcg_rand_n (ARRAY_LENGTH (sizes)((int) (sizeof (sizes) / sizeof ((sizes) [0])))); | ||
| 810 | } | ||
| 811 | |||
| 812 | static int | ||
| 813 | random_color (void) | ||
| 814 | { | ||
| 815 | return lcg_rand_n (ARRAY_LENGTH (colors)((int) (sizeof (colors) / sizeof ((colors) [0])))); | ||
| 816 | } | ||
| 817 | |||
| 818 | static int | ||
| 819 | random_format (void) | ||
| 820 | { | ||
| 821 | return lcg_rand_n (ARRAY_LENGTH (formats)((int) (sizeof (formats) / sizeof ((formats) [0])))); | ||
| 822 | } | ||
| 823 | |||
| 824 | static pixman_bool_t | ||
| 825 | run_test (uint32_t seed) | ||
| 826 | { | ||
| 827 | image_t src, mask, dst; | ||
| 828 | const operator_t *op; | ||
| 829 | int ca; | ||
| 830 | int ok; | ||
| 831 | |||
| 832 | lcg_srand (seed); | ||
| 833 | |||
| 834 | image_init (&dst, random_color(), random_format(), 1); | ||
| 835 | image_init (&src, random_color(), random_format(), random_size()); | ||
| 836 | image_init (&mask, random_color(), random_format(), random_size()); | ||
| 837 | |||
| 838 | op = &(operators [lcg_rand_n (ARRAY_LENGTH (operators)((int) (sizeof (operators) / sizeof ((operators) [0]))))]); | ||
| 839 | |||
| 840 | ca = lcg_rand_n (3); | ||
| 841 | |||
| 842 | switch (ca) | ||
| 843 | { | ||
| 844 | case 0: | ||
| 845 | ok = composite_test (&dst, op, &src, NULL((void*)0), FALSE0); | ||
| 846 | break; | ||
| 847 | case 1: | ||
| 848 | ok = composite_test (&dst, op, &src, &mask, FALSE0); | ||
| 849 | break; | ||
| 850 | case 2: | ||
| 851 | ok = composite_test (&dst, op, &src, &mask, | ||
| 852 | mask.size? TRUE1 : FALSE0); | ||
| 853 | break; | ||
| 854 | default: | ||
| 855 | ok = FALSE0; | ||
| 856 | break; | ||
| 857 | } | ||
| 858 | |||
| 859 | image_fini (&src); | ||
| 860 | image_fini (&mask); | ||
| 861 | image_fini (&dst); | ||
| 862 | |||
| 863 | return ok; | ||
| 864 | } | ||
| 865 | |||
| 866 | int | ||
| 867 | main (int argc, char **argv) | ||
| 868 | { | ||
| 869 | #define N_TESTS(8 * 1024 * 1024) (8 * 1024 * 1024) | ||
| 870 | int result = 0; | ||
| 871 | int i; | ||
| 872 | |||
| 873 | if (argc > 1) | ||
| 874 | { | ||
| 875 | char *end; | ||
| 876 | |||
| 877 | i = strtol (argv[1], &end, 0); | ||
| 878 | |||
| 879 | if (end != argv[1]) | ||
| 880 | { | ||
| 881 | if (!run_test (i)) | ||
| 882 | return 1; | ||
| 883 | else | ||
| 884 | return 0; | ||
| 885 | } | ||
| 886 | else | ||
| 887 | { | ||
| 888 | printf ("Usage:\n\n %s <number>\n\n", argv[0]); | ||
| 889 | return -1; | ||
| 890 | } | ||
| 891 | } | ||
| 892 | |||
| 893 | #ifdef USE_OPENMP | ||
| 894 | # pragma omp parallel for default(none) shared(result) shared(argv) | ||
| 895 | #endif | ||
| 896 | for (i = 1; i <= N_TESTS(8 * 1024 * 1024); ++i) | ||
| 897 | { | ||
| 898 | if (!result && !run_test (i)) | ||
| 899 | { | ||
| 900 | printf ("Test %d failed.\n", i); | ||
| 901 | |||
| 902 | result = i; | ||
| 903 | } | ||
| 904 | } | ||
| 905 | |||
| 906 | return result; | ||
| 907 | } |