103b705cfSriastradh#include <stdio.h>
203b705cfSriastradh#include <stdlib.h>
303b705cfSriastradh#include <string.h>
403b705cfSriastradh#include <unistd.h>
503b705cfSriastradh#include <sys/ipc.h>
603b705cfSriastradh#include <sys/shm.h>
703b705cfSriastradh
803b705cfSriastradh#include "test.h"
903b705cfSriastradh
1003b705cfSriastradhstatic Window get_root(struct test_display *t)
1103b705cfSriastradh{
1203b705cfSriastradh	XSetWindowAttributes attr;
1303b705cfSriastradh	Window w;
1403b705cfSriastradh
1503b705cfSriastradh	/* Be nasty and install a fullscreen window on top so that we
1603b705cfSriastradh	 * can guarantee we do not get clipped by children.
1703b705cfSriastradh	 */
1803b705cfSriastradh	attr.override_redirect = 1;
1942542f5fSchristos	w = XCreateWindow(t->dpy, DefaultRootWindow(t->dpy),
2042542f5fSchristos			  0, 0, t->width, t->height, 0,
2142542f5fSchristos			  DefaultDepth(t->dpy, DefaultScreen(t->dpy)),
2242542f5fSchristos			  InputOutput,
2342542f5fSchristos			  DefaultVisual(t->dpy, DefaultScreen(t->dpy)),
2442542f5fSchristos			  CWOverrideRedirect, &attr);
2503b705cfSriastradh	XMapWindow(t->dpy, w);
2603b705cfSriastradh
2703b705cfSriastradh	return w;
2803b705cfSriastradh}
2903b705cfSriastradh
3042542f5fSchristosstatic Display *out_display(int argc, char **argv)
3103b705cfSriastradh{
3203b705cfSriastradh	Display *dpy;
3303b705cfSriastradh	const char *name = NULL;
3403b705cfSriastradh	int i;
3503b705cfSriastradh
3603b705cfSriastradh	for (i = 0; i < argc; i++) {
3703b705cfSriastradh		if (strncmp(argv[i], "-d", 2) == 0) {
3803b705cfSriastradh			if (argv[i][2] == '\0') {
3903b705cfSriastradh				if (i+1 < argc) {
4003b705cfSriastradh					name = argv[i+1];
4103b705cfSriastradh					i++;
4203b705cfSriastradh				}
4303b705cfSriastradh			} else
4403b705cfSriastradh				name = argv[i] + 2;
4503b705cfSriastradh		}
4603b705cfSriastradh	}
4703b705cfSriastradh
4803b705cfSriastradh	if (name == NULL)
4903b705cfSriastradh		name = getenv("DISPLAY");
5003b705cfSriastradh	if (name == NULL)
5103b705cfSriastradh		name = ":0"; /* useful default */
5203b705cfSriastradh
5303b705cfSriastradh	dpy = XOpenDisplay(name);
5403b705cfSriastradh	if (dpy == NULL)
5542542f5fSchristos		die("unable to open out display %s\n", name);
5603b705cfSriastradh
5703b705cfSriastradh	printf("Opened connection to %s for testing.\n", name);
5803b705cfSriastradh	return dpy;
5903b705cfSriastradh}
6003b705cfSriastradh
6103b705cfSriastradhstatic Display *ref_display(int width, int height, int depth)
6203b705cfSriastradh{
6303b705cfSriastradh	Display *dpy;
6403b705cfSriastradh	char buf[160];
6503b705cfSriastradh	const char *name;
6603b705cfSriastradh	int try;
6703b705cfSriastradh
6803b705cfSriastradh	name = getenv("REF_DISPLAY");
6903b705cfSriastradh	if (name) {
7003b705cfSriastradh		dpy = XOpenDisplay(name);
7103b705cfSriastradh		if (dpy == NULL)
7203b705cfSriastradh			die("unable to open reference display %s\n", name);
7303b705cfSriastradh
7403b705cfSriastradh		printf("Opened connection to %s for reference.\n", name);
7503b705cfSriastradh		return dpy;
7603b705cfSriastradh	}
7703b705cfSriastradh
7803b705cfSriastradh	snprintf(buf, sizeof(buf),
7903b705cfSriastradh		 "Xvfb -ac -terminate -screen 0 %dx%dx%d :99 >/dev/null 2>&1 &",
8003b705cfSriastradh		 width, height, depth);
8103b705cfSriastradh	if (system(buf))
8203b705cfSriastradh		die("unable to spawn '%s' for reference display\n", buf);
8303b705cfSriastradh
8403b705cfSriastradh	try = 0;
8503b705cfSriastradh	while (try++ < 1000) {
8603b705cfSriastradh		dpy = XOpenDisplay(":99");
8703b705cfSriastradh		if (dpy)
8803b705cfSriastradh			break;
8903b705cfSriastradh		usleep(1000);
9003b705cfSriastradh	}
9103b705cfSriastradh
9203b705cfSriastradh	if (dpy == NULL)
9303b705cfSriastradh		die("unable to open reference display\n");
9403b705cfSriastradh
9503b705cfSriastradh	return dpy;
9603b705cfSriastradh}
9703b705cfSriastradh
9803b705cfSriastradhstatic void shm_setup(struct test_display *d)
9903b705cfSriastradh{
10042542f5fSchristos	int major, minor;
10103b705cfSriastradh	int size;
10203b705cfSriastradh
10342542f5fSchristos	XShmQueryVersion(d->dpy, &major, &minor, &d->has_shm_pixmaps);
10403b705cfSriastradh	if (major == 0 && minor == 0)
10503b705cfSriastradh		die("XSHM not supported\n");
10603b705cfSriastradh
10703b705cfSriastradh	size = d->width * d->height * 4;
10803b705cfSriastradh	d->max_shm_size = size;
10903b705cfSriastradh
11003b705cfSriastradh	d->shm.shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
11103b705cfSriastradh	if (d->shm.shmid == -1)
11203b705cfSriastradh		die("failed to allocated %d bytes for a shm segment\n", size);
11303b705cfSriastradh
11403b705cfSriastradh	d->shm.shmaddr = shmat(d->shm.shmid, NULL, 0);
11503b705cfSriastradh	d->shm.readOnly = 0;
11603b705cfSriastradh	XShmAttach(d->dpy, &d->shm);
11703b705cfSriastradh	XSync(d->dpy, 1);
11803b705cfSriastradh}
11903b705cfSriastradh
12003b705cfSriastradhstatic void default_setup(struct test_display *dpy)
12103b705cfSriastradh{
12203b705cfSriastradh	dpy->width = WidthOfScreen(DefaultScreenOfDisplay(dpy->dpy));
12303b705cfSriastradh	dpy->height = HeightOfScreen(DefaultScreenOfDisplay(dpy->dpy));
12403b705cfSriastradh	dpy->format =
12503b705cfSriastradh		XRenderFindVisualFormat(dpy->dpy,
12603b705cfSriastradh					DefaultVisual(dpy->dpy,
12703b705cfSriastradh						      DefaultScreen(dpy->dpy)));
12842542f5fSchristos	dpy->depth = DefaultDepth(dpy->dpy, DefaultScreen(dpy->dpy));
12903b705cfSriastradh}
13003b705cfSriastradh
13103b705cfSriastradhstatic void test_get_displays(int argc, char **argv,
13242542f5fSchristos			      struct test_display *out,
13303b705cfSriastradh			      struct test_display *ref)
13403b705cfSriastradh{
13542542f5fSchristos	out->dpy = out_display(argc, argv);
13642542f5fSchristos	default_setup(out);
13742542f5fSchristos	shm_setup(out);
13842542f5fSchristos	out->root = get_root(out);
13942542f5fSchristos	out->target = OUT;
14003b705cfSriastradh
14142542f5fSchristos	ref->dpy = ref_display(out->width, out->height, out->depth);
14203b705cfSriastradh	default_setup(ref);
14303b705cfSriastradh	shm_setup(ref);
14403b705cfSriastradh	ref->root = get_root(ref);
14542542f5fSchristos	ref->target = REF;
14603b705cfSriastradh}
14703b705cfSriastradh
14803b705cfSriastradhvoid test_init(struct test *test, int argc, char **argv)
14903b705cfSriastradh{
15003b705cfSriastradh	memset(test, 0, sizeof(*test));
15142542f5fSchristos	test_get_displays(argc, argv, &test->out, &test->ref);
15203b705cfSriastradh}
15303b705cfSriastradh
15403b705cfSriastradhvoid test_timer_start(struct test_display *t, struct timespec *tv)
15503b705cfSriastradh{
15603b705cfSriastradh	clock_gettime(CLOCK_MONOTONIC, tv);
15703b705cfSriastradh}
15803b705cfSriastradh
15903b705cfSriastradhdouble test_timer_stop(struct test_display *t, struct timespec *tv)
16003b705cfSriastradh{
16103b705cfSriastradh	XImage *image;
16203b705cfSriastradh	struct timespec now;
16303b705cfSriastradh
16403b705cfSriastradh	image = XGetImage(t->dpy, t->root, 0, 0, 1, 1, AllPlanes, ZPixmap);
16503b705cfSriastradh	clock_gettime(CLOCK_MONOTONIC, &now);
16603b705cfSriastradh	XDestroyImage(image);
16703b705cfSriastradh
16803b705cfSriastradh	return (now.tv_sec - tv->tv_sec) + 1e-9*(now.tv_nsec - tv->tv_nsec);
16903b705cfSriastradh}
170