main.c 9.34 KB
Newer Older
Eric Anholt's avatar
Eric Anholt committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * Copyright © 2004 Eric Anholt
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Eric Anholt not be used in
 * advertising or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Eric Anholt makes no
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
 * ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

#include "rendercheck.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
27
#include <strings.h>
28
#include <getopt.h>
Eric Anholt's avatar
Eric Anholt committed
29
#include "version.h"
Eric Anholt's avatar
Eric Anholt committed
30

31
bool is_verbose = false, minimalrendering = false;
32
int enabled_tests = ~0;		/* Enable all tests by default */
Eric Anholt's avatar
Eric Anholt committed
33

34
int format_whitelist_len = 0;
Adam Jackson's avatar
Adam Jackson committed
35
char **format_whitelist = NULL;
36

Eric Anholt's avatar
Eric Anholt committed
37 38 39 40 41
/* Number of times to repeat operations so that pixmaps will tend to get moved
 * into offscreen memory and allow hardware acceleration.
 */
int pixmap_move_iter = 1;

42
int win_width = 40;
43
int win_height = 200;
Eric Anholt's avatar
Eric Anholt committed
44

45
int
Eric Anholt's avatar
Eric Anholt committed
46 47 48 49 50 51 52 53 54 55 56 57 58
bit_count(int i)
{
	int count;

	count = (i >> 1) & 033333333333;
	count = i - count - ((count >> 1) & 033333333333);
	count = (((count + (count >> 3)) & 030707070707) % 077);
	/* HAKMEM 169 */
	return count;
}

/* This is not complete, but decent enough for now.*/
void
59
describe_format(char **desc, const char *prefix, XRenderPictFormat *format)
Eric Anholt's avatar
Eric Anholt committed
60 61 62 63 64
{
	char ad[4] = "", rd[4] = "", gd[4] = "", bd[4] = "";
	int ac, rc, gc, bc;
	int ashift;

65 66 67
	if (!prefix)
	    prefix = "";

Eric Anholt's avatar
Eric Anholt committed
68 69 70 71 72 73 74 75 76 77 78 79
	ac = bit_count(format->direct.alphaMask);
	rc = bit_count(format->direct.redMask);
	gc = bit_count(format->direct.greenMask);
	bc = bit_count(format->direct.blueMask);

	if (ac != 0) {
		snprintf(ad, 4, "a%d", ac);
		ashift = format->direct.alpha;
	} else if (rc + bc + gc < format->depth) {
		/* There are bits that are not part of A,R,G,B. Mark them with
		 * an x.
		 */
80 81
		snprintf(ad, 4, "x%d", format->depth - rc - gc - bc);
		if (format->direct.red == 0 || format->direct.blue == 0)
Eric Anholt's avatar
Eric Anholt committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
			ashift = format->depth;
		else
			ashift = 0;
	} else
		ashift = 0;

	if (rc  != 0)
		snprintf(rd, 4, "r%d", rc);
	if (gc  != 0)
		snprintf(gd, 4, "g%d", gc);
	if (bc  != 0)
		snprintf(bd, 4, "b%d", bc);

	if (ashift > format->direct.red) {
		if (format->direct.red > format->direct.blue)
97
			asprintf(desc, "%s%s%s%s%s", prefix, ad, rd, gd, bd);
Eric Anholt's avatar
Eric Anholt committed
98
		else
99
			asprintf(desc, "%s%s%s%s%s", prefix, ad, bd, gd, rd);
Eric Anholt's avatar
Eric Anholt committed
100 101
	} else {
		if (format->direct.red > format->direct.blue)
102
			asprintf(desc, "%s%s%s%s%s", prefix, rd, gd, bd, ad);
Eric Anholt's avatar
Eric Anholt committed
103
		else
104
			asprintf(desc, "%s%s%s%s%s", prefix, bd, gd, rd, ad);
Eric Anholt's avatar
Eric Anholt committed
105 106 107
	}
}

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
struct {
    int flag;
    const char *name;
} available_tests[] = {
    {TEST_FILL, "fill"},
    {TEST_DSTCOORDS, "dcoords"},
    {TEST_SRCCOORDS, "scoords"},
    {TEST_MASKCOORDS, "mcoords"},
    {TEST_TSRCCOORDS, "tscoords"},
    {TEST_TMASKCOORDS, "tmcoords"},
    {TEST_BLEND, "blend"},
    {TEST_COMPOSITE, "composite"},
    {TEST_CACOMPOSITE, "cacomposite"},
    {TEST_GRADIENTS, "gradients"},
    {TEST_REPEAT, "repeat"},
    {TEST_TRIANGLES, "triangles"},
    {TEST_BUG7366, "bug7366"},
    {0, NULL}
};

128 129 130 131 132 133 134 135 136 137 138 139
static void
print_test_separator(int i)
{
        if (i % 5 == 0) {
            if(i != 0)
                putc('\n', stderr);
            putc('\t', stderr);
        } else {
            fprintf(stderr, ", ");
        }
}

140 141 142 143 144 145
void print_tests(FILE *file, int tests) {
    int i, j;
    
    for (i=0, j=0; available_tests[i].name; i++) {
        if (!(available_tests[i].flag & tests))
            continue;
146
	print_test_separator(j++);
147 148 149
        fprintf(stderr, "%s", available_tests[i].name);
        j++;
    }
150 151 152 153 154 155 156
    for_each_test(test) {
	if (!(test->bit & tests))
	    continue;
	print_test_separator(j++);
        fprintf(stderr, "%s", test->arg_name);
        j++;
    }
157 158 159 160 161
    if (j)
        fprintf(file, "\n");
}

_X_NORETURN
162 163 164
static void
usage (char *program)
{
165
    fprintf(stderr, "usage: %s [-d|--display display] [-v|--verbose]\n"
166
	"\t[-t test1,test2,...] [-o op1,op2,...] [-f format1,format2,...]\n"
Aaron Plattner's avatar
Aaron Plattner committed
167
	"\t[--sync] [--minimalrendering] [--version]\n"
168 169
	"Available tests:\n", program);
    print_tests(stderr, ~0);
170 171 172
    exit(1);
}

Eric Anholt's avatar
Eric Anholt committed
173 174 175 176
int main(int argc, char **argv)
{
	Display *dpy;
	XEvent ev;
Adam Jackson's avatar
Adam Jackson committed
177
	int i, o, maj, min, ret = 1;
178 179
	static int is_sync = false, print_version = false;
	static int longopt_minimalrendering = 0;
Eric Anholt's avatar
Eric Anholt committed
180
	XWindowAttributes a;
181
	XSetWindowAttributes as;
Eric Anholt's avatar
Eric Anholt committed
182
	picture_info window;
183
	char *display = NULL;
184
	char *test_name, *format, *opname, *nextname;
185

186 187 188
	static struct option longopts[] = {
		{ "display",	required_argument,	NULL,	'd' },
		{ "iterations",	required_argument,	NULL,	'i' },
189
		{ "formats",	required_argument,	NULL,	'f' },
190
		{ "tests",	required_argument,	NULL,	't' },
191
		{ "ops",	required_argument,	NULL,	'o' },
192
		{ "verbose",	no_argument,		NULL,	'v' },
193 194 195 196
		{ "sync",	no_argument,		&is_sync, true},
		{ "minimalrendering", no_argument,
		  &longopt_minimalrendering, true},
		{ "version",	no_argument,		&print_version, true },
197 198 199
		{ NULL,		0,			NULL,	0 }
	};

200
	while ((o = getopt_long(argc, argv, "d:i:f:t:o:v", longopts, NULL)) != -1) {
201 202 203
		switch (o) {
		case 'd':
			display = optarg;
204 205 206 207
			break;
		case 'i':
			pixmap_move_iter = atoi(optarg);
			break;
208 209
		case 'o':
			for (i = 0; i < num_ops; i++)
210
				ops[i].disabled = true;
211 212 213 214 215 216 217

			nextname = optarg;
			while ((opname = strsep(&nextname, ",")) != NULL) {
				for (i = 0; i < num_ops; i++) {
					if (strcasecmp(ops[i].name, opname) !=
					    0)
						continue;
218
					ops[i].disabled = false;
219 220 221 222 223
					break;
				}
				if (i == num_ops)
					usage(argv[0]);
			}
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
			break;
		case 'f':
			nextname = optarg;
			for (format_whitelist_len = 0;;format_whitelist_len++)
			{
				if ((format = strsep(&nextname, ",")) == NULL)
					break;
			}

			format_whitelist = malloc(sizeof(char *) *
			    format_whitelist_len);
			if (format_whitelist == NULL)
				errx(1, "malloc");

			/* Now the list is separated by \0s, so use strlen to
			 * step between entries.
			 */
			format = optarg;
			for (i = 0; i < format_whitelist_len; i++) {
				format_whitelist[i] = strdup(format);
				format += strlen(format) + 1;
			}

247
			break;
248 249 250 251 252 253
		case 't':
			nextname = optarg;

			/* disable all tests */
			enabled_tests = 0;

254
			while ((test_name = strsep(&nextname, ",")) != NULL) {
255
				int i;
256
				bool found = false;
257
				for(i=0; available_tests[i].name; i++) {
258
					if(strcmp(test_name, available_tests[i].name) == 0) {
259
						enabled_tests |= available_tests[i].flag;
260 261 262 263 264 265 266 267 268
						found = true;
						break;
					}
				}
				for_each_test(test) {
					if (strcmp(test_name,
						   test->arg_name) == 0) {
						enabled_tests |= test->bit;
						found = true;
269 270
						break;
					}
271
				}
272
				if (!found)
273
					usage(argv[0]);
274
			}
275

276 277
			break;
		case 'v':
278
			is_verbose = true;
279
			break;
280 281
		case 0:
			break;
282 283 284 285 286
		default:
			usage(argv[0]);
			break;
		}
	}
Eric Anholt's avatar
Eric Anholt committed
287

288 289
	minimalrendering = longopt_minimalrendering;

Aaron Plattner's avatar
Aaron Plattner committed
290 291 292
	/* Print the version string.  Bail out if --version was requested and
	 * continue otherwise.
	 */
Eric Anholt's avatar
Eric Anholt committed
293
	printf("rendercheck %s\n", VERSION);
Aaron Plattner's avatar
Aaron Plattner committed
294 295 296
	if (print_version)
		return 0;

297 298 299
	dpy = XOpenDisplay(display);
	if (dpy == NULL)
		errx(1, "Couldn't open display.");
300 301
	if (is_sync)
		XSynchronize(dpy, 1);
Eric Anholt's avatar
Eric Anholt committed
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319

	if (!XRenderQueryExtension(dpy, &i, &i))
		errx(1, "Render extension missing.");

	XRenderQueryVersion(dpy, &maj, &min);
	if (maj != 0 || min < 1)
		errx(1, "Render extension version too low (%d.%d).", maj, min);

	printf("Render extension version %d.%d\n", maj, min);

	/* Conjoint/Disjoint were added in version 0.2, so disable those ops if
	 * the server doesn't support them.
	 */
	if (min < 2) {
		printf("Server doesn't support conjoint/disjoint ops, disabling.\n");
		num_ops = PictOpSaturate;
	}

320 321
	window.d = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0,
	    win_width, win_height, 0, 0, WhitePixel(dpy, 0));
322 323 324 325

	as.override_redirect = True;
	XChangeWindowAttributes(dpy, window.d, CWOverrideRedirect, &as);

Eric Anholt's avatar
Eric Anholt committed
326 327 328
	XGetWindowAttributes(dpy, window.d, &a);
	window.format = XRenderFindVisualFormat(dpy, a.visual);
	window.pict = XRenderCreatePicture(dpy, window.d,
329
	    window.format, 0, NULL);
330 331 332 333
	describe_format(&format, NULL, window.format);
	printf("Window format: %s\n", format);
	asprintf(&window.name, "%s window", format);
	free(format);
Eric Anholt's avatar
Eric Anholt committed
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
	XSelectInput(dpy, window.d, ExposureMask);
	XMapWindow(dpy, window.d);

	/* We have to premultiply the alpha into the r, g, b values of the
	 * sample colors.  Render colors are premultiplied with alpha, so r,g,b
	 * can never be greater than alpha.
	 */
	for (i = 0; i < num_colors; i++) {
		colors[i].r *= colors[i].a;
		colors[i].g *= colors[i].a;
		colors[i].b *= colors[i].a;
	}

	while (XNextEvent(dpy, &ev) == 0) {
		if (ev.type == Expose && !ev.xexpose.count) {
349
			if (do_tests(dpy, &window))
Adam Jackson's avatar
Adam Jackson committed
350
				ret = 0;
351
			else
Adam Jackson's avatar
Adam Jackson committed
352 353
				ret = 1;
			break;
Eric Anholt's avatar
Eric Anholt committed
354 355
		}
	}
356

Adam Jackson's avatar
Adam Jackson committed
357 358 359 360 361
	free(window.name);
	for (i = 0; i < format_whitelist_len; i++)
		free(format_whitelist[i]);
	free(format_whitelist);

362
        XCloseDisplay(dpy);
Adam Jackson's avatar
Adam Jackson committed
363
	return ret;
Eric Anholt's avatar
Eric Anholt committed
364
}