1 /*
2 * Test program, which can detect some problems with nearest neighbour
3 * and bilinear scaling in pixman. Testing is done by running lots
4 * of random SRC and OVER compositing operations a8r8g8b8, x8a8r8g8b8
5 * and r5g6b5 color formats.
6 *
7 * Script 'fuzzer-find-diff.pl' can be used to narrow down the problem in
8 * the case of test failure.
9 */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include "utils.h"
13
14 #define MAX_SRC_WIDTH 48
15 #define MAX_SRC_HEIGHT 8
16 #define MAX_DST_WIDTH 48
17 #define MAX_DST_HEIGHT 8
18 #define MAX_STRIDE 4
19
20 /*
21 * Composite operation with pseudorandom images
22 */
23
24 static pixman_format_code_t
get_format(int bpp)25 get_format (int bpp)
26 {
27 if (bpp == 4)
28 {
29 switch (prng_rand_n (4))
30 {
31 default:
32 case 0:
33 return PIXMAN_a8r8g8b8;
34 case 1:
35 return PIXMAN_x8r8g8b8;
36 case 2:
37 return PIXMAN_a8b8g8r8;
38 case 3:
39 return PIXMAN_x8b8g8r8;
40 }
41 }
42 else
43 {
44 return PIXMAN_r5g6b5;
45 }
46 }
47
48 uint32_t
test_composite(int testnum,int verbose)49 test_composite (int testnum,
50 int verbose)
51 {
52 int i;
53 pixman_image_t * src_img;
54 pixman_image_t * mask_img;
55 pixman_image_t * dst_img;
56 pixman_transform_t transform;
57 pixman_region16_t clip;
58 int src_width, src_height;
59 int mask_width, mask_height;
60 int dst_width, dst_height;
61 int src_stride, mask_stride, dst_stride;
62 int src_x, src_y;
63 int mask_x, mask_y;
64 int dst_x, dst_y;
65 int src_bpp;
66 int mask_bpp = 1;
67 int dst_bpp;
68 int w, h;
69 pixman_fixed_t scale_x = 65536, scale_y = 65536;
70 pixman_fixed_t translate_x = 0, translate_y = 0;
71 pixman_fixed_t mask_scale_x = 65536, mask_scale_y = 65536;
72 pixman_fixed_t mask_translate_x = 0, mask_translate_y = 0;
73 pixman_op_t op;
74 pixman_repeat_t repeat = PIXMAN_REPEAT_NONE;
75 pixman_repeat_t mask_repeat = PIXMAN_REPEAT_NONE;
76 pixman_format_code_t src_fmt, mask_fmt, dst_fmt;
77 uint32_t * srcbuf;
78 uint32_t * dstbuf;
79 uint32_t * maskbuf;
80 uint32_t crc32;
81 FLOAT_REGS_CORRUPTION_DETECTOR_START ();
82
83 prng_srand (testnum);
84
85 src_bpp = (prng_rand_n (2) == 0) ? 2 : 4;
86 dst_bpp = (prng_rand_n (2) == 0) ? 2 : 4;
87 switch (prng_rand_n (3))
88 {
89 case 0:
90 op = PIXMAN_OP_SRC;
91 break;
92 case 1:
93 op = PIXMAN_OP_OVER;
94 break;
95 default:
96 op = PIXMAN_OP_ADD;
97 break;
98 }
99
100 src_width = prng_rand_n (MAX_SRC_WIDTH) + 1;
101 src_height = prng_rand_n (MAX_SRC_HEIGHT) + 1;
102
103 if (prng_rand_n (2))
104 {
105 mask_width = prng_rand_n (MAX_SRC_WIDTH) + 1;
106 mask_height = prng_rand_n (MAX_SRC_HEIGHT) + 1;
107 }
108 else
109 {
110 mask_width = mask_height = 1;
111 }
112
113 dst_width = prng_rand_n (MAX_DST_WIDTH) + 1;
114 dst_height = prng_rand_n (MAX_DST_HEIGHT) + 1;
115 src_stride = src_width * src_bpp + prng_rand_n (MAX_STRIDE) * src_bpp;
116 mask_stride = mask_width * mask_bpp + prng_rand_n (MAX_STRIDE) * mask_bpp;
117 dst_stride = dst_width * dst_bpp + prng_rand_n (MAX_STRIDE) * dst_bpp;
118
119 if (src_stride & 3)
120 src_stride += 2;
121
122 if (mask_stride & 1)
123 mask_stride += 1;
124 if (mask_stride & 2)
125 mask_stride += 2;
126
127 if (dst_stride & 3)
128 dst_stride += 2;
129
130 src_x = -(src_width / 4) + prng_rand_n (src_width * 3 / 2);
131 src_y = -(src_height / 4) + prng_rand_n (src_height * 3 / 2);
132 mask_x = -(mask_width / 4) + prng_rand_n (mask_width * 3 / 2);
133 mask_y = -(mask_height / 4) + prng_rand_n (mask_height * 3 / 2);
134 dst_x = -(dst_width / 4) + prng_rand_n (dst_width * 3 / 2);
135 dst_y = -(dst_height / 4) + prng_rand_n (dst_height * 3 / 2);
136 w = prng_rand_n (dst_width * 3 / 2 - dst_x);
137 h = prng_rand_n (dst_height * 3 / 2 - dst_y);
138
139 srcbuf = (uint32_t *)malloc (src_stride * src_height);
140 maskbuf = (uint32_t *)malloc (mask_stride * mask_height);
141 dstbuf = (uint32_t *)malloc (dst_stride * dst_height);
142
143 prng_randmemset (srcbuf, src_stride * src_height, 0);
144 prng_randmemset (maskbuf, mask_stride * mask_height, 0);
145 prng_randmemset (dstbuf, dst_stride * dst_height, 0);
146
147 src_fmt = get_format (src_bpp);
148 mask_fmt = PIXMAN_a8;
149 dst_fmt = get_format (dst_bpp);
150
151 if (prng_rand_n (2))
152 {
153 srcbuf += (src_stride / 4) * (src_height - 1);
154 src_stride = - src_stride;
155 }
156
157 if (prng_rand_n (2))
158 {
159 maskbuf += (mask_stride / 4) * (mask_height - 1);
160 mask_stride = - mask_stride;
161 }
162
163 if (prng_rand_n (2))
164 {
165 dstbuf += (dst_stride / 4) * (dst_height - 1);
166 dst_stride = - dst_stride;
167 }
168
169 src_img = pixman_image_create_bits (
170 src_fmt, src_width, src_height, srcbuf, src_stride);
171
172 mask_img = pixman_image_create_bits (
173 mask_fmt, mask_width, mask_height, maskbuf, mask_stride);
174
175 dst_img = pixman_image_create_bits (
176 dst_fmt, dst_width, dst_height, dstbuf, dst_stride);
177
178 image_endian_swap (src_img);
179 image_endian_swap (dst_img);
180
181 if (prng_rand_n (4) > 0)
182 {
183 scale_x = -32768 * 3 + prng_rand_n (65536 * 5);
184 scale_y = -32768 * 3 + prng_rand_n (65536 * 5);
185 translate_x = prng_rand_n (65536);
186 translate_y = prng_rand_n (65536);
187 pixman_transform_init_scale (&transform, scale_x, scale_y);
188 pixman_transform_translate (&transform, NULL, translate_x, translate_y);
189 pixman_image_set_transform (src_img, &transform);
190 }
191
192 if (prng_rand_n (2) > 0)
193 {
194 mask_scale_x = -32768 * 3 + prng_rand_n (65536 * 5);
195 mask_scale_y = -32768 * 3 + prng_rand_n (65536 * 5);
196 mask_translate_x = prng_rand_n (65536);
197 mask_translate_y = prng_rand_n (65536);
198 pixman_transform_init_scale (&transform, mask_scale_x, mask_scale_y);
199 pixman_transform_translate (&transform, NULL, mask_translate_x, mask_translate_y);
200 pixman_image_set_transform (mask_img, &transform);
201 }
202
203 switch (prng_rand_n (4))
204 {
205 case 0:
206 mask_repeat = PIXMAN_REPEAT_NONE;
207 break;
208
209 case 1:
210 mask_repeat = PIXMAN_REPEAT_NORMAL;
211 break;
212
213 case 2:
214 mask_repeat = PIXMAN_REPEAT_PAD;
215 break;
216
217 case 3:
218 mask_repeat = PIXMAN_REPEAT_REFLECT;
219 break;
220
221 default:
222 break;
223 }
224 pixman_image_set_repeat (mask_img, mask_repeat);
225
226 switch (prng_rand_n (4))
227 {
228 case 0:
229 repeat = PIXMAN_REPEAT_NONE;
230 break;
231
232 case 1:
233 repeat = PIXMAN_REPEAT_NORMAL;
234 break;
235
236 case 2:
237 repeat = PIXMAN_REPEAT_PAD;
238 break;
239
240 case 3:
241 repeat = PIXMAN_REPEAT_REFLECT;
242 break;
243
244 default:
245 break;
246 }
247 pixman_image_set_repeat (src_img, repeat);
248
249 if (prng_rand_n (2))
250 pixman_image_set_filter (src_img, PIXMAN_FILTER_NEAREST, NULL, 0);
251 else
252 pixman_image_set_filter (src_img, PIXMAN_FILTER_BILINEAR, NULL, 0);
253
254 if (prng_rand_n (2))
255 pixman_image_set_filter (mask_img, PIXMAN_FILTER_NEAREST, NULL, 0);
256 else
257 pixman_image_set_filter (mask_img, PIXMAN_FILTER_BILINEAR, NULL, 0);
258
259 if (prng_rand_n (8) == 0)
260 {
261 pixman_box16_t clip_boxes[2];
262 int n = prng_rand_n (2) + 1;
263
264 for (i = 0; i < n; i++)
265 {
266 clip_boxes[i].x1 = prng_rand_n (src_width);
267 clip_boxes[i].y1 = prng_rand_n (src_height);
268 clip_boxes[i].x2 =
269 clip_boxes[i].x1 + prng_rand_n (src_width - clip_boxes[i].x1);
270 clip_boxes[i].y2 =
271 clip_boxes[i].y1 + prng_rand_n (src_height - clip_boxes[i].y1);
272
273 if (verbose)
274 {
275 printf ("source clip box: [%d,%d-%d,%d]\n",
276 clip_boxes[i].x1, clip_boxes[i].y1,
277 clip_boxes[i].x2, clip_boxes[i].y2);
278 }
279 }
280
281 pixman_region_init_rects (&clip, clip_boxes, n);
282 pixman_image_set_clip_region (src_img, &clip);
283 pixman_image_set_source_clipping (src_img, 1);
284 pixman_region_fini (&clip);
285 }
286
287 if (prng_rand_n (8) == 0)
288 {
289 pixman_box16_t clip_boxes[2];
290 int n = prng_rand_n (2) + 1;
291
292 for (i = 0; i < n; i++)
293 {
294 clip_boxes[i].x1 = prng_rand_n (mask_width);
295 clip_boxes[i].y1 = prng_rand_n (mask_height);
296 clip_boxes[i].x2 =
297 clip_boxes[i].x1 + prng_rand_n (mask_width - clip_boxes[i].x1);
298 clip_boxes[i].y2 =
299 clip_boxes[i].y1 + prng_rand_n (mask_height - clip_boxes[i].y1);
300
301 if (verbose)
302 {
303 printf ("mask clip box: [%d,%d-%d,%d]\n",
304 clip_boxes[i].x1, clip_boxes[i].y1,
305 clip_boxes[i].x2, clip_boxes[i].y2);
306 }
307 }
308
309 pixman_region_init_rects (&clip, clip_boxes, n);
310 pixman_image_set_clip_region (mask_img, &clip);
311 pixman_image_set_source_clipping (mask_img, 1);
312 pixman_region_fini (&clip);
313 }
314
315 if (prng_rand_n (8) == 0)
316 {
317 pixman_box16_t clip_boxes[2];
318 int n = prng_rand_n (2) + 1;
319 for (i = 0; i < n; i++)
320 {
321 clip_boxes[i].x1 = prng_rand_n (dst_width);
322 clip_boxes[i].y1 = prng_rand_n (dst_height);
323 clip_boxes[i].x2 =
324 clip_boxes[i].x1 + prng_rand_n (dst_width - clip_boxes[i].x1);
325 clip_boxes[i].y2 =
326 clip_boxes[i].y1 + prng_rand_n (dst_height - clip_boxes[i].y1);
327
328 if (verbose)
329 {
330 printf ("destination clip box: [%d,%d-%d,%d]\n",
331 clip_boxes[i].x1, clip_boxes[i].y1,
332 clip_boxes[i].x2, clip_boxes[i].y2);
333 }
334 }
335 pixman_region_init_rects (&clip, clip_boxes, n);
336 pixman_image_set_clip_region (dst_img, &clip);
337 pixman_region_fini (&clip);
338 }
339
340 if (prng_rand_n (2) == 0)
341 {
342 mask_fmt = PIXMAN_null;
343 pixman_image_unref (mask_img);
344 mask_img = NULL;
345 mask_x = 0;
346 mask_y = 0;
347 }
348
349 if (verbose)
350 {
351 printf ("op=%s, src_fmt=%s, mask_fmt=%s, dst_fmt=%s\n",
352 operator_name (op), format_name (src_fmt),
353 format_name (mask_fmt), format_name (dst_fmt));
354 printf ("scale_x=%d, scale_y=%d, repeat=%d, filter=%d\n",
355 scale_x, scale_y, repeat, src_img->common.filter);
356 printf ("translate_x=%d, translate_y=%d\n",
357 translate_x, translate_y);
358 if (mask_fmt != PIXMAN_null)
359 {
360 printf ("mask_scale_x=%d, mask_scale_y=%d, "
361 "mask_repeat=%d, mask_filter=%d\n",
362 mask_scale_x, mask_scale_y, mask_repeat,
363 mask_img->common.filter);
364 printf ("mask_translate_x=%d, mask_translate_y=%d\n",
365 mask_translate_x, mask_translate_y);
366 }
367 printf ("src_width=%d, src_height=%d, src_x=%d, src_y=%d\n",
368 src_width, src_height, src_x, src_y);
369 if (mask_fmt != PIXMAN_null)
370 {
371 printf ("mask_width=%d, mask_height=%d, mask_x=%d, mask_y=%d\n",
372 mask_width, mask_height, mask_x, mask_y);
373 }
374 printf ("dst_width=%d, dst_height=%d, dst_x=%d, dst_y=%d\n",
375 dst_width, dst_height, dst_x, dst_y);
376 printf ("w=%d, h=%d\n", w, h);
377 }
378
379 pixman_image_composite (op, src_img, mask_img, dst_img,
380 src_x, src_y, mask_x, mask_y, dst_x, dst_y, w, h);
381
382 crc32 = compute_crc32_for_image (0, dst_img);
383
384 if (verbose)
385 print_image (dst_img);
386
387 pixman_image_unref (src_img);
388 if (mask_img != NULL)
389 pixman_image_unref (mask_img);
390 pixman_image_unref (dst_img);
391
392 if (src_stride < 0)
393 srcbuf += (src_stride / 4) * (src_height - 1);
394
395 if (mask_stride < 0)
396 maskbuf += (mask_stride / 4) * (mask_height - 1);
397
398 if (dst_stride < 0)
399 dstbuf += (dst_stride / 4) * (dst_height - 1);
400
401 free (srcbuf);
402 free (maskbuf);
403 free (dstbuf);
404
405 FLOAT_REGS_CORRUPTION_DETECTOR_FINISH ();
406 return crc32;
407 }
408
409 #if BILINEAR_INTERPOLATION_BITS == 7
410 #define CHECKSUM 0x92E0F068
411 #elif BILINEAR_INTERPOLATION_BITS == 4
412 #define CHECKSUM 0x8EFFA1E5
413 #else
414 #define CHECKSUM 0x00000000
415 #endif
416
417 int
main(int argc,const char * argv[])418 main (int argc, const char *argv[])
419 {
420 pixman_disable_out_of_bounds_workaround ();
421
422 return fuzzer_test_main("scaling", 8000000, CHECKSUM,
423 test_composite, argc, argv);
424 }
425