take two
[profile/ivi/xorg-x11-drv-intel.git] / test / render-trapezoid-image.c
1 #include <stdint.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 #include <X11/Xutil.h> /* for XDestroyImage */
6 #include <pixman.h> /* for pixman blt functions */
7
8 #include "test.h"
9
10 enum trapezoid {
11         RECT_ALIGN,
12         RECT_UNALIGN,
13         GENERAL
14 };
15
16 static const uint8_t ops[] = {
17         PictOpClear,
18         PictOpSrc,
19         PictOpDst,
20 };
21
22 static XRenderPictFormat *mask_format(Display *dpy, enum mask mask)
23 {
24         switch (mask) {
25         default:
26         case MASK_NONE:
27         case MASK_NONE_AA:
28                 return NULL;
29         case MASK_A1:
30                 return  XRenderFindStandardFormat(dpy, PictStandardA1);
31         case MASK_A8:
32                 return  XRenderFindStandardFormat(dpy, PictStandardA8);
33         }
34 }
35
36 static const char *mask_name(enum mask mask)
37 {
38         switch (mask) {
39         default:
40         case MASK_NONE: return "none";
41         case MASK_NONE_AA: return "none/aa";
42         case MASK_A1: return "a1";
43         case MASK_A8: return "a8";
44         }
45 }
46
47 static const char *trapezoid_name(enum trapezoid trapezoid)
48 {
49         switch (trapezoid) {
50         default:
51         case RECT_ALIGN: return "pixel-aligned";
52         case RECT_UNALIGN: return "rectilinear";
53         case GENERAL: return "general";
54         }
55 }
56
57 static void
58 show_cells(char *buf,
59            const uint32_t *real, const uint32_t *ref,
60            int x, int y, int w, int h)
61 {
62         int i, j, len = 0;
63
64         for (j = y - 2; j <= y + 2; j++) {
65                 if (j < 0 || j >= h)
66                         continue;
67
68                 for (i = x - 2; i <= x + 2; i++) {
69                         if (i < 0 || i >= w)
70                                 continue;
71
72                         len += sprintf(buf+len, "%08x ", real[j*w+i]);
73                 }
74
75                 len += sprintf(buf+len, "\t");
76
77                 for (i = x - 2; i <= x + 2; i++) {
78                         if (i < 0 || i >= w)
79                                 continue;
80
81                         len += sprintf(buf+len, "%08x ", ref[j*w+i]);
82                 }
83
84                 len += sprintf(buf+len, "\n");
85         }
86 }
87
88
89 static void fill_rect(struct test_display *t, Picture p, XRenderPictFormat *format,
90                       uint8_t op, int x, int y, int w, int h,
91                       int dx, int dy, enum mask mask,
92                       int use_window, int tx, int ty,
93                       uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
94 {
95         XRenderColor color;
96         XTrapezoid trap;
97         Drawable tmp;
98         Picture src;
99         int w1 = w + (dx!=0);
100         int h1 = h + (dy!=0);
101
102         if (use_window) {
103                 XSetWindowAttributes attr;
104
105                 attr.override_redirect = 1;
106                 tmp = XCreateWindow(t->dpy, DefaultRootWindow(t->dpy),
107                                     tx, ty,
108                                     w1, h1,
109                                     0, format->depth,
110                                     InputOutput,
111                                     DefaultVisual(t->dpy,
112                                                   DefaultScreen(t->dpy)),
113                                     CWOverrideRedirect, &attr);
114                 XMapWindow(t->dpy, tmp);
115         } else
116                 tmp = XCreatePixmap(t->dpy, DefaultRootWindow(t->dpy),
117                                     w1, h1, format->depth);
118
119         src = XRenderCreatePicture(t->dpy, tmp, format, 0, NULL);
120         color.red = red * alpha;
121         color.green = green * alpha;
122         color.blue = blue * alpha;
123         color.alpha = alpha << 8 | alpha;
124         XRenderFillRectangle(t->dpy, PictOpSrc, src, &color, 0, 0, w1, h1);
125
126         trap.left.p1.x = trap.left.p2.x = (x << 16) + dx;
127         trap.top = trap.left.p1.y = trap.right.p1.y = (y << 16) + dy;
128         trap.right.p1.x = trap.right.p2.x = ((x + w) << 16) + dx;
129         trap.bottom = trap.left.p2.y = trap.right.p2.y = ((y + h) << 16) + dy;
130
131         XRenderCompositeTrapezoids(t->dpy,
132                                    op, src, p, mask_format(t->dpy, mask),
133                                    0, 0, &trap, 1);
134
135         XRenderFreePicture(t->dpy, src);
136         if (use_window)
137                 XDestroyWindow(t->dpy, tmp);
138         else
139                 XFreePixmap(t->dpy, tmp);
140 }
141
142 static void pixel_tests(struct test *t, int reps, int sets, enum target target, int use_window)
143 {
144         struct test_target tt;
145         XImage image;
146         uint32_t *cells = malloc(t->real.width*t->real.height*4);
147         struct {
148                 uint16_t x, y;
149         } *pixels = malloc(reps*sizeof(*pixels));
150         int r, s;
151
152         printf("Testing setting of single pixels (%s using %s): ",
153                test_target_name(target),
154                use_window ? "window" : "pixmap");
155         fflush(stdout);
156
157         test_target_create_render(&t->real, target, &tt);
158
159         for (s = 0; s < sets; s++) {
160                 for (r = 0; r < reps; r++) {
161                         int x = rand() % (tt.width - 1);
162                         int y = rand() % (tt.height - 1);
163                         int red = rand() % 0xff;
164                         int green = rand() % 0xff;
165                         int blue = rand() % 0xff;
166                         int alpha = rand() % 0xff;
167
168                         int tx, ty;
169
170                         do {
171                                 tx = rand() % (tt.width - 1);
172                                 ty = rand() % (tt.height - 1);
173                         } while (tx == x && ty == y);
174
175                         fill_rect(&t->real, tt.picture,
176                                   use_window ? t->real.format : tt.format,
177                                   PictOpSrc, x, y, 1, 1,
178                                   0, 0, MASK_NONE,
179                                   use_window, tx, ty,
180                                   red, green, blue, alpha);
181
182                         pixels[r].x = x;
183                         pixels[r].y = y;
184                         cells[y*t->real.width+x] = color(red, green, blue, alpha);
185                 }
186
187                 test_init_image(&image, &t->real.shm, tt.format, 1, 1);
188
189                 for (r = 0; r < reps; r++) {
190                         uint32_t result;
191                         uint32_t x = pixels[r].x;
192                         uint32_t y = pixels[r].y;
193
194                         XShmGetImage(t->real.dpy, tt.draw, &image,
195                                      x, y, AllPlanes);
196
197                         result = *(uint32_t *)image.data;
198                         if (!pixel_equal(image.depth, result,
199                                          cells[y*tt.width+x])) {
200                                 uint32_t mask = depth_mask(image.depth);
201                                 die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n",
202                                     x, y,
203                                     cells[y*tt.width+x] & mask,
204                                     cells[y*tt.width+x],
205                                     result & mask,
206                                     result);
207                         }
208                 }
209         }
210         printf("passed [%d iterations x %d]\n", reps, sets);
211
212         test_target_destroy_render(&t->real, &tt);
213
214         free(pixels);
215         free(cells);
216 }
217
218 static void clear(struct test_display *dpy, struct test_target *tt)
219 {
220         XRenderColor render_color = {0};
221         XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color,
222                              0, 0, tt->width, tt->height);
223 }
224
225 static void set_mask(struct test_display *t, struct test_target *tt, enum mask mask)
226 {
227         XRenderPictureAttributes pa;
228
229         switch (mask) {
230         case MASK_NONE:
231                 pa.poly_edge = PolyEdgeSharp;
232                 break;
233         default:
234                 pa.poly_edge = PolyEdgeSmooth;
235                 break;
236         }
237
238         XRenderChangePicture(t->dpy, tt->picture, CPPolyEdge, &pa);
239 }
240
241 static void fill(uint32_t *cells,
242                  int x, int y,
243                  int w, int h,
244                  int max_width, int max_height,
245                  uint32_t pixel)
246 {
247         if (x < 0)
248                 w += x, x = 0;
249         if (y < 0)
250                 h += y, y = 0;
251         if (x >= max_width || y >= max_height)
252                 return;
253
254         if (x + w > max_width)
255                 w = max_width - x;
256         if (y + h > max_height)
257                 h = max_height - y;
258         if (w <= 0 || h <= 0)
259                 return;
260
261         pixman_fill(cells, max_width, 32, x, y, w, h, pixel);
262 }
263
264 static void area_tests(struct test *t, int reps, int sets, enum target target, int use_window)
265 {
266         struct test_target tt;
267         XImage image;
268         uint32_t *cells = calloc(sizeof(uint32_t), t->real.width*t->real.height);
269         int r, s, x, y;
270
271         printf("Testing area sets (%s using %s source): ",
272                test_target_name(target),
273                use_window ? "window" : "pixmap");
274         fflush(stdout);
275
276         test_target_create_render(&t->real, target, &tt);
277         clear(&t->real, &tt);
278
279         test_init_image(&image, &t->real.shm, tt.format, tt.width, tt.height);
280
281         for (s = 0; s < sets; s++) {
282                 for (r = 0; r < reps; r++) {
283                         int red = rand() % 0xff;
284                         int green = rand() % 0xff;
285                         int blue = rand() % 0xff;
286                         int alpha = rand() % 0xff;
287                         int tx, ty, try = 50;
288                         int w, h;
289
290                         x = rand() % (2*tt.width) - tt.width;
291                         y = rand() % (2*tt.height) - tt.height;
292                         if (use_window) {
293                                 do {
294                                         w = 1 + rand() % (tt.width - 1);
295                                         h = 1 + rand() % (tt.height - 1);
296
297                                         tx = w == tt.width ? 0 : rand() % (tt.width - w);
298                                         ty = h == tt.height ? 0 : rand() % (tt.height - h);
299                                 } while (((tx+w > x && tx < x+w) &&
300                                           (ty+h > y && ty < y+h)) &&
301                                          --try);
302
303                                 if (!try)
304                                         continue;
305                         } else {
306                                 w = 1 + rand() % (2*tt.width);
307                                 h = 1 + rand() % (2*tt.height);
308                                 tx = ty = 0;
309                         }
310
311                         fill_rect(&t->real, tt.picture,
312                                   use_window ? t->real.format : tt.format,
313                                   PictOpSrc, x, y, w, h,
314                                   0, 0, MASK_NONE,
315                                   use_window, tx, ty,
316                                   red, green, blue, alpha);
317
318                         if (use_window)
319                                 fill(cells, tx, ty, w, h, tt.width, tt.height,
320                                      color(red, green, blue, alpha));
321                         fill(cells, x, y, w, h, tt.width, tt.height,
322                              color(red, green, blue, alpha));
323
324                 }
325
326                 XShmGetImage(t->real.dpy, tt.draw, &image, 0, 0, AllPlanes);
327
328                 for (y = 0; y < tt.height; y++) {
329                         for (x = 0; x < tt.width; x++) {
330                                 uint32_t result =
331                                         *(uint32_t *)(image.data +
332                                                       y*image.bytes_per_line +
333                                                       image.bits_per_pixel*x/8);
334                                 if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) {
335                                         char buf[600];
336                                         uint32_t mask = depth_mask(image.depth);
337                                         show_cells(buf,
338                                                    (uint32_t*)image.data, cells,
339                                                    x, y, tt.width, tt.height);
340
341                                         die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n%s",
342                                             x, y,
343                                             cells[y*tt.width+x] & mask,
344                                             cells[y*tt.width+x],
345                                             result & mask,
346                                             result, buf);
347                                 }
348                         }
349                 }
350         }
351
352         printf("passed [%d iterations x %d]\n", reps, sets);
353
354         test_target_destroy_render(&t->real, &tt);
355         free(cells);
356 }
357
358 static void rect_tests(struct test *t,
359                        int dx, int dy,
360                        enum mask mask,
361                        int reps, int sets,
362                        enum target target,
363                        int use_window)
364 {
365         struct test_target real, ref;
366         int r, s;
367
368         printf("Testing area fills (offset %dx%d, mask %s) (%s using %s source): ",
369                dx, dy, mask_name(mask), test_target_name(target),
370                use_window ? "window" : "pixmap");
371         fflush(stdout);
372
373         test_target_create_render(&t->real, target, &real);
374         clear(&t->real, &real);
375         set_mask(&t->real, &real, mask);
376
377         test_target_create_render(&t->ref, target, &ref);
378         clear(&t->ref, &ref);
379         set_mask(&t->ref, &ref, mask);
380
381         for (s = 0; s < sets; s++) {
382                 for (r = 0; r < reps; r++) {
383                         int x, y, w, h;
384                         int op = ops[rand() % sizeof(ops)];
385                         int red = rand() % 0xff;
386                         int green = rand() % 0xff;
387                         int blue = rand() % 0xff;
388                         int alpha = rand() % 0xff;
389                         int tx, ty, try = 50;
390
391                         do {
392                                 x = rand() % (real.width - 1);
393                                 y = rand() % (real.height - 1);
394                                 w = 1 + rand() % (real.width - x - 1);
395                                 h = 1 + rand() % (real.height - y - 1);
396                                 tx = w == real.width ? 0 : rand() % (real.width - w);
397                                 ty = h == real.height ? 0 : rand() % (real.height - h);
398                         } while (((tx+w > x && tx < x+w) &&
399                                   (ty+h > y && ty < y+h)) &&
400                                  --try);
401
402                         if (try) {
403                                 fill_rect(&t->real, real.picture,
404                                           use_window ? t->real.format : real.format,
405                                           op, x, y, w, h,
406                                           dx, dy, mask,
407                                           use_window, tx, ty,
408                                           red, green, blue, alpha);
409                                 fill_rect(&t->ref, ref.picture,
410                                           use_window ? t->ref.format : ref.format,
411                                           op, x, y, w, h,
412                                           dx, dy, mask,
413                                           use_window, tx, ty,
414                                           red, green, blue, alpha);
415                         }
416                 }
417
418                 test_compare(t,
419                              real.draw, real.format,
420                              ref.draw, ref.format,
421                              0, 0, real.width, real.height,
422                              "");
423         }
424
425         printf("passed [%d iterations x %d]\n", reps, sets);
426
427         test_target_destroy_render(&t->real, &real);
428         test_target_destroy_render(&t->ref, &ref);
429 }
430
431 static void random_trapezoid(XTrapezoid *trap, enum trapezoid trapezoid,
432                              int x1, int y1, int x2, int y2)
433 {
434         switch (trapezoid) {
435         case RECT_ALIGN:
436                 x1 = x1 + rand() % (x2 - x1);
437                 x2 = x1 + rand() % (x2 - x1);
438                 y1 = y1 + rand() % (y2 - y1);
439                 y2 = y1 + rand() % (y2 - y1);
440
441                 trap->left.p1.x = trap->left.p2.x = x1 << 16;
442                 trap->top = trap->left.p1.y = trap->right.p1.y = y1 << 16;
443                 trap->right.p1.x = trap->right.p2.x = x2 << 16;
444                 trap->bottom = trap->left.p2.y = trap->right.p2.y = y2 << 16;
445                 break;
446
447         case RECT_UNALIGN:
448                 x1 <<= 16; x2 <<= 16;
449                 y1 <<= 16; y2 <<= 16;
450
451                 x1 = x1 + rand() % (x2 - x1);
452                 x2 = x1 + rand() % (x2 - x1);
453                 y1 = y1 + rand() % (y2 - y1);
454                 y2 = y1 + rand() % (y2 - y1);
455
456                 trap->left.p1.x = trap->left.p2.x = x1;
457                 trap->top = trap->left.p1.y = trap->right.p1.y = y1;
458                 trap->right.p1.x = trap->right.p2.x = x2;
459                 trap->bottom = trap->left.p2.y = trap->right.p2.y = y2;
460                 break;
461
462         case GENERAL:
463                 x1 <<= 16; x2 <<= 16;
464                 y1 <<= 16; y2 <<= 16;
465
466                 trap->top = y1 + rand() % (y2 - y1);
467                 trap->bottom = y1 + rand() % (y2 - y1);
468
469                 trap->left.p1.x = x1 + rand() % (x2 - x1);
470                 trap->left.p2.x = x1 + rand() % (x2 - x1);
471
472                 trap->right.p1.x = x1 + rand() % (x2 - x1);
473                 trap->right.p2.x = x1 + rand() % (x2 - x1);
474                 break;
475         }
476 }
477
478 static void fill_traps(struct test_display *t, Picture p, XRenderPictFormat *format,
479                        uint8_t op, XTrapezoid *traps, int ntraps, enum mask mask,
480                        int srcx, int srcy, int srcw, int srch,
481                        uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
482 {
483         XRenderColor color;
484         Drawable tmp;
485         Picture src;
486
487         tmp = XCreatePixmap(t->dpy, DefaultRootWindow(t->dpy),
488                             srcw, srch, format->depth);
489
490         src = XRenderCreatePicture(t->dpy, tmp, format, 0, NULL);
491         color.red = red * alpha;
492         color.green = green * alpha;
493         color.blue = blue * alpha;
494         color.alpha = alpha << 8 | alpha;
495         XRenderFillRectangle(t->dpy, PictOpSrc, src, &color, 0, 0, srcw, srch);
496
497         XRenderCompositeTrapezoids(t->dpy,
498                                    op, src, p, mask_format(t->dpy, mask),
499                                    srcx, srcy, traps, ntraps);
500
501         XRenderFreePicture(t->dpy, src);
502         XFreePixmap(t->dpy, tmp);
503 }
504
505 static void trap_tests(struct test *t,
506                        enum mask mask,
507                        enum trapezoid trapezoid,
508                        int reps, int sets,
509                        enum target target)
510 {
511         struct test_target real, ref;
512         XTrapezoid *traps;
513         int max_traps = 65536;
514         int r, s, n;
515
516         traps = malloc(sizeof(*traps) * max_traps);
517         if (traps == NULL)
518                 return;
519
520         printf("Testing trapezoids (%s with mask %s) (%s): ",
521                trapezoid_name(trapezoid),
522                mask_name(mask),
523                test_target_name(target));
524         fflush(stdout);
525
526         test_target_create_render(&t->real, target, &real);
527         clear(&t->real, &real);
528         set_mask(&t->real, &real, mask);
529
530         test_target_create_render(&t->ref, target, &ref);
531         clear(&t->ref, &ref);
532         set_mask(&t->ref, &ref, mask);
533
534         for (s = 0; s < sets; s++) {
535                 for (r = 0; r < reps; r++) {
536                         int op = ops[rand() % sizeof(ops)];
537                         int red = rand() % 0xff;
538                         int green = rand() % 0xff;
539                         int blue = rand() % 0xff;
540                         int alpha = rand() % 0xff;
541                         int num_traps = rand() % max_traps;
542                         int srcx = rand() % 2*real.width - real.width;
543                         int srcy = rand() % 2*real.height - real.height;
544                         int srcw = rand() % real.width;
545                         int srch = rand() % real.height;
546
547                         for (n = 0; n < num_traps; n++)
548                                 random_trapezoid(&traps[n], 0,
549                                                  0, 0, real.width, real.height);
550
551
552                         fill_traps(&t->real, real.picture, real.format,
553                                    op, traps, num_traps, mask,
554                                    srcx, srcy, srcw, srch,
555                                    red, green, blue, alpha);
556
557                         fill_traps(&t->ref, ref.picture, ref.format,
558                                    op, traps, num_traps, mask,
559                                    srcx, srcy, srcw, srch,
560                                    red, green, blue, alpha);
561                 }
562
563                 test_compare(t,
564                              real.draw, real.format,
565                              ref.draw, ref.format,
566                              0, 0, real.width, real.height,
567                              "");
568         }
569
570         printf("passed [%d iterations x %d]\n", reps, sets);
571
572         test_target_destroy_render(&t->real, &real);
573         test_target_destroy_render(&t->ref, &ref);
574         free(traps);
575 }
576
577 int main(int argc, char **argv)
578 {
579         struct test test;
580         int i, dx, dy;
581         enum target target;
582         enum mask mask;
583         enum trapezoid trapezoid;
584
585         test_init(&test, argc, argv);
586
587         for (i = 0; i <= DEFAULT_ITERATIONS; i++) {
588                 int reps = 1 << i;
589                 int sets = 1 << (12 - i);
590
591                 if (sets < 2)
592                         sets = 2;
593
594                 for (target = TARGET_FIRST; target <= TARGET_LAST; target++) {
595                         pixel_tests(&test, reps, sets, target, 0);
596                         area_tests(&test, reps, sets, target, 0);
597                         for (dy = 0; dy < 1 << 16; dy += 1 << 14)
598                                 for (dx = 0; dx < 1 << 16; dx += 1 << 14)
599                                         for (mask = MASK_NONE; mask <= MASK_A8; mask++)
600                                                 rect_tests(&test, dx, dy, mask, reps, sets, target, 0);
601                         if (target != CHILD) {
602                                 pixel_tests(&test, reps, sets, target, 1);
603                                 area_tests(&test, reps, sets, target, 1);
604                                 for (dy = 0; dy < 1 << 16; dy += 1 << 14)
605                                         for (dx = 0; dx < 1 << 16; dx += 1 << 14)
606                                                 for (mask = MASK_NONE; mask <= MASK_A8; mask++)
607                                                         rect_tests(&test, dx, dy, mask, reps, sets, target, 1);
608                         }
609                 }
610
611                 for (target = TARGET_FIRST; target <= TARGET_LAST; target++)
612                         for (trapezoid = RECT_ALIGN; trapezoid <= GENERAL; trapezoid++)
613                                 trap_tests(&test, mask, trapezoid, reps, sets, target);
614         }
615
616         return 0;
617 }