1#include <stdint.h> 2#include <stdio.h> 3#include <stdlib.h> 4 5#include <X11/Xlib.h> 6#include <X11/Xutil.h> 7#include <X11/extensions/Xfixes.h> 8#include <X11/extensions/Xrandr.h> 9#include <unistd.h> 10#include <fcntl.h> 11#include <string.h> 12#include <time.h> 13 14#include <xf86drm.h> 15#include <drm.h> 16 17#include "dri2.h" 18 19#define COUNT 60 20 21static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window) 22{ 23 XRRScreenResources *res; 24 25 res = XRRGetScreenResourcesCurrent(dpy, window); 26 if (res == NULL) 27 res = XRRGetScreenResources(dpy, window); 28 29 return res; 30} 31 32static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id) 33{ 34 int i; 35 36 for (i = 0; i < res->nmode; i++) { 37 if (res->modes[i].id == id) 38 return &res->modes[i]; 39 } 40 41 return NULL; 42} 43 44static int dri2_open(Display *dpy) 45{ 46 drm_auth_t auth; 47 char *driver, *device; 48 int fd; 49 50 if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device)) 51 return -1; 52 53 printf ("Connecting to %s driver on %s\n", driver, device); 54 55 fd = open(device, O_RDWR); 56 if (fd < 0) 57 return -1; 58 59 if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 60 return -1; 61 62 if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic)) 63 return -1; 64 65 return fd; 66} 67 68static void dri2_copy_swap(Display *dpy, Drawable d, 69 int width, int height, int has_front) 70{ 71 XRectangle rect; 72 XserverRegion region; 73 74 rect.x = 0; 75 rect.y = 0; 76 rect.width = width; 77 rect.height = height; 78 79 region = XFixesCreateRegion(dpy, &rect, 1); 80 DRI2CopyRegion(dpy, d, region, DRI2BufferFrontLeft, DRI2BufferBackLeft); 81 if (has_front) 82 DRI2CopyRegion(dpy, d, region, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 83 XFixesDestroyRegion(dpy, region); 84} 85 86static double elapsed(const struct timespec *start, 87 const struct timespec *end) 88{ 89 return (end->tv_sec - start->tv_sec) + 90 1e-9*(end->tv_nsec - start->tv_nsec); 91} 92 93static uint64_t check_msc(Display *dpy, Window win, uint64_t last_msc) 94{ 95 uint64_t current_msc, current_ust, current_sbc; 96 DRI2GetMSC(dpy, win, ¤t_ust, ¤t_msc, ¤t_sbc); 97 if (current_msc < last_msc) { 98 printf("Invalid MSC: was %llu, now %llu\n", 99 (long long)last_msc, (long long)current_msc); 100 } 101 return current_msc; 102} 103 104static void run(Display *dpy, int width, int height, 105 unsigned int *attachments, int nattachments, 106 const char *name) 107{ 108 Window win; 109 XSetWindowAttributes attr; 110 int count; 111 DRI2Buffer *buffers; 112 struct timespec start, end; 113 uint64_t msc; 114 115 /* Be nasty and install a fullscreen window on top so that we 116 * can guarantee we do not get clipped by children. 117 */ 118 attr.override_redirect = 1; 119 win = XCreateWindow(dpy, DefaultRootWindow(dpy), 120 0, 0, width, height, 0, 121 DefaultDepth(dpy, DefaultScreen(dpy)), 122 InputOutput, 123 DefaultVisual(dpy, DefaultScreen(dpy)), 124 CWOverrideRedirect, &attr); 125 XMapWindow(dpy, win); 126 127 DRI2CreateDrawable(dpy, win); 128 msc = check_msc(dpy, win, 0); 129 130 buffers = DRI2GetBuffers(dpy, win, &width, &height, 131 attachments, nattachments, &count); 132 if (count != nattachments) 133 return; 134 135 msc = check_msc(dpy, win, msc); 136 clock_gettime(CLOCK_MONOTONIC, &start); 137 for (count = 0; count < COUNT; count++) 138 DRI2SwapBuffers(dpy, win, 0, 0, 0); 139 msc = check_msc(dpy, win, msc); 140 clock_gettime(CLOCK_MONOTONIC, &end); 141 printf("%d %s (%dx%d) swaps in %fs.\n", 142 count, name, width, height, elapsed(&start, &end)); 143 144 msc = check_msc(dpy, win, msc); 145 clock_gettime(CLOCK_MONOTONIC, &start); 146 for (count = 0; count < COUNT; count++) 147 dri2_copy_swap(dpy, win, width, height, nattachments == 2); 148 msc = check_msc(dpy, win, msc); 149 clock_gettime(CLOCK_MONOTONIC, &end); 150 151 printf("%d %s (%dx%d) blits in %fs.\n", 152 count, name, width, height, elapsed(&start, &end)); 153 154 DRI2SwapInterval(dpy, win, 0); 155 156 msc = check_msc(dpy, win, msc); 157 clock_gettime(CLOCK_MONOTONIC, &start); 158 for (count = 0; count < COUNT; count++) 159 DRI2SwapBuffers(dpy, win, 0, 0, 0); 160 msc = check_msc(dpy, win, msc); 161 clock_gettime(CLOCK_MONOTONIC, &end); 162 printf("%d %s (%dx%d) vblank=0 swaps in %fs.\n", 163 count, name, width, height, elapsed(&start, &end)); 164 165 XDestroyWindow(dpy, win); 166 free(buffers); 167 168 XSync(dpy, 1); 169} 170 171int main(void) 172{ 173 Display *dpy; 174 int i, j, fd; 175 unsigned int attachments[] = { 176 DRI2BufferBackLeft, 177 DRI2BufferFrontLeft, 178 }; 179 XRRScreenResources *res; 180 XRRCrtcInfo **original_crtc; 181 Window root; 182 uint64_t last_msc; 183 184 dpy = XOpenDisplay(NULL); 185 if (dpy == NULL) 186 return 77; 187 188 if (!XRRQueryVersion(dpy, &i, &j)) 189 return 77; 190 191 fd = dri2_open(dpy); 192 if (fd < 0) 193 return 1; 194 195 root = DefaultRootWindow(dpy); 196 DRI2CreateDrawable(dpy, root); 197 198 res = _XRRGetScreenResourcesCurrent(dpy, root); 199 if (res == NULL) 200 return 1; 201 202 original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc); 203 for (i = 0; i < res->ncrtc; i++) 204 original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]); 205 206 printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc); 207 last_msc = check_msc(dpy, root, 0); 208 for (i = 0; i < res->ncrtc; i++) 209 XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 210 0, 0, None, RR_Rotate_0, NULL, 0); 211 last_msc = check_msc(dpy, root, last_msc); 212 213 for (i = 0; i < res->noutput; i++) { 214 XRROutputInfo *output; 215 XRRModeInfo *mode; 216 217 output = XRRGetOutputInfo(dpy, res, res->outputs[i]); 218 if (output == NULL) 219 continue; 220 221 mode = NULL; 222 if (res->nmode) 223 mode = lookup_mode(res, output->modes[0]); 224 225 for (j = 0; mode && j < 2*output->ncrtc; j++) { 226 int c = j; 227 if (c >= output->ncrtc) 228 c = 2*output->ncrtc - j - 1; 229 230 printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld\n", 231 i, c, (long)res->outputs[i], (long)output->crtcs[c]); 232 last_msc = check_msc(dpy, root, last_msc); 233 XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime, 234 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1); 235 last_msc = check_msc(dpy, root, last_msc); 236 237 run(dpy, mode->width, mode->height, attachments, 1, "fullscreen"); 238 run(dpy, mode->width, mode->height, attachments, 2, "fullscreen (with front)"); 239 240 run(dpy, mode->width/2, mode->height/2, attachments, 1, "windowed"); 241 run(dpy, mode->width/2, mode->height/2, attachments, 2, "windowed (with front)"); 242 243 last_msc = check_msc(dpy, root, last_msc); 244 XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime, 245 0, 0, None, RR_Rotate_0, NULL, 0); 246 last_msc = check_msc(dpy, root, last_msc); 247 } 248 249 XRRFreeOutputInfo(output); 250 } 251 252 for (i = 0; i < res->ncrtc; i++) 253 XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 254 original_crtc[i]->x, 255 original_crtc[i]->y, 256 original_crtc[i]->mode, 257 original_crtc[i]->rotation, 258 original_crtc[i]->outputs, 259 original_crtc[i]->noutput); 260 return 0; 261} 262