1428d7b3dSmrg#include <stdio.h>
2428d7b3dSmrg#include <stdlib.h>
3428d7b3dSmrg#include <string.h>
4428d7b3dSmrg#include <unistd.h>
5428d7b3dSmrg#include <sys/ipc.h>
6428d7b3dSmrg#include <sys/shm.h>
7428d7b3dSmrg
8428d7b3dSmrg#include "test.h"
9428d7b3dSmrg
10428d7b3dSmrgstatic Window get_root(struct test_display *t)
11428d7b3dSmrg{
12428d7b3dSmrg	XSetWindowAttributes attr;
13428d7b3dSmrg	Window w;
14428d7b3dSmrg
15428d7b3dSmrg	/* Be nasty and install a fullscreen window on top so that we
16428d7b3dSmrg	 * can guarantee we do not get clipped by children.
17428d7b3dSmrg	 */
18428d7b3dSmrg	attr.override_redirect = 1;
19428d7b3dSmrg	w = XCreateWindow(t->dpy, DefaultRootWindow(t->dpy),
20428d7b3dSmrg			  0, 0, t->width, t->height, 0,
21428d7b3dSmrg			  DefaultDepth(t->dpy, DefaultScreen(t->dpy)),
22428d7b3dSmrg			  InputOutput,
23428d7b3dSmrg			  DefaultVisual(t->dpy, DefaultScreen(t->dpy)),
24428d7b3dSmrg			  CWOverrideRedirect, &attr);
25428d7b3dSmrg	XMapWindow(t->dpy, w);
26428d7b3dSmrg
27428d7b3dSmrg	return w;
28428d7b3dSmrg}
29428d7b3dSmrg
30428d7b3dSmrgstatic Display *out_display(int argc, char **argv)
31428d7b3dSmrg{
32428d7b3dSmrg	Display *dpy;
33428d7b3dSmrg	const char *name = NULL;
34428d7b3dSmrg	int i;
35428d7b3dSmrg
36428d7b3dSmrg	for (i = 0; i < argc; i++) {
37428d7b3dSmrg		if (strncmp(argv[i], "-d", 2) == 0) {
38428d7b3dSmrg			if (argv[i][2] == '\0') {
39428d7b3dSmrg				if (i+1 < argc) {
40428d7b3dSmrg					name = argv[i+1];
41428d7b3dSmrg					i++;
42428d7b3dSmrg				}
43428d7b3dSmrg			} else
44428d7b3dSmrg				name = argv[i] + 2;
45428d7b3dSmrg		}
46428d7b3dSmrg	}
47428d7b3dSmrg
48428d7b3dSmrg	if (name == NULL)
49428d7b3dSmrg		name = getenv("DISPLAY");
50428d7b3dSmrg	if (name == NULL)
51428d7b3dSmrg		name = ":0"; /* useful default */
52428d7b3dSmrg
53428d7b3dSmrg	dpy = XOpenDisplay(name);
54428d7b3dSmrg	if (dpy == NULL)
55428d7b3dSmrg		die("unable to open out display %s\n", name);
56428d7b3dSmrg
57428d7b3dSmrg	printf("Opened connection to %s for testing.\n", name);
58428d7b3dSmrg	return dpy;
59428d7b3dSmrg}
60428d7b3dSmrg
61428d7b3dSmrgstatic Display *ref_display(int width, int height, int depth)
62428d7b3dSmrg{
63428d7b3dSmrg	Display *dpy;
64428d7b3dSmrg	char buf[160];
65428d7b3dSmrg	const char *name;
66428d7b3dSmrg	int try;
67428d7b3dSmrg
68428d7b3dSmrg	name = getenv("REF_DISPLAY");
69428d7b3dSmrg	if (name) {
70428d7b3dSmrg		dpy = XOpenDisplay(name);
71428d7b3dSmrg		if (dpy == NULL)
72428d7b3dSmrg			die("unable to open reference display %s\n", name);
73428d7b3dSmrg
74428d7b3dSmrg		printf("Opened connection to %s for reference.\n", name);
75428d7b3dSmrg		return dpy;
76428d7b3dSmrg	}
77428d7b3dSmrg
78428d7b3dSmrg	snprintf(buf, sizeof(buf),
79428d7b3dSmrg		 "Xvfb -ac -terminate -screen 0 %dx%dx%d :99 >/dev/null 2>&1 &",
80428d7b3dSmrg		 width, height, depth);
81428d7b3dSmrg	if (system(buf))
82428d7b3dSmrg		die("unable to spawn '%s' for reference display\n", buf);
83428d7b3dSmrg
84428d7b3dSmrg	try = 0;
85428d7b3dSmrg	while (try++ < 1000) {
86428d7b3dSmrg		dpy = XOpenDisplay(":99");
87428d7b3dSmrg		if (dpy)
88428d7b3dSmrg			break;
89428d7b3dSmrg		usleep(1000);
90428d7b3dSmrg	}
91428d7b3dSmrg
92428d7b3dSmrg	if (dpy == NULL)
93428d7b3dSmrg		die("unable to open reference display\n");
94428d7b3dSmrg
95428d7b3dSmrg	return dpy;
96428d7b3dSmrg}
97428d7b3dSmrg
98428d7b3dSmrgstatic void shm_setup(struct test_display *d)
99428d7b3dSmrg{
100428d7b3dSmrg	int major, minor;
101428d7b3dSmrg	int size;
102428d7b3dSmrg
103428d7b3dSmrg	XShmQueryVersion(d->dpy, &major, &minor, &d->has_shm_pixmaps);
104428d7b3dSmrg	if (major == 0 && minor == 0)
105428d7b3dSmrg		die("XSHM not supported\n");
106428d7b3dSmrg
107428d7b3dSmrg	size = d->width * d->height * 4;
108428d7b3dSmrg	d->max_shm_size = size;
109428d7b3dSmrg
110428d7b3dSmrg	d->shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
111428d7b3dSmrg	if (d->shm.shmid == -1)
112428d7b3dSmrg		die("failed to allocated %d bytes for a shm segment\n", size);
113428d7b3dSmrg
114428d7b3dSmrg	d->shm.shmaddr = shmat(d->shm.shmid, NULL, 0);
115428d7b3dSmrg	d->shm.readOnly = 0;
116428d7b3dSmrg	XShmAttach(d->dpy, &d->shm);
117428d7b3dSmrg	XSync(d->dpy, 1);
118428d7b3dSmrg}
119428d7b3dSmrg
120428d7b3dSmrgstatic void default_setup(struct test_display *dpy)
121428d7b3dSmrg{
122428d7b3dSmrg	dpy->width = WidthOfScreen(DefaultScreenOfDisplay(dpy->dpy));
123428d7b3dSmrg	dpy->height = HeightOfScreen(DefaultScreenOfDisplay(dpy->dpy));
124428d7b3dSmrg	dpy->format =
125428d7b3dSmrg		XRenderFindVisualFormat(dpy->dpy,
126428d7b3dSmrg					DefaultVisual(dpy->dpy,
127428d7b3dSmrg						      DefaultScreen(dpy->dpy)));
128428d7b3dSmrg	dpy->depth = DefaultDepth(dpy->dpy, DefaultScreen(dpy->dpy));
129428d7b3dSmrg}
130428d7b3dSmrg
131428d7b3dSmrgstatic void test_get_displays(int argc, char **argv,
132428d7b3dSmrg			      struct test_display *out,
133428d7b3dSmrg			      struct test_display *ref)
134428d7b3dSmrg{
135428d7b3dSmrg	out->dpy = out_display(argc, argv);
136428d7b3dSmrg	default_setup(out);
137428d7b3dSmrg	shm_setup(out);
138428d7b3dSmrg	out->root = get_root(out);
139428d7b3dSmrg	out->target = OUT;
140428d7b3dSmrg
141428d7b3dSmrg	ref->dpy = ref_display(out->width, out->height, out->depth);
142428d7b3dSmrg	default_setup(ref);
143428d7b3dSmrg	shm_setup(ref);
144428d7b3dSmrg	ref->root = get_root(ref);
145428d7b3dSmrg	ref->target = REF;
146428d7b3dSmrg}
147428d7b3dSmrg
148428d7b3dSmrgvoid test_init(struct test *test, int argc, char **argv)
149428d7b3dSmrg{
150428d7b3dSmrg	memset(test, 0, sizeof(*test));
151428d7b3dSmrg	test_get_displays(argc, argv, &test->out, &test->ref);
152428d7b3dSmrg}
153428d7b3dSmrg
154428d7b3dSmrgvoid test_timer_start(struct test_display *t, struct timespec *tv)
155428d7b3dSmrg{
156428d7b3dSmrg	clock_gettime(CLOCK_MONOTONIC, tv);
157428d7b3dSmrg}
158428d7b3dSmrg
159428d7b3dSmrgdouble test_timer_stop(struct test_display *t, struct timespec *tv)
160428d7b3dSmrg{
161428d7b3dSmrg	XImage *image;
162428d7b3dSmrg	struct timespec now;
163428d7b3dSmrg
164428d7b3dSmrg	image = XGetImage(t->dpy, t->root, 0, 0, 1, 1, AllPlanes, ZPixmap);
165428d7b3dSmrg	clock_gettime(CLOCK_MONOTONIC, &now);
166428d7b3dSmrg	XDestroyImage(image);
167428d7b3dSmrg
168428d7b3dSmrg	return (now.tv_sec - tv->tv_sec) + 1e-9*(now.tv_nsec - tv->tv_nsec);
169428d7b3dSmrg}
170