test_image.c revision fe8aea9e
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 uint32_t *out, *ref; 201 char buf[600]; 202 uint32_t mask; 203 int i, j; 204 205 if (w * h * 4 > t->out.max_shm_size) 206 return test_compare_fallback(t, 207 out_draw, out_format, 208 ref_draw, ref_format, 209 x, y, w, h); 210 211 test_init_image(&out_image, &t->out.shm, out_format, w, h); 212 test_init_image(&ref_image, &t->ref.shm, ref_format, w, h); 213 214 die_unless(out_image.depth == ref_image.depth); 215 die_unless(out_image.bits_per_pixel == ref_image.bits_per_pixel); 216 die_unless(out_image.bits_per_pixel == 32); 217 218 XShmGetImage(t->out.dpy, out_draw, &out_image, x, y, AllPlanes); 219 out = (uint32_t *)out_image.data; 220 221 XShmGetImage(t->ref.dpy, ref_draw, &ref_image, x, y, AllPlanes); 222 ref = (uint32_t *)ref_image.data; 223 224 /* Start with an exact comparison. However, one quicky desires 225 * a fuzzy comparator to hide hardware inaccuracies... 226 */ 227 mask = depth_mask(out_image.depth); 228 for (j = 0; j < h; j++) { 229 for (i = 0; i < w; i++) { 230 uint32_t a = out[i] & mask; 231 uint32_t b = ref[i] & mask; 232 if (a != b && pixel_difference(a, b) > MAX_DELTA) { 233 show_pixels(buf, 234 &out_image, &ref_image, 235 i, j, w, h); 236 save_image(&out_image, "out.png"); 237 save_image(&ref_image, "ref.png"); 238 die("discrepancy found at (%d+%d, %d+%d): found %08x, expected %08x (delta: %d)\n%s%s\n", 239 x,i, y,j, a, b, pixel_difference(a, b), buf, info); 240 } 241 } 242 out = (uint32_t *)((char *)out + out_image.bytes_per_line); 243 ref = (uint32_t *)((char *)ref + ref_image.bytes_per_line); 244 } 245} 246 247static int 248_native_byte_order_lsb(void) 249{ 250 int x = 1; 251 return *((char *) &x) == 1; 252} 253 254void 255test_init_image(XImage *ximage, 256 XShmSegmentInfo *shm, 257 XRenderPictFormat *format, 258 int width, int height) 259{ 260 int native_byte_order = _native_byte_order_lsb() ? LSBFirst : MSBFirst; 261 262 ximage->width = width; 263 ximage->height = height; 264 ximage->format = ZPixmap; 265 ximage->data = shm->shmaddr; 266 ximage->obdata = (void *)shm; 267 ximage->byte_order = native_byte_order; 268 ximage->bitmap_unit = 32; 269 ximage->bitmap_bit_order = native_byte_order; 270 ximage->bitmap_pad = 32; 271 ximage->depth = format->depth; 272 ximage->bytes_per_line = 4*width; 273 ximage->bits_per_pixel = 32; 274 ximage->red_mask = 0xff << 16; 275 ximage->green_mask = 0xff << 8; 276 ximage->blue_mask = 0xff << 0; 277 ximage->xoffset = 0; 278 279 XInitImage(ximage); 280} 281