dri2-test.c revision fe8aea9e
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 <X11/Xlib-xcb.h> 10#include <xcb/xcb.h> 11#include <xcb/xcbext.h> 12#include <xcb/dri2.h> 13#include <unistd.h> 14#include <fcntl.h> 15#include <string.h> 16#include <time.h> 17 18#include <xf86drm.h> 19#include <drm.h> 20 21#include "dri2.h" 22 23#define COUNT 60 24 25static int prime[] = { 0, 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 27, 29, 31, 37, 41, 43, 47, 51, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131 }; 26 27static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window) 28{ 29 XRRScreenResources *res; 30 31 res = XRRGetScreenResourcesCurrent(dpy, window); 32 if (res == NULL) 33 res = XRRGetScreenResources(dpy, window); 34 35 return res; 36} 37 38static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id) 39{ 40 int i; 41 42 for (i = 0; i < res->nmode; i++) { 43 if (res->modes[i].id == id) 44 return &res->modes[i]; 45 } 46 47 return NULL; 48} 49 50static int dri2_open(Display *dpy) 51{ 52 drm_auth_t auth; 53 char *driver, *device; 54 int fd; 55 56 if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device)) 57 return -1; 58 59 printf ("Connecting to %s driver on %s\n", driver, device); 60 61 fd = open(device, O_RDWR); 62 if (fd < 0) 63 return -1; 64 65 if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 66 return -1; 67 68 if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic)) 69 return -1; 70 71 return fd; 72} 73 74static void dri2_copy_swap(Display *dpy, Drawable d, 75 int width, int height, int has_front) 76{ 77 XRectangle rect; 78 XserverRegion region; 79 80 rect.x = 0; 81 rect.y = 0; 82 rect.width = width; 83 rect.height = height; 84 85 region = XFixesCreateRegion(dpy, &rect, 1); 86 DRI2CopyRegion(dpy, d, region, DRI2BufferFrontLeft, DRI2BufferBackLeft); 87 if (has_front) 88 DRI2CopyRegion(dpy, d, region, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 89 XFixesDestroyRegion(dpy, region); 90} 91 92static double elapsed(const struct timespec *start, 93 const struct timespec *end) 94{ 95 return (end->tv_sec - start->tv_sec) + 96 1e-9*(end->tv_nsec - start->tv_nsec); 97} 98 99static uint64_t check_msc(Display *dpy, Window win, uint64_t last_msc) 100{ 101 uint64_t current_msc, current_ust, current_sbc; 102 DRI2GetMSC(dpy, win, ¤t_ust, ¤t_msc, ¤t_sbc); 103 if (current_msc < last_msc) { 104 printf("Invalid MSC: was %llu, now %llu\n", 105 (long long)last_msc, (long long)current_msc); 106 } 107 return current_msc; 108} 109 110static void wait_next_vblank(Display *dpy, Window win) 111{ 112 uint64_t msc, ust, sbc; 113 DRI2WaitMSC(dpy, win, 0, 1, 0, &ust, &msc, &sbc); 114} 115 116static void swap_buffers(xcb_connection_t *c, Window win, 117 unsigned int *attachments, int nattachments) 118{ 119 unsigned int seq[2]; 120 121 seq[0] = xcb_dri2_swap_buffers_unchecked(c, win, 122 0, 0, 0, 0, 0, 0).sequence; 123 124 125 seq[1] = xcb_dri2_get_buffers_unchecked(c, win, 126 nattachments, nattachments, 127 attachments).sequence; 128 129 xcb_flush(c); 130 xcb_discard_reply(c, seq[0]); 131 xcb_discard_reply(c, seq[1]); 132} 133 134static void run(Display *dpy, int width, int height, 135 unsigned int *attachments, int nattachments, 136 const char *name) 137{ 138 xcb_connection_t *c = XGetXCBConnection(dpy); 139 Window win; 140 XSetWindowAttributes attr; 141 DRI2Buffer *buffers; 142 struct timespec start, end; 143 uint64_t start_msc, end_msc; 144 int modulus, remainder, count; 145 146 /* Be nasty and install a fullscreen window on top so that we 147 * can guarantee we do not get clipped by children. 148 */ 149 attr.override_redirect = 1; 150 win = XCreateWindow(dpy, DefaultRootWindow(dpy), 151 0, 0, width, height, 0, 152 DefaultDepth(dpy, DefaultScreen(dpy)), 153 InputOutput, 154 DefaultVisual(dpy, DefaultScreen(dpy)), 155 CWOverrideRedirect, &attr); 156 XMapWindow(dpy, win); 157 158 DRI2CreateDrawable(dpy, win); 159 DRI2SwapInterval(dpy, win, 1); 160 start_msc = check_msc(dpy, win, 0); 161 162 buffers = DRI2GetBuffers(dpy, win, &width, &height, 163 attachments, nattachments, &count); 164 if (count != nattachments) 165 return; 166 167 swap_buffers(c, win, attachments, nattachments); 168 start_msc = check_msc(dpy, win, start_msc); 169 clock_gettime(CLOCK_MONOTONIC, &start); 170 for (count = 0; count < COUNT; count++) 171 swap_buffers(c, win, attachments, nattachments); 172 end_msc = check_msc(dpy, win, start_msc); 173 clock_gettime(CLOCK_MONOTONIC, &end); 174 printf("%d [%ld] %s (%dx%d) swaps in %fs.\n", 175 count, (long)(end_msc - start_msc), 176 name, width, height, elapsed(&start, &end)); 177 178 swap_buffers(c, win, attachments, nattachments); 179 start_msc = check_msc(dpy, win, end_msc); 180 clock_gettime(CLOCK_MONOTONIC, &start); 181 for (count = 0; count < COUNT; count++) 182 dri2_copy_swap(dpy, win, width, height, nattachments == 2); 183 end_msc = check_msc(dpy, win, start_msc); 184 clock_gettime(CLOCK_MONOTONIC, &end); 185 186 printf("%d [%ld] %s (%dx%d) blits in %fs.\n", 187 count, (long)(end_msc - start_msc), 188 name, width, height, elapsed(&start, &end)); 189 190 DRI2SwapInterval(dpy, win, 0); 191 wait_next_vblank(dpy, win); 192 193 swap_buffers(c, win, attachments, nattachments); 194 start_msc = check_msc(dpy, win, end_msc); 195 clock_gettime(CLOCK_MONOTONIC, &start); 196 for (count = 0; count < COUNT; count++) 197 swap_buffers(c, win, attachments, nattachments); 198 end_msc = check_msc(dpy, win, start_msc); 199 clock_gettime(CLOCK_MONOTONIC, &end); 200 printf("%d [%ld] %s (%dx%d) vblank=0 swaps in %fs.\n", 201 count, (long)(end_msc - start_msc), 202 name, width, height, elapsed(&start, &end)); 203 204 start_msc = check_msc(dpy, win, end_msc); 205 clock_gettime(CLOCK_MONOTONIC, &start); 206 for (count = 0; count < COUNT; count++) 207 wait_next_vblank(dpy, win); 208 end_msc = check_msc(dpy, win, start_msc); 209 clock_gettime(CLOCK_MONOTONIC, &end); 210 printf("%d [%ld] %s waits in %fs.\n", 211 count, (long)(end_msc - start_msc), 212 name, elapsed(&start, &end)); 213 214 printf("Testing past & future waits\n"); 215 for (modulus = 1; modulus <= 128; modulus <<= 1) { 216 for (count = 0; prime[count] < modulus; count++) { 217 uint64_t msc, ust, sbc; 218 uint64_t target; 219 220 remainder = prime[count]; 221 222 DRI2WaitMSC(dpy, win, 0, 1, 0, &ust, &msc, &sbc); 223 224 target = msc + modulus + 1; 225 target &= -modulus; 226 target += remainder; 227 228 DRI2WaitMSC(dpy, win, target, modulus, remainder, 229 &ust, &msc, &sbc); 230 if (msc != target) { 231 printf("Missed future MSC (%d, %d): expected=%lld, found=%lld\n", 232 modulus, remainder, 233 (long long)target, (long long)msc); 234 } 235 236 target = msc; 237 target &= -modulus; 238 target += remainder; 239 if (target <= msc) 240 target += modulus; 241 242 DRI2WaitMSC(dpy, win, msc, modulus, remainder, 243 &ust, &msc, &sbc); 244 245 if (msc != target) { 246 printf("Missed past MSC (%d, %d): expected=%lld, found=%lld\n", 247 modulus, remainder, 248 (long long)target, (long long)msc); 249 } 250 } 251 } 252 253 XDestroyWindow(dpy, win); 254 free(buffers); 255 256 XSync(dpy, 1); 257} 258 259int main(void) 260{ 261 Display *dpy; 262 int i, j, fd; 263 unsigned int attachments[] = { 264 DRI2BufferBackLeft, 265 DRI2BufferFrontLeft, 266 }; 267 XRRScreenResources *res; 268 XRRCrtcInfo **original_crtc; 269 Window root; 270 uint64_t last_msc; 271 272 dpy = XOpenDisplay(NULL); 273 if (dpy == NULL) 274 return 77; 275 276 if (!XRRQueryVersion(dpy, &i, &j)) 277 return 77; 278 279 fd = dri2_open(dpy); 280 if (fd < 0) 281 return 1; 282 283 root = DefaultRootWindow(dpy); 284 DRI2CreateDrawable(dpy, root); 285 286 res = _XRRGetScreenResourcesCurrent(dpy, root); 287 if (res == NULL) 288 return 1; 289 290 original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc); 291 for (i = 0; i < res->ncrtc; i++) 292 original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]); 293 294 printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc); 295 last_msc = check_msc(dpy, root, 0); 296 for (i = 0; i < res->ncrtc; i++) 297 XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 298 0, 0, None, RR_Rotate_0, NULL, 0); 299 last_msc = check_msc(dpy, root, last_msc); 300 301 for (i = 0; i < res->noutput; i++) { 302 XRROutputInfo *output; 303 XRRModeInfo *mode; 304 305 output = XRRGetOutputInfo(dpy, res, res->outputs[i]); 306 if (output == NULL) 307 continue; 308 309 mode = NULL; 310 if (res->nmode) 311 mode = lookup_mode(res, output->modes[0]); 312 313 for (j = 0; mode && j < 2*output->ncrtc; j++) { 314 int c = j; 315 if (c >= output->ncrtc) 316 c = 2*output->ncrtc - j - 1; 317 318 printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld\n", 319 i, c, (long)res->outputs[i], (long)output->crtcs[c]); 320 last_msc = check_msc(dpy, root, last_msc); 321 XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime, 322 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1); 323 last_msc = check_msc(dpy, root, last_msc); 324 325 run(dpy, mode->width, mode->height, attachments, 1, "fullscreen"); 326 run(dpy, mode->width, mode->height, attachments, 2, "fullscreen (with front)"); 327 328 run(dpy, mode->width/2, mode->height/2, attachments, 1, "windowed"); 329 run(dpy, mode->width/2, mode->height/2, attachments, 2, "windowed (with front)"); 330 331 last_msc = check_msc(dpy, root, last_msc); 332 XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime, 333 0, 0, None, RR_Rotate_0, NULL, 0); 334 last_msc = check_msc(dpy, root, last_msc); 335 } 336 337 XRRFreeOutputInfo(output); 338 } 339 340 for (i = 0; i < res->ncrtc; i++) 341 XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 342 original_crtc[i]->x, 343 original_crtc[i]->y, 344 original_crtc[i]->mode, 345 original_crtc[i]->rotation, 346 original_crtc[i]->outputs, 347 original_crtc[i]->noutput); 348 return 0; 349} 350