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 | } |