103b705cfSriastradh#include <stdint.h>
203b705cfSriastradh#include <stdio.h>
303b705cfSriastradh#include <stdlib.h>
403b705cfSriastradh
503b705cfSriastradh#include <X11/Xlib.h>
603b705cfSriastradh#include <X11/Xutil.h>
703b705cfSriastradh#include <X11/extensions/Xfixes.h>
803b705cfSriastradh#include <unistd.h>
903b705cfSriastradh#include <fcntl.h>
1003b705cfSriastradh#include <string.h>
1103b705cfSriastradh#include <time.h>
1203b705cfSriastradh
1303b705cfSriastradh#include <xf86drm.h>
1403b705cfSriastradh#include <drm.h>
1503b705cfSriastradh
1603b705cfSriastradh#include "dri2.h"
1703b705cfSriastradh
1803b705cfSriastradh#define COUNT 60
1903b705cfSriastradh
2003b705cfSriastradhstatic int dri2_open(Display *dpy)
2103b705cfSriastradh{
2203b705cfSriastradh	drm_auth_t auth;
2303b705cfSriastradh	char *driver, *device;
2403b705cfSriastradh	int fd;
2503b705cfSriastradh
2603b705cfSriastradh	if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device))
2703b705cfSriastradh		return -1;
2803b705cfSriastradh
2903b705cfSriastradh	printf ("Connecting to %s driver on %s\n", driver, device);
3003b705cfSriastradh
3142542f5fSchristos	fd = open(device, O_RDWR);
3203b705cfSriastradh	if (fd < 0)
3303b705cfSriastradh		return -1;
3403b705cfSriastradh
3503b705cfSriastradh	if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
3603b705cfSriastradh		return -1;
3703b705cfSriastradh
3803b705cfSriastradh	if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic))
3903b705cfSriastradh		return -1;
4003b705cfSriastradh
4103b705cfSriastradh	return fd;
4203b705cfSriastradh}
4303b705cfSriastradh
4403b705cfSriastradhstatic void dri2_copy_swap(Display *dpy, Drawable d,
4503b705cfSriastradh			   int width, int height, int has_front)
4603b705cfSriastradh{
4703b705cfSriastradh	XRectangle rect;
4803b705cfSriastradh	XserverRegion region;
4903b705cfSriastradh
5003b705cfSriastradh	rect.x = 0;
5103b705cfSriastradh	rect.y = 0;
5203b705cfSriastradh	rect.width = width;
5303b705cfSriastradh	rect.height = height;
5403b705cfSriastradh
5503b705cfSriastradh	region = XFixesCreateRegion(dpy, &rect, 1);
5603b705cfSriastradh	DRI2CopyRegion(dpy, d, region, DRI2BufferFrontLeft, DRI2BufferBackLeft);
5703b705cfSriastradh	if (has_front)
5803b705cfSriastradh		DRI2CopyRegion(dpy, d, region, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
5903b705cfSriastradh	XFixesDestroyRegion(dpy, region);
6003b705cfSriastradh}
6103b705cfSriastradh
6203b705cfSriastradhstatic void xsync(Display *dpy, Window win)
6303b705cfSriastradh{
6403b705cfSriastradh	XImage *image;
6503b705cfSriastradh
6603b705cfSriastradh	image = XGetImage(dpy, win, 0, 0, 1, 1, ~0, ZPixmap);
6703b705cfSriastradh	if (image)
6803b705cfSriastradh		XDestroyImage(image);
6903b705cfSriastradh}
7003b705cfSriastradh
7103b705cfSriastradhstatic double elapsed(const struct timespec *start,
7203b705cfSriastradh		      const struct timespec *end)
7303b705cfSriastradh{
7403b705cfSriastradh	return (end->tv_sec - start->tv_sec) +
7503b705cfSriastradh		1e-9*(end->tv_nsec - start->tv_nsec);
7603b705cfSriastradh}
7703b705cfSriastradh
7803b705cfSriastradhstatic void run(Display *dpy, int width, int height,
7903b705cfSriastradh		unsigned int *attachments, int nattachments,
8003b705cfSriastradh		const char *name)
8103b705cfSriastradh{
8203b705cfSriastradh	Window win;
8303b705cfSriastradh	XSetWindowAttributes attr;
8403b705cfSriastradh	int count;
8503b705cfSriastradh	DRI2Buffer *buffers;
8603b705cfSriastradh	struct timespec start, end;
8703b705cfSriastradh
8803b705cfSriastradh	/* Be nasty and install a fullscreen window on top so that we
8903b705cfSriastradh	 * can guarantee we do not get clipped by children.
9003b705cfSriastradh	 */
9103b705cfSriastradh	attr.override_redirect = 1;
9203b705cfSriastradh	win = XCreateWindow(dpy, DefaultRootWindow(dpy),
9303b705cfSriastradh			 0, 0, width, height, 0,
9403b705cfSriastradh			 DefaultDepth(dpy, DefaultScreen(dpy)),
9503b705cfSriastradh			 InputOutput,
9603b705cfSriastradh			 DefaultVisual(dpy, DefaultScreen(dpy)),
9703b705cfSriastradh			 CWOverrideRedirect, &attr);
9803b705cfSriastradh	XMapWindow(dpy, win);
9903b705cfSriastradh	xsync(dpy, win);
10003b705cfSriastradh
10103b705cfSriastradh	DRI2CreateDrawable(dpy, win);
10203b705cfSriastradh
10303b705cfSriastradh	buffers = DRI2GetBuffers(dpy, win, &width, &height,
10403b705cfSriastradh				 attachments, nattachments, &count);
10503b705cfSriastradh	if (count != nattachments)
10603b705cfSriastradh		return;
10703b705cfSriastradh
10803b705cfSriastradh	xsync(dpy, win);
10903b705cfSriastradh	clock_gettime(CLOCK_MONOTONIC, &start);
11003b705cfSriastradh	for (count = 0; count < COUNT; count++)
11103b705cfSriastradh		DRI2SwapBuffers(dpy, win, 0, 0, 0);
11203b705cfSriastradh	xsync(dpy, win);
11303b705cfSriastradh	clock_gettime(CLOCK_MONOTONIC, &end);
11403b705cfSriastradh	printf("%d %s (%dx%d) swaps in %fs.\n",
11503b705cfSriastradh	       count, name, width, height, elapsed(&start, &end));
11603b705cfSriastradh
11703b705cfSriastradh	xsync(dpy, win);
11803b705cfSriastradh	clock_gettime(CLOCK_MONOTONIC, &start);
11903b705cfSriastradh	for (count = 0; count < COUNT; count++)
12003b705cfSriastradh		dri2_copy_swap(dpy, win, width, height, nattachments == 2);
12103b705cfSriastradh	xsync(dpy, win);
12203b705cfSriastradh	clock_gettime(CLOCK_MONOTONIC, &end);
12303b705cfSriastradh
12403b705cfSriastradh	printf("%d %s (%dx%d) blits in %fs.\n",
12503b705cfSriastradh	       count, name, width, height, elapsed(&start, &end));
12603b705cfSriastradh
12703b705cfSriastradh	DRI2SwapInterval(dpy, win, 0);
12803b705cfSriastradh
12903b705cfSriastradh	xsync(dpy, win);
13003b705cfSriastradh	clock_gettime(CLOCK_MONOTONIC, &start);
13103b705cfSriastradh	for (count = 0; count < COUNT; count++)
13203b705cfSriastradh		DRI2SwapBuffers(dpy, win, 0, 0, 0);
13303b705cfSriastradh	xsync(dpy, win);
13403b705cfSriastradh	clock_gettime(CLOCK_MONOTONIC, &end);
13503b705cfSriastradh	printf("%d %s (%dx%d) vblank=0 swaps in %fs.\n",
13603b705cfSriastradh	       count, name, width, height, elapsed(&start, &end));
13703b705cfSriastradh
13803b705cfSriastradh	XDestroyWindow(dpy, win);
13903b705cfSriastradh	free(buffers);
14003b705cfSriastradh
14103b705cfSriastradh	XSync(dpy, 1);
14203b705cfSriastradh}
14303b705cfSriastradh
14403b705cfSriastradhint main(void)
14503b705cfSriastradh{
14603b705cfSriastradh	Display *dpy;
14703b705cfSriastradh	int width, height, fd;
14803b705cfSriastradh	unsigned int attachments[] = {
14903b705cfSriastradh		DRI2BufferBackLeft,
15003b705cfSriastradh		DRI2BufferFrontLeft,
15103b705cfSriastradh	};
15203b705cfSriastradh
15303b705cfSriastradh	dpy = XOpenDisplay (NULL);
15403b705cfSriastradh	if (dpy == NULL)
15503b705cfSriastradh		return 77;
15603b705cfSriastradh
15703b705cfSriastradh	fd = dri2_open(dpy);
15803b705cfSriastradh	if (fd < 0)
15903b705cfSriastradh		return 1;
16003b705cfSriastradh
16103b705cfSriastradh	width = WidthOfScreen(DefaultScreenOfDisplay(dpy));
16203b705cfSriastradh	height = HeightOfScreen(DefaultScreenOfDisplay(dpy));
16303b705cfSriastradh	run(dpy, width, height, attachments, 1, "fullscreen");
16403b705cfSriastradh	run(dpy, width, height, attachments, 2, "fullscreen (with front)");
16503b705cfSriastradh
16603b705cfSriastradh	width /= 2;
16703b705cfSriastradh	height /= 2;
16803b705cfSriastradh	run(dpy, width, height, attachments, 1, "windowed");
16903b705cfSriastradh	run(dpy, width, height, attachments, 2, "windowed (with front)");
17003b705cfSriastradh
17103b705cfSriastradh	return 0;
17203b705cfSriastradh}
173