test_display.c revision 03b705cf
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5#include <sys/ipc.h>
6#include <sys/shm.h>
7
8#include "test.h"
9
10static Window get_root(struct test_display *t)
11{
12	XSetWindowAttributes attr;
13	Window w;
14
15	/* Be nasty and install a fullscreen window on top so that we
16	 * can guarantee we do not get clipped by children.
17	 */
18	attr.override_redirect = 1;
19	w= XCreateWindow(t->dpy, DefaultRootWindow(t->dpy),
20			 0, 0, t->width, t->height, 0,
21			 DefaultDepth(t->dpy, DefaultScreen(t->dpy)),
22			 InputOutput,
23			 DefaultVisual(t->dpy, DefaultScreen(t->dpy)),
24			 CWOverrideRedirect, &attr);
25	XMapWindow(t->dpy, w);
26
27	return w;
28}
29
30static Display *real_display(int argc, char **argv)
31{
32	Display *dpy;
33	const char *name = NULL;
34	int i;
35
36	for (i = 0; i < argc; i++) {
37		if (strncmp(argv[i], "-d", 2) == 0) {
38			if (argv[i][2] == '\0') {
39				if (i+1 < argc) {
40					name = argv[i+1];
41					i++;
42				}
43			} else
44				name = argv[i] + 2;
45		}
46	}
47
48	if (name == NULL)
49		name = getenv("DISPLAY");
50	if (name == NULL)
51		name = ":0"; /* useful default */
52
53	dpy = XOpenDisplay(name);
54	if (dpy == NULL)
55		die("unable to open real display %s\n", name);
56
57	printf("Opened connection to %s for testing.\n", name);
58	return dpy;
59}
60
61static Display *ref_display(int width, int height, int depth)
62{
63	Display *dpy;
64	char buf[160];
65	const char *name;
66	int try;
67
68	name = getenv("REF_DISPLAY");
69	if (name) {
70		dpy = XOpenDisplay(name);
71		if (dpy == NULL)
72			die("unable to open reference display %s\n", name);
73
74		printf("Opened connection to %s for reference.\n", name);
75		return dpy;
76	}
77
78	snprintf(buf, sizeof(buf),
79		 "Xvfb -ac -terminate -screen 0 %dx%dx%d :99 >/dev/null 2>&1 &",
80		 width, height, depth);
81	if (system(buf))
82		die("unable to spawn '%s' for reference display\n", buf);
83
84	try = 0;
85	while (try++ < 1000) {
86		dpy = XOpenDisplay(":99");
87		if (dpy)
88			break;
89		usleep(1000);
90	}
91
92	if (dpy == NULL)
93		die("unable to open reference display\n");
94
95	return dpy;
96}
97
98static void shm_setup(struct test_display *d)
99{
100	int major, minor, has_pixmaps;
101	int size;
102
103	XShmQueryVersion(d->dpy, &major, &minor, &has_pixmaps);
104	if (major == 0 && minor == 0)
105		die("XSHM not supported\n");
106
107	size = d->width * d->height * 4;
108	d->max_shm_size = size;
109
110	d->shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
111	if (d->shm.shmid == -1)
112		die("failed to allocated %d bytes for a shm segment\n", size);
113
114	d->shm.shmaddr = shmat(d->shm.shmid, NULL, 0);
115	d->shm.readOnly = 0;
116	XShmAttach(d->dpy, &d->shm);
117	XSync(d->dpy, 1);
118}
119
120static void default_setup(struct test_display *dpy)
121{
122	dpy->width = WidthOfScreen(DefaultScreenOfDisplay(dpy->dpy));
123	dpy->height = HeightOfScreen(DefaultScreenOfDisplay(dpy->dpy));
124	dpy->format =
125		XRenderFindVisualFormat(dpy->dpy,
126					DefaultVisual(dpy->dpy,
127						      DefaultScreen(dpy->dpy)));
128}
129
130static void test_get_displays(int argc, char **argv,
131			      struct test_display *real,
132			      struct test_display *ref)
133{
134	real->dpy = real_display(argc, argv);
135	default_setup(real);
136	shm_setup(real);
137	real->root = get_root(real);
138
139	ref->dpy = ref_display(real->width, real->height,
140			       DefaultDepth(real->dpy, DefaultScreen(real->dpy)));
141	default_setup(ref);
142	shm_setup(ref);
143	ref->root = get_root(ref);
144}
145
146void test_init(struct test *test, int argc, char **argv)
147{
148	memset(test, 0, sizeof(*test));
149	test_get_displays(argc, argv, &test->real, &test->ref);
150}
151
152void test_timer_start(struct test_display *t, struct timespec *tv)
153{
154	clock_gettime(CLOCK_MONOTONIC, tv);
155}
156
157double test_timer_stop(struct test_display *t, struct timespec *tv)
158{
159	XImage *image;
160	struct timespec now;
161
162	image = XGetImage(t->dpy, t->root, 0, 0, 1, 1, AllPlanes, ZPixmap);
163	clock_gettime(CLOCK_MONOTONIC, &now);
164	XDestroyImage(image);
165
166	return (now.tv_sec - tv->tv_sec) + 1e-9*(now.tv_nsec - tv->tv_nsec);
167}
168