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 10static void 11show_cells(char *buf, 12 const uint32_t *out, const uint32_t *ref, 13 int x, int y, int w, int h) 14{ 15 int i, j, len = 0; 16 17 for (j = y - 2; j <= y + 2; j++) { 18 if (j < 0 || j >= h) 19 continue; 20 21 for (i = x - 2; i <= x + 2; i++) { 22 if (i < 0 || i >= w) 23 continue; 24 25 len += sprintf(buf+len, "%08x ", out[j*w+i]); 26 } 27 28 len += sprintf(buf+len, "\t"); 29 30 for (i = x - 2; i <= x + 2; i++) { 31 if (i < 0 || i >= w) 32 continue; 33 34 len += sprintf(buf+len, "%08x ", ref[j*w+i]); 35 } 36 37 len += sprintf(buf+len, "\n"); 38 } 39} 40 41static void fill_rect(struct test_display *t, 42 Drawable d, 43 XRenderPictFormat *format, 44 int use_window, int tx, int ty, 45 uint8_t alu, int x, int y, int w, int h, uint32_t fg) 46{ 47 XGCValues val; 48 Drawable tmp; 49 GC gc; 50 51 val.graphics_exposures = 0; 52 val.function = alu; 53 val.foreground = fg; 54 55 if (use_window) { 56 XSetWindowAttributes attr; 57 58 attr.override_redirect = 1; 59 tmp = XCreateWindow(t->dpy, DefaultRootWindow(t->dpy), 60 tx, ty, 61 w, h, 62 0, format->depth, 63 InputOutput, 64 DefaultVisual(t->dpy, 65 DefaultScreen(t->dpy)), 66 CWOverrideRedirect, &attr); 67 XMapWindow(t->dpy, tmp); 68 } else 69 tmp = XCreatePixmap(t->dpy, d, w, h, format->depth); 70 71 gc = XCreateGC(t->dpy, d, GCGraphicsExposures | GCForeground, &val); 72 XFillRectangle(t->dpy, tmp, gc, 0, 0, w, h); 73 74 XChangeGC(t->dpy, gc, GCFunction, &val); 75 XCopyArea(t->dpy, tmp, d, gc, 0, 0, w, h, x, y); 76 77 XFreeGC(t->dpy, gc); 78 if (use_window) 79 XDestroyWindow(t->dpy, tmp); 80 else 81 XFreePixmap(t->dpy, tmp); 82} 83 84static void pixel_tests(struct test *t, int reps, int sets, enum target target) 85{ 86 struct test_target tt; 87 XImage image; 88 uint32_t *cells = malloc(t->out.width*t->out.height*4); 89 struct { 90 uint16_t x, y; 91 } *pixels = malloc(reps*sizeof(*pixels)); 92 int r, s; 93 94 test_target_create_render(&t->out, target, &tt); 95 96 printf("Testing setting of single pixels (%s): ", 97 test_target_name(target)); 98 fflush(stdout); 99 100 for (s = 0; s < sets; s++) { 101 for (r = 0; r < reps; r++) { 102 int x = rand() % (tt.width - 1); 103 int y = rand() % (tt.height - 1); 104 uint32_t fg = rand(); 105 106 fill_rect(&t->out, tt.draw, tt.format, 107 0, 0, 0, 108 GXcopy, x, y, 1, 1, fg); 109 110 pixels[r].x = x; 111 pixels[r].y = y; 112 cells[y*tt.width+x] = fg; 113 } 114 115 test_init_image(&image, &t->out.shm, tt.format, 1, 1); 116 117 for (r = 0; r < reps; r++) { 118 uint32_t x = pixels[r].x; 119 uint32_t y = pixels[r].y; 120 uint32_t result; 121 122 XShmGetImage(t->out.dpy, tt.draw, &image, 123 x, y, AllPlanes); 124 125 result = *(uint32_t *)image.data; 126 if (!pixel_equal(image.depth, result, 127 cells[y*tt.width+x])) { 128 uint32_t mask = depth_mask(image.depth); 129 130 die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n", 131 x, y, 132 cells[y*tt.width+x] & mask, 133 cells[y*tt.width+x], 134 result & mask, 135 result); 136 } 137 } 138 } 139 printf("passed [%d iterations x %d]\n", reps, sets); 140 141 test_target_destroy_render(&t->out, &tt); 142 free(pixels); 143 free(cells); 144} 145 146static void clear(struct test_display *dpy, struct test_target *tt) 147{ 148 XRenderColor render_color = {0}; 149 XRenderFillRectangle(dpy->dpy, PictOpClear, tt->picture, &render_color, 150 0, 0, tt->width, tt->height); 151} 152 153static void area_tests(struct test *t, int reps, int sets, enum target target) 154{ 155 struct test_target tt; 156 XImage image; 157 uint32_t *cells = calloc(sizeof(uint32_t), t->out.width*t->out.height); 158 int r, s, x, y; 159 160 printf("Testing area sets (%s): ", test_target_name(target)); 161 fflush(stdout); 162 163 test_target_create_render(&t->out, target, &tt); 164 clear(&t->out, &tt); 165 166 test_init_image(&image, &t->out.shm, tt.format, tt.width, tt.height); 167 168 for (s = 0; s < sets; s++) { 169 for (r = 0; r < reps; r++) { 170 int w = 1 + rand() % (tt.width - 1); 171 int h = 1 + rand() % (tt.height - 1); 172 uint32_t fg = rand(); 173 174 x = rand() % (2*tt.width) - tt.width; 175 y = rand() % (2*tt.height) - tt.height; 176 177 fill_rect(&t->out, tt.draw, tt.format, 178 0, 0, 0, 179 GXcopy, x, y, w, h, fg); 180 181 if (x < 0) 182 w += x, x = 0; 183 if (y < 0) 184 h += y, y = 0; 185 if (x >= tt.width || y >= tt.height) 186 continue; 187 188 if (x + w > tt.width) 189 w = tt.width - x; 190 if (y + h > tt.height) 191 h = tt.height - y; 192 if (w <= 0 || h <= 0) 193 continue; 194 195 pixman_fill(cells, tt.width, 32, x, y, w, h, fg); 196 } 197 198 XShmGetImage(t->out.dpy, tt.draw, &image, 0, 0, AllPlanes); 199 200 for (y = 0; y < tt.height; y++) { 201 for (x = 0; x < tt.width; x++) { 202 uint32_t result = *(uint32_t *) 203 (image.data + 204 y*image.bytes_per_line + 205 x*image.bits_per_pixel/8); 206 if (!pixel_equal(image.depth, result, cells[y*tt.width+x])) { 207 char buf[600]; 208 uint32_t mask = depth_mask(image.depth); 209 show_cells(buf, 210 (uint32_t*)image.data, cells, 211 x, y, tt.width, tt.height); 212 213 die("failed to set pixel (%d,%d) to %08x [%08x], found %08x [%08x] instead\n%s", 214 x, y, 215 cells[y*tt.width+x] & mask, 216 cells[y*tt.width+x], 217 result & mask, 218 result, buf); 219 } 220 } 221 } 222 } 223 224 printf("passed [%d iterations x %d]\n", reps, sets); 225 226 test_target_destroy_render(&t->out, &tt); 227 free(cells); 228} 229 230static void rect_tests(struct test *t, int reps, int sets, enum target target, int use_window) 231{ 232 struct test_target out, ref; 233 int r, s; 234 235 printf("Testing area fills (%s, using %s source): ", 236 test_target_name(target), use_window ? "window" : "pixmap"); 237 fflush(stdout); 238 239 test_target_create_render(&t->out, target, &out); 240 clear(&t->out, &out); 241 242 test_target_create_render(&t->ref, target, &ref); 243 clear(&t->ref, &ref); 244 245 for (s = 0; s < sets; s++) { 246 for (r = 0; r < reps; r++) { 247 int x = rand() % (out.width - 1); 248 int y = rand() % (out.height - 1); 249 int w = 1 + rand() % (out.width - x - 1); 250 int h = 1 + rand() % (out.height - y - 1); 251 int tmpx = w == out.width ? 0 : rand() % (out.width - w); 252 int tmpy = h == out.height ? 0 : rand() % (out.height - h); 253 uint8_t alu = rand() % (GXset + 1); 254 uint32_t fg = rand(); 255 256 fill_rect(&t->out, out.draw, out.format, 257 use_window, tmpx, tmpy, 258 alu, x, y, w, h, fg); 259 fill_rect(&t->ref, ref.draw, ref.format, 260 use_window, tmpx, tmpy, 261 alu, x, y, w, h, fg); 262 } 263 264 test_compare(t, 265 out.draw, out.format, 266 ref.draw, ref.format, 267 0, 0, out.width, out.height, 268 ""); 269 } 270 271 printf("passed [%d iterations x %d]\n", reps, sets); 272 273 test_target_destroy_render(&t->out, &out); 274 test_target_destroy_render(&t->ref, &ref); 275} 276 277int main(int argc, char **argv) 278{ 279 struct test test; 280 int i; 281 282 test_init(&test, argc, argv); 283 284 for (i = 0; i <= DEFAULT_ITERATIONS; i++) { 285 int reps = REPS(i), sets = SETS(i); 286 enum target t; 287 288 for (t = TARGET_FIRST; t <= TARGET_LAST; t++) { 289 pixel_tests(&test, reps, sets, t); 290 area_tests(&test, reps, sets, t); 291 rect_tests(&test, reps, sets, t, 0); 292 if (t != PIXMAP) 293 rect_tests(&test, reps, sets, t, 1); 294 } 295 } 296 297 return 0; 298} 299