1#include <stdint.h> 2#include <stdio.h> 3#include <string.h> 4#include <png.h> 5 6#include "test.h" 7 8#define MAX_DELTA 3 9 10int pixel_difference(uint32_t a, uint32_t b) 11{ 12 int max = 0; 13 int i; 14 15 for (i = 0; i < 32; i += 8) { 16 uint8_t ac = (a >> i) & 0xff; 17 uint8_t bc = (b >> i) & 0xff; 18 int d; 19 20 if (ac > bc) 21 d = ac - bc; 22 else 23 d = bc - ac; 24 if (d > max) 25 max = d; 26 } 27 28 return max; 29} 30 31static void 32show_pixels(char *buf, 33 const XImage *out, const XImage *ref, 34 int x, int y, int w, int h) 35{ 36 int i, j, len = 0; 37 38 for (j = y - 2; j <= y + 2; j++) { 39 if (j < 0 || j >= h) 40 continue; 41 42 for (i = x - 2; i <= x + 2; i++) { 43 if (i < 0 || i >= w) 44 continue; 45 46 len += sprintf(buf+len, 47 "%08x ", 48 *(uint32_t*)(out->data + 49 j*out->bytes_per_line + 50 i*out->bits_per_pixel/8)); 51 } 52 53 len += sprintf(buf+len, "\t"); 54 55 for (i = x - 2; i <= x + 2; i++) { 56 if (i < 0 || i >= w) 57 continue; 58 59 len += sprintf(buf+len, 60 "%08x ", 61 *(uint32_t*)(ref->data + 62 j*out->bytes_per_line + 63 i*out->bits_per_pixel/8)); 64 } 65 66 len += sprintf(buf+len, "\n"); 67 } 68} 69 70static void test_compare_fallback(struct test *t, 71 Drawable out_draw, XRenderPictFormat *out_format, 72 Drawable ref_draw, XRenderPictFormat *ref_format, 73 int x, int y, int w, int h) 74{ 75 XImage *out_image, *ref_image; 76 char *out, *ref; 77 char buf[600]; 78 uint32_t mask; 79 int i, j; 80 81 die_unless(out_format->depth == ref_format->depth); 82 83 out_image = XGetImage(t->out.dpy, out_draw, 84 x, y, w, h, 85 AllPlanes, ZPixmap); 86 out = out_image->data; 87 88 ref_image = XGetImage(t->ref.dpy, ref_draw, 89 x, y, w, h, 90 AllPlanes, ZPixmap); 91 ref = ref_image->data; 92 93 mask = depth_mask(out_image->depth); 94 95 /* Start with an exact comparison. However, one quicky desires 96 * a fuzzy comparator to hide hardware inaccuracies... 97 */ 98 for (j = 0; j < h; j++) { 99 for (i = 0; i < w; i++) { 100 uint32_t a = ((uint32_t *)out)[i] & mask; 101 uint32_t b = ((uint32_t *)ref)[i] & mask; 102 if (a != b && pixel_difference(a, b) > MAX_DELTA) { 103 show_pixels(buf, 104 out_image, ref_image, 105 i, j, w, h); 106 die("discrepancy found at (%d+%d, %d+%d): found %08x, expected %08x (delta: %d)\n%s", 107 x,i, y,j, a, b, pixel_difference(a, b), buf); 108 } 109 } 110 out += out_image->bytes_per_line; 111 ref += ref_image->bytes_per_line; 112 } 113 114 XDestroyImage(out_image); 115 XDestroyImage(ref_image); 116} 117 118static void 119unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) 120{ 121 unsigned int i; 122 123 for (i = 0; i < row_info->rowbytes; i += 4) { 124 uint8_t *b = &data[i]; 125 uint32_t pixel; 126 uint8_t alpha; 127 128 memcpy (&pixel, b, sizeof (uint32_t)); 129 alpha = (pixel & 0xff000000) >> 24; 130 if (alpha == 0) { 131 b[0] = (pixel & 0xff0000) >> 16; 132 b[1] = (pixel & 0x00ff00) >> 8; 133 b[2] = (pixel & 0x0000ff) >> 0; 134 b[3] = 0xff; 135 } else { 136 b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha; 137 b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha; 138 b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha; 139 b[3] = alpha; 140 } 141 } 142} 143 144static void save_image(XImage *image, const char *filename) 145{ 146 FILE *file; 147 png_struct *png = NULL; 148 png_info *info = NULL; 149 png_byte **rows = NULL; 150 int i; 151 152 file = fopen(filename, "w"); 153 if (file == NULL) 154 return; 155 156 png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); 157 if (png == NULL) 158 goto out; 159 160 info = png_create_info_struct(png); 161 if (info == NULL) 162 goto out; 163 164 rows = png_malloc(png, sizeof(png_byte *) * image->height); 165 if (rows == NULL) 166 goto out; 167 for (i = 0; i < image->height; i++) 168 rows[i] = (png_byte *)(image->data + image->bytes_per_line * i); 169 170 if (setjmp(png_jmpbuf(png))) 171 goto out; 172 173 png_set_IHDR(png, info, 174 image->width, image->height, 8, 175 PNG_COLOR_TYPE_RGB_ALPHA, 176 PNG_INTERLACE_NONE, 177 PNG_COMPRESSION_TYPE_DEFAULT, 178 PNG_FILTER_TYPE_DEFAULT); 179 180 png_init_io(png, file); 181 png_write_info(png, info); 182 png_set_write_user_transform_fn(png, unpremultiply_data); 183 png_write_image(png, rows); 184 png_write_end(png, info); 185 186out: 187 if (rows) 188 png_free(png, rows); 189 png_destroy_write_struct(&png, &info); 190 fclose(file); 191} 192 193void test_compare(struct test *t, 194 Drawable out_draw, XRenderPictFormat *out_format, 195 Drawable ref_draw, XRenderPictFormat *ref_format, 196 int x, int y, int w, int h, 197 const char *info) 198{ 199 XImage out_image, ref_image; 200 Pixmap tmp; 201 char *out, *ref; 202 char buf[600]; 203 uint32_t mask; 204 int i, j; 205 XGCValues gcv; 206 GC gc; 207 208 if (w * h * 4 > t->out.max_shm_size) 209 return test_compare_fallback(t, 210 out_draw, out_format, 211 ref_draw, ref_format, 212 x, y, w, h); 213 214 test_init_image(&out_image, &t->out.shm, out_format, w, h); 215 test_init_image(&ref_image, &t->ref.shm, ref_format, w, h); 216 217 gcv.graphics_exposures = 0; 218 219 die_unless(out_image.depth == ref_image.depth); 220 die_unless(out_image.bits_per_pixel == ref_image.bits_per_pixel); 221 die_unless(out_image.bits_per_pixel == 32); 222 223 mask = depth_mask(out_image.depth); 224 225 tmp = XCreatePixmap(t->out.dpy, out_draw, w, h, out_image.depth); 226 gc = XCreateGC(t->out.dpy, tmp, GCGraphicsExposures, &gcv); 227 XCopyArea(t->out.dpy, out_draw, tmp, gc, x, y, w, h, 0, 0); 228 XShmGetImage(t->out.dpy, tmp, &out_image, 0, 0, AllPlanes); 229 XFreeGC(t->out.dpy, gc); 230 XFreePixmap(t->out.dpy, tmp); 231 out = out_image.data; 232 233 tmp = XCreatePixmap(t->ref.dpy, ref_draw, w, h, ref_image.depth); 234 gc = XCreateGC(t->ref.dpy, tmp, GCGraphicsExposures, &gcv); 235 XCopyArea(t->ref.dpy, ref_draw, tmp, gc, x, y, w, h, 0, 0); 236 XShmGetImage(t->ref.dpy, tmp, &ref_image, 0, 0, AllPlanes); 237 XFreeGC(t->ref.dpy, gc); 238 XFreePixmap(t->ref.dpy, tmp); 239 ref = ref_image.data; 240 241 /* Start with an exact comparison. However, one quicky desires 242 * a fuzzy comparator to hide hardware inaccuracies... 243 */ 244 for (j = 0; j < h; j++) { 245 for (i = 0; i < w; i++) { 246 uint32_t a = ((uint32_t *)out)[i] & mask; 247 uint32_t b = ((uint32_t *)ref)[i] & mask; 248 if (a != b && pixel_difference(a, b) > MAX_DELTA) { 249 show_pixels(buf, 250 &out_image, &ref_image, 251 i, j, w, h); 252 save_image(&out_image, "out.png"); 253 save_image(&ref_image, "ref.png"); 254 die("discrepancy found at (%d+%d, %d+%d): found %08x, expected %08x (delta: %d)\n%s%s\n", 255 x,i, y,j, a, b, pixel_difference(a, b), buf, info); 256 } 257 } 258 out += out_image.bytes_per_line; 259 ref += ref_image.bytes_per_line; 260 } 261} 262 263static int 264_native_byte_order_lsb(void) 265{ 266 int x = 1; 267 return *((char *) &x) == 1; 268} 269 270void 271test_init_image(XImage *ximage, 272 XShmSegmentInfo *shm, 273 XRenderPictFormat *format, 274 int width, int height) 275{ 276 int native_byte_order = _native_byte_order_lsb() ? LSBFirst : MSBFirst; 277 278 ximage->width = width; 279 ximage->height = height; 280 ximage->format = ZPixmap; 281 ximage->data = shm->shmaddr; 282 ximage->obdata = (void *)shm; 283 ximage->byte_order = native_byte_order; 284 ximage->bitmap_unit = 32; 285 ximage->bitmap_bit_order = native_byte_order; 286 ximage->bitmap_pad = 32; 287 ximage->depth = format->depth; 288 ximage->bytes_per_line = 4*width; 289 ximage->bits_per_pixel = 32; 290 ximage->red_mask = 0xff << 16; 291 ximage->green_mask = 0xff << 8; 292 ximage->blue_mask = 0xff << 0; 293 ximage->xoffset = 0; 294 295 XInitImage(ximage); 296} 297