present-test.c revision fe8aea9e
1/* 2 * Copyright (c) 2014 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 */ 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#endif 28 29#include <X11/Xlib.h> 30#include <X11/Xlib-xcb.h> 31#include <X11/xshmfence.h> 32#include <X11/Xutil.h> 33#include <X11/Xlibint.h> 34#include <X11/extensions/dpms.h> 35#include <X11/extensions/randr.h> 36#include <X11/extensions/Xcomposite.h> 37#include <X11/extensions/Xrandr.h> 38#include <X11/extensions/Xrender.h> 39#include <X11/extensions/XShm.h> 40#if HAVE_X11_EXTENSIONS_SHMPROTO_H 41#include <X11/extensions/shmproto.h> 42#elif HAVE_X11_EXTENSIONS_SHMSTR_H 43#include <X11/extensions/shmstr.h> 44#else 45#error Failed to find the right header for X11 MIT-SHM protocol definitions 46#endif 47#include <xcb/xcb.h> 48#include <xcb/present.h> 49#include <xcb/xfixes.h> 50#include <xcb/dri3.h> 51#include <xf86drm.h> 52#include <i915_drm.h> 53 54#include <stdio.h> 55#include <string.h> 56#include <fcntl.h> 57#include <unistd.h> 58#include <assert.h> 59#include <errno.h> 60#include <setjmp.h> 61#include <signal.h> 62 63#include <sys/mman.h> 64#include <sys/ipc.h> 65#include <sys/shm.h> 66#include <pciaccess.h> 67 68#include "dri3.h" 69 70#define ALIGN(x, y) (((x) + (y) - 1) & -(y)) 71#define PAGE_ALIGN(x) ALIGN(x, 4096) 72 73#define GTT I915_GEM_DOMAIN_GTT 74#define CPU I915_GEM_DOMAIN_CPU 75 76static int _x_error_occurred; 77static uint32_t stamp; 78 79static int 80_check_error_handler(Display *display, 81 XErrorEvent *event) 82{ 83 printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n", 84 DisplayString(display), 85 event->serial, 86 event->error_code, 87 event->request_code, 88 event->minor_code); 89 _x_error_occurred++; 90 return False; /* ignored */ 91} 92 93static int is_i915_device(int fd) 94{ 95 drm_version_t version; 96 char name[5] = ""; 97 98 memset(&version, 0, sizeof(version)); 99 version.name_len = 4; 100 version.name = name; 101 102 if (drmIoctl(fd, DRM_IOCTL_VERSION, &version)) 103 return 0; 104 105 return strcmp("i915", name) == 0; 106} 107 108static int is_intel(int fd) 109{ 110 struct drm_i915_getparam gp; 111 int ret; 112 113 /* Confirm that this is a i915.ko device with GEM/KMS enabled */ 114 ret = is_i915_device(fd); 115 if (ret) { 116 gp.param = I915_PARAM_HAS_GEM; 117 gp.value = &ret; 118 if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 119 ret = 0; 120 } 121 return ret; 122} 123 124static void *setup_msc(Display *dpy, Window win) 125{ 126 xcb_connection_t *c = XGetXCBConnection(dpy); 127 xcb_void_cookie_t cookie; 128 uint32_t id = xcb_generate_id(c); 129 xcb_generic_error_t *error; 130 void *q; 131 132 cookie = xcb_present_select_input_checked(c, id, win, XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY); 133 q = xcb_register_for_special_xge(c, &xcb_present_id, id, &stamp); 134 135 error = xcb_request_check(c, cookie); 136 assert(error == NULL); 137 138 return q; 139} 140 141static uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc, uint64_t *ust) 142{ 143 xcb_connection_t *c = XGetXCBConnection(dpy); 144 static uint32_t serial = 1; 145 uint64_t msc = 0; 146 int complete = 0; 147 148 xcb_present_notify_msc(c, win, serial ^ 0xcc00ffee, 0, 0, 0); 149 xcb_flush(c); 150 151 do { 152 xcb_present_complete_notify_event_t *ce; 153 xcb_generic_event_t *ev; 154 155 ev = xcb_wait_for_special_event(c, q); 156 if (ev == NULL) 157 break; 158 159 ce = (xcb_present_complete_notify_event_t *)ev; 160 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC && 161 ce->serial == (serial ^ 0xcc00ffee)) { 162 msc = ce->msc; 163 if (ust) 164 *ust = ce->ust; 165 complete = 1; 166 } 167 free(ev); 168 } while (!complete); 169 170 if ((int64_t)(msc - last_msc) < 0) { 171 printf("Invalid MSC: was %llu, now %llu\n", 172 (long long)last_msc, (long long)msc); 173 } 174 175 if (++serial == 0) 176 serial = 1; 177 178 return msc; 179} 180 181static uint64_t wait_vblank(Display *dpy, Window win, void *q) 182{ 183 xcb_connection_t *c = XGetXCBConnection(dpy); 184 static uint32_t serial = 1; 185 uint64_t msc = 0; 186 int complete = 0; 187 188 xcb_present_notify_msc(c, win, serial ^ 0xdeadbeef, 0, 1, 0); 189 xcb_flush(c); 190 191 do { 192 xcb_present_complete_notify_event_t *ce; 193 xcb_generic_event_t *ev; 194 195 ev = xcb_wait_for_special_event(c, q); 196 if (ev == NULL) 197 break; 198 199 ce = (xcb_present_complete_notify_event_t *)ev; 200 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC && 201 ce->serial == (serial ^ 0xdeadbeef)) { 202 msc = ce->msc; 203 complete = 1; 204 } 205 free(ev); 206 } while (!complete); 207 208 if (++serial == 0) 209 serial = 1; 210 211 return msc; 212} 213 214static uint64_t msc_interval(Display *dpy, Window win, void *q) 215{ 216 xcb_connection_t *c = XGetXCBConnection(dpy); 217 uint64_t msc, ust; 218 int complete = 0; 219 220 msc = check_msc(dpy, win, q, 0, NULL); 221 222 xcb_present_notify_msc(c, win, 0xc0ffee00, msc, 0, 0); 223 xcb_present_notify_msc(c, win, 0xc0ffee01, msc + 10, 0, 0); 224 xcb_flush(c); 225 226 ust = msc = 0; 227 do { 228 xcb_present_complete_notify_event_t *ce; 229 xcb_generic_event_t *ev; 230 231 ev = xcb_wait_for_special_event(c, q); 232 if (ev == NULL) 233 break; 234 235 ce = (xcb_present_complete_notify_event_t *)ev; 236 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC && 237 ce->serial == 0xc0ffee00) { 238 msc -= ce->msc; 239 ust -= ce->ust; 240 complete++; 241 } 242 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC && 243 ce->serial == 0xc0ffee01) { 244 msc += ce->msc; 245 ust += ce->ust; 246 complete++; 247 } 248 free(ev); 249 } while (complete != 2); 250 251 printf("10 frame interval: msc=%lld, ust=%lld\n", 252 (long long)msc, (long long)ust); 253 XSync(dpy, True); 254 if (msc == 0) 255 return 0; 256 257 return (ust + msc/2) / msc; 258} 259 260static void teardown_msc(Display *dpy, void *q) 261{ 262 xcb_unregister_for_special_event(XGetXCBConnection(dpy), q); 263} 264 265static int test_whole(Display *dpy, Window win, const char *phase) 266{ 267 xcb_connection_t *c = XGetXCBConnection(dpy); 268 Pixmap pixmap; 269 struct dri3_fence fence; 270 Window root; 271 unsigned int width, height; 272 unsigned border, depth; 273 int x, y, ret = 1; 274 275 XGetGeometry(dpy, win, 276 &root, &x, &y, &width, &height, &border, &depth); 277 278 if (dri3_create_fence(dpy, win, &fence)) 279 return 0; 280 281 printf("%s: Testing simple flip: %dx%d\n", phase, width, height); 282 _x_error_occurred = 0; 283 284 xshmfence_reset(fence.addr); 285 286 pixmap = XCreatePixmap(dpy, win, width, height, depth); 287 xcb_present_pixmap(c, win, pixmap, 0, 288 0, /* valid */ 289 0, /* update */ 290 0, /* x_off */ 291 0, /* y_off */ 292 None, 293 None, /* wait fence */ 294 fence.xid, 295 XCB_PRESENT_OPTION_NONE, 296 0, /* target msc */ 297 0, /* divisor */ 298 0, /* remainder */ 299 0, NULL); 300 XFreePixmap(dpy, pixmap); 301 302 pixmap = XCreatePixmap(dpy, win, width, height, depth); 303 xcb_present_pixmap(c, win, pixmap, 0, 304 0, /* valid */ 305 0, /* update */ 306 0, /* x_off */ 307 0, /* y_off */ 308 None, 309 None, /* wait fence */ 310 None, /* sync fence */ 311 XCB_PRESENT_OPTION_NONE, 312 0, /* target msc */ 313 0, /* divisor */ 314 0, /* remainder */ 315 0, NULL); 316 XFreePixmap(dpy, pixmap); 317 XFlush(dpy); 318 319 ret = !!xshmfence_await(fence.addr); 320 dri3_fence_free(dpy, &fence); 321 322 XSync(dpy, True); 323 ret += !!_x_error_occurred; 324 325 return ret; 326} 327 328static uint64_t flush_flips(Display *dpy, Window win, Pixmap pixmap, void *Q, uint64_t *ust) 329{ 330 xcb_connection_t *c = XGetXCBConnection(dpy); 331 uint64_t msc; 332 int complete; 333 334 msc = check_msc(dpy, win, Q, 0, NULL); 335 xcb_present_pixmap(c, win, pixmap, 336 0xdeadbeef, /* serial */ 337 0, /* valid */ 338 0, /* update */ 339 0, /* x_off */ 340 0, /* y_off */ 341 None, 342 None, /* wait fence */ 343 None, 344 XCB_PRESENT_OPTION_NONE, 345 msc + 60, /* target msc */ 346 0, /* divisor */ 347 0, /* remainder */ 348 0, NULL); 349 xcb_flush(c); 350 complete = 0; 351 do { 352 xcb_present_complete_notify_event_t *ce; 353 xcb_generic_event_t *ev; 354 355 ev = xcb_wait_for_special_event(c, Q); 356 if (ev == NULL) 357 break; 358 359 ce = (xcb_present_complete_notify_event_t *)ev; 360 complete = (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP && 361 ce->serial == 0xdeadbeef); 362 free(ev); 363 } while (!complete); 364 XSync(dpy, True); 365 366 return check_msc(dpy, win, Q, msc, ust); 367} 368 369static int test_double(Display *dpy, Window win, const char *phase, void *Q) 370{ 371#define COUNT (15*60) 372 xcb_connection_t *c = XGetXCBConnection(dpy); 373 Pixmap pixmap; 374 Window root; 375 unsigned int width, height; 376 unsigned border, depth; 377 int x, y, n, ret; 378 struct { 379 uint64_t msc, ust; 380 } frame[COUNT+1]; 381 int offset = 0; 382 383 XGetGeometry(dpy, win, 384 &root, &x, &y, &width, &height, &border, &depth); 385 386 printf("%s: Testing flip double buffering: %dx%d\n", phase, width, height); 387 _x_error_occurred = 0; 388 389 pixmap = XCreatePixmap(dpy, win, width, height, depth); 390 flush_flips(dpy, win, pixmap, Q, NULL); 391 for (n = 0; n <= COUNT; n++) { 392 int complete; 393 394 xcb_present_pixmap(c, win, pixmap, n, 395 0, /* valid */ 396 0, /* update */ 397 0, /* x_off */ 398 0, /* y_off */ 399 None, 400 None, /* wait fence */ 401 None, 402 XCB_PRESENT_OPTION_NONE, 403 0, /* target msc */ 404 0, /* divisor */ 405 0, /* remainder */ 406 0, NULL); 407 xcb_flush(c); 408 409 complete = 0; 410 do { 411 xcb_present_complete_notify_event_t *ce; 412 xcb_generic_event_t *ev; 413 414 ev = xcb_wait_for_special_event(c, Q); 415 if (ev == NULL) 416 break; 417 418 ce = (xcb_present_complete_notify_event_t *)ev; 419 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP && 420 ce->serial == n) { 421 frame[n].msc = ce->msc; 422 frame[n].ust = ce->ust; 423 complete = 1; 424 } 425 free(ev); 426 } while (!complete); 427 } 428 XFreePixmap(dpy, pixmap); 429 430 XSync(dpy, True); 431 ret = !!_x_error_occurred; 432 433 if (frame[COUNT].msc - frame[0].msc != COUNT) { 434 printf("Expected %d frames interval, %d elapsed instead\n", 435 COUNT, (int)(frame[COUNT].msc - frame[0].msc)); 436 for (n = 0; n <= COUNT; n++) { 437 if (frame[n].msc - frame[0].msc != n + offset) { 438 printf("frame[%d]: msc=%03lld, ust=%lld\n", n, 439 (long long)(frame[n].msc - frame[0].msc), 440 (long long)(frame[n].ust - frame[0].ust)); 441 offset = frame[n].msc - frame[0].msc - n; 442 ret++; 443 } 444 } 445 } 446 447 return ret; 448} 449 450static int test_future(Display *dpy, Window win, const char *phase, void *Q) 451{ 452 xcb_connection_t *c = XGetXCBConnection(dpy); 453 Pixmap pixmap; 454 struct dri3_fence fence; 455 Window root; 456 unsigned int width, height; 457 unsigned border, depth; 458 int x, y, ret = 0, n; 459 uint64_t msc, ust; 460 int complete, count; 461 int early = 0, late = 0; 462 int earliest = 0, latest = 0; 463 uint64_t interval; 464 465 XGetGeometry(dpy, win, 466 &root, &x, &y, &width, &height, &border, &depth); 467 468 if (dri3_create_fence(dpy, win, &fence)) 469 return 0; 470 471 printf("%s: Testing flips into the future: %dx%d\n", phase, width, height); 472 _x_error_occurred = 0; 473 474 interval = msc_interval(dpy, win, Q); 475 if (interval == 0) { 476 printf("Zero delay between frames\n"); 477 return 1; 478 } 479 480 pixmap = XCreatePixmap(dpy, win, width, height, depth); 481 msc = flush_flips(dpy, win, pixmap, Q, &ust); 482 for (n = 1; n <= 10; n++) 483 xcb_present_pixmap(c, win, pixmap, 484 n, /* serial */ 485 0, /* valid */ 486 0, /* update */ 487 0, /* x_off */ 488 0, /* y_off */ 489 None, 490 None, /* wait fence */ 491 None, 492 XCB_PRESENT_OPTION_NONE, 493 msc + 60 + n*15*60, /* target msc */ 494 0, /* divisor */ 495 0, /* remainder */ 496 0, NULL); 497 xcb_present_pixmap(c, win, pixmap, 498 0xdeadbeef, /* serial */ 499 0, /* valid */ 500 0, /* update */ 501 0, /* x_off */ 502 0, /* y_off */ 503 None, 504 None, /* wait fence */ 505 None, 506 XCB_PRESENT_OPTION_NONE, 507 msc + 60 + n*15*60, /* target msc */ 508 0, /* divisor */ 509 0, /* remainder */ 510 0, NULL); 511 xcb_flush(c); 512 513 complete = 0; 514 count = 0; 515 do { 516 xcb_present_complete_notify_event_t *ce; 517 xcb_generic_event_t *ev; 518 519 ev = xcb_wait_for_special_event(c, Q); 520 if (ev == NULL) 521 break; 522 523 ce = (xcb_present_complete_notify_event_t *)ev; 524 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP); 525 526 if (ce->serial == 0xdeadbeef) { 527 int64_t time; 528 529 time = ce->ust - (ust + (60 + 15*60*n) * interval); 530 if (time < -(int64_t)interval) { 531 fprintf(stderr, 532 "\tflips completed too early by %lldms\n", 533 (long long)(-time / 1000)); 534 } else if (time > (int64_t)interval) { 535 fprintf(stderr, 536 "\tflips completed too late by %lldms\n", 537 (long long)(time / 1000)); 538 } 539 complete = 1; 540 } else { 541 int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60)); 542 if (diff < 0) { 543 if (-diff > earliest) { 544 fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff); 545 earliest = -diff; 546 } 547 early++; 548 ret++; 549 } else if (diff > 0) { 550 if (diff > latest) { 551 fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff); 552 latest = diff; 553 } 554 late++; 555 ret++; 556 } 557 count++; 558 } 559 free(ev); 560 } while (!complete); 561 562 if (early) 563 printf("\t%d frames shown too early (worst %d)!\n", early, earliest); 564 if (late) 565 printf("\t%d frames shown too late (worst %d)!\n", late, latest); 566 567 if (count != 10) { 568 fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", 10 - count); 569 ret++; 570 571 do { 572 xcb_present_complete_notify_event_t *ce; 573 xcb_generic_event_t *ev; 574 575 ev = xcb_wait_for_special_event(c, Q); 576 if (ev == NULL) 577 break; 578 579 ce = (xcb_present_complete_notify_event_t *)ev; 580 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP); 581 free(ev); 582 } while (++count != 10); 583 } 584 585 ret += !!_x_error_occurred; 586 587 return ret; 588} 589 590static int test_exhaustion(Display *dpy, Window win, const char *phase, void *Q) 591{ 592#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */ 593 xcb_connection_t *c = XGetXCBConnection(dpy); 594 Pixmap pixmap; 595 struct dri3_fence fence[2]; 596 Window root; 597 xcb_xfixes_region_t region; 598 unsigned int width, height; 599 unsigned border, depth; 600 int x, y, ret = 0, n; 601 uint64_t target, final; 602 603 XGetGeometry(dpy, win, 604 &root, &x, &y, &width, &height, &border, &depth); 605 606 if (dri3_create_fence(dpy, win, &fence[0]) || 607 dri3_create_fence(dpy, win, &fence[1])) 608 return 0; 609 610 printf("%s: Testing flips with long vblank queues: %dx%d\n", phase, width, height); 611 _x_error_occurred = 0; 612 613 region = xcb_generate_id(c); 614 xcb_xfixes_create_region(c, region, 0, NULL); 615 616 pixmap = XCreatePixmap(dpy, win, width, height, depth); 617 xshmfence_reset(fence[0].addr); 618 xshmfence_reset(fence[1].addr); 619 target = check_msc(dpy, win, Q, 0, NULL); 620 for (n = N_VBLANKS; n--; ) 621 xcb_present_pixmap(c, win, pixmap, 0, 622 0, /* valid */ 623 region, /* update */ 624 0, /* x_off */ 625 0, /* y_off */ 626 None, 627 None, /* wait fence */ 628 None, 629 XCB_PRESENT_OPTION_NONE, 630 target + N_VBLANKS, /* target msc */ 631 1, /* divisor */ 632 0, /* remainder */ 633 0, NULL); 634 xcb_present_pixmap(c, win, pixmap, 0, 635 region, /* valid */ 636 region, /* update */ 637 0, /* x_off */ 638 0, /* y_off */ 639 None, 640 None, /* wait fence */ 641 fence[0].xid, 642 XCB_PRESENT_OPTION_NONE, 643 target, /* target msc */ 644 0, /* divisor */ 645 0, /* remainder */ 646 0, NULL); 647 for (n = 1; n < N_VBLANKS; n++) 648 xcb_present_pixmap(c, win, pixmap, 0, 649 region, /* valid */ 650 region, /* update */ 651 0, /* x_off */ 652 0, /* y_off */ 653 None, 654 None, /* wait fence */ 655 None, 656 XCB_PRESENT_OPTION_NONE, 657 target + n, /* target msc */ 658 0, /* divisor */ 659 0, /* remainder */ 660 0, NULL); 661 xcb_present_pixmap(c, win, pixmap, 0, 662 region, /* valid */ 663 region, /* update */ 664 0, /* x_off */ 665 0, /* y_off */ 666 None, 667 None, /* wait fence */ 668 fence[1].xid, 669 XCB_PRESENT_OPTION_NONE, 670 target + N_VBLANKS, /* target msc */ 671 0, /* divisor */ 672 0, /* remainder */ 673 0, NULL); 674 xcb_flush(c); 675 676 ret += !!xshmfence_await(fence[0].addr); 677 final = check_msc(dpy, win, Q, 0, NULL); 678 if (final < target) { 679 printf("\tFirst flip too early, MSC was %llu, expected %llu\n", 680 (long long)final, (long long)target); 681 ret++; 682 } else if (final > target + 1) { 683 printf("\tFirst flip too late, MSC was %llu, expected %llu\n", 684 (long long)final, (long long)target); 685 ret++; 686 } 687 688 ret += !!xshmfence_await(fence[1].addr); 689 final = check_msc(dpy, win, Q, 0, NULL); 690 if (final < target + N_VBLANKS) { 691 printf("\tLast flip too early, MSC was %llu, expected %llu\n", 692 (long long)final, (long long)(target + N_VBLANKS)); 693 ret++; 694 } else if (final > target + N_VBLANKS + 1) { 695 printf("\tLast flip too late, MSC was %llu, expected %llu\n", 696 (long long)final, (long long)(target + N_VBLANKS)); 697 ret++; 698 } 699 700 flush_flips(dpy, win, pixmap, Q, NULL); 701 702 XFreePixmap(dpy, pixmap); 703 xcb_xfixes_destroy_region(c, region); 704 dri3_fence_free(dpy, &fence[1]); 705 dri3_fence_free(dpy, &fence[0]); 706 707 XSync(dpy, True); 708 ret += !!_x_error_occurred; 709 710 return ret; 711#undef N_VBLANKS 712} 713 714static int test_accuracy(Display *dpy, Window win, const char *phase, void *Q) 715{ 716#define N_VBLANKS (60 * 120) /* ~2 minutes */ 717 xcb_connection_t *c = XGetXCBConnection(dpy); 718 Pixmap pixmap; 719 Window root; 720 unsigned int width, height; 721 unsigned border, depth; 722 int x, y, ret = 0, n; 723 uint64_t target; 724 int early = 0, late = 0; 725 int earliest = 0, latest = 0; 726 int complete, count; 727 728 XGetGeometry(dpy, win, 729 &root, &x, &y, &width, &height, &border, &depth); 730 731 printf("%s: Testing flip accuracy: %dx%d\n", phase, width, height); 732 _x_error_occurred = 0; 733 734 pixmap = XCreatePixmap(dpy, win, width, height, depth); 735 target = flush_flips(dpy, win, pixmap, Q, NULL); 736 for (n = 0; n <= N_VBLANKS; n++) 737 xcb_present_pixmap(c, win, pixmap, 738 n, /* serial */ 739 0, /* valid */ 740 0, /* update */ 741 0, /* x_off */ 742 0, /* y_off */ 743 None, 744 None, /* wait fence */ 745 None, 746 XCB_PRESENT_OPTION_NONE, 747 target + 60 + n, /* target msc */ 748 0, /* divisor */ 749 0, /* remainder */ 750 0, NULL); 751 xcb_present_pixmap(c, win, pixmap, 752 0xdeadbeef, /* serial */ 753 0, /* valid */ 754 0, /* update */ 755 0, /* x_off */ 756 0, /* y_off */ 757 None, 758 None, /* wait fence */ 759 None, 760 XCB_PRESENT_OPTION_NONE, 761 target + 60 + n, /* target msc */ 762 0, /* divisor */ 763 0, /* remainder */ 764 0, NULL); 765 xcb_flush(c); 766 767 complete = 0; 768 count = 0; 769 do { 770 xcb_present_complete_notify_event_t *ce; 771 xcb_generic_event_t *ev; 772 773 ev = xcb_wait_for_special_event(c, Q); 774 if (ev == NULL) 775 break; 776 777 ce = (xcb_present_complete_notify_event_t *)ev; 778 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP); 779 780 if (ce->serial != 0xdeadbeef) { 781 int diff = (int64_t)(ce->msc - (target + ce->serial + 60)); 782 if (diff < 0) { 783 if (-diff > earliest) { 784 fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff); 785 earliest = -diff; 786 } 787 early++; 788 ret++; 789 } else if (diff > 0) { 790 if (diff > latest) { 791 fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff); 792 latest = diff; 793 } 794 late++; 795 ret++; 796 } 797 count++; 798 } else 799 complete = 1; 800 free(ev); 801 } while (!complete); 802 803 if (early) 804 printf("\t%d frames shown too early (worst %d)!\n", early, earliest); 805 if (late) 806 printf("\t%d frames shown too late (worst %d)!\n", late, latest); 807 808 if (count != N_VBLANKS+1) { 809 fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", N_VBLANKS+1 - count); 810 ret++; 811 do { 812 xcb_present_complete_notify_event_t *ce; 813 xcb_generic_event_t *ev; 814 815 ev = xcb_wait_for_special_event(c, Q); 816 if (ev == NULL) 817 break; 818 819 ce = (xcb_present_complete_notify_event_t *)ev; 820 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP); 821 free(ev); 822 } while (++count != N_VBLANKS+1); 823 } 824 825 XFreePixmap(dpy, pixmap); 826 827 XSync(dpy, True); 828 ret += !!_x_error_occurred; 829 830 return ret; 831#undef N_VBLANKS 832} 833 834static int test_modulus(Display *dpy, Window win, const char *phase, void *Q) 835{ 836 xcb_connection_t *c = XGetXCBConnection(dpy); 837 Pixmap pixmap; 838 Window root; 839 unsigned int width, height; 840 unsigned border, depth; 841 xcb_xfixes_region_t region; 842 int x, y, ret = 0; 843 uint64_t target; 844 int early = 0, late = 0; 845 int earliest = 0, latest = 0; 846 int complete, expect, count; 847 848 XGetGeometry(dpy, win, 849 &root, &x, &y, &width, &height, &border, &depth); 850 851 printf("%s: Testing flip modulus: %dx%d\n", phase, width, height); 852 _x_error_occurred = 0; 853 854 region = xcb_generate_id(c); 855 xcb_xfixes_create_region(c, region, 0, NULL); 856 857 pixmap = XCreatePixmap(dpy, win, width, height, depth); 858 target = flush_flips(dpy, win, pixmap, Q, NULL); 859 expect = 0; 860 for (x = 1; x <= 7; x++) { 861 for (y = 0; y < x; y++) { 862 xcb_present_pixmap(c, win, pixmap, 863 y << 16 | x, /* serial */ 864 region, /* valid */ 865 region, /* update */ 866 0, /* x_off */ 867 0, /* y_off */ 868 None, 869 None, /* wait fence */ 870 None, 871 XCB_PRESENT_OPTION_NONE, 872 0, /* target msc */ 873 x, /* divisor */ 874 y, /* remainder */ 875 0, NULL); 876 expect++; 877 } 878 } 879 xcb_present_pixmap(c, win, pixmap, 880 0xdeadbeef, /* serial */ 881 0, /* valid */ 882 0, /* update */ 883 0, /* x_off */ 884 0, /* y_off */ 885 None, 886 None, /* wait fence */ 887 None, 888 XCB_PRESENT_OPTION_NONE, 889 target + 2*x, /* target msc */ 890 0, /* divisor */ 891 0, /* remainder */ 892 0, NULL); 893 xcb_flush(c); 894 895 complete = 0; 896 count = 0; 897 do { 898 xcb_present_complete_notify_event_t *ce; 899 xcb_generic_event_t *ev; 900 901 ev = xcb_wait_for_special_event(c, Q); 902 if (ev == NULL) 903 break; 904 905 ce = (xcb_present_complete_notify_event_t *)ev; 906 if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP) 907 break; 908 909 assert(ce->serial); 910 if (ce->serial != 0xdeadbeef) { 911 uint64_t msc; 912 int diff; 913 914 x = ce->serial & 0xffff; 915 y = ce->serial >> 16; 916 917 msc = target; 918 msc -= target % x; 919 msc += y; 920 if (msc <= target) 921 msc += x; 922 923 diff = (int64_t)(ce->msc - msc); 924 if (diff < 0) { 925 if (-diff > earliest) { 926 fprintf(stderr, "\tframe (%d, %d) displayed early by %d frames\n", y, x, -diff); 927 earliest = -diff; 928 } 929 early++; 930 ret++; 931 } else if (diff > 0) { 932 if (diff > latest) { 933 fprintf(stderr, "\tframe (%d, %d) displayed late by %d frames\n", y, x, diff); 934 latest = diff; 935 } 936 late++; 937 ret++; 938 } 939 count++; 940 } else 941 complete = 1; 942 free(ev); 943 } while (!complete); 944 945 if (early) 946 printf("\t%d frames shown too early (worst %d)!\n", early, earliest); 947 if (late) 948 printf("\t%d frames shown too late (worst %d)!\n", late, latest); 949 950 if (count != expect) { 951 fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", expect - count); 952 ret++; 953 do { 954 xcb_present_complete_notify_event_t *ce; 955 xcb_generic_event_t *ev; 956 957 ev = xcb_wait_for_special_event(c, Q); 958 if (ev == NULL) 959 break; 960 961 ce = (xcb_present_complete_notify_event_t *)ev; 962 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 963 free(ev); 964 } while (++count != expect); 965 } 966 967 XFreePixmap(dpy, pixmap); 968 xcb_xfixes_destroy_region(c, region); 969 970 XSync(dpy, True); 971 ret += !!_x_error_occurred; 972 973 return ret; 974} 975 976static int test_future_msc(Display *dpy, void *Q) 977{ 978 xcb_connection_t *c = XGetXCBConnection(dpy); 979 Window root = DefaultRootWindow(dpy); 980 int ret = 0, n; 981 uint64_t msc, ust; 982 int complete, count; 983 int early = 0, late = 0; 984 int earliest = 0, latest = 0; 985 uint64_t interval; 986 987 printf("Testing notifies into the future\n"); 988 _x_error_occurred = 0; 989 990 interval = msc_interval(dpy, root, Q); 991 if (interval == 0) { 992 printf("Zero delay between frames\n"); 993 return 1; 994 } 995 msc = check_msc(dpy, root, Q, 0, &ust); 996 printf("Initial msc=%llx, interval between frames %lldus\n", 997 (long long)msc, (long long)interval); 998 999 for (n = 1; n <= 10; n++) 1000 xcb_present_notify_msc(c, root, n, msc + 60 + n*15*60, 0, 0); 1001 xcb_present_notify_msc(c, root, 0xdeadbeef, msc + 60 + n*15*60, 0, 0); 1002 xcb_flush(c); 1003 1004 complete = 0; 1005 count = 0; 1006 do { 1007 xcb_present_complete_notify_event_t *ce; 1008 xcb_generic_event_t *ev; 1009 1010 ev = xcb_wait_for_special_event(c, Q); 1011 if (ev == NULL) 1012 break; 1013 1014 ce = (xcb_present_complete_notify_event_t *)ev; 1015 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1016 1017 if (ce->serial == 0xdeadbeef) { 1018 int64_t time, tolerance; 1019 1020 tolerance = 60 + 15*60*n/10; 1021 if (tolerance < interval) 1022 tolerance = interval; 1023 1024 time = ce->ust - (ust + (60 + 15*60*n) * interval); 1025 if (time < -(int64_t)tolerance) { 1026 fprintf(stderr, 1027 "\tnotifies completed too early by %lldms, tolerance %lldus\n", 1028 (long long)(-time / 1000), (long long)tolerance); 1029 } else if (time > (int64_t)tolerance) { 1030 fprintf(stderr, 1031 "\tnotifies completed too late by %lldms, tolerance %lldus\n", 1032 (long long)(time / 1000), (long long)tolerance); 1033 } 1034 complete = 1; 1035 } else { 1036 int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60)); 1037 1038 if (ce->serial != count + 1) { 1039 fprintf(stderr, "vblank received out of order! expected %d, received %d\n", 1040 count + 1, (int)ce->serial); 1041 ret++; 1042 } 1043 count++; 1044 1045 if (diff < 0) { 1046 if (-diff > earliest) { 1047 fprintf(stderr, "\tnotify %d early by %d msc\n", ce->serial, -diff); 1048 earliest = -diff; 1049 } 1050 early++; 1051 ret++; 1052 } else if (diff > 0) { 1053 if (diff > latest) { 1054 fprintf(stderr, "\tnotify %d late by %d msc\n", ce->serial, diff); 1055 latest = diff; 1056 } 1057 late++; 1058 ret++; 1059 } 1060 } 1061 free(ev); 1062 } while (!complete); 1063 1064 if (early) 1065 printf("\t%d notifies too early (worst %d)!\n", early, earliest); 1066 if (late) 1067 printf("\t%d notifies too late (worst %d)!\n", late, latest); 1068 1069 if (count != 10) { 1070 fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", 10 - count); 1071 ret++; 1072 do { 1073 xcb_present_complete_notify_event_t *ce; 1074 xcb_generic_event_t *ev; 1075 1076 ev = xcb_wait_for_special_event(c, Q); 1077 if (ev == NULL) 1078 break; 1079 1080 ce = (xcb_present_complete_notify_event_t *)ev; 1081 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1082 free(ev); 1083 } while (++count != 10); 1084 } 1085 1086 XSync(dpy, True); 1087 ret += !!_x_error_occurred; 1088 1089 return ret; 1090} 1091 1092static int test_wrap_msc(Display *dpy) 1093{ 1094 xcb_connection_t *c = XGetXCBConnection(dpy); 1095 Window root, win; 1096 int x, y; 1097 unsigned int width, height; 1098 unsigned border, depth; 1099 XSetWindowAttributes attr; 1100 int ret = 0, n; 1101 uint64_t msc, ust; 1102 int complete; 1103 uint64_t interval; 1104 void *Q; 1105 1106 XGetGeometry(dpy, DefaultRootWindow(dpy), 1107 &root, &x, &y, &width, &height, &border, &depth); 1108 1109 attr.override_redirect = 1; 1110 win = XCreateWindow(dpy, root, 1111 0, 0, width, height, 0, depth, 1112 InputOutput, DefaultVisual(dpy, DefaultScreen(dpy)), 1113 CWOverrideRedirect, &attr); 1114 XMapWindow(dpy, win); 1115 XSync(dpy, True); 1116 if (_x_error_occurred) 1117 return 1; 1118 1119 printf("Testing wraparound notifies\n"); 1120 _x_error_occurred = 0; 1121 1122 Q = setup_msc(dpy, win); 1123 interval = msc_interval(dpy, win, Q); 1124 if (interval == 0) { 1125 printf("Zero delay between frames\n"); 1126 return 1; 1127 } 1128 msc = check_msc(dpy, win, Q, 0, &ust); 1129 printf("Initial msc=%llx, interval between frames %lldus\n", 1130 (long long)msc, (long long)interval); 1131 1132 for (n = 1; n <= 10; n++) 1133 xcb_present_notify_msc(c, win, n, 1134 msc + ((long long)n<<32) + n, 1135 0, 0); 1136 for (n = 1; n <= 10; n++) 1137 xcb_present_notify_msc(c, win, -n, 1138 0, (long long)n << 32, 0); 1139 xcb_present_notify_msc(c, win, 0xdeadbeef, msc + 60*10, 0, 0); 1140 xcb_flush(c); 1141 1142 complete = 0; 1143 do { 1144 xcb_present_complete_notify_event_t *ce; 1145 xcb_generic_event_t *ev; 1146 1147 ev = xcb_wait_for_special_event(c, Q); 1148 if (ev == NULL) 1149 break; 1150 1151 ce = (xcb_present_complete_notify_event_t *)ev; 1152 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1153 1154 if (ce->serial == 0xdeadbeef) { 1155 complete = 1; 1156 } else { 1157 fprintf(stderr, 1158 "\tnotify %d recieved at +%llu\n", 1159 ce->serial, ce->msc - msc); 1160 ret++; 1161 } 1162 free(ev); 1163 } while (!complete); 1164 1165 teardown_msc(dpy, Q); 1166 XDestroyWindow(dpy, win); 1167 XSync(dpy, True); 1168 1169 return ret; 1170} 1171 1172static int test_exhaustion_msc(Display *dpy, void *Q) 1173{ 1174#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */ 1175 xcb_connection_t *c = XGetXCBConnection(dpy); 1176 Window root = DefaultRootWindow(dpy); 1177 int ret = 0, n, complete; 1178 int earliest = 0, early = 0; 1179 int latest = 0, late = 0; 1180 uint64_t msc; 1181 1182 printf("Testing notifies with long queues\n"); 1183 _x_error_occurred = 0; 1184 1185 msc = check_msc(dpy, root, Q, 0, NULL); 1186 for (n = N_VBLANKS; n--; ) 1187 xcb_present_notify_msc(c, root, N_VBLANKS, msc + N_VBLANKS, 0, 0); 1188 for (n = 1; n <= N_VBLANKS ; n++) 1189 xcb_present_notify_msc(c, root, n, msc + n, 0, 0); 1190 xcb_flush(c); 1191 1192 complete = 2*N_VBLANKS; 1193 do { 1194 xcb_present_complete_notify_event_t *ce; 1195 xcb_generic_event_t *ev; 1196 int diff; 1197 1198 ev = xcb_wait_for_special_event(c, Q); 1199 if (ev == NULL) 1200 break; 1201 1202 ce = (xcb_present_complete_notify_event_t *)ev; 1203 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1204 1205 diff = (int64_t)(ce->msc - msc - ce->serial); 1206 if (diff < 0) { 1207 if (-diff > earliest) { 1208 fprintf(stderr, "\tnotify %d early by %d msc\n",(int)ce->serial, -diff); 1209 earliest = -diff; 1210 } 1211 early++; 1212 ret++; 1213 } else if (diff > 0) { 1214 if (diff > latest) { 1215 fprintf(stderr, "\tnotify %d late by %d msc\n", (int)ce->serial, diff); 1216 latest = diff; 1217 } 1218 late++; 1219 ret++; 1220 } 1221 free(ev); 1222 } while (--complete); 1223 1224 if (early) 1225 printf("\t%d notifies too early (worst %d)!\n", early, earliest); 1226 if (late) 1227 printf("\t%d notifies too late (worst %d)!\n", late, latest); 1228 1229 XSync(dpy, True); 1230 ret += !!_x_error_occurred; 1231 1232 return ret; 1233#undef N_VBLANKS 1234} 1235 1236static int test_accuracy_msc(Display *dpy, void *Q) 1237{ 1238#define N_VBLANKS (60 * 120) /* ~2 minutes */ 1239 xcb_connection_t *c = XGetXCBConnection(dpy); 1240 Window root = DefaultRootWindow(dpy); 1241 int ret = 0, n; 1242 uint64_t msc; 1243 int early = 0, late = 0; 1244 int earliest = 0, latest = 0; 1245 int complete, count; 1246 1247 printf("Testing notify accuracy\n"); 1248 _x_error_occurred = 0; 1249 1250 msc = check_msc(dpy, root, Q, 0, NULL); 1251 for (n = 0; n <= N_VBLANKS; n++) 1252 xcb_present_notify_msc(c, root, n, msc + 60 + n, 0, 0); 1253 xcb_present_notify_msc(c, root, 0xdeadbeef, msc + 60 + n, 0, 0); 1254 xcb_flush(c); 1255 1256 complete = 0; 1257 count = 0; 1258 do { 1259 xcb_present_complete_notify_event_t *ce; 1260 xcb_generic_event_t *ev; 1261 1262 ev = xcb_wait_for_special_event(c, Q); 1263 if (ev == NULL) 1264 break; 1265 1266 ce = (xcb_present_complete_notify_event_t *)ev; 1267 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1268 1269 if (ce->serial != 0xdeadbeef) { 1270 int diff = (int64_t)(ce->msc - (msc + ce->serial + 60)); 1271 if (diff < 0) { 1272 if (-diff > earliest) { 1273 fprintf(stderr, "\tnotify %d early by %d msc\n", ce->serial, -diff); 1274 earliest = -diff; 1275 } 1276 early++; 1277 ret++; 1278 } else if (diff > 0) { 1279 if (diff > latest) { 1280 fprintf(stderr, "\tnotify %d late by %d msc\n", ce->serial, diff); 1281 latest = diff; 1282 } 1283 late++; 1284 ret++; 1285 } 1286 count++; 1287 } else 1288 complete = 1; 1289 free(ev); 1290 } while (!complete); 1291 1292 if (early) 1293 printf("\t%d notifies too early (worst %d)!\n", early, earliest); 1294 if (late) 1295 printf("\t%d notifies too late (worst %d)!\n", late, latest); 1296 1297 if (count != N_VBLANKS+1) { 1298 fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", N_VBLANKS+1 - count); 1299 ret++; 1300 do { 1301 xcb_present_complete_notify_event_t *ce; 1302 xcb_generic_event_t *ev; 1303 1304 ev = xcb_wait_for_special_event(c, Q); 1305 if (ev == NULL) 1306 break; 1307 1308 ce = (xcb_present_complete_notify_event_t *)ev; 1309 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1310 free(ev); 1311 } while (++count != N_VBLANKS+1); 1312 } 1313 1314 XSync(dpy, True); 1315 ret += !!_x_error_occurred; 1316 1317 return ret; 1318#undef N_VBLANKS 1319} 1320 1321static int test_modulus_msc(Display *dpy, void *Q) 1322{ 1323 xcb_connection_t *c = XGetXCBConnection(dpy); 1324 Window root = DefaultRootWindow(dpy); 1325 xcb_present_complete_notify_event_t *ce; 1326 xcb_generic_event_t *ev; 1327 int x, y, ret = 0; 1328 uint64_t target; 1329 int early = 0, late = 0; 1330 int earliest = 0, latest = 0; 1331 int complete, count, expect; 1332 1333 printf("Testing notify modulus\n"); 1334 _x_error_occurred = 0; 1335 1336 target = wait_vblank(dpy, root, Q); 1337 1338 expect = 0; 1339 xcb_present_notify_msc(c, root, 0, 0, 0, 0); 1340 for (x = 1; x <= 19; x++) { 1341 for (y = 0; y < x; y++) { 1342 xcb_present_notify_msc(c, root, y << 16 | x, 0, x, y); 1343 expect++; 1344 } 1345 } 1346 xcb_present_notify_msc(c, root, 0xdeadbeef, target + 2*x, 0, 0); 1347 xcb_flush(c); 1348 1349 ev = xcb_wait_for_special_event(c, Q); 1350 if (ev) { 1351 ce = (xcb_present_complete_notify_event_t *)ev; 1352 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1353 assert(ce->serial == 0); 1354 assert(target == ce->msc); 1355 target = ce->msc; 1356 } 1357 1358 complete = 0; 1359 count = 0; 1360 do { 1361 ev = xcb_wait_for_special_event(c, Q); 1362 if (ev == NULL) 1363 break; 1364 1365 ce = (xcb_present_complete_notify_event_t *)ev; 1366 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1367 1368 assert(ce->serial); 1369 if (ce->serial != 0xdeadbeef) { 1370 uint64_t msc; 1371 int diff; 1372 1373 x = ce->serial & 0xffff; 1374 y = ce->serial >> 16; 1375 1376 msc = target; 1377 msc -= target % x; 1378 msc += y; 1379 if (msc <= target) 1380 msc += x; 1381 1382 diff = (int64_t)(ce->msc - msc); 1383 if (diff < 0) { 1384 if (-diff > earliest) { 1385 fprintf(stderr, "\tnotify (%d, %d) early by %d msc (target %lld, reported %lld)\n", y, x, -diff, (long long)msc, (long long)ce->msc); 1386 earliest = -diff; 1387 } 1388 early++; 1389 ret++; 1390 } else if (diff > 0) { 1391 if (diff > latest) { 1392 fprintf(stderr, "\tnotify (%d, %d) late by %d msc (target %lld, reported %lld)\n", y, x, diff, (long long)msc, (long long)ce->msc); 1393 latest = diff; 1394 } 1395 late++; 1396 ret++; 1397 } 1398 count++; 1399 } else 1400 complete = 1; 1401 free(ev); 1402 } while (!complete); 1403 1404 if (early) 1405 printf("\t%d notifies too early (worst %d)!\n", early, earliest); 1406 if (late) 1407 printf("\t%d notifies too late (worst %d)!\n", late, latest); 1408 1409 if (count != expect) { 1410 fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", expect - count); 1411 ret++; 1412 do { 1413 ev = xcb_wait_for_special_event(c, Q); 1414 if (ev == NULL) 1415 break; 1416 1417 ce = (xcb_present_complete_notify_event_t *)ev; 1418 assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1419 free(ev); 1420 } while (++count != expect); 1421 } 1422 1423 XSync(dpy, True); 1424 ret += !!_x_error_occurred; 1425 1426 return ret; 1427} 1428 1429static inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window) 1430{ 1431 XRRScreenResources *res; 1432 1433 res = XRRGetScreenResourcesCurrent(dpy, window); 1434 if (res == NULL) 1435 res = XRRGetScreenResources(dpy, window); 1436 1437 return res; 1438} 1439 1440static XRRModeInfo *lookup_mode(XRRScreenResources *res, int id) 1441{ 1442 int i; 1443 1444 for (i = 0; i < res->nmode; i++) { 1445 if (res->modes[i].id == id) 1446 return &res->modes[i]; 1447 } 1448 1449 return NULL; 1450} 1451 1452static int for_each_crtc(Display *dpy, 1453 int (*func)(Display *dpy, 1454 RRCrtc crtc, 1455 int width, int height, 1456 void *closure), 1457 void *closure) 1458{ 1459 XRRScreenResources *res; 1460 XRRCrtcInfo **original_crtc; 1461 int i, j, err = 0; 1462 1463 if (!XRRQueryVersion(dpy, &i, &j)) 1464 return -1; 1465 1466 res = _XRRGetScreenResourcesCurrent(dpy, DefaultRootWindow(dpy)); 1467 if (res == NULL) 1468 return -1; 1469 1470 original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc); 1471 for (i = 0; i < res->ncrtc; i++) 1472 original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]); 1473 1474 for (i = 0; i < res->noutput; i++) { 1475 XRROutputInfo *output; 1476 XRRModeInfo *mode; 1477 1478 output = XRRGetOutputInfo(dpy, res, res->outputs[i]); 1479 if (output == NULL) 1480 continue; 1481 1482 mode = NULL; 1483 if (res->nmode) 1484 mode = lookup_mode(res, output->modes[0]); 1485 1486 for (j = 0; mode && j < output->ncrtc; j++) { 1487 printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld\n", 1488 i, j, (long)res->outputs[i], (long)output->crtcs[j]); 1489 XRRSetCrtcConfig(dpy, res, output->crtcs[j], CurrentTime, 1490 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1); 1491 XSync(dpy, True); 1492 1493 err += func(dpy, output->crtcs[j], mode->width, mode->height, closure); 1494 1495 XRRSetCrtcConfig(dpy, res, output->crtcs[j], CurrentTime, 1496 0, 0, None, RR_Rotate_0, NULL, 0); 1497 XSync(dpy, True); 1498 } 1499 1500 XRRFreeOutputInfo(output); 1501 } 1502 1503 for (i = 0; i < res->ncrtc; i++) 1504 XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 1505 original_crtc[i]->x, 1506 original_crtc[i]->y, 1507 original_crtc[i]->mode, 1508 original_crtc[i]->rotation, 1509 original_crtc[i]->outputs, 1510 original_crtc[i]->noutput); 1511 1512 free(original_crtc); 1513 XRRFreeScreenResources(res); 1514 1515 return err; 1516} 1517 1518struct test_crtc { 1519 Window win; 1520 int depth; 1521 unsigned flags; 1522 1523 struct dri3_fence fence; 1524 void *queue; 1525 uint64_t msc; 1526}; 1527#define SYNC 0x1 1528#define FUTURE 0x2 1529 1530static int __test_crtc(Display *dpy, RRCrtc crtc, 1531 int width, int height, 1532 void *closure) 1533{ 1534 struct test_crtc *test = closure; 1535 Pixmap pixmap; 1536 int err = 0; 1537 1538 test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL); 1539 1540 if (test->flags & SYNC) 1541 xshmfence_reset(test->fence.addr); 1542 1543 pixmap = XCreatePixmap(dpy, test->win, width, height, test->depth); 1544 xcb_present_pixmap(XGetXCBConnection(dpy), 1545 test->win, pixmap, 1546 0, /* sbc */ 1547 0, /* valid */ 1548 0, /* update */ 1549 0, /* x_off */ 1550 0, /* y_off */ 1551 crtc, 1552 None, /* wait fence */ 1553 test->flags & SYNC ? test->fence.xid : None, 1554 XCB_PRESENT_OPTION_NONE, 1555 test->msc, /* target msc */ 1556 1, /* divisor */ 1557 0, /* remainder */ 1558 0, NULL); 1559 if (test->flags & SYNC) { 1560 Pixmap tmp = XCreatePixmap(dpy, test->win, width, height, test->depth); 1561 xcb_present_pixmap(XGetXCBConnection(dpy), 1562 test->win, tmp, 1563 1, /* sbc */ 1564 0, /* valid */ 1565 0, /* update */ 1566 0, /* x_off */ 1567 0, /* y_off */ 1568 crtc, 1569 None, /* wait fence */ 1570 None, /* sync fence */ 1571 XCB_PRESENT_OPTION_NONE, 1572 test->msc + (test->flags & FUTURE ? 5 * 16 : 1), /* target msc */ 1573 1, /* divisor */ 1574 0, /* remainder */ 1575 0, NULL); 1576 XFreePixmap(dpy, tmp); 1577 XFlush(dpy); 1578 err += !!xshmfence_await(test->fence.addr); 1579 } 1580 XFreePixmap(dpy, pixmap); 1581 1582 test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL); 1583 return err; 1584} 1585 1586static int test_crtc(Display *dpy, void *queue, uint64_t last_msc) 1587{ 1588 struct test_crtc test; 1589 int err = 0; 1590 1591 XSync(dpy, True); 1592 _x_error_occurred = 0; 1593 1594 test.win = DefaultRootWindow(dpy); 1595 test.depth = DefaultDepth(dpy, DefaultScreen(dpy)); 1596 if (dri3_create_fence(dpy, test.win, &test.fence)) 1597 return -1; 1598 test.queue = queue; 1599 test.msc = last_msc; 1600 1601 printf("Testing each crtc, without waiting for each flip\n"); 1602 test.flags = 0; 1603 test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 1604 err += for_each_crtc(dpy, __test_crtc, &test); 1605 test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 1606 1607 printf("Testing each crtc, waiting for flips to complete\n"); 1608 test.flags = SYNC; 1609 test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 1610 err += for_each_crtc(dpy, __test_crtc, &test); 1611 test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 1612 1613 printf("Testing each crtc, with future flips\n"); 1614 test.flags = FUTURE | SYNC; 1615 test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 1616 err += for_each_crtc(dpy, __test_crtc, &test); 1617 test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 1618 1619 dri3_fence_free(dpy, &test.fence); 1620 XSync(dpy, True); 1621 err += !!_x_error_occurred; 1622 1623 if (err) 1624 printf("%s: failures=%d\n", __func__, err); 1625 1626 return err; 1627} 1628 1629static int 1630can_use_shm(Display *dpy) 1631{ 1632 int major, minor, has_pixmap; 1633 1634 if (!XShmQueryExtension(dpy)) 1635 return 0; 1636 1637 XShmQueryVersion(dpy, &major, &minor, &has_pixmap); 1638 return has_pixmap; 1639} 1640 1641static int test_shm(Display *dpy) 1642{ 1643 Window win = DefaultRootWindow(dpy); 1644 XShmSegmentInfo shm; 1645 Pixmap pixmap; 1646 Window root; 1647 unsigned int width, height; 1648 unsigned border, depth; 1649 int x, y, ret = 1; 1650 1651 if (!can_use_shm(dpy)) 1652 return 0; 1653 1654 _x_error_occurred = 0; 1655 1656 XGetGeometry(dpy, win, &root, &x, &y, 1657 &width, &height, &border, &depth); 1658 1659 printf("Using %dx%d SHM\n", width, height); 1660 1661 shm.shmid = shmget(IPC_PRIVATE, height * 4*width, IPC_CREAT | 0666); 1662 if (shm.shmid == -1) 1663 return 0; 1664 1665 shm.shmaddr = shmat(shm.shmid, 0, 0); 1666 if (shm.shmaddr == (char *) -1) 1667 goto rmid; 1668 1669 shm.readOnly = False; 1670 XShmAttach(dpy, &shm); 1671 1672 pixmap = XShmCreatePixmap(dpy, DefaultRootWindow(dpy), 1673 shm.shmaddr, &shm, width, height, 24); 1674 if (_x_error_occurred) 1675 goto detach; 1676 1677 xcb_present_pixmap(XGetXCBConnection(dpy), 1678 win, pixmap, 1679 0, /* sbc */ 1680 0, /* valid */ 1681 0, /* update */ 1682 0, /* x_off */ 1683 0, /* y_off */ 1684 None, 1685 None, /* wait fence */ 1686 None, 1687 XCB_PRESENT_OPTION_NONE, 1688 0, /* target msc */ 1689 0, /* divisor */ 1690 0, /* remainder */ 1691 0, NULL); 1692 XFreePixmap(dpy, pixmap); 1693 1694 XSync(dpy, True); 1695 if (_x_error_occurred) 1696 goto detach; 1697 1698 ret = 0; 1699detach: 1700 XShmDetach(dpy, &shm); 1701 shmdt(shm.shmaddr); 1702 XSync(dpy, False); 1703rmid: 1704 shmctl(shm.shmid, IPC_RMID, NULL); 1705 return ret; 1706} 1707 1708static uint32_t gem_create(int fd, int size) 1709{ 1710 struct drm_i915_gem_create create; 1711 1712 create.handle = 0; 1713 create.size = size; 1714 (void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); 1715 1716 return create.handle; 1717} 1718 1719struct local_i915_gem_caching { 1720 uint32_t handle; 1721 uint32_t caching; 1722}; 1723 1724#define LOCAL_I915_GEM_SET_CACHING 0x2f 1725#define LOCAL_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHING, struct local_i915_gem_caching) 1726 1727static int gem_set_caching(int fd, uint32_t handle, int caching) 1728{ 1729 struct local_i915_gem_caching arg; 1730 1731 arg.handle = handle; 1732 arg.caching = caching; 1733 1734 return drmIoctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHING, &arg) == 0; 1735} 1736 1737static int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride) 1738{ 1739 struct drm_i915_gem_set_tiling set_tiling; 1740 int err; 1741 1742restart: 1743 set_tiling.handle = handle; 1744 set_tiling.tiling_mode = tiling; 1745 set_tiling.stride = stride; 1746 1747 if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) 1748 return 1; 1749 1750 err = errno; 1751 if (err == EINTR) 1752 goto restart; 1753 1754 if (err == EAGAIN) { 1755 sched_yield(); 1756 goto restart; 1757 } 1758 1759 return 0; 1760} 1761 1762static int gem_export(int fd, uint32_t handle) 1763{ 1764 struct drm_prime_handle args; 1765 1766 args.handle = handle; 1767 args.flags = O_CLOEXEC; 1768 1769 if (drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args)) 1770 return -1; 1771 1772 return args.fd; 1773} 1774 1775static void gem_close(int fd, uint32_t handle) 1776{ 1777 struct drm_gem_close close; 1778 1779 close.handle = handle; 1780 (void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close); 1781} 1782 1783static int test_dri3_tiling(Display *dpy) 1784{ 1785 Window win = DefaultRootWindow(dpy); 1786 const int tiling[] = { I915_TILING_NONE, I915_TILING_X, I915_TILING_Y }; 1787 Window root; 1788 unsigned int width, height; 1789 unsigned border, depth, bpp; 1790 unsigned stride, size; 1791 void *Q; 1792 int x, y; 1793 int device; 1794 int line = -1; 1795 int t; 1796 1797 device = dri3_open(dpy); 1798 if (device < 0) 1799 return 0; 1800 1801 if (!is_intel(device)) 1802 return 0; 1803 1804 printf("Opened Intel DRI3 device\n"); 1805 1806 XGetGeometry(dpy, win, &root, &x, &y, 1807 &width, &height, &border, &depth); 1808 1809 switch (depth) { 1810 case 8: bpp = 8; break; 1811 case 15: case 16: bpp = 16; break; 1812 case 24: case 32: bpp = 32; break; 1813 default: return 0; 1814 } 1815 1816 stride = ALIGN(width * bpp/8, 512); 1817 size = PAGE_ALIGN(stride * ALIGN(height, 32)); 1818 printf("Creating DRI3 %dx%d (source stride=%d, size=%d) for GTT\n", 1819 width, height, stride, size); 1820 1821 _x_error_occurred = 0; 1822 Q = setup_msc(dpy, root); 1823 1824 for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) { 1825 uint64_t msc; 1826 uint32_t src; 1827 int src_fd; 1828 Pixmap src_pix; 1829 1830 src = gem_create(device, size); 1831 if (!src) { 1832 line = __LINE__; 1833 goto fail; 1834 } 1835 1836 gem_set_tiling(device, src, tiling[t], stride); 1837 1838 src_fd = gem_export(device, src); 1839 if (src_fd < 0) { 1840 line = __LINE__; 1841 goto fail; 1842 } 1843 1844 src_pix = dri3_create_pixmap(dpy, root, 1845 width, height, depth, 1846 src_fd, bpp, stride, size); 1847 1848 msc = wait_vblank(dpy, root, Q); 1849 1850 xcb_present_pixmap(XGetXCBConnection(dpy), 1851 win, src_pix, 1852 0, /* sbc */ 1853 0, /* valid */ 1854 0, /* update */ 1855 0, /* x_off */ 1856 0, /* y_off */ 1857 None, 1858 None, /* wait fence */ 1859 None, 1860 XCB_PRESENT_OPTION_NONE, 1861 msc + 2, /* target msc */ 1862 1, /* divisor */ 1863 0, /* remainder */ 1864 0, NULL); 1865 1866 xcb_present_pixmap(XGetXCBConnection(dpy), 1867 win, src_pix, 1868 0, /* sbc */ 1869 0, /* valid */ 1870 0, /* update */ 1871 0, /* x_off */ 1872 0, /* y_off */ 1873 None, 1874 None, /* wait fence */ 1875 None, 1876 XCB_PRESENT_OPTION_NONE, 1877 msc + 3, /* target msc */ 1878 1, /* divisor */ 1879 0, /* remainder */ 1880 0, NULL); 1881 1882 XSync(dpy, True); 1883 if (_x_error_occurred) { 1884 line = __LINE__; 1885 goto fail; 1886 } 1887 XFreePixmap(dpy, src_pix); 1888 _x_error_occurred = 0; 1889 1890 close(src_fd); 1891 gem_close(device, src); 1892 } 1893 1894 teardown_msc(dpy, Q); 1895 return 0; 1896 1897fail: 1898 printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line); 1899 teardown_msc(dpy, Q); 1900 return 1; 1901} 1902 1903static int test_dri3(Display *dpy) 1904{ 1905 Window win = DefaultRootWindow(dpy); 1906 Pixmap pixmap; 1907 Window root; 1908 unsigned int width, height; 1909 unsigned border, depth; 1910 unsigned stride, size; 1911 int x, y, ret = 1; 1912 int device, handle; 1913 int bpp; 1914 1915 device = dri3_open(dpy); 1916 if (device < 0) 1917 return 0; 1918 1919 if (!is_intel(device)) 1920 return 0; 1921 1922 printf("Opened Intel DRI3 device\n"); 1923 1924 XGetGeometry(dpy, win, &root, &x, &y, 1925 &width, &height, &border, &depth); 1926 1927 switch (depth) { 1928 case 8: bpp = 8; break; 1929 case 15: case 16: bpp = 16; break; 1930 case 24: case 32: bpp = 32; break; 1931 default: return 0; 1932 } 1933 1934 stride = width * bpp/8; 1935 size = PAGE_ALIGN(stride * height); 1936 printf("Creating DRI3 %dx%d (source stride=%d, size=%d) for GTT\n", 1937 width, height, stride, size); 1938 1939 pixmap = 0; 1940 handle = gem_create(device, size); 1941 if (handle) { 1942 pixmap = dri3_create_pixmap(dpy, root, 1943 width, height, depth, 1944 gem_export(device, handle), bpp, stride, size); 1945 gem_close(device, handle); 1946 } 1947 if (pixmap == 0) 1948 goto fail; 1949 1950 xcb_present_pixmap(XGetXCBConnection(dpy), 1951 win, pixmap, 1952 0, /* sbc */ 1953 0, /* valid */ 1954 0, /* update */ 1955 0, /* x_off */ 1956 0, /* y_off */ 1957 None, 1958 None, /* wait fence */ 1959 None, 1960 XCB_PRESENT_OPTION_NONE, 1961 0, /* target msc */ 1962 0, /* divisor */ 1963 0, /* remainder */ 1964 0, NULL); 1965 XFreePixmap(dpy, pixmap); 1966 1967 XSync(dpy, True); 1968 if (_x_error_occurred) 1969 goto fail; 1970 1971 printf("Creating DRI3 %dx%d (source stride=%d, size=%d) for CPU\n", 1972 width, height, stride, size); 1973 1974 pixmap = 0; 1975 handle = gem_create(device, size); 1976 if (handle) { 1977 gem_set_caching(device, handle, CPU); 1978 handle = dri3_create_pixmap(dpy, root, 1979 width, height, depth, 1980 gem_export(device, handle), bpp, stride, size); 1981 gem_close(device, handle); 1982 } 1983 if (pixmap == 0) 1984 goto fail; 1985 1986 xcb_present_pixmap(XGetXCBConnection(dpy), 1987 win, pixmap, 1988 0, /* sbc */ 1989 0, /* valid */ 1990 0, /* update */ 1991 0, /* x_off */ 1992 0, /* y_off */ 1993 None, 1994 None, /* wait fence */ 1995 None, 1996 XCB_PRESENT_OPTION_NONE, 1997 0, /* target msc */ 1998 0, /* divisor */ 1999 0, /* remainder */ 2000 0, NULL); 2001 XFreePixmap(dpy, pixmap); 2002 2003 XSync(dpy, True); 2004 if (_x_error_occurred) 2005 goto fail; 2006 2007 ret = 0; 2008fail: 2009 close(device); 2010 return ret; 2011} 2012 2013static int has_present(Display *dpy) 2014{ 2015 xcb_connection_t *c = XGetXCBConnection(dpy); 2016 xcb_generic_error_t *error = NULL; 2017 void *reply; 2018 2019 reply = xcb_xfixes_query_version_reply(c, 2020 xcb_xfixes_query_version(c, 2021 XCB_XFIXES_MAJOR_VERSION, 2022 XCB_XFIXES_MINOR_VERSION), 2023 &error); 2024 free(reply); 2025 free(error); 2026 if (reply == NULL) { 2027 fprintf(stderr, "XFixes not supported on %s\n", DisplayString(dpy)); 2028 return 0; 2029 } 2030 2031 reply = xcb_dri3_query_version_reply(c, 2032 xcb_dri3_query_version(c, 2033 XCB_DRI3_MAJOR_VERSION, 2034 XCB_DRI3_MINOR_VERSION), 2035 &error); 2036 free(reply); 2037 free(error); 2038 if (reply == NULL) { 2039 fprintf(stderr, "DRI3 not supported on %s\n", DisplayString(dpy)); 2040 return 0; 2041 } 2042 2043 reply = xcb_present_query_version_reply(c, 2044 xcb_present_query_version(c, 2045 XCB_PRESENT_MAJOR_VERSION, 2046 XCB_PRESENT_MINOR_VERSION), 2047 &error); 2048 2049 free(reply); 2050 free(error); 2051 if (reply == NULL) { 2052 fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy)); 2053 return 0; 2054 } 2055 2056 return 1; 2057} 2058 2059static int has_composite(Display *dpy) 2060{ 2061 int event, error; 2062 int major, minor; 2063 2064 if (!XCompositeQueryExtension(dpy, &event, &error)) 2065 return 0; 2066 2067 XCompositeQueryVersion(dpy, &major, &minor); 2068 2069 return major > 0 || minor >= 4; 2070} 2071 2072int main(void) 2073{ 2074 Display *dpy; 2075 Window root; 2076 int dummy; 2077 int error = 0; 2078 uint64_t last_msc; 2079 void *queue; 2080 2081 dpy = XOpenDisplay(NULL); 2082 if (dpy == NULL) 2083 return 77; 2084 2085 if (!has_present(dpy)) 2086 return 77; 2087 2088 if (DPMSQueryExtension(dpy, &dummy, &dummy)) 2089 DPMSDisable(dpy); 2090 2091 root = DefaultRootWindow(dpy); 2092 2093 signal(SIGALRM, SIG_IGN); 2094 XSetErrorHandler(_check_error_handler); 2095 2096 queue = setup_msc(dpy, root); 2097 last_msc = check_msc(dpy, root, queue, 0, NULL); 2098 2099 error += test_future_msc(dpy, queue); 2100 last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2101 2102 error += test_wrap_msc(dpy); 2103 last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2104 2105 error += test_accuracy_msc(dpy, queue); 2106 last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2107 2108 error += test_modulus_msc(dpy, queue); 2109 last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2110 2111 error += test_exhaustion_msc(dpy, queue); 2112 last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2113 2114 for (dummy = 0; dummy <= 3; dummy++) { 2115 Window win; 2116 uint64_t msc = 0; 2117 XSetWindowAttributes attr; 2118 Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy)); 2119 unsigned int width, height; 2120 unsigned border, depth; 2121 const char *phase; 2122 int x, y; 2123 void *Q; 2124 2125 attr.override_redirect = 1; 2126 2127 XGetGeometry(dpy, root, &win, &x, &y, 2128 &width, &height, &border, &depth); 2129 2130 _x_error_occurred = 0; 2131 switch (dummy) { 2132 case 0: 2133 win = root; 2134 phase = "root"; 2135 break; 2136 case 1: 2137 win = XCreateWindow(dpy, root, 2138 0, 0, width, height, 0, depth, 2139 InputOutput, visual, 2140 CWOverrideRedirect, &attr); 2141 phase = "fullscreen"; 2142 break; 2143 case 2: 2144 win = XCreateWindow(dpy, root, 2145 0, 0, width/2, height/2, 0, depth, 2146 InputOutput, visual, 2147 CWOverrideRedirect, &attr); 2148 phase = "window"; 2149 break; 2150 case 3: 2151 if (!has_composite(dpy)) 2152 continue; 2153 2154 win = XCreateWindow(dpy, root, 2155 0, 0, width, height, 0, 2156 DefaultDepth(dpy, DefaultScreen(dpy)), 2157 InputOutput, 2158 DefaultVisual(dpy, DefaultScreen(dpy)), 2159 CWOverrideRedirect, &attr); 2160 XCompositeRedirectWindow(dpy, win, CompositeRedirectManual); 2161 phase = "composite"; 2162 break; 2163 2164 default: 2165 phase = "broken"; 2166 win = root; 2167 abort(); 2168 break; 2169 } 2170 2171 XMapWindow(dpy, win); 2172 XSync(dpy, True); 2173 if (_x_error_occurred) 2174 continue; 2175 2176 Q = setup_msc(dpy, win); 2177 msc = check_msc(dpy, win, Q, msc, NULL); 2178 2179 error += test_whole(dpy, win, phase); 2180 msc = check_msc(dpy, win, Q, msc, NULL); 2181 2182 error += test_double(dpy, win, phase, Q); 2183 msc = check_msc(dpy, win, Q, msc, NULL); 2184 2185 error += test_future(dpy, win, phase, Q); 2186 msc = check_msc(dpy, win, Q, msc, NULL); 2187 2188 error += test_accuracy(dpy, win, phase, Q); 2189 msc = check_msc(dpy, win, Q, msc, NULL); 2190 2191 error += test_modulus(dpy, win, phase, Q); 2192 msc = check_msc(dpy, win, Q, msc, NULL); 2193 2194 error += test_exhaustion(dpy, win, phase, Q); 2195 msc = check_msc(dpy, win, Q, msc, NULL); 2196 2197 teardown_msc(dpy, Q); 2198 if (win != root) 2199 XDestroyWindow(dpy, win); 2200 } 2201 2202 error += test_crtc(dpy, queue, last_msc); 2203 last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2204 2205 error += test_shm(dpy); 2206 last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2207 2208 error += test_dri3(dpy); 2209 last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2210 2211 error += test_dri3_tiling(dpy); 2212 last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2213 2214 teardown_msc(dpy, queue); 2215 2216 if (DPMSQueryExtension(dpy, &dummy, &dummy)) 2217 DPMSEnable(dpy); 2218 return !!error; 2219} 2220