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
pixel_difference(uint32_t a,uint32_t b)10 int 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
31 static void
show_pixels(char * buf,const XImage * out,const XImage * ref,int x,int y,int w,int h)32 show_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
test_compare_fallback(struct test * t,Drawable out_draw,XRenderPictFormat * out_format,Drawable ref_draw,XRenderPictFormat * ref_format,int x,int y,int w,int h)70 static 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
118 static void
unpremultiply_data(png_structp png,png_row_infop row_info,png_bytep data)119 unpremultiply_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
save_image(XImage * image,const char * filename)144 static 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
186 out:
187 if (rows)
188 png_free(png, rows);
189 png_destroy_write_struct(&png, &info);
190 fclose(file);
191 }
192
test_compare(struct test * t,Drawable out_draw,XRenderPictFormat * out_format,Drawable ref_draw,XRenderPictFormat * ref_format,int x,int y,int w,int h,const char * info)193 void 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
247 static int
_native_byte_order_lsb(void)248 _native_byte_order_lsb(void)
249 {
250 int x = 1;
251 return *((char *) &x) == 1;
252 }
253
254 void
test_init_image(XImage * ximage,XShmSegmentInfo * shm,XRenderPictFormat * format,int width,int height)255 test_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