test_image.c revision 03b705cf
1#include <stdint.h>
2#include <stdio.h>
3#include <string.h>
4
5#include "test.h"
6
7#define MAX_DELTA 3
8
9int pixel_difference(uint32_t a, uint32_t b)
10{
11	int max = 0;
12	int i;
13
14	for (i = 0; i < 32; i += 8) {
15		uint8_t ac = (a >> i) & 0xff;
16		uint8_t bc = (b >> i) & 0xff;
17		int d;
18
19		if (ac > bc)
20			d = ac - bc;
21		else
22			d = bc - ac;
23		if (d > max)
24			max = d;
25	}
26
27	return max;
28}
29
30static void
31show_pixels(char *buf,
32	    const XImage *real, const XImage *ref,
33	    int x, int y, int w, int h)
34{
35	int i, j, len = 0;
36
37	for (j = y - 2; j <= y + 2; j++) {
38		if (j < 0 || j >= h)
39			continue;
40
41		for (i = x - 2; i <= x + 2; i++) {
42			if (i < 0 || i >= w)
43				continue;
44
45			len += sprintf(buf+len,
46				       "%08x ",
47				       *(uint32_t*)(real->data +
48						    j*real->bytes_per_line +
49						    i*real->bits_per_pixel/8));
50		}
51
52		len += sprintf(buf+len, "\t");
53
54		for (i = x - 2; i <= x + 2; i++) {
55			if (i < 0 || i >= w)
56				continue;
57
58			len += sprintf(buf+len,
59				       "%08x ",
60				       *(uint32_t*)(ref->data +
61						    j*real->bytes_per_line +
62						    i*real->bits_per_pixel/8));
63		}
64
65		len += sprintf(buf+len, "\n");
66	}
67}
68
69static void test_compare_fallback(struct test *t,
70				  Drawable real_draw, XRenderPictFormat *real_format,
71				  Drawable ref_draw, XRenderPictFormat *ref_format,
72				  int x, int y, int w, int h)
73{
74	XImage *real_image, *ref_image;
75	char *real, *ref;
76	char buf[600];
77	uint32_t mask;
78	int i, j;
79
80	die_unless(real_format->depth == ref_format->depth);
81
82	real_image = XGetImage(t->real.dpy, real_draw,
83			       x, y, w, h,
84			       AllPlanes, ZPixmap);
85	real = real_image->data;
86
87	ref_image = XGetImage(t->ref.dpy, ref_draw,
88			      x, y, w, h,
89			      AllPlanes, ZPixmap);
90	ref = ref_image->data;
91
92	mask = depth_mask(real_image->depth);
93
94	/* Start with an exact comparison. However, one quicky desires
95	 * a fuzzy comparator to hide hardware inaccuracies...
96	 */
97	for (j = 0; j < h; j++) {
98		for (i = 0; i < w; i++) {
99			uint32_t a = ((uint32_t *)real)[i] & mask;
100			uint32_t b = ((uint32_t *)ref)[i] & mask;
101			if (a != b && pixel_difference(a, b) > MAX_DELTA) {
102				show_pixels(buf,
103					    real_image, ref_image,
104					    i, j, w, h);
105				die("discrepancy found at (%d+%d, %d+%d): found %08x, expected %08x (delta: %d)\n%s",
106				    x,i, y,j, a, b, pixel_difference(a, b), buf);
107			}
108		}
109		real += real_image->bytes_per_line;
110		ref += ref_image->bytes_per_line;
111	}
112
113	XDestroyImage(real_image);
114	XDestroyImage(ref_image);
115}
116
117void test_compare(struct test *t,
118		  Drawable real_draw, XRenderPictFormat *real_format,
119		  Drawable ref_draw, XRenderPictFormat *ref_format,
120		  int x, int y, int w, int h,
121		  const char *info)
122{
123	XImage real_image, ref_image;
124	Pixmap tmp;
125	char *real, *ref;
126	char buf[600];
127	uint32_t mask;
128	int i, j;
129	XGCValues gcv;
130	GC gc;
131
132	if (w * h * 4 > t->real.max_shm_size)
133		return test_compare_fallback(t,
134					     real_draw, real_format,
135					     ref_draw, ref_format,
136					     x, y, w, h);
137
138	test_init_image(&real_image, &t->real.shm, real_format, w, h);
139	test_init_image(&ref_image, &t->ref.shm, ref_format, w, h);
140
141	gcv.graphics_exposures = 0;
142
143	die_unless(real_image.depth == ref_image.depth);
144	die_unless(real_image.bits_per_pixel == ref_image.bits_per_pixel);
145	die_unless(real_image.bits_per_pixel == 32);
146
147	mask = depth_mask(real_image.depth);
148
149	tmp = XCreatePixmap(t->real.dpy, real_draw, w, h, real_image.depth);
150	gc = XCreateGC(t->real.dpy, tmp, GCGraphicsExposures, &gcv);
151	XCopyArea(t->real.dpy, real_draw, tmp, gc, x, y, w, h, 0, 0);
152	XShmGetImage(t->real.dpy, tmp, &real_image, 0, 0, AllPlanes);
153	XFreeGC(t->real.dpy, gc);
154	XFreePixmap(t->real.dpy, tmp);
155	real = real_image.data;
156
157	tmp = XCreatePixmap(t->ref.dpy, ref_draw, w, h, ref_image.depth);
158	gc = XCreateGC(t->ref.dpy, tmp, GCGraphicsExposures, &gcv);
159	XCopyArea(t->ref.dpy, ref_draw, tmp, gc, x, y, w, h, 0, 0);
160	XShmGetImage(t->ref.dpy, tmp, &ref_image, 0, 0, AllPlanes);
161	XFreeGC(t->ref.dpy, gc);
162	XFreePixmap(t->ref.dpy, tmp);
163	ref = ref_image.data;
164
165	/* Start with an exact comparison. However, one quicky desires
166	 * a fuzzy comparator to hide hardware inaccuracies...
167	 */
168	for (j = 0; j < h; j++) {
169		for (i = 0; i < w; i++) {
170			uint32_t a = ((uint32_t *)real)[i] & mask;
171			uint32_t b = ((uint32_t *)ref)[i] & mask;
172			if (a != b && pixel_difference(a, b) > MAX_DELTA) {
173				show_pixels(buf,
174					    &real_image, &ref_image,
175					    i, j, w, h);
176				die("discrepancy found at (%d+%d, %d+%d): found %08x, expected %08x (delta: %d)\n%s%s\n",
177				    x,i, y,j, a, b, pixel_difference(a, b), buf, info);
178			}
179		}
180		real += real_image.bytes_per_line;
181		ref += ref_image.bytes_per_line;
182	}
183}
184
185static int
186_native_byte_order_lsb(void)
187{
188	int x = 1;
189	return *((char *) &x) == 1;
190}
191
192void
193test_init_image(XImage *ximage,
194		XShmSegmentInfo *shm,
195		XRenderPictFormat *format,
196		int width, int height)
197{
198	int native_byte_order = _native_byte_order_lsb() ? LSBFirst : MSBFirst;
199
200	ximage->width = width;
201	ximage->height = height;
202	ximage->format = ZPixmap;
203	ximage->data = shm->shmaddr;
204	ximage->obdata = (void *)shm;
205	ximage->byte_order = native_byte_order;
206	ximage->bitmap_unit = 32;
207	ximage->bitmap_bit_order = native_byte_order;
208	ximage->bitmap_pad = 32;
209	ximage->depth = format->depth;
210	ximage->bytes_per_line = 4*width;
211	ximage->bits_per_pixel = 32;
212	ximage->red_mask = 0xff << 16;
213	ximage->green_mask = 0xff << 8;
214	ximage->blue_mask = 0xff << 0;
215	ximage->xoffset = 0;
216
217	XInitImage(ximage);
218}
219