1428d7b3dSmrg#include <stdint.h>
2428d7b3dSmrg#include <stdio.h>
3428d7b3dSmrg#include <stdlib.h>
4428d7b3dSmrg
5428d7b3dSmrg#include <X11/Xlib.h>
6428d7b3dSmrg#include <X11/Xutil.h>
7428d7b3dSmrg#include <X11/extensions/Xfixes.h>
8428d7b3dSmrg#include <unistd.h>
9428d7b3dSmrg#include <fcntl.h>
10428d7b3dSmrg#include <string.h>
11428d7b3dSmrg#include <time.h>
12428d7b3dSmrg
13428d7b3dSmrg#include <xf86drm.h>
14428d7b3dSmrg#include <drm.h>
15428d7b3dSmrg
16428d7b3dSmrg#include "dri2.h"
17428d7b3dSmrg
18428d7b3dSmrg#define COUNT 60
19428d7b3dSmrg
20428d7b3dSmrgstatic int dri2_open(Display *dpy)
21428d7b3dSmrg{
22428d7b3dSmrg	drm_auth_t auth;
23428d7b3dSmrg	char *driver, *device;
24428d7b3dSmrg	int fd;
25428d7b3dSmrg
26428d7b3dSmrg	if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device))
27428d7b3dSmrg		return -1;
28428d7b3dSmrg
29428d7b3dSmrg	printf ("Connecting to %s driver on %s\n", driver, device);
30428d7b3dSmrg
31428d7b3dSmrg	fd = open(device, O_RDWR);
32428d7b3dSmrg	if (fd < 0)
33428d7b3dSmrg		return -1;
34428d7b3dSmrg
35428d7b3dSmrg	if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
36428d7b3dSmrg		return -1;
37428d7b3dSmrg
38428d7b3dSmrg	if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic))
39428d7b3dSmrg		return -1;
40428d7b3dSmrg
41428d7b3dSmrg	return fd;
42428d7b3dSmrg}
43428d7b3dSmrg
44428d7b3dSmrgstatic void dri2_copy_swap(Display *dpy, Drawable d,
45428d7b3dSmrg			   int width, int height, int has_front)
46428d7b3dSmrg{
47428d7b3dSmrg	XRectangle rect;
48428d7b3dSmrg	XserverRegion region;
49428d7b3dSmrg
50428d7b3dSmrg	rect.x = 0;
51428d7b3dSmrg	rect.y = 0;
52428d7b3dSmrg	rect.width = width;
53428d7b3dSmrg	rect.height = height;
54428d7b3dSmrg
55428d7b3dSmrg	region = XFixesCreateRegion(dpy, &rect, 1);
56428d7b3dSmrg	DRI2CopyRegion(dpy, d, region, DRI2BufferFrontLeft, DRI2BufferBackLeft);
57428d7b3dSmrg	if (has_front)
58428d7b3dSmrg		DRI2CopyRegion(dpy, d, region, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
59428d7b3dSmrg	XFixesDestroyRegion(dpy, region);
60428d7b3dSmrg}
61428d7b3dSmrg
62428d7b3dSmrgstatic void xsync(Display *dpy, Window win)
63428d7b3dSmrg{
64428d7b3dSmrg	XImage *image;
65428d7b3dSmrg
66428d7b3dSmrg	image = XGetImage(dpy, win, 0, 0, 1, 1, ~0, ZPixmap);
67428d7b3dSmrg	if (image)
68428d7b3dSmrg		XDestroyImage(image);
69428d7b3dSmrg}
70428d7b3dSmrg
71428d7b3dSmrgstatic double elapsed(const struct timespec *start,
72428d7b3dSmrg		      const struct timespec *end)
73428d7b3dSmrg{
74428d7b3dSmrg	return (end->tv_sec - start->tv_sec) +
75428d7b3dSmrg		1e-9*(end->tv_nsec - start->tv_nsec);
76428d7b3dSmrg}
77428d7b3dSmrg
78428d7b3dSmrgstatic void run(Display *dpy, int width, int height,
79428d7b3dSmrg		unsigned int *attachments, int nattachments,
80428d7b3dSmrg		const char *name)
81428d7b3dSmrg{
82428d7b3dSmrg	Window win;
83428d7b3dSmrg	XSetWindowAttributes attr;
84428d7b3dSmrg	int count;
85428d7b3dSmrg	DRI2Buffer *buffers;
86428d7b3dSmrg	struct timespec start, end;
87428d7b3dSmrg
88428d7b3dSmrg	/* Be nasty and install a fullscreen window on top so that we
89428d7b3dSmrg	 * can guarantee we do not get clipped by children.
90428d7b3dSmrg	 */
91428d7b3dSmrg	attr.override_redirect = 1;
92428d7b3dSmrg	win = XCreateWindow(dpy, DefaultRootWindow(dpy),
93428d7b3dSmrg			 0, 0, width, height, 0,
94428d7b3dSmrg			 DefaultDepth(dpy, DefaultScreen(dpy)),
95428d7b3dSmrg			 InputOutput,
96428d7b3dSmrg			 DefaultVisual(dpy, DefaultScreen(dpy)),
97428d7b3dSmrg			 CWOverrideRedirect, &attr);
98428d7b3dSmrg	XMapWindow(dpy, win);
99428d7b3dSmrg	xsync(dpy, win);
100428d7b3dSmrg
101428d7b3dSmrg	DRI2CreateDrawable(dpy, win);
102428d7b3dSmrg
103428d7b3dSmrg	buffers = DRI2GetBuffers(dpy, win, &width, &height,
104428d7b3dSmrg				 attachments, nattachments, &count);
105428d7b3dSmrg	if (count != nattachments)
106428d7b3dSmrg		return;
107428d7b3dSmrg
108428d7b3dSmrg	xsync(dpy, win);
109428d7b3dSmrg	clock_gettime(CLOCK_MONOTONIC, &start);
110428d7b3dSmrg	for (count = 0; count < COUNT; count++)
111428d7b3dSmrg		DRI2SwapBuffers(dpy, win, 0, 0, 0);
112428d7b3dSmrg	xsync(dpy, win);
113428d7b3dSmrg	clock_gettime(CLOCK_MONOTONIC, &end);
114428d7b3dSmrg	printf("%d %s (%dx%d) swaps in %fs.\n",
115428d7b3dSmrg	       count, name, width, height, elapsed(&start, &end));
116428d7b3dSmrg
117428d7b3dSmrg	xsync(dpy, win);
118428d7b3dSmrg	clock_gettime(CLOCK_MONOTONIC, &start);
119428d7b3dSmrg	for (count = 0; count < COUNT; count++)
120428d7b3dSmrg		dri2_copy_swap(dpy, win, width, height, nattachments == 2);
121428d7b3dSmrg	xsync(dpy, win);
122428d7b3dSmrg	clock_gettime(CLOCK_MONOTONIC, &end);
123428d7b3dSmrg
124428d7b3dSmrg	printf("%d %s (%dx%d) blits in %fs.\n",
125428d7b3dSmrg	       count, name, width, height, elapsed(&start, &end));
126428d7b3dSmrg
127428d7b3dSmrg	DRI2SwapInterval(dpy, win, 0);
128428d7b3dSmrg
129428d7b3dSmrg	xsync(dpy, win);
130428d7b3dSmrg	clock_gettime(CLOCK_MONOTONIC, &start);
131428d7b3dSmrg	for (count = 0; count < COUNT; count++)
132428d7b3dSmrg		DRI2SwapBuffers(dpy, win, 0, 0, 0);
133428d7b3dSmrg	xsync(dpy, win);
134428d7b3dSmrg	clock_gettime(CLOCK_MONOTONIC, &end);
135428d7b3dSmrg	printf("%d %s (%dx%d) vblank=0 swaps in %fs.\n",
136428d7b3dSmrg	       count, name, width, height, elapsed(&start, &end));
137428d7b3dSmrg
138428d7b3dSmrg	XDestroyWindow(dpy, win);
139428d7b3dSmrg	free(buffers);
140428d7b3dSmrg
141428d7b3dSmrg	XSync(dpy, 1);
142428d7b3dSmrg}
143428d7b3dSmrg
144428d7b3dSmrgint main(void)
145428d7b3dSmrg{
146428d7b3dSmrg	Display *dpy;
147428d7b3dSmrg	int width, height, fd;
148428d7b3dSmrg	unsigned int attachments[] = {
149428d7b3dSmrg		DRI2BufferBackLeft,
150428d7b3dSmrg		DRI2BufferFrontLeft,
151428d7b3dSmrg	};
152428d7b3dSmrg
153428d7b3dSmrg	dpy = XOpenDisplay (NULL);
154428d7b3dSmrg	if (dpy == NULL)
155428d7b3dSmrg		return 77;
156428d7b3dSmrg
157428d7b3dSmrg	fd = dri2_open(dpy);
158428d7b3dSmrg	if (fd < 0)
159428d7b3dSmrg		return 1;
160428d7b3dSmrg
161428d7b3dSmrg	width = WidthOfScreen(DefaultScreenOfDisplay(dpy));
162428d7b3dSmrg	height = HeightOfScreen(DefaultScreenOfDisplay(dpy));
163428d7b3dSmrg	run(dpy, width, height, attachments, 1, "fullscreen");
164428d7b3dSmrg	run(dpy, width, height, attachments, 2, "fullscreen (with front)");
165428d7b3dSmrg
166428d7b3dSmrg	width /= 2;
167428d7b3dSmrg	height /= 2;
168428d7b3dSmrg	run(dpy, width, height, attachments, 1, "windowed");
169428d7b3dSmrg	run(dpy, width, height, attachments, 2, "windowed (with front)");
170428d7b3dSmrg
171428d7b3dSmrg	return 0;
172428d7b3dSmrg}
173