142542f5fSchristos/* 242542f5fSchristos * Copyright (c) 2014 Intel Corporation 342542f5fSchristos * 442542f5fSchristos * Permission is hereby granted, free of charge, to any person obtaining a 542542f5fSchristos * copy of this software and associated documentation files (the "Software"), 642542f5fSchristos * to deal in the Software without restriction, including without limitation 742542f5fSchristos * the rights to use, copy, modify, merge, publish, distribute, sublicense, 842542f5fSchristos * and/or sell copies of the Software, and to permit persons to whom the 942542f5fSchristos * Software is furnished to do so, subject to the following conditions: 1042542f5fSchristos * 1142542f5fSchristos * The above copyright notice and this permission notice (including the next 1242542f5fSchristos * paragraph) shall be included in all copies or substantial portions of the 1342542f5fSchristos * Software. 1442542f5fSchristos * 1542542f5fSchristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1642542f5fSchristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1742542f5fSchristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1842542f5fSchristos * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1942542f5fSchristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2042542f5fSchristos * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2142542f5fSchristos * SOFTWARE. 2242542f5fSchristos * 2342542f5fSchristos */ 2442542f5fSchristos 2542542f5fSchristos#ifdef HAVE_CONFIG_H 2642542f5fSchristos#include "config.h" 2742542f5fSchristos#endif 2842542f5fSchristos 2942542f5fSchristos#include <X11/Xlib.h> 3042542f5fSchristos#include <X11/Xlib-xcb.h> 3142542f5fSchristos#include <X11/xshmfence.h> 3242542f5fSchristos#include <X11/Xutil.h> 3342542f5fSchristos#include <X11/Xlibint.h> 34fe8aea9eSmrg#include <X11/extensions/dpms.h> 3542542f5fSchristos#include <X11/extensions/randr.h> 36fe8aea9eSmrg#include <X11/extensions/Xcomposite.h> 3742542f5fSchristos#include <X11/extensions/Xrandr.h> 3842542f5fSchristos#include <X11/extensions/Xrender.h> 3942542f5fSchristos#include <X11/extensions/XShm.h> 4042542f5fSchristos#if HAVE_X11_EXTENSIONS_SHMPROTO_H 4142542f5fSchristos#include <X11/extensions/shmproto.h> 4242542f5fSchristos#elif HAVE_X11_EXTENSIONS_SHMSTR_H 4342542f5fSchristos#include <X11/extensions/shmstr.h> 4442542f5fSchristos#else 4542542f5fSchristos#error Failed to find the right header for X11 MIT-SHM protocol definitions 4642542f5fSchristos#endif 4742542f5fSchristos#include <xcb/xcb.h> 4842542f5fSchristos#include <xcb/present.h> 49fe8aea9eSmrg#include <xcb/xfixes.h> 50fe8aea9eSmrg#include <xcb/dri3.h> 5142542f5fSchristos#include <xf86drm.h> 5242542f5fSchristos#include <i915_drm.h> 5342542f5fSchristos 5442542f5fSchristos#include <stdio.h> 5542542f5fSchristos#include <string.h> 5642542f5fSchristos#include <fcntl.h> 5742542f5fSchristos#include <unistd.h> 5842542f5fSchristos#include <assert.h> 5942542f5fSchristos#include <errno.h> 6042542f5fSchristos#include <setjmp.h> 6142542f5fSchristos#include <signal.h> 6242542f5fSchristos 6342542f5fSchristos#include <sys/mman.h> 6442542f5fSchristos#include <sys/ipc.h> 6542542f5fSchristos#include <sys/shm.h> 6642542f5fSchristos#include <pciaccess.h> 6742542f5fSchristos 6842542f5fSchristos#include "dri3.h" 6942542f5fSchristos 7042542f5fSchristos#define ALIGN(x, y) (((x) + (y) - 1) & -(y)) 7142542f5fSchristos#define PAGE_ALIGN(x) ALIGN(x, 4096) 7242542f5fSchristos 7342542f5fSchristos#define GTT I915_GEM_DOMAIN_GTT 7442542f5fSchristos#define CPU I915_GEM_DOMAIN_CPU 7542542f5fSchristos 7642542f5fSchristosstatic int _x_error_occurred; 7742542f5fSchristosstatic uint32_t stamp; 7842542f5fSchristos 7942542f5fSchristosstatic int 8042542f5fSchristos_check_error_handler(Display *display, 8142542f5fSchristos XErrorEvent *event) 8242542f5fSchristos{ 8342542f5fSchristos printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n", 8442542f5fSchristos DisplayString(display), 8542542f5fSchristos event->serial, 8642542f5fSchristos event->error_code, 8742542f5fSchristos event->request_code, 8842542f5fSchristos event->minor_code); 8942542f5fSchristos _x_error_occurred++; 9042542f5fSchristos return False; /* ignored */ 9142542f5fSchristos} 9242542f5fSchristos 9342542f5fSchristosstatic int is_i915_device(int fd) 9442542f5fSchristos{ 9542542f5fSchristos drm_version_t version; 9642542f5fSchristos char name[5] = ""; 9742542f5fSchristos 9842542f5fSchristos memset(&version, 0, sizeof(version)); 9942542f5fSchristos version.name_len = 4; 10042542f5fSchristos version.name = name; 10142542f5fSchristos 10242542f5fSchristos if (drmIoctl(fd, DRM_IOCTL_VERSION, &version)) 10342542f5fSchristos return 0; 10442542f5fSchristos 10542542f5fSchristos return strcmp("i915", name) == 0; 10642542f5fSchristos} 10742542f5fSchristos 10842542f5fSchristosstatic int is_intel(int fd) 10942542f5fSchristos{ 11042542f5fSchristos struct drm_i915_getparam gp; 11142542f5fSchristos int ret; 11242542f5fSchristos 11342542f5fSchristos /* Confirm that this is a i915.ko device with GEM/KMS enabled */ 11442542f5fSchristos ret = is_i915_device(fd); 11542542f5fSchristos if (ret) { 11642542f5fSchristos gp.param = I915_PARAM_HAS_GEM; 11742542f5fSchristos gp.value = &ret; 11842542f5fSchristos if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp)) 11942542f5fSchristos ret = 0; 12042542f5fSchristos } 12142542f5fSchristos return ret; 12242542f5fSchristos} 12342542f5fSchristos 12442542f5fSchristosstatic void *setup_msc(Display *dpy, Window win) 12542542f5fSchristos{ 12642542f5fSchristos xcb_connection_t *c = XGetXCBConnection(dpy); 12742542f5fSchristos xcb_void_cookie_t cookie; 12842542f5fSchristos uint32_t id = xcb_generate_id(c); 12942542f5fSchristos xcb_generic_error_t *error; 13042542f5fSchristos void *q; 13142542f5fSchristos 13242542f5fSchristos cookie = xcb_present_select_input_checked(c, id, win, XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY); 13342542f5fSchristos q = xcb_register_for_special_xge(c, &xcb_present_id, id, &stamp); 13442542f5fSchristos 13542542f5fSchristos error = xcb_request_check(c, cookie); 13642542f5fSchristos assert(error == NULL); 13742542f5fSchristos 13842542f5fSchristos return q; 13942542f5fSchristos} 14042542f5fSchristos 141fe8aea9eSmrgstatic uint64_t check_msc(Display *dpy, Window win, void *q, uint64_t last_msc, uint64_t *ust) 14242542f5fSchristos{ 14342542f5fSchristos xcb_connection_t *c = XGetXCBConnection(dpy); 144fe8aea9eSmrg static uint32_t serial = 1; 14542542f5fSchristos uint64_t msc = 0; 146fe8aea9eSmrg int complete = 0; 14742542f5fSchristos 148fe8aea9eSmrg xcb_present_notify_msc(c, win, serial ^ 0xcc00ffee, 0, 0, 0); 14942542f5fSchristos xcb_flush(c); 15042542f5fSchristos 15142542f5fSchristos do { 15242542f5fSchristos xcb_present_complete_notify_event_t *ce; 15342542f5fSchristos xcb_generic_event_t *ev; 15442542f5fSchristos 15542542f5fSchristos ev = xcb_wait_for_special_event(c, q); 15642542f5fSchristos if (ev == NULL) 15742542f5fSchristos break; 15842542f5fSchristos 15942542f5fSchristos ce = (xcb_present_complete_notify_event_t *)ev; 160fe8aea9eSmrg if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC && 161fe8aea9eSmrg ce->serial == (serial ^ 0xcc00ffee)) { 162fe8aea9eSmrg msc = ce->msc; 163fe8aea9eSmrg if (ust) 164fe8aea9eSmrg *ust = ce->ust; 165fe8aea9eSmrg complete = 1; 166fe8aea9eSmrg } 167fe8aea9eSmrg free(ev); 168fe8aea9eSmrg } while (!complete); 169fe8aea9eSmrg 170fe8aea9eSmrg if ((int64_t)(msc - last_msc) < 0) { 171fe8aea9eSmrg printf("Invalid MSC: was %llu, now %llu\n", 172fe8aea9eSmrg (long long)last_msc, (long long)msc); 173fe8aea9eSmrg } 174fe8aea9eSmrg 175fe8aea9eSmrg if (++serial == 0) 176fe8aea9eSmrg serial = 1; 177fe8aea9eSmrg 178fe8aea9eSmrg return msc; 179fe8aea9eSmrg} 180fe8aea9eSmrg 181fe8aea9eSmrgstatic uint64_t wait_vblank(Display *dpy, Window win, void *q) 182fe8aea9eSmrg{ 183fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 184fe8aea9eSmrg static uint32_t serial = 1; 185fe8aea9eSmrg uint64_t msc = 0; 186fe8aea9eSmrg int complete = 0; 187fe8aea9eSmrg 188fe8aea9eSmrg xcb_present_notify_msc(c, win, serial ^ 0xdeadbeef, 0, 1, 0); 189fe8aea9eSmrg xcb_flush(c); 190fe8aea9eSmrg 191fe8aea9eSmrg do { 192fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 193fe8aea9eSmrg xcb_generic_event_t *ev; 194fe8aea9eSmrg 195fe8aea9eSmrg ev = xcb_wait_for_special_event(c, q); 196fe8aea9eSmrg if (ev == NULL) 197fe8aea9eSmrg break; 198fe8aea9eSmrg 199fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 200fe8aea9eSmrg if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC && 201fe8aea9eSmrg ce->serial == (serial ^ 0xdeadbeef)) { 20242542f5fSchristos msc = ce->msc; 203fe8aea9eSmrg complete = 1; 204fe8aea9eSmrg } 205fe8aea9eSmrg free(ev); 206fe8aea9eSmrg } while (!complete); 207fe8aea9eSmrg 208fe8aea9eSmrg if (++serial == 0) 209fe8aea9eSmrg serial = 1; 210fe8aea9eSmrg 211fe8aea9eSmrg return msc; 212fe8aea9eSmrg} 213fe8aea9eSmrg 214fe8aea9eSmrgstatic uint64_t msc_interval(Display *dpy, Window win, void *q) 215fe8aea9eSmrg{ 216fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 217fe8aea9eSmrg uint64_t msc, ust; 218fe8aea9eSmrg int complete = 0; 219fe8aea9eSmrg 220fe8aea9eSmrg msc = check_msc(dpy, win, q, 0, NULL); 221fe8aea9eSmrg 222fe8aea9eSmrg xcb_present_notify_msc(c, win, 0xc0ffee00, msc, 0, 0); 223fe8aea9eSmrg xcb_present_notify_msc(c, win, 0xc0ffee01, msc + 10, 0, 0); 224fe8aea9eSmrg xcb_flush(c); 225fe8aea9eSmrg 226fe8aea9eSmrg ust = msc = 0; 227fe8aea9eSmrg do { 228fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 229fe8aea9eSmrg xcb_generic_event_t *ev; 230fe8aea9eSmrg 231fe8aea9eSmrg ev = xcb_wait_for_special_event(c, q); 232fe8aea9eSmrg if (ev == NULL) 233fe8aea9eSmrg break; 234fe8aea9eSmrg 235fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 236fe8aea9eSmrg if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC && 237fe8aea9eSmrg ce->serial == 0xc0ffee00) { 238fe8aea9eSmrg msc -= ce->msc; 239fe8aea9eSmrg ust -= ce->ust; 240fe8aea9eSmrg complete++; 241fe8aea9eSmrg } 242fe8aea9eSmrg if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC && 243fe8aea9eSmrg ce->serial == 0xc0ffee01) { 244fe8aea9eSmrg msc += ce->msc; 245fe8aea9eSmrg ust += ce->ust; 246fe8aea9eSmrg complete++; 247fe8aea9eSmrg } 248fe8aea9eSmrg free(ev); 249fe8aea9eSmrg } while (complete != 2); 250fe8aea9eSmrg 251fe8aea9eSmrg printf("10 frame interval: msc=%lld, ust=%lld\n", 252fe8aea9eSmrg (long long)msc, (long long)ust); 253fe8aea9eSmrg XSync(dpy, True); 254fe8aea9eSmrg if (msc == 0) 255fe8aea9eSmrg return 0; 256fe8aea9eSmrg 257fe8aea9eSmrg return (ust + msc/2) / msc; 258fe8aea9eSmrg} 259fe8aea9eSmrg 260fe8aea9eSmrgstatic void teardown_msc(Display *dpy, void *q) 261fe8aea9eSmrg{ 262fe8aea9eSmrg xcb_unregister_for_special_event(XGetXCBConnection(dpy), q); 263fe8aea9eSmrg} 264fe8aea9eSmrg 265fe8aea9eSmrgstatic int test_whole(Display *dpy, Window win, const char *phase) 266fe8aea9eSmrg{ 267fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 268fe8aea9eSmrg Pixmap pixmap; 269fe8aea9eSmrg struct dri3_fence fence; 270fe8aea9eSmrg Window root; 271fe8aea9eSmrg unsigned int width, height; 272fe8aea9eSmrg unsigned border, depth; 273fe8aea9eSmrg int x, y, ret = 1; 274fe8aea9eSmrg 275fe8aea9eSmrg XGetGeometry(dpy, win, 276fe8aea9eSmrg &root, &x, &y, &width, &height, &border, &depth); 277fe8aea9eSmrg 278fe8aea9eSmrg if (dri3_create_fence(dpy, win, &fence)) 279fe8aea9eSmrg return 0; 280fe8aea9eSmrg 281fe8aea9eSmrg printf("%s: Testing simple flip: %dx%d\n", phase, width, height); 282fe8aea9eSmrg _x_error_occurred = 0; 283fe8aea9eSmrg 284fe8aea9eSmrg xshmfence_reset(fence.addr); 285fe8aea9eSmrg 286fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 287fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 0, 288fe8aea9eSmrg 0, /* valid */ 289fe8aea9eSmrg 0, /* update */ 290fe8aea9eSmrg 0, /* x_off */ 291fe8aea9eSmrg 0, /* y_off */ 292fe8aea9eSmrg None, 293fe8aea9eSmrg None, /* wait fence */ 294fe8aea9eSmrg fence.xid, 295fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 296fe8aea9eSmrg 0, /* target msc */ 297fe8aea9eSmrg 0, /* divisor */ 298fe8aea9eSmrg 0, /* remainder */ 299fe8aea9eSmrg 0, NULL); 300fe8aea9eSmrg XFreePixmap(dpy, pixmap); 301fe8aea9eSmrg 302fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 303fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 0, 304fe8aea9eSmrg 0, /* valid */ 305fe8aea9eSmrg 0, /* update */ 306fe8aea9eSmrg 0, /* x_off */ 307fe8aea9eSmrg 0, /* y_off */ 308fe8aea9eSmrg None, 309fe8aea9eSmrg None, /* wait fence */ 310fe8aea9eSmrg None, /* sync fence */ 311fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 312fe8aea9eSmrg 0, /* target msc */ 313fe8aea9eSmrg 0, /* divisor */ 314fe8aea9eSmrg 0, /* remainder */ 315fe8aea9eSmrg 0, NULL); 316fe8aea9eSmrg XFreePixmap(dpy, pixmap); 317fe8aea9eSmrg XFlush(dpy); 318fe8aea9eSmrg 319fe8aea9eSmrg ret = !!xshmfence_await(fence.addr); 320fe8aea9eSmrg dri3_fence_free(dpy, &fence); 321fe8aea9eSmrg 322fe8aea9eSmrg XSync(dpy, True); 323fe8aea9eSmrg ret += !!_x_error_occurred; 324fe8aea9eSmrg 325fe8aea9eSmrg return ret; 326fe8aea9eSmrg} 327fe8aea9eSmrg 328fe8aea9eSmrgstatic uint64_t flush_flips(Display *dpy, Window win, Pixmap pixmap, void *Q, uint64_t *ust) 329fe8aea9eSmrg{ 330fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 331fe8aea9eSmrg uint64_t msc; 332fe8aea9eSmrg int complete; 333fe8aea9eSmrg 334fe8aea9eSmrg msc = check_msc(dpy, win, Q, 0, NULL); 335fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 336fe8aea9eSmrg 0xdeadbeef, /* serial */ 337fe8aea9eSmrg 0, /* valid */ 338fe8aea9eSmrg 0, /* update */ 339fe8aea9eSmrg 0, /* x_off */ 340fe8aea9eSmrg 0, /* y_off */ 341fe8aea9eSmrg None, 342fe8aea9eSmrg None, /* wait fence */ 343fe8aea9eSmrg None, 344fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 345fe8aea9eSmrg msc + 60, /* target msc */ 346fe8aea9eSmrg 0, /* divisor */ 347fe8aea9eSmrg 0, /* remainder */ 348fe8aea9eSmrg 0, NULL); 349fe8aea9eSmrg xcb_flush(c); 350fe8aea9eSmrg complete = 0; 351fe8aea9eSmrg do { 352fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 353fe8aea9eSmrg xcb_generic_event_t *ev; 354fe8aea9eSmrg 355fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 356fe8aea9eSmrg if (ev == NULL) 357fe8aea9eSmrg break; 358fe8aea9eSmrg 359fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 360fe8aea9eSmrg complete = (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP && 361fe8aea9eSmrg ce->serial == 0xdeadbeef); 362fe8aea9eSmrg free(ev); 363fe8aea9eSmrg } while (!complete); 364fe8aea9eSmrg XSync(dpy, True); 365fe8aea9eSmrg 366fe8aea9eSmrg return check_msc(dpy, win, Q, msc, ust); 367fe8aea9eSmrg} 368fe8aea9eSmrg 369fe8aea9eSmrgstatic int test_double(Display *dpy, Window win, const char *phase, void *Q) 370fe8aea9eSmrg{ 371fe8aea9eSmrg#define COUNT (15*60) 372fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 373fe8aea9eSmrg Pixmap pixmap; 374fe8aea9eSmrg Window root; 375fe8aea9eSmrg unsigned int width, height; 376fe8aea9eSmrg unsigned border, depth; 377fe8aea9eSmrg int x, y, n, ret; 378fe8aea9eSmrg struct { 379fe8aea9eSmrg uint64_t msc, ust; 380fe8aea9eSmrg } frame[COUNT+1]; 381fe8aea9eSmrg int offset = 0; 382fe8aea9eSmrg 383fe8aea9eSmrg XGetGeometry(dpy, win, 384fe8aea9eSmrg &root, &x, &y, &width, &height, &border, &depth); 385fe8aea9eSmrg 386fe8aea9eSmrg printf("%s: Testing flip double buffering: %dx%d\n", phase, width, height); 387fe8aea9eSmrg _x_error_occurred = 0; 388fe8aea9eSmrg 389fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 390fe8aea9eSmrg flush_flips(dpy, win, pixmap, Q, NULL); 391fe8aea9eSmrg for (n = 0; n <= COUNT; n++) { 392fe8aea9eSmrg int complete; 393fe8aea9eSmrg 394fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, n, 395fe8aea9eSmrg 0, /* valid */ 396fe8aea9eSmrg 0, /* update */ 397fe8aea9eSmrg 0, /* x_off */ 398fe8aea9eSmrg 0, /* y_off */ 399fe8aea9eSmrg None, 400fe8aea9eSmrg None, /* wait fence */ 401fe8aea9eSmrg None, 402fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 403fe8aea9eSmrg 0, /* target msc */ 404fe8aea9eSmrg 0, /* divisor */ 405fe8aea9eSmrg 0, /* remainder */ 406fe8aea9eSmrg 0, NULL); 407fe8aea9eSmrg xcb_flush(c); 408fe8aea9eSmrg 409fe8aea9eSmrg complete = 0; 410fe8aea9eSmrg do { 411fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 412fe8aea9eSmrg xcb_generic_event_t *ev; 413fe8aea9eSmrg 414fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 415fe8aea9eSmrg if (ev == NULL) 416fe8aea9eSmrg break; 417fe8aea9eSmrg 418fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 419fe8aea9eSmrg if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP && 420fe8aea9eSmrg ce->serial == n) { 421fe8aea9eSmrg frame[n].msc = ce->msc; 422fe8aea9eSmrg frame[n].ust = ce->ust; 423fe8aea9eSmrg complete = 1; 424fe8aea9eSmrg } 425fe8aea9eSmrg free(ev); 426fe8aea9eSmrg } while (!complete); 427fe8aea9eSmrg } 428fe8aea9eSmrg XFreePixmap(dpy, pixmap); 429fe8aea9eSmrg 430fe8aea9eSmrg XSync(dpy, True); 431fe8aea9eSmrg ret = !!_x_error_occurred; 432fe8aea9eSmrg 433fe8aea9eSmrg if (frame[COUNT].msc - frame[0].msc != COUNT) { 434fe8aea9eSmrg printf("Expected %d frames interval, %d elapsed instead\n", 435fe8aea9eSmrg COUNT, (int)(frame[COUNT].msc - frame[0].msc)); 436fe8aea9eSmrg for (n = 0; n <= COUNT; n++) { 437fe8aea9eSmrg if (frame[n].msc - frame[0].msc != n + offset) { 438fe8aea9eSmrg printf("frame[%d]: msc=%03lld, ust=%lld\n", n, 439fe8aea9eSmrg (long long)(frame[n].msc - frame[0].msc), 440fe8aea9eSmrg (long long)(frame[n].ust - frame[0].ust)); 441fe8aea9eSmrg offset = frame[n].msc - frame[0].msc - n; 442fe8aea9eSmrg ret++; 443fe8aea9eSmrg } 444fe8aea9eSmrg } 445fe8aea9eSmrg } 446fe8aea9eSmrg 447fe8aea9eSmrg return ret; 448fe8aea9eSmrg} 449fe8aea9eSmrg 450fe8aea9eSmrgstatic int test_future(Display *dpy, Window win, const char *phase, void *Q) 451fe8aea9eSmrg{ 452fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 453fe8aea9eSmrg Pixmap pixmap; 454fe8aea9eSmrg struct dri3_fence fence; 455fe8aea9eSmrg Window root; 456fe8aea9eSmrg unsigned int width, height; 457fe8aea9eSmrg unsigned border, depth; 458fe8aea9eSmrg int x, y, ret = 0, n; 459fe8aea9eSmrg uint64_t msc, ust; 460fe8aea9eSmrg int complete, count; 461fe8aea9eSmrg int early = 0, late = 0; 462fe8aea9eSmrg int earliest = 0, latest = 0; 463fe8aea9eSmrg uint64_t interval; 464fe8aea9eSmrg 465fe8aea9eSmrg XGetGeometry(dpy, win, 466fe8aea9eSmrg &root, &x, &y, &width, &height, &border, &depth); 467fe8aea9eSmrg 468fe8aea9eSmrg if (dri3_create_fence(dpy, win, &fence)) 469fe8aea9eSmrg return 0; 470fe8aea9eSmrg 471fe8aea9eSmrg printf("%s: Testing flips into the future: %dx%d\n", phase, width, height); 472fe8aea9eSmrg _x_error_occurred = 0; 473fe8aea9eSmrg 474fe8aea9eSmrg interval = msc_interval(dpy, win, Q); 475fe8aea9eSmrg if (interval == 0) { 476fe8aea9eSmrg printf("Zero delay between frames\n"); 477fe8aea9eSmrg return 1; 478fe8aea9eSmrg } 479fe8aea9eSmrg 480fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 481fe8aea9eSmrg msc = flush_flips(dpy, win, pixmap, Q, &ust); 482fe8aea9eSmrg for (n = 1; n <= 10; n++) 483fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 484fe8aea9eSmrg n, /* serial */ 485fe8aea9eSmrg 0, /* valid */ 486fe8aea9eSmrg 0, /* update */ 487fe8aea9eSmrg 0, /* x_off */ 488fe8aea9eSmrg 0, /* y_off */ 489fe8aea9eSmrg None, 490fe8aea9eSmrg None, /* wait fence */ 491fe8aea9eSmrg None, 492fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 493fe8aea9eSmrg msc + 60 + n*15*60, /* target msc */ 494fe8aea9eSmrg 0, /* divisor */ 495fe8aea9eSmrg 0, /* remainder */ 496fe8aea9eSmrg 0, NULL); 497fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 498fe8aea9eSmrg 0xdeadbeef, /* serial */ 499fe8aea9eSmrg 0, /* valid */ 500fe8aea9eSmrg 0, /* update */ 501fe8aea9eSmrg 0, /* x_off */ 502fe8aea9eSmrg 0, /* y_off */ 503fe8aea9eSmrg None, 504fe8aea9eSmrg None, /* wait fence */ 505fe8aea9eSmrg None, 506fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 507fe8aea9eSmrg msc + 60 + n*15*60, /* target msc */ 508fe8aea9eSmrg 0, /* divisor */ 509fe8aea9eSmrg 0, /* remainder */ 510fe8aea9eSmrg 0, NULL); 511fe8aea9eSmrg xcb_flush(c); 512fe8aea9eSmrg 513fe8aea9eSmrg complete = 0; 514fe8aea9eSmrg count = 0; 515fe8aea9eSmrg do { 516fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 517fe8aea9eSmrg xcb_generic_event_t *ev; 518fe8aea9eSmrg 519fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 520fe8aea9eSmrg if (ev == NULL) 521fe8aea9eSmrg break; 522fe8aea9eSmrg 523fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 524fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP); 525fe8aea9eSmrg 526fe8aea9eSmrg if (ce->serial == 0xdeadbeef) { 527fe8aea9eSmrg int64_t time; 528fe8aea9eSmrg 529fe8aea9eSmrg time = ce->ust - (ust + (60 + 15*60*n) * interval); 530fe8aea9eSmrg if (time < -(int64_t)interval) { 531fe8aea9eSmrg fprintf(stderr, 532fe8aea9eSmrg "\tflips completed too early by %lldms\n", 533fe8aea9eSmrg (long long)(-time / 1000)); 534fe8aea9eSmrg } else if (time > (int64_t)interval) { 535fe8aea9eSmrg fprintf(stderr, 536fe8aea9eSmrg "\tflips completed too late by %lldms\n", 537fe8aea9eSmrg (long long)(time / 1000)); 538fe8aea9eSmrg } 539fe8aea9eSmrg complete = 1; 540fe8aea9eSmrg } else { 541fe8aea9eSmrg int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60)); 542fe8aea9eSmrg if (diff < 0) { 543fe8aea9eSmrg if (-diff > earliest) { 544fe8aea9eSmrg fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff); 545fe8aea9eSmrg earliest = -diff; 546fe8aea9eSmrg } 547fe8aea9eSmrg early++; 548fe8aea9eSmrg ret++; 549fe8aea9eSmrg } else if (diff > 0) { 550fe8aea9eSmrg if (diff > latest) { 551fe8aea9eSmrg fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff); 552fe8aea9eSmrg latest = diff; 553fe8aea9eSmrg } 554fe8aea9eSmrg late++; 555fe8aea9eSmrg ret++; 556fe8aea9eSmrg } 557fe8aea9eSmrg count++; 558fe8aea9eSmrg } 559fe8aea9eSmrg free(ev); 560fe8aea9eSmrg } while (!complete); 561fe8aea9eSmrg 562fe8aea9eSmrg if (early) 563fe8aea9eSmrg printf("\t%d frames shown too early (worst %d)!\n", early, earliest); 564fe8aea9eSmrg if (late) 565fe8aea9eSmrg printf("\t%d frames shown too late (worst %d)!\n", late, latest); 566fe8aea9eSmrg 567fe8aea9eSmrg if (count != 10) { 568fe8aea9eSmrg fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", 10 - count); 569fe8aea9eSmrg ret++; 570fe8aea9eSmrg 571fe8aea9eSmrg do { 572fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 573fe8aea9eSmrg xcb_generic_event_t *ev; 574fe8aea9eSmrg 575fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 576fe8aea9eSmrg if (ev == NULL) 577fe8aea9eSmrg break; 578fe8aea9eSmrg 579fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 580fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP); 581fe8aea9eSmrg free(ev); 582fe8aea9eSmrg } while (++count != 10); 583fe8aea9eSmrg } 584fe8aea9eSmrg 585fe8aea9eSmrg ret += !!_x_error_occurred; 586fe8aea9eSmrg 587fe8aea9eSmrg return ret; 588fe8aea9eSmrg} 589fe8aea9eSmrg 590fe8aea9eSmrgstatic int test_exhaustion(Display *dpy, Window win, const char *phase, void *Q) 591fe8aea9eSmrg{ 592fe8aea9eSmrg#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */ 593fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 594fe8aea9eSmrg Pixmap pixmap; 595fe8aea9eSmrg struct dri3_fence fence[2]; 596fe8aea9eSmrg Window root; 597fe8aea9eSmrg xcb_xfixes_region_t region; 598fe8aea9eSmrg unsigned int width, height; 599fe8aea9eSmrg unsigned border, depth; 600fe8aea9eSmrg int x, y, ret = 0, n; 601fe8aea9eSmrg uint64_t target, final; 602fe8aea9eSmrg 603fe8aea9eSmrg XGetGeometry(dpy, win, 604fe8aea9eSmrg &root, &x, &y, &width, &height, &border, &depth); 605fe8aea9eSmrg 606fe8aea9eSmrg if (dri3_create_fence(dpy, win, &fence[0]) || 607fe8aea9eSmrg dri3_create_fence(dpy, win, &fence[1])) 608fe8aea9eSmrg return 0; 609fe8aea9eSmrg 610fe8aea9eSmrg printf("%s: Testing flips with long vblank queues: %dx%d\n", phase, width, height); 611fe8aea9eSmrg _x_error_occurred = 0; 612fe8aea9eSmrg 613fe8aea9eSmrg region = xcb_generate_id(c); 614fe8aea9eSmrg xcb_xfixes_create_region(c, region, 0, NULL); 615fe8aea9eSmrg 616fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 617fe8aea9eSmrg xshmfence_reset(fence[0].addr); 618fe8aea9eSmrg xshmfence_reset(fence[1].addr); 619fe8aea9eSmrg target = check_msc(dpy, win, Q, 0, NULL); 620fe8aea9eSmrg for (n = N_VBLANKS; n--; ) 621fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 0, 622fe8aea9eSmrg 0, /* valid */ 623fe8aea9eSmrg region, /* update */ 624fe8aea9eSmrg 0, /* x_off */ 625fe8aea9eSmrg 0, /* y_off */ 626fe8aea9eSmrg None, 627fe8aea9eSmrg None, /* wait fence */ 628fe8aea9eSmrg None, 629fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 630fe8aea9eSmrg target + N_VBLANKS, /* target msc */ 631fe8aea9eSmrg 1, /* divisor */ 632fe8aea9eSmrg 0, /* remainder */ 633fe8aea9eSmrg 0, NULL); 634fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 0, 635fe8aea9eSmrg region, /* valid */ 636fe8aea9eSmrg region, /* update */ 637fe8aea9eSmrg 0, /* x_off */ 638fe8aea9eSmrg 0, /* y_off */ 639fe8aea9eSmrg None, 640fe8aea9eSmrg None, /* wait fence */ 641fe8aea9eSmrg fence[0].xid, 642fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 643fe8aea9eSmrg target, /* target msc */ 644fe8aea9eSmrg 0, /* divisor */ 645fe8aea9eSmrg 0, /* remainder */ 646fe8aea9eSmrg 0, NULL); 647fe8aea9eSmrg for (n = 1; n < N_VBLANKS; n++) 648fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 0, 649fe8aea9eSmrg region, /* valid */ 650fe8aea9eSmrg region, /* update */ 651fe8aea9eSmrg 0, /* x_off */ 652fe8aea9eSmrg 0, /* y_off */ 653fe8aea9eSmrg None, 654fe8aea9eSmrg None, /* wait fence */ 655fe8aea9eSmrg None, 656fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 657fe8aea9eSmrg target + n, /* target msc */ 658fe8aea9eSmrg 0, /* divisor */ 659fe8aea9eSmrg 0, /* remainder */ 660fe8aea9eSmrg 0, NULL); 661fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 0, 662fe8aea9eSmrg region, /* valid */ 663fe8aea9eSmrg region, /* update */ 664fe8aea9eSmrg 0, /* x_off */ 665fe8aea9eSmrg 0, /* y_off */ 666fe8aea9eSmrg None, 667fe8aea9eSmrg None, /* wait fence */ 668fe8aea9eSmrg fence[1].xid, 669fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 670fe8aea9eSmrg target + N_VBLANKS, /* target msc */ 671fe8aea9eSmrg 0, /* divisor */ 672fe8aea9eSmrg 0, /* remainder */ 673fe8aea9eSmrg 0, NULL); 674fe8aea9eSmrg xcb_flush(c); 675fe8aea9eSmrg 676fe8aea9eSmrg ret += !!xshmfence_await(fence[0].addr); 677fe8aea9eSmrg final = check_msc(dpy, win, Q, 0, NULL); 678fe8aea9eSmrg if (final < target) { 679fe8aea9eSmrg printf("\tFirst flip too early, MSC was %llu, expected %llu\n", 680fe8aea9eSmrg (long long)final, (long long)target); 681fe8aea9eSmrg ret++; 682fe8aea9eSmrg } else if (final > target + 1) { 683fe8aea9eSmrg printf("\tFirst flip too late, MSC was %llu, expected %llu\n", 684fe8aea9eSmrg (long long)final, (long long)target); 685fe8aea9eSmrg ret++; 686fe8aea9eSmrg } 687fe8aea9eSmrg 688fe8aea9eSmrg ret += !!xshmfence_await(fence[1].addr); 689fe8aea9eSmrg final = check_msc(dpy, win, Q, 0, NULL); 690fe8aea9eSmrg if (final < target + N_VBLANKS) { 691fe8aea9eSmrg printf("\tLast flip too early, MSC was %llu, expected %llu\n", 692fe8aea9eSmrg (long long)final, (long long)(target + N_VBLANKS)); 693fe8aea9eSmrg ret++; 694fe8aea9eSmrg } else if (final > target + N_VBLANKS + 1) { 695fe8aea9eSmrg printf("\tLast flip too late, MSC was %llu, expected %llu\n", 696fe8aea9eSmrg (long long)final, (long long)(target + N_VBLANKS)); 697fe8aea9eSmrg ret++; 698fe8aea9eSmrg } 699fe8aea9eSmrg 700fe8aea9eSmrg flush_flips(dpy, win, pixmap, Q, NULL); 701fe8aea9eSmrg 702fe8aea9eSmrg XFreePixmap(dpy, pixmap); 703fe8aea9eSmrg xcb_xfixes_destroy_region(c, region); 704fe8aea9eSmrg dri3_fence_free(dpy, &fence[1]); 705fe8aea9eSmrg dri3_fence_free(dpy, &fence[0]); 706fe8aea9eSmrg 707fe8aea9eSmrg XSync(dpy, True); 708fe8aea9eSmrg ret += !!_x_error_occurred; 709fe8aea9eSmrg 710fe8aea9eSmrg return ret; 711fe8aea9eSmrg#undef N_VBLANKS 712fe8aea9eSmrg} 713fe8aea9eSmrg 714fe8aea9eSmrgstatic int test_accuracy(Display *dpy, Window win, const char *phase, void *Q) 715fe8aea9eSmrg{ 716fe8aea9eSmrg#define N_VBLANKS (60 * 120) /* ~2 minutes */ 717fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 718fe8aea9eSmrg Pixmap pixmap; 719fe8aea9eSmrg Window root; 720fe8aea9eSmrg unsigned int width, height; 721fe8aea9eSmrg unsigned border, depth; 722fe8aea9eSmrg int x, y, ret = 0, n; 723fe8aea9eSmrg uint64_t target; 724fe8aea9eSmrg int early = 0, late = 0; 725fe8aea9eSmrg int earliest = 0, latest = 0; 726fe8aea9eSmrg int complete, count; 727fe8aea9eSmrg 728fe8aea9eSmrg XGetGeometry(dpy, win, 729fe8aea9eSmrg &root, &x, &y, &width, &height, &border, &depth); 730fe8aea9eSmrg 731fe8aea9eSmrg printf("%s: Testing flip accuracy: %dx%d\n", phase, width, height); 732fe8aea9eSmrg _x_error_occurred = 0; 733fe8aea9eSmrg 734fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 735fe8aea9eSmrg target = flush_flips(dpy, win, pixmap, Q, NULL); 736fe8aea9eSmrg for (n = 0; n <= N_VBLANKS; n++) 737fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 738fe8aea9eSmrg n, /* serial */ 739fe8aea9eSmrg 0, /* valid */ 740fe8aea9eSmrg 0, /* update */ 741fe8aea9eSmrg 0, /* x_off */ 742fe8aea9eSmrg 0, /* y_off */ 743fe8aea9eSmrg None, 744fe8aea9eSmrg None, /* wait fence */ 745fe8aea9eSmrg None, 746fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 747fe8aea9eSmrg target + 60 + n, /* target msc */ 748fe8aea9eSmrg 0, /* divisor */ 749fe8aea9eSmrg 0, /* remainder */ 750fe8aea9eSmrg 0, NULL); 751fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 752fe8aea9eSmrg 0xdeadbeef, /* serial */ 753fe8aea9eSmrg 0, /* valid */ 754fe8aea9eSmrg 0, /* update */ 755fe8aea9eSmrg 0, /* x_off */ 756fe8aea9eSmrg 0, /* y_off */ 757fe8aea9eSmrg None, 758fe8aea9eSmrg None, /* wait fence */ 759fe8aea9eSmrg None, 760fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 761fe8aea9eSmrg target + 60 + n, /* target msc */ 762fe8aea9eSmrg 0, /* divisor */ 763fe8aea9eSmrg 0, /* remainder */ 764fe8aea9eSmrg 0, NULL); 765fe8aea9eSmrg xcb_flush(c); 766fe8aea9eSmrg 767fe8aea9eSmrg complete = 0; 768fe8aea9eSmrg count = 0; 769fe8aea9eSmrg do { 770fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 771fe8aea9eSmrg xcb_generic_event_t *ev; 772fe8aea9eSmrg 773fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 774fe8aea9eSmrg if (ev == NULL) 775fe8aea9eSmrg break; 776fe8aea9eSmrg 777fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 778fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP); 779fe8aea9eSmrg 780fe8aea9eSmrg if (ce->serial != 0xdeadbeef) { 781fe8aea9eSmrg int diff = (int64_t)(ce->msc - (target + ce->serial + 60)); 782fe8aea9eSmrg if (diff < 0) { 783fe8aea9eSmrg if (-diff > earliest) { 784fe8aea9eSmrg fprintf(stderr, "\tframe %d displayed early by %d frames\n", ce->serial, -diff); 785fe8aea9eSmrg earliest = -diff; 786fe8aea9eSmrg } 787fe8aea9eSmrg early++; 788fe8aea9eSmrg ret++; 789fe8aea9eSmrg } else if (diff > 0) { 790fe8aea9eSmrg if (diff > latest) { 791fe8aea9eSmrg fprintf(stderr, "\tframe %d displayed late by %d frames\n", ce->serial, diff); 792fe8aea9eSmrg latest = diff; 793fe8aea9eSmrg } 794fe8aea9eSmrg late++; 795fe8aea9eSmrg ret++; 796fe8aea9eSmrg } 797fe8aea9eSmrg count++; 798fe8aea9eSmrg } else 799fe8aea9eSmrg complete = 1; 80042542f5fSchristos free(ev); 801fe8aea9eSmrg } while (!complete); 802fe8aea9eSmrg 803fe8aea9eSmrg if (early) 804fe8aea9eSmrg printf("\t%d frames shown too early (worst %d)!\n", early, earliest); 805fe8aea9eSmrg if (late) 806fe8aea9eSmrg printf("\t%d frames shown too late (worst %d)!\n", late, latest); 807fe8aea9eSmrg 808fe8aea9eSmrg if (count != N_VBLANKS+1) { 809fe8aea9eSmrg fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", N_VBLANKS+1 - count); 810fe8aea9eSmrg ret++; 811fe8aea9eSmrg do { 812fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 813fe8aea9eSmrg xcb_generic_event_t *ev; 814fe8aea9eSmrg 815fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 816fe8aea9eSmrg if (ev == NULL) 817fe8aea9eSmrg break; 818fe8aea9eSmrg 819fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 820fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP); 821fe8aea9eSmrg free(ev); 822fe8aea9eSmrg } while (++count != N_VBLANKS+1); 823fe8aea9eSmrg } 824fe8aea9eSmrg 825fe8aea9eSmrg XFreePixmap(dpy, pixmap); 826fe8aea9eSmrg 827fe8aea9eSmrg XSync(dpy, True); 828fe8aea9eSmrg ret += !!_x_error_occurred; 829fe8aea9eSmrg 830fe8aea9eSmrg return ret; 831fe8aea9eSmrg#undef N_VBLANKS 832fe8aea9eSmrg} 833fe8aea9eSmrg 834fe8aea9eSmrgstatic int test_modulus(Display *dpy, Window win, const char *phase, void *Q) 835fe8aea9eSmrg{ 836fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 837fe8aea9eSmrg Pixmap pixmap; 838fe8aea9eSmrg Window root; 839fe8aea9eSmrg unsigned int width, height; 840fe8aea9eSmrg unsigned border, depth; 841fe8aea9eSmrg xcb_xfixes_region_t region; 842fe8aea9eSmrg int x, y, ret = 0; 843fe8aea9eSmrg uint64_t target; 844fe8aea9eSmrg int early = 0, late = 0; 845fe8aea9eSmrg int earliest = 0, latest = 0; 846fe8aea9eSmrg int complete, expect, count; 847fe8aea9eSmrg 848fe8aea9eSmrg XGetGeometry(dpy, win, 849fe8aea9eSmrg &root, &x, &y, &width, &height, &border, &depth); 850fe8aea9eSmrg 851fe8aea9eSmrg printf("%s: Testing flip modulus: %dx%d\n", phase, width, height); 852fe8aea9eSmrg _x_error_occurred = 0; 853fe8aea9eSmrg 854fe8aea9eSmrg region = xcb_generate_id(c); 855fe8aea9eSmrg xcb_xfixes_create_region(c, region, 0, NULL); 856fe8aea9eSmrg 857fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 858fe8aea9eSmrg target = flush_flips(dpy, win, pixmap, Q, NULL); 859fe8aea9eSmrg expect = 0; 860fe8aea9eSmrg for (x = 1; x <= 7; x++) { 861fe8aea9eSmrg for (y = 0; y < x; y++) { 862fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 863fe8aea9eSmrg y << 16 | x, /* serial */ 864fe8aea9eSmrg region, /* valid */ 865fe8aea9eSmrg region, /* update */ 866fe8aea9eSmrg 0, /* x_off */ 867fe8aea9eSmrg 0, /* y_off */ 868fe8aea9eSmrg None, 869fe8aea9eSmrg None, /* wait fence */ 870fe8aea9eSmrg None, 871fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 872fe8aea9eSmrg 0, /* target msc */ 873fe8aea9eSmrg x, /* divisor */ 874fe8aea9eSmrg y, /* remainder */ 875fe8aea9eSmrg 0, NULL); 876fe8aea9eSmrg expect++; 877fe8aea9eSmrg } 878fe8aea9eSmrg } 879fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 880fe8aea9eSmrg 0xdeadbeef, /* serial */ 881fe8aea9eSmrg 0, /* valid */ 882fe8aea9eSmrg 0, /* update */ 883fe8aea9eSmrg 0, /* x_off */ 884fe8aea9eSmrg 0, /* y_off */ 885fe8aea9eSmrg None, 886fe8aea9eSmrg None, /* wait fence */ 887fe8aea9eSmrg None, 888fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 889fe8aea9eSmrg target + 2*x, /* target msc */ 890fe8aea9eSmrg 0, /* divisor */ 891fe8aea9eSmrg 0, /* remainder */ 892fe8aea9eSmrg 0, NULL); 893fe8aea9eSmrg xcb_flush(c); 894fe8aea9eSmrg 895fe8aea9eSmrg complete = 0; 896fe8aea9eSmrg count = 0; 897fe8aea9eSmrg do { 898fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 899fe8aea9eSmrg xcb_generic_event_t *ev; 900fe8aea9eSmrg 901fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 902fe8aea9eSmrg if (ev == NULL) 903fe8aea9eSmrg break; 904fe8aea9eSmrg 905fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 906fe8aea9eSmrg if (ce->kind != XCB_PRESENT_COMPLETE_KIND_PIXMAP) 907fe8aea9eSmrg break; 908fe8aea9eSmrg 909fe8aea9eSmrg assert(ce->serial); 910fe8aea9eSmrg if (ce->serial != 0xdeadbeef) { 911fe8aea9eSmrg uint64_t msc; 912fe8aea9eSmrg int diff; 913fe8aea9eSmrg 914fe8aea9eSmrg x = ce->serial & 0xffff; 915fe8aea9eSmrg y = ce->serial >> 16; 916fe8aea9eSmrg 917fe8aea9eSmrg msc = target; 918fe8aea9eSmrg msc -= target % x; 919fe8aea9eSmrg msc += y; 920fe8aea9eSmrg if (msc <= target) 921fe8aea9eSmrg msc += x; 922fe8aea9eSmrg 923fe8aea9eSmrg diff = (int64_t)(ce->msc - msc); 924fe8aea9eSmrg if (diff < 0) { 925fe8aea9eSmrg if (-diff > earliest) { 926fe8aea9eSmrg fprintf(stderr, "\tframe (%d, %d) displayed early by %d frames\n", y, x, -diff); 927fe8aea9eSmrg earliest = -diff; 928fe8aea9eSmrg } 929fe8aea9eSmrg early++; 930fe8aea9eSmrg ret++; 931fe8aea9eSmrg } else if (diff > 0) { 932fe8aea9eSmrg if (diff > latest) { 933fe8aea9eSmrg fprintf(stderr, "\tframe (%d, %d) displayed late by %d frames\n", y, x, diff); 934fe8aea9eSmrg latest = diff; 935fe8aea9eSmrg } 936fe8aea9eSmrg late++; 937fe8aea9eSmrg ret++; 938fe8aea9eSmrg } 939fe8aea9eSmrg count++; 940fe8aea9eSmrg } else 941fe8aea9eSmrg complete = 1; 942fe8aea9eSmrg free(ev); 943fe8aea9eSmrg } while (!complete); 944fe8aea9eSmrg 945fe8aea9eSmrg if (early) 946fe8aea9eSmrg printf("\t%d frames shown too early (worst %d)!\n", early, earliest); 947fe8aea9eSmrg if (late) 948fe8aea9eSmrg printf("\t%d frames shown too late (worst %d)!\n", late, latest); 949fe8aea9eSmrg 950fe8aea9eSmrg if (count != expect) { 951fe8aea9eSmrg fprintf(stderr, "Sentinel frame received too early! %d frames outstanding\n", expect - count); 952fe8aea9eSmrg ret++; 953fe8aea9eSmrg do { 954fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 955fe8aea9eSmrg xcb_generic_event_t *ev; 956fe8aea9eSmrg 957fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 958fe8aea9eSmrg if (ev == NULL) 959fe8aea9eSmrg break; 960fe8aea9eSmrg 961fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 962fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 963fe8aea9eSmrg free(ev); 964fe8aea9eSmrg } while (++count != expect); 965fe8aea9eSmrg } 966fe8aea9eSmrg 967fe8aea9eSmrg XFreePixmap(dpy, pixmap); 968fe8aea9eSmrg xcb_xfixes_destroy_region(c, region); 969fe8aea9eSmrg 970fe8aea9eSmrg XSync(dpy, True); 971fe8aea9eSmrg ret += !!_x_error_occurred; 972fe8aea9eSmrg 973fe8aea9eSmrg return ret; 974fe8aea9eSmrg} 975fe8aea9eSmrg 976fe8aea9eSmrgstatic int test_future_msc(Display *dpy, void *Q) 977fe8aea9eSmrg{ 978fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 979fe8aea9eSmrg Window root = DefaultRootWindow(dpy); 980fe8aea9eSmrg int ret = 0, n; 981fe8aea9eSmrg uint64_t msc, ust; 982fe8aea9eSmrg int complete, count; 983fe8aea9eSmrg int early = 0, late = 0; 984fe8aea9eSmrg int earliest = 0, latest = 0; 985fe8aea9eSmrg uint64_t interval; 986fe8aea9eSmrg 987fe8aea9eSmrg printf("Testing notifies into the future\n"); 988fe8aea9eSmrg _x_error_occurred = 0; 989fe8aea9eSmrg 990fe8aea9eSmrg interval = msc_interval(dpy, root, Q); 991fe8aea9eSmrg if (interval == 0) { 992fe8aea9eSmrg printf("Zero delay between frames\n"); 993fe8aea9eSmrg return 1; 994fe8aea9eSmrg } 995fe8aea9eSmrg msc = check_msc(dpy, root, Q, 0, &ust); 996fe8aea9eSmrg printf("Initial msc=%llx, interval between frames %lldus\n", 997fe8aea9eSmrg (long long)msc, (long long)interval); 998fe8aea9eSmrg 999fe8aea9eSmrg for (n = 1; n <= 10; n++) 1000fe8aea9eSmrg xcb_present_notify_msc(c, root, n, msc + 60 + n*15*60, 0, 0); 1001fe8aea9eSmrg xcb_present_notify_msc(c, root, 0xdeadbeef, msc + 60 + n*15*60, 0, 0); 1002fe8aea9eSmrg xcb_flush(c); 1003fe8aea9eSmrg 1004fe8aea9eSmrg complete = 0; 1005fe8aea9eSmrg count = 0; 1006fe8aea9eSmrg do { 1007fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 1008fe8aea9eSmrg xcb_generic_event_t *ev; 1009fe8aea9eSmrg 1010fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 1011fe8aea9eSmrg if (ev == NULL) 1012fe8aea9eSmrg break; 1013fe8aea9eSmrg 1014fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 1015fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1016fe8aea9eSmrg 1017fe8aea9eSmrg if (ce->serial == 0xdeadbeef) { 1018fe8aea9eSmrg int64_t time, tolerance; 1019fe8aea9eSmrg 1020fe8aea9eSmrg tolerance = 60 + 15*60*n/10; 1021fe8aea9eSmrg if (tolerance < interval) 1022fe8aea9eSmrg tolerance = interval; 1023fe8aea9eSmrg 1024fe8aea9eSmrg time = ce->ust - (ust + (60 + 15*60*n) * interval); 1025fe8aea9eSmrg if (time < -(int64_t)tolerance) { 1026fe8aea9eSmrg fprintf(stderr, 1027fe8aea9eSmrg "\tnotifies completed too early by %lldms, tolerance %lldus\n", 1028fe8aea9eSmrg (long long)(-time / 1000), (long long)tolerance); 1029fe8aea9eSmrg } else if (time > (int64_t)tolerance) { 1030fe8aea9eSmrg fprintf(stderr, 1031fe8aea9eSmrg "\tnotifies completed too late by %lldms, tolerance %lldus\n", 1032fe8aea9eSmrg (long long)(time / 1000), (long long)tolerance); 1033fe8aea9eSmrg } 1034fe8aea9eSmrg complete = 1; 1035fe8aea9eSmrg } else { 1036fe8aea9eSmrg int diff = (int64_t)(ce->msc - (15*60*ce->serial + msc + 60)); 1037fe8aea9eSmrg 1038fe8aea9eSmrg if (ce->serial != count + 1) { 1039fe8aea9eSmrg fprintf(stderr, "vblank received out of order! expected %d, received %d\n", 1040fe8aea9eSmrg count + 1, (int)ce->serial); 1041fe8aea9eSmrg ret++; 1042fe8aea9eSmrg } 1043fe8aea9eSmrg count++; 1044fe8aea9eSmrg 1045fe8aea9eSmrg if (diff < 0) { 1046fe8aea9eSmrg if (-diff > earliest) { 1047fe8aea9eSmrg fprintf(stderr, "\tnotify %d early by %d msc\n", ce->serial, -diff); 1048fe8aea9eSmrg earliest = -diff; 1049fe8aea9eSmrg } 1050fe8aea9eSmrg early++; 1051fe8aea9eSmrg ret++; 1052fe8aea9eSmrg } else if (diff > 0) { 1053fe8aea9eSmrg if (diff > latest) { 1054fe8aea9eSmrg fprintf(stderr, "\tnotify %d late by %d msc\n", ce->serial, diff); 1055fe8aea9eSmrg latest = diff; 1056fe8aea9eSmrg } 1057fe8aea9eSmrg late++; 1058fe8aea9eSmrg ret++; 1059fe8aea9eSmrg } 1060fe8aea9eSmrg } 1061fe8aea9eSmrg free(ev); 1062fe8aea9eSmrg } while (!complete); 1063fe8aea9eSmrg 1064fe8aea9eSmrg if (early) 1065fe8aea9eSmrg printf("\t%d notifies too early (worst %d)!\n", early, earliest); 1066fe8aea9eSmrg if (late) 1067fe8aea9eSmrg printf("\t%d notifies too late (worst %d)!\n", late, latest); 1068fe8aea9eSmrg 1069fe8aea9eSmrg if (count != 10) { 1070fe8aea9eSmrg fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", 10 - count); 1071fe8aea9eSmrg ret++; 1072fe8aea9eSmrg do { 1073fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 1074fe8aea9eSmrg xcb_generic_event_t *ev; 1075fe8aea9eSmrg 1076fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 1077fe8aea9eSmrg if (ev == NULL) 1078fe8aea9eSmrg break; 1079fe8aea9eSmrg 1080fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 1081fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1082fe8aea9eSmrg free(ev); 1083fe8aea9eSmrg } while (++count != 10); 1084fe8aea9eSmrg } 1085fe8aea9eSmrg 1086fe8aea9eSmrg XSync(dpy, True); 1087fe8aea9eSmrg ret += !!_x_error_occurred; 1088fe8aea9eSmrg 1089fe8aea9eSmrg return ret; 1090fe8aea9eSmrg} 1091fe8aea9eSmrg 1092fe8aea9eSmrgstatic int test_wrap_msc(Display *dpy) 1093fe8aea9eSmrg{ 1094fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 1095fe8aea9eSmrg Window root, win; 1096fe8aea9eSmrg int x, y; 1097fe8aea9eSmrg unsigned int width, height; 1098fe8aea9eSmrg unsigned border, depth; 1099fe8aea9eSmrg XSetWindowAttributes attr; 1100fe8aea9eSmrg int ret = 0, n; 1101fe8aea9eSmrg uint64_t msc, ust; 1102fe8aea9eSmrg int complete; 1103fe8aea9eSmrg uint64_t interval; 1104fe8aea9eSmrg void *Q; 1105fe8aea9eSmrg 1106fe8aea9eSmrg XGetGeometry(dpy, DefaultRootWindow(dpy), 1107fe8aea9eSmrg &root, &x, &y, &width, &height, &border, &depth); 1108fe8aea9eSmrg 1109fe8aea9eSmrg attr.override_redirect = 1; 1110fe8aea9eSmrg win = XCreateWindow(dpy, root, 1111fe8aea9eSmrg 0, 0, width, height, 0, depth, 1112fe8aea9eSmrg InputOutput, DefaultVisual(dpy, DefaultScreen(dpy)), 1113fe8aea9eSmrg CWOverrideRedirect, &attr); 1114fe8aea9eSmrg XMapWindow(dpy, win); 1115fe8aea9eSmrg XSync(dpy, True); 1116fe8aea9eSmrg if (_x_error_occurred) 1117fe8aea9eSmrg return 1; 111842542f5fSchristos 1119fe8aea9eSmrg printf("Testing wraparound notifies\n"); 1120fe8aea9eSmrg _x_error_occurred = 0; 1121fe8aea9eSmrg 1122fe8aea9eSmrg Q = setup_msc(dpy, win); 1123fe8aea9eSmrg interval = msc_interval(dpy, win, Q); 1124fe8aea9eSmrg if (interval == 0) { 1125fe8aea9eSmrg printf("Zero delay between frames\n"); 1126fe8aea9eSmrg return 1; 112742542f5fSchristos } 1128fe8aea9eSmrg msc = check_msc(dpy, win, Q, 0, &ust); 1129fe8aea9eSmrg printf("Initial msc=%llx, interval between frames %lldus\n", 1130fe8aea9eSmrg (long long)msc, (long long)interval); 1131fe8aea9eSmrg 1132fe8aea9eSmrg for (n = 1; n <= 10; n++) 1133fe8aea9eSmrg xcb_present_notify_msc(c, win, n, 1134fe8aea9eSmrg msc + ((long long)n<<32) + n, 1135fe8aea9eSmrg 0, 0); 1136fe8aea9eSmrg for (n = 1; n <= 10; n++) 1137fe8aea9eSmrg xcb_present_notify_msc(c, win, -n, 1138fe8aea9eSmrg 0, (long long)n << 32, 0); 1139fe8aea9eSmrg xcb_present_notify_msc(c, win, 0xdeadbeef, msc + 60*10, 0, 0); 1140fe8aea9eSmrg xcb_flush(c); 114142542f5fSchristos 1142fe8aea9eSmrg complete = 0; 1143fe8aea9eSmrg do { 1144fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 1145fe8aea9eSmrg xcb_generic_event_t *ev; 1146fe8aea9eSmrg 1147fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 1148fe8aea9eSmrg if (ev == NULL) 1149fe8aea9eSmrg break; 1150fe8aea9eSmrg 1151fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 1152fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1153fe8aea9eSmrg 1154fe8aea9eSmrg if (ce->serial == 0xdeadbeef) { 1155fe8aea9eSmrg complete = 1; 1156fe8aea9eSmrg } else { 1157fe8aea9eSmrg fprintf(stderr, 1158fe8aea9eSmrg "\tnotify %d recieved at +%llu\n", 1159fe8aea9eSmrg ce->serial, ce->msc - msc); 1160fe8aea9eSmrg ret++; 1161fe8aea9eSmrg } 1162fe8aea9eSmrg free(ev); 1163fe8aea9eSmrg } while (!complete); 1164fe8aea9eSmrg 1165fe8aea9eSmrg teardown_msc(dpy, Q); 1166fe8aea9eSmrg XDestroyWindow(dpy, win); 1167fe8aea9eSmrg XSync(dpy, True); 1168fe8aea9eSmrg 1169fe8aea9eSmrg return ret; 117042542f5fSchristos} 117142542f5fSchristos 1172fe8aea9eSmrgstatic int test_exhaustion_msc(Display *dpy, void *Q) 117342542f5fSchristos{ 1174fe8aea9eSmrg#define N_VBLANKS 256 /* kernel event queue length: 128 vblanks */ 1175fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 1176fe8aea9eSmrg Window root = DefaultRootWindow(dpy); 1177fe8aea9eSmrg int ret = 0, n, complete; 1178fe8aea9eSmrg int earliest = 0, early = 0; 1179fe8aea9eSmrg int latest = 0, late = 0; 1180fe8aea9eSmrg uint64_t msc; 1181fe8aea9eSmrg 1182fe8aea9eSmrg printf("Testing notifies with long queues\n"); 1183fe8aea9eSmrg _x_error_occurred = 0; 1184fe8aea9eSmrg 1185fe8aea9eSmrg msc = check_msc(dpy, root, Q, 0, NULL); 1186fe8aea9eSmrg for (n = N_VBLANKS; n--; ) 1187fe8aea9eSmrg xcb_present_notify_msc(c, root, N_VBLANKS, msc + N_VBLANKS, 0, 0); 1188fe8aea9eSmrg for (n = 1; n <= N_VBLANKS ; n++) 1189fe8aea9eSmrg xcb_present_notify_msc(c, root, n, msc + n, 0, 0); 1190fe8aea9eSmrg xcb_flush(c); 1191fe8aea9eSmrg 1192fe8aea9eSmrg complete = 2*N_VBLANKS; 1193fe8aea9eSmrg do { 1194fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 1195fe8aea9eSmrg xcb_generic_event_t *ev; 1196fe8aea9eSmrg int diff; 1197fe8aea9eSmrg 1198fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 1199fe8aea9eSmrg if (ev == NULL) 1200fe8aea9eSmrg break; 1201fe8aea9eSmrg 1202fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 1203fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1204fe8aea9eSmrg 1205fe8aea9eSmrg diff = (int64_t)(ce->msc - msc - ce->serial); 1206fe8aea9eSmrg if (diff < 0) { 1207fe8aea9eSmrg if (-diff > earliest) { 1208fe8aea9eSmrg fprintf(stderr, "\tnotify %d early by %d msc\n",(int)ce->serial, -diff); 1209fe8aea9eSmrg earliest = -diff; 1210fe8aea9eSmrg } 1211fe8aea9eSmrg early++; 1212fe8aea9eSmrg ret++; 1213fe8aea9eSmrg } else if (diff > 0) { 1214fe8aea9eSmrg if (diff > latest) { 1215fe8aea9eSmrg fprintf(stderr, "\tnotify %d late by %d msc\n", (int)ce->serial, diff); 1216fe8aea9eSmrg latest = diff; 1217fe8aea9eSmrg } 1218fe8aea9eSmrg late++; 1219fe8aea9eSmrg ret++; 1220fe8aea9eSmrg } 1221fe8aea9eSmrg free(ev); 1222fe8aea9eSmrg } while (--complete); 1223fe8aea9eSmrg 1224fe8aea9eSmrg if (early) 1225fe8aea9eSmrg printf("\t%d notifies too early (worst %d)!\n", early, earliest); 1226fe8aea9eSmrg if (late) 1227fe8aea9eSmrg printf("\t%d notifies too late (worst %d)!\n", late, latest); 1228fe8aea9eSmrg 1229fe8aea9eSmrg XSync(dpy, True); 1230fe8aea9eSmrg ret += !!_x_error_occurred; 1231fe8aea9eSmrg 1232fe8aea9eSmrg return ret; 1233fe8aea9eSmrg#undef N_VBLANKS 123442542f5fSchristos} 1235fe8aea9eSmrg 1236fe8aea9eSmrgstatic int test_accuracy_msc(Display *dpy, void *Q) 123742542f5fSchristos{ 1238fe8aea9eSmrg#define N_VBLANKS (60 * 120) /* ~2 minutes */ 1239fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 1240fe8aea9eSmrg Window root = DefaultRootWindow(dpy); 1241fe8aea9eSmrg int ret = 0, n; 1242fe8aea9eSmrg uint64_t msc; 1243fe8aea9eSmrg int early = 0, late = 0; 1244fe8aea9eSmrg int earliest = 0, latest = 0; 1245fe8aea9eSmrg int complete, count; 124642542f5fSchristos 1247fe8aea9eSmrg printf("Testing notify accuracy\n"); 1248fe8aea9eSmrg _x_error_occurred = 0; 124942542f5fSchristos 1250fe8aea9eSmrg msc = check_msc(dpy, root, Q, 0, NULL); 1251fe8aea9eSmrg for (n = 0; n <= N_VBLANKS; n++) 1252fe8aea9eSmrg xcb_present_notify_msc(c, root, n, msc + 60 + n, 0, 0); 1253fe8aea9eSmrg xcb_present_notify_msc(c, root, 0xdeadbeef, msc + 60 + n, 0, 0); 1254fe8aea9eSmrg xcb_flush(c); 1255fe8aea9eSmrg 1256fe8aea9eSmrg complete = 0; 1257fe8aea9eSmrg count = 0; 1258fe8aea9eSmrg do { 1259fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 1260fe8aea9eSmrg xcb_generic_event_t *ev; 1261fe8aea9eSmrg 1262fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 1263fe8aea9eSmrg if (ev == NULL) 1264fe8aea9eSmrg break; 1265fe8aea9eSmrg 1266fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 1267fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1268fe8aea9eSmrg 1269fe8aea9eSmrg if (ce->serial != 0xdeadbeef) { 1270fe8aea9eSmrg int diff = (int64_t)(ce->msc - (msc + ce->serial + 60)); 1271fe8aea9eSmrg if (diff < 0) { 1272fe8aea9eSmrg if (-diff > earliest) { 1273fe8aea9eSmrg fprintf(stderr, "\tnotify %d early by %d msc\n", ce->serial, -diff); 1274fe8aea9eSmrg earliest = -diff; 1275fe8aea9eSmrg } 1276fe8aea9eSmrg early++; 1277fe8aea9eSmrg ret++; 1278fe8aea9eSmrg } else if (diff > 0) { 1279fe8aea9eSmrg if (diff > latest) { 1280fe8aea9eSmrg fprintf(stderr, "\tnotify %d late by %d msc\n", ce->serial, diff); 1281fe8aea9eSmrg latest = diff; 1282fe8aea9eSmrg } 1283fe8aea9eSmrg late++; 1284fe8aea9eSmrg ret++; 1285fe8aea9eSmrg } 1286fe8aea9eSmrg count++; 1287fe8aea9eSmrg } else 1288fe8aea9eSmrg complete = 1; 1289fe8aea9eSmrg free(ev); 1290fe8aea9eSmrg } while (!complete); 1291fe8aea9eSmrg 1292fe8aea9eSmrg if (early) 1293fe8aea9eSmrg printf("\t%d notifies too early (worst %d)!\n", early, earliest); 1294fe8aea9eSmrg if (late) 1295fe8aea9eSmrg printf("\t%d notifies too late (worst %d)!\n", late, latest); 1296fe8aea9eSmrg 1297fe8aea9eSmrg if (count != N_VBLANKS+1) { 1298fe8aea9eSmrg fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", N_VBLANKS+1 - count); 1299fe8aea9eSmrg ret++; 1300fe8aea9eSmrg do { 1301fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 1302fe8aea9eSmrg xcb_generic_event_t *ev; 1303fe8aea9eSmrg 1304fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 1305fe8aea9eSmrg if (ev == NULL) 1306fe8aea9eSmrg break; 1307fe8aea9eSmrg 1308fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 1309fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1310fe8aea9eSmrg free(ev); 1311fe8aea9eSmrg } while (++count != N_VBLANKS+1); 1312fe8aea9eSmrg } 1313fe8aea9eSmrg 1314fe8aea9eSmrg XSync(dpy, True); 1315fe8aea9eSmrg ret += !!_x_error_occurred; 1316fe8aea9eSmrg 1317fe8aea9eSmrg return ret; 1318fe8aea9eSmrg#undef N_VBLANKS 1319fe8aea9eSmrg} 132042542f5fSchristos 1321fe8aea9eSmrgstatic int test_modulus_msc(Display *dpy, void *Q) 1322fe8aea9eSmrg{ 1323fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 1324fe8aea9eSmrg Window root = DefaultRootWindow(dpy); 1325fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 1326fe8aea9eSmrg xcb_generic_event_t *ev; 1327fe8aea9eSmrg int x, y, ret = 0; 1328fe8aea9eSmrg uint64_t target; 1329fe8aea9eSmrg int early = 0, late = 0; 1330fe8aea9eSmrg int earliest = 0, latest = 0; 1331fe8aea9eSmrg int complete, count, expect; 1332fe8aea9eSmrg 1333fe8aea9eSmrg printf("Testing notify modulus\n"); 133442542f5fSchristos _x_error_occurred = 0; 133542542f5fSchristos 1336fe8aea9eSmrg target = wait_vblank(dpy, root, Q); 133742542f5fSchristos 1338fe8aea9eSmrg expect = 0; 1339fe8aea9eSmrg xcb_present_notify_msc(c, root, 0, 0, 0, 0); 1340fe8aea9eSmrg for (x = 1; x <= 19; x++) { 1341fe8aea9eSmrg for (y = 0; y < x; y++) { 1342fe8aea9eSmrg xcb_present_notify_msc(c, root, y << 16 | x, 0, x, y); 1343fe8aea9eSmrg expect++; 1344fe8aea9eSmrg } 1345fe8aea9eSmrg } 1346fe8aea9eSmrg xcb_present_notify_msc(c, root, 0xdeadbeef, target + 2*x, 0, 0); 1347fe8aea9eSmrg xcb_flush(c); 134842542f5fSchristos 1349fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 1350fe8aea9eSmrg if (ev) { 1351fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 1352fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1353fe8aea9eSmrg assert(ce->serial == 0); 1354fe8aea9eSmrg assert(target == ce->msc); 1355fe8aea9eSmrg target = ce->msc; 1356fe8aea9eSmrg } 135742542f5fSchristos 1358fe8aea9eSmrg complete = 0; 1359fe8aea9eSmrg count = 0; 1360fe8aea9eSmrg do { 1361fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 1362fe8aea9eSmrg if (ev == NULL) 1363fe8aea9eSmrg break; 1364fe8aea9eSmrg 1365fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 1366fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1367fe8aea9eSmrg 1368fe8aea9eSmrg assert(ce->serial); 1369fe8aea9eSmrg if (ce->serial != 0xdeadbeef) { 1370fe8aea9eSmrg uint64_t msc; 1371fe8aea9eSmrg int diff; 1372fe8aea9eSmrg 1373fe8aea9eSmrg x = ce->serial & 0xffff; 1374fe8aea9eSmrg y = ce->serial >> 16; 1375fe8aea9eSmrg 1376fe8aea9eSmrg msc = target; 1377fe8aea9eSmrg msc -= target % x; 1378fe8aea9eSmrg msc += y; 1379fe8aea9eSmrg if (msc <= target) 1380fe8aea9eSmrg msc += x; 1381fe8aea9eSmrg 1382fe8aea9eSmrg diff = (int64_t)(ce->msc - msc); 1383fe8aea9eSmrg if (diff < 0) { 1384fe8aea9eSmrg if (-diff > earliest) { 1385fe8aea9eSmrg fprintf(stderr, "\tnotify (%d, %d) early by %d msc (target %lld, reported %lld)\n", y, x, -diff, (long long)msc, (long long)ce->msc); 1386fe8aea9eSmrg earliest = -diff; 1387fe8aea9eSmrg } 1388fe8aea9eSmrg early++; 1389fe8aea9eSmrg ret++; 1390fe8aea9eSmrg } else if (diff > 0) { 1391fe8aea9eSmrg if (diff > latest) { 1392fe8aea9eSmrg fprintf(stderr, "\tnotify (%d, %d) late by %d msc (target %lld, reported %lld)\n", y, x, diff, (long long)msc, (long long)ce->msc); 1393fe8aea9eSmrg latest = diff; 1394fe8aea9eSmrg } 1395fe8aea9eSmrg late++; 1396fe8aea9eSmrg ret++; 1397fe8aea9eSmrg } 1398fe8aea9eSmrg count++; 1399fe8aea9eSmrg } else 1400fe8aea9eSmrg complete = 1; 1401fe8aea9eSmrg free(ev); 1402fe8aea9eSmrg } while (!complete); 1403fe8aea9eSmrg 1404fe8aea9eSmrg if (early) 1405fe8aea9eSmrg printf("\t%d notifies too early (worst %d)!\n", early, earliest); 1406fe8aea9eSmrg if (late) 1407fe8aea9eSmrg printf("\t%d notifies too late (worst %d)!\n", late, latest); 1408fe8aea9eSmrg 1409fe8aea9eSmrg if (count != expect) { 1410fe8aea9eSmrg fprintf(stderr, "Sentinel vblank received too early! %d waits outstanding\n", expect - count); 1411fe8aea9eSmrg ret++; 1412fe8aea9eSmrg do { 1413fe8aea9eSmrg ev = xcb_wait_for_special_event(c, Q); 1414fe8aea9eSmrg if (ev == NULL) 1415fe8aea9eSmrg break; 1416fe8aea9eSmrg 1417fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 1418fe8aea9eSmrg assert(ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC); 1419fe8aea9eSmrg free(ev); 1420fe8aea9eSmrg } while (++count != expect); 1421fe8aea9eSmrg } 142242542f5fSchristos 142342542f5fSchristos XSync(dpy, True); 142442542f5fSchristos ret += !!_x_error_occurred; 142542542f5fSchristos 142642542f5fSchristos return ret; 142742542f5fSchristos} 142842542f5fSchristos 142942542f5fSchristosstatic inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window) 143042542f5fSchristos{ 143142542f5fSchristos XRRScreenResources *res; 143242542f5fSchristos 143342542f5fSchristos res = XRRGetScreenResourcesCurrent(dpy, window); 143442542f5fSchristos if (res == NULL) 143542542f5fSchristos res = XRRGetScreenResources(dpy, window); 143642542f5fSchristos 143742542f5fSchristos return res; 143842542f5fSchristos} 143942542f5fSchristos 144042542f5fSchristosstatic XRRModeInfo *lookup_mode(XRRScreenResources *res, int id) 144142542f5fSchristos{ 144242542f5fSchristos int i; 144342542f5fSchristos 144442542f5fSchristos for (i = 0; i < res->nmode; i++) { 144542542f5fSchristos if (res->modes[i].id == id) 144642542f5fSchristos return &res->modes[i]; 144742542f5fSchristos } 144842542f5fSchristos 144942542f5fSchristos return NULL; 145042542f5fSchristos} 145142542f5fSchristos 145242542f5fSchristosstatic int for_each_crtc(Display *dpy, 145342542f5fSchristos int (*func)(Display *dpy, 145442542f5fSchristos RRCrtc crtc, 145542542f5fSchristos int width, int height, 145642542f5fSchristos void *closure), 145742542f5fSchristos void *closure) 145842542f5fSchristos{ 145942542f5fSchristos XRRScreenResources *res; 146042542f5fSchristos XRRCrtcInfo **original_crtc; 146142542f5fSchristos int i, j, err = 0; 146242542f5fSchristos 146342542f5fSchristos if (!XRRQueryVersion(dpy, &i, &j)) 146442542f5fSchristos return -1; 146542542f5fSchristos 146642542f5fSchristos res = _XRRGetScreenResourcesCurrent(dpy, DefaultRootWindow(dpy)); 146742542f5fSchristos if (res == NULL) 146842542f5fSchristos return -1; 146942542f5fSchristos 147042542f5fSchristos original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc); 147142542f5fSchristos for (i = 0; i < res->ncrtc; i++) 147242542f5fSchristos original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]); 147342542f5fSchristos 147442542f5fSchristos for (i = 0; i < res->noutput; i++) { 147542542f5fSchristos XRROutputInfo *output; 147642542f5fSchristos XRRModeInfo *mode; 147742542f5fSchristos 147842542f5fSchristos output = XRRGetOutputInfo(dpy, res, res->outputs[i]); 147942542f5fSchristos if (output == NULL) 148042542f5fSchristos continue; 148142542f5fSchristos 148242542f5fSchristos mode = NULL; 148342542f5fSchristos if (res->nmode) 148442542f5fSchristos mode = lookup_mode(res, output->modes[0]); 148542542f5fSchristos 148642542f5fSchristos for (j = 0; mode && j < output->ncrtc; j++) { 148742542f5fSchristos printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld\n", 148842542f5fSchristos i, j, (long)res->outputs[i], (long)output->crtcs[j]); 148942542f5fSchristos XRRSetCrtcConfig(dpy, res, output->crtcs[j], CurrentTime, 149042542f5fSchristos 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1); 149142542f5fSchristos XSync(dpy, True); 149242542f5fSchristos 149342542f5fSchristos err += func(dpy, output->crtcs[j], mode->width, mode->height, closure); 149442542f5fSchristos 149542542f5fSchristos XRRSetCrtcConfig(dpy, res, output->crtcs[j], CurrentTime, 149642542f5fSchristos 0, 0, None, RR_Rotate_0, NULL, 0); 149742542f5fSchristos XSync(dpy, True); 149842542f5fSchristos } 149942542f5fSchristos 150042542f5fSchristos XRRFreeOutputInfo(output); 150142542f5fSchristos } 150242542f5fSchristos 150342542f5fSchristos for (i = 0; i < res->ncrtc; i++) 150442542f5fSchristos XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 150542542f5fSchristos original_crtc[i]->x, 150642542f5fSchristos original_crtc[i]->y, 150742542f5fSchristos original_crtc[i]->mode, 150842542f5fSchristos original_crtc[i]->rotation, 150942542f5fSchristos original_crtc[i]->outputs, 151042542f5fSchristos original_crtc[i]->noutput); 151142542f5fSchristos 151242542f5fSchristos free(original_crtc); 151342542f5fSchristos XRRFreeScreenResources(res); 151442542f5fSchristos 1515fe8aea9eSmrg return err; 151642542f5fSchristos} 151742542f5fSchristos 151842542f5fSchristosstruct test_crtc { 151942542f5fSchristos Window win; 152042542f5fSchristos int depth; 152142542f5fSchristos unsigned flags; 152242542f5fSchristos 152342542f5fSchristos struct dri3_fence fence; 152442542f5fSchristos void *queue; 152542542f5fSchristos uint64_t msc; 152642542f5fSchristos}; 152742542f5fSchristos#define SYNC 0x1 1528fe8aea9eSmrg#define FUTURE 0x2 152942542f5fSchristos 153042542f5fSchristosstatic int __test_crtc(Display *dpy, RRCrtc crtc, 153142542f5fSchristos int width, int height, 153242542f5fSchristos void *closure) 153342542f5fSchristos{ 153442542f5fSchristos struct test_crtc *test = closure; 153542542f5fSchristos Pixmap pixmap; 153642542f5fSchristos int err = 0; 153742542f5fSchristos 1538fe8aea9eSmrg test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL); 153942542f5fSchristos 154042542f5fSchristos if (test->flags & SYNC) 154142542f5fSchristos xshmfence_reset(test->fence.addr); 154242542f5fSchristos 154342542f5fSchristos pixmap = XCreatePixmap(dpy, test->win, width, height, test->depth); 154442542f5fSchristos xcb_present_pixmap(XGetXCBConnection(dpy), 154542542f5fSchristos test->win, pixmap, 154642542f5fSchristos 0, /* sbc */ 154742542f5fSchristos 0, /* valid */ 154842542f5fSchristos 0, /* update */ 154942542f5fSchristos 0, /* x_off */ 155042542f5fSchristos 0, /* y_off */ 155142542f5fSchristos crtc, 155242542f5fSchristos None, /* wait fence */ 155342542f5fSchristos test->flags & SYNC ? test->fence.xid : None, 155442542f5fSchristos XCB_PRESENT_OPTION_NONE, 1555fe8aea9eSmrg test->msc, /* target msc */ 155642542f5fSchristos 1, /* divisor */ 155742542f5fSchristos 0, /* remainder */ 155842542f5fSchristos 0, NULL); 155942542f5fSchristos if (test->flags & SYNC) { 1560fe8aea9eSmrg Pixmap tmp = XCreatePixmap(dpy, test->win, width, height, test->depth); 156142542f5fSchristos xcb_present_pixmap(XGetXCBConnection(dpy), 1562fe8aea9eSmrg test->win, tmp, 156342542f5fSchristos 1, /* sbc */ 156442542f5fSchristos 0, /* valid */ 156542542f5fSchristos 0, /* update */ 156642542f5fSchristos 0, /* x_off */ 156742542f5fSchristos 0, /* y_off */ 156842542f5fSchristos crtc, 156942542f5fSchristos None, /* wait fence */ 157042542f5fSchristos None, /* sync fence */ 157142542f5fSchristos XCB_PRESENT_OPTION_NONE, 1572fe8aea9eSmrg test->msc + (test->flags & FUTURE ? 5 * 16 : 1), /* target msc */ 157342542f5fSchristos 1, /* divisor */ 157442542f5fSchristos 0, /* remainder */ 157542542f5fSchristos 0, NULL); 1576fe8aea9eSmrg XFreePixmap(dpy, tmp); 157742542f5fSchristos XFlush(dpy); 157842542f5fSchristos err += !!xshmfence_await(test->fence.addr); 157942542f5fSchristos } 1580fe8aea9eSmrg XFreePixmap(dpy, pixmap); 158142542f5fSchristos 1582fe8aea9eSmrg test->msc = check_msc(dpy, test->win, test->queue, test->msc, NULL); 158342542f5fSchristos return err; 158442542f5fSchristos} 158542542f5fSchristos 158642542f5fSchristosstatic int test_crtc(Display *dpy, void *queue, uint64_t last_msc) 158742542f5fSchristos{ 158842542f5fSchristos struct test_crtc test; 158942542f5fSchristos int err = 0; 159042542f5fSchristos 159142542f5fSchristos XSync(dpy, True); 159242542f5fSchristos _x_error_occurred = 0; 159342542f5fSchristos 159442542f5fSchristos test.win = DefaultRootWindow(dpy); 159542542f5fSchristos test.depth = DefaultDepth(dpy, DefaultScreen(dpy)); 159642542f5fSchristos if (dri3_create_fence(dpy, test.win, &test.fence)) 159742542f5fSchristos return -1; 159842542f5fSchristos test.queue = queue; 159942542f5fSchristos test.msc = last_msc; 160042542f5fSchristos 160142542f5fSchristos printf("Testing each crtc, without waiting for each flip\n"); 160242542f5fSchristos test.flags = 0; 1603fe8aea9eSmrg test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 160442542f5fSchristos err += for_each_crtc(dpy, __test_crtc, &test); 1605fe8aea9eSmrg test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 160642542f5fSchristos 160742542f5fSchristos printf("Testing each crtc, waiting for flips to complete\n"); 160842542f5fSchristos test.flags = SYNC; 1609fe8aea9eSmrg test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 161042542f5fSchristos err += for_each_crtc(dpy, __test_crtc, &test); 1611fe8aea9eSmrg test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 161242542f5fSchristos 1613fe8aea9eSmrg printf("Testing each crtc, with future flips\n"); 1614fe8aea9eSmrg test.flags = FUTURE | SYNC; 1615fe8aea9eSmrg test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 1616fe8aea9eSmrg err += for_each_crtc(dpy, __test_crtc, &test); 1617fe8aea9eSmrg test.msc = check_msc(dpy, test.win, test.queue, test.msc, NULL); 161842542f5fSchristos 1619fe8aea9eSmrg dri3_fence_free(dpy, &test.fence); 162042542f5fSchristos XSync(dpy, True); 162142542f5fSchristos err += !!_x_error_occurred; 162242542f5fSchristos 162342542f5fSchristos if (err) 162442542f5fSchristos printf("%s: failures=%d\n", __func__, err); 162542542f5fSchristos 162642542f5fSchristos return err; 162742542f5fSchristos} 162842542f5fSchristos 162942542f5fSchristosstatic int 163042542f5fSchristoscan_use_shm(Display *dpy) 163142542f5fSchristos{ 163242542f5fSchristos int major, minor, has_pixmap; 163342542f5fSchristos 163442542f5fSchristos if (!XShmQueryExtension(dpy)) 163542542f5fSchristos return 0; 163642542f5fSchristos 163742542f5fSchristos XShmQueryVersion(dpy, &major, &minor, &has_pixmap); 163842542f5fSchristos return has_pixmap; 163942542f5fSchristos} 164042542f5fSchristos 164142542f5fSchristosstatic int test_shm(Display *dpy) 164242542f5fSchristos{ 164342542f5fSchristos Window win = DefaultRootWindow(dpy); 164442542f5fSchristos XShmSegmentInfo shm; 164542542f5fSchristos Pixmap pixmap; 164642542f5fSchristos Window root; 164742542f5fSchristos unsigned int width, height; 164842542f5fSchristos unsigned border, depth; 164942542f5fSchristos int x, y, ret = 1; 165042542f5fSchristos 165142542f5fSchristos if (!can_use_shm(dpy)) 165242542f5fSchristos return 0; 165342542f5fSchristos 165442542f5fSchristos _x_error_occurred = 0; 165542542f5fSchristos 165642542f5fSchristos XGetGeometry(dpy, win, &root, &x, &y, 165742542f5fSchristos &width, &height, &border, &depth); 165842542f5fSchristos 165942542f5fSchristos printf("Using %dx%d SHM\n", width, height); 166042542f5fSchristos 166142542f5fSchristos shm.shmid = shmget(IPC_PRIVATE, height * 4*width, IPC_CREAT | 0666); 166242542f5fSchristos if (shm.shmid == -1) 166342542f5fSchristos return 0; 166442542f5fSchristos 166542542f5fSchristos shm.shmaddr = shmat(shm.shmid, 0, 0); 166642542f5fSchristos if (shm.shmaddr == (char *) -1) 166742542f5fSchristos goto rmid; 166842542f5fSchristos 166942542f5fSchristos shm.readOnly = False; 167042542f5fSchristos XShmAttach(dpy, &shm); 167142542f5fSchristos 167242542f5fSchristos pixmap = XShmCreatePixmap(dpy, DefaultRootWindow(dpy), 167342542f5fSchristos shm.shmaddr, &shm, width, height, 24); 167442542f5fSchristos if (_x_error_occurred) 167542542f5fSchristos goto detach; 167642542f5fSchristos 167742542f5fSchristos xcb_present_pixmap(XGetXCBConnection(dpy), 167842542f5fSchristos win, pixmap, 167942542f5fSchristos 0, /* sbc */ 168042542f5fSchristos 0, /* valid */ 168142542f5fSchristos 0, /* update */ 168242542f5fSchristos 0, /* x_off */ 168342542f5fSchristos 0, /* y_off */ 168442542f5fSchristos None, 168542542f5fSchristos None, /* wait fence */ 168642542f5fSchristos None, 168742542f5fSchristos XCB_PRESENT_OPTION_NONE, 168842542f5fSchristos 0, /* target msc */ 168942542f5fSchristos 0, /* divisor */ 169042542f5fSchristos 0, /* remainder */ 169142542f5fSchristos 0, NULL); 169242542f5fSchristos XFreePixmap(dpy, pixmap); 169342542f5fSchristos 169442542f5fSchristos XSync(dpy, True); 169542542f5fSchristos if (_x_error_occurred) 169642542f5fSchristos goto detach; 169742542f5fSchristos 169842542f5fSchristos ret = 0; 169942542f5fSchristosdetach: 170042542f5fSchristos XShmDetach(dpy, &shm); 170142542f5fSchristos shmdt(shm.shmaddr); 170242542f5fSchristos XSync(dpy, False); 170342542f5fSchristosrmid: 170442542f5fSchristos shmctl(shm.shmid, IPC_RMID, NULL); 170542542f5fSchristos return ret; 170642542f5fSchristos} 170742542f5fSchristos 170842542f5fSchristosstatic uint32_t gem_create(int fd, int size) 170942542f5fSchristos{ 171042542f5fSchristos struct drm_i915_gem_create create; 171142542f5fSchristos 171242542f5fSchristos create.handle = 0; 171342542f5fSchristos create.size = size; 171442542f5fSchristos (void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); 171542542f5fSchristos 171642542f5fSchristos return create.handle; 171742542f5fSchristos} 171842542f5fSchristos 171942542f5fSchristosstruct local_i915_gem_caching { 172042542f5fSchristos uint32_t handle; 172142542f5fSchristos uint32_t caching; 172242542f5fSchristos}; 172342542f5fSchristos 172442542f5fSchristos#define LOCAL_I915_GEM_SET_CACHING 0x2f 172542542f5fSchristos#define LOCAL_IOCTL_I915_GEM_SET_CACHING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHING, struct local_i915_gem_caching) 172642542f5fSchristos 172742542f5fSchristosstatic int gem_set_caching(int fd, uint32_t handle, int caching) 172842542f5fSchristos{ 172942542f5fSchristos struct local_i915_gem_caching arg; 173042542f5fSchristos 173142542f5fSchristos arg.handle = handle; 173242542f5fSchristos arg.caching = caching; 173342542f5fSchristos 173442542f5fSchristos return drmIoctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHING, &arg) == 0; 173542542f5fSchristos} 173642542f5fSchristos 1737fe8aea9eSmrgstatic int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride) 1738fe8aea9eSmrg{ 1739fe8aea9eSmrg struct drm_i915_gem_set_tiling set_tiling; 1740fe8aea9eSmrg int err; 1741fe8aea9eSmrg 1742fe8aea9eSmrgrestart: 1743fe8aea9eSmrg set_tiling.handle = handle; 1744fe8aea9eSmrg set_tiling.tiling_mode = tiling; 1745fe8aea9eSmrg set_tiling.stride = stride; 1746fe8aea9eSmrg 1747fe8aea9eSmrg if (drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling) == 0) 1748fe8aea9eSmrg return 1; 1749fe8aea9eSmrg 1750fe8aea9eSmrg err = errno; 1751fe8aea9eSmrg if (err == EINTR) 1752fe8aea9eSmrg goto restart; 1753fe8aea9eSmrg 1754fe8aea9eSmrg if (err == EAGAIN) { 1755fe8aea9eSmrg sched_yield(); 1756fe8aea9eSmrg goto restart; 1757fe8aea9eSmrg } 1758fe8aea9eSmrg 1759fe8aea9eSmrg return 0; 1760fe8aea9eSmrg} 1761fe8aea9eSmrg 176242542f5fSchristosstatic int gem_export(int fd, uint32_t handle) 176342542f5fSchristos{ 176442542f5fSchristos struct drm_prime_handle args; 176542542f5fSchristos 176642542f5fSchristos args.handle = handle; 176742542f5fSchristos args.flags = O_CLOEXEC; 176842542f5fSchristos 176942542f5fSchristos if (drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args)) 177042542f5fSchristos return -1; 177142542f5fSchristos 177242542f5fSchristos return args.fd; 177342542f5fSchristos} 177442542f5fSchristos 177542542f5fSchristosstatic void gem_close(int fd, uint32_t handle) 177642542f5fSchristos{ 177742542f5fSchristos struct drm_gem_close close; 177842542f5fSchristos 177942542f5fSchristos close.handle = handle; 178042542f5fSchristos (void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close); 178142542f5fSchristos} 178242542f5fSchristos 1783fe8aea9eSmrgstatic int test_dri3_tiling(Display *dpy) 1784fe8aea9eSmrg{ 1785fe8aea9eSmrg Window win = DefaultRootWindow(dpy); 1786fe8aea9eSmrg const int tiling[] = { I915_TILING_NONE, I915_TILING_X, I915_TILING_Y }; 1787fe8aea9eSmrg Window root; 1788fe8aea9eSmrg unsigned int width, height; 1789fe8aea9eSmrg unsigned border, depth, bpp; 1790fe8aea9eSmrg unsigned stride, size; 1791fe8aea9eSmrg void *Q; 1792fe8aea9eSmrg int x, y; 1793fe8aea9eSmrg int device; 1794fe8aea9eSmrg int line = -1; 1795fe8aea9eSmrg int t; 1796fe8aea9eSmrg 1797fe8aea9eSmrg device = dri3_open(dpy); 1798fe8aea9eSmrg if (device < 0) 1799fe8aea9eSmrg return 0; 1800fe8aea9eSmrg 1801fe8aea9eSmrg if (!is_intel(device)) 1802fe8aea9eSmrg return 0; 1803fe8aea9eSmrg 1804fe8aea9eSmrg printf("Opened Intel DRI3 device\n"); 1805fe8aea9eSmrg 1806fe8aea9eSmrg XGetGeometry(dpy, win, &root, &x, &y, 1807fe8aea9eSmrg &width, &height, &border, &depth); 1808fe8aea9eSmrg 1809fe8aea9eSmrg switch (depth) { 1810fe8aea9eSmrg case 8: bpp = 8; break; 1811fe8aea9eSmrg case 15: case 16: bpp = 16; break; 1812fe8aea9eSmrg case 24: case 32: bpp = 32; break; 1813fe8aea9eSmrg default: return 0; 1814fe8aea9eSmrg } 1815fe8aea9eSmrg 1816fe8aea9eSmrg stride = ALIGN(width * bpp/8, 512); 1817fe8aea9eSmrg size = PAGE_ALIGN(stride * ALIGN(height, 32)); 1818fe8aea9eSmrg printf("Creating DRI3 %dx%d (source stride=%d, size=%d) for GTT\n", 1819fe8aea9eSmrg width, height, stride, size); 1820fe8aea9eSmrg 1821fe8aea9eSmrg _x_error_occurred = 0; 1822fe8aea9eSmrg Q = setup_msc(dpy, root); 1823fe8aea9eSmrg 1824fe8aea9eSmrg for (t = 0; t < sizeof(tiling)/sizeof(tiling[0]); t++) { 1825fe8aea9eSmrg uint64_t msc; 1826fe8aea9eSmrg uint32_t src; 1827fe8aea9eSmrg int src_fd; 1828fe8aea9eSmrg Pixmap src_pix; 1829fe8aea9eSmrg 1830fe8aea9eSmrg src = gem_create(device, size); 1831fe8aea9eSmrg if (!src) { 1832fe8aea9eSmrg line = __LINE__; 1833fe8aea9eSmrg goto fail; 1834fe8aea9eSmrg } 1835fe8aea9eSmrg 1836fe8aea9eSmrg gem_set_tiling(device, src, tiling[t], stride); 1837fe8aea9eSmrg 1838fe8aea9eSmrg src_fd = gem_export(device, src); 1839fe8aea9eSmrg if (src_fd < 0) { 1840fe8aea9eSmrg line = __LINE__; 1841fe8aea9eSmrg goto fail; 1842fe8aea9eSmrg } 1843fe8aea9eSmrg 1844fe8aea9eSmrg src_pix = dri3_create_pixmap(dpy, root, 1845fe8aea9eSmrg width, height, depth, 1846fe8aea9eSmrg src_fd, bpp, stride, size); 1847fe8aea9eSmrg 1848fe8aea9eSmrg msc = wait_vblank(dpy, root, Q); 1849fe8aea9eSmrg 1850fe8aea9eSmrg xcb_present_pixmap(XGetXCBConnection(dpy), 1851fe8aea9eSmrg win, src_pix, 1852fe8aea9eSmrg 0, /* sbc */ 1853fe8aea9eSmrg 0, /* valid */ 1854fe8aea9eSmrg 0, /* update */ 1855fe8aea9eSmrg 0, /* x_off */ 1856fe8aea9eSmrg 0, /* y_off */ 1857fe8aea9eSmrg None, 1858fe8aea9eSmrg None, /* wait fence */ 1859fe8aea9eSmrg None, 1860fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 1861fe8aea9eSmrg msc + 2, /* target msc */ 1862fe8aea9eSmrg 1, /* divisor */ 1863fe8aea9eSmrg 0, /* remainder */ 1864fe8aea9eSmrg 0, NULL); 1865fe8aea9eSmrg 1866fe8aea9eSmrg xcb_present_pixmap(XGetXCBConnection(dpy), 1867fe8aea9eSmrg win, src_pix, 1868fe8aea9eSmrg 0, /* sbc */ 1869fe8aea9eSmrg 0, /* valid */ 1870fe8aea9eSmrg 0, /* update */ 1871fe8aea9eSmrg 0, /* x_off */ 1872fe8aea9eSmrg 0, /* y_off */ 1873fe8aea9eSmrg None, 1874fe8aea9eSmrg None, /* wait fence */ 1875fe8aea9eSmrg None, 1876fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 1877fe8aea9eSmrg msc + 3, /* target msc */ 1878fe8aea9eSmrg 1, /* divisor */ 1879fe8aea9eSmrg 0, /* remainder */ 1880fe8aea9eSmrg 0, NULL); 1881fe8aea9eSmrg 1882fe8aea9eSmrg XSync(dpy, True); 1883fe8aea9eSmrg if (_x_error_occurred) { 1884fe8aea9eSmrg line = __LINE__; 1885fe8aea9eSmrg goto fail; 1886fe8aea9eSmrg } 1887fe8aea9eSmrg XFreePixmap(dpy, src_pix); 1888fe8aea9eSmrg _x_error_occurred = 0; 1889fe8aea9eSmrg 1890fe8aea9eSmrg close(src_fd); 1891fe8aea9eSmrg gem_close(device, src); 1892fe8aea9eSmrg } 1893fe8aea9eSmrg 1894fe8aea9eSmrg teardown_msc(dpy, Q); 1895fe8aea9eSmrg return 0; 1896fe8aea9eSmrg 1897fe8aea9eSmrgfail: 1898fe8aea9eSmrg printf("%s failed with tiling %d, line %d\n", __func__, tiling[t], line); 1899fe8aea9eSmrg teardown_msc(dpy, Q); 1900fe8aea9eSmrg return 1; 1901fe8aea9eSmrg} 1902fe8aea9eSmrg 190342542f5fSchristosstatic int test_dri3(Display *dpy) 190442542f5fSchristos{ 190542542f5fSchristos Window win = DefaultRootWindow(dpy); 190642542f5fSchristos Pixmap pixmap; 190742542f5fSchristos Window root; 190842542f5fSchristos unsigned int width, height; 190942542f5fSchristos unsigned border, depth; 191042542f5fSchristos unsigned stride, size; 191142542f5fSchristos int x, y, ret = 1; 191242542f5fSchristos int device, handle; 191342542f5fSchristos int bpp; 191442542f5fSchristos 191542542f5fSchristos device = dri3_open(dpy); 191642542f5fSchristos if (device < 0) 191742542f5fSchristos return 0; 191842542f5fSchristos 191942542f5fSchristos if (!is_intel(device)) 192042542f5fSchristos return 0; 192142542f5fSchristos 192242542f5fSchristos printf("Opened Intel DRI3 device\n"); 192342542f5fSchristos 192442542f5fSchristos XGetGeometry(dpy, win, &root, &x, &y, 192542542f5fSchristos &width, &height, &border, &depth); 192642542f5fSchristos 192742542f5fSchristos switch (depth) { 192842542f5fSchristos case 8: bpp = 8; break; 192942542f5fSchristos case 15: case 16: bpp = 16; break; 193042542f5fSchristos case 24: case 32: bpp = 32; break; 193142542f5fSchristos default: return 0; 193242542f5fSchristos } 193342542f5fSchristos 193442542f5fSchristos stride = width * bpp/8; 193542542f5fSchristos size = PAGE_ALIGN(stride * height); 193642542f5fSchristos printf("Creating DRI3 %dx%d (source stride=%d, size=%d) for GTT\n", 193742542f5fSchristos width, height, stride, size); 193842542f5fSchristos 193942542f5fSchristos pixmap = 0; 194042542f5fSchristos handle = gem_create(device, size); 194142542f5fSchristos if (handle) { 194242542f5fSchristos pixmap = dri3_create_pixmap(dpy, root, 194342542f5fSchristos width, height, depth, 194442542f5fSchristos gem_export(device, handle), bpp, stride, size); 194542542f5fSchristos gem_close(device, handle); 194642542f5fSchristos } 194742542f5fSchristos if (pixmap == 0) 194842542f5fSchristos goto fail; 194942542f5fSchristos 195042542f5fSchristos xcb_present_pixmap(XGetXCBConnection(dpy), 195142542f5fSchristos win, pixmap, 195242542f5fSchristos 0, /* sbc */ 195342542f5fSchristos 0, /* valid */ 195442542f5fSchristos 0, /* update */ 195542542f5fSchristos 0, /* x_off */ 195642542f5fSchristos 0, /* y_off */ 195742542f5fSchristos None, 195842542f5fSchristos None, /* wait fence */ 195942542f5fSchristos None, 196042542f5fSchristos XCB_PRESENT_OPTION_NONE, 196142542f5fSchristos 0, /* target msc */ 196242542f5fSchristos 0, /* divisor */ 196342542f5fSchristos 0, /* remainder */ 196442542f5fSchristos 0, NULL); 196542542f5fSchristos XFreePixmap(dpy, pixmap); 196642542f5fSchristos 196742542f5fSchristos XSync(dpy, True); 196842542f5fSchristos if (_x_error_occurred) 196942542f5fSchristos goto fail; 197042542f5fSchristos 197142542f5fSchristos printf("Creating DRI3 %dx%d (source stride=%d, size=%d) for CPU\n", 197242542f5fSchristos width, height, stride, size); 197342542f5fSchristos 197442542f5fSchristos pixmap = 0; 197542542f5fSchristos handle = gem_create(device, size); 197642542f5fSchristos if (handle) { 197742542f5fSchristos gem_set_caching(device, handle, CPU); 197842542f5fSchristos handle = dri3_create_pixmap(dpy, root, 197942542f5fSchristos width, height, depth, 198042542f5fSchristos gem_export(device, handle), bpp, stride, size); 198142542f5fSchristos gem_close(device, handle); 198242542f5fSchristos } 198342542f5fSchristos if (pixmap == 0) 198442542f5fSchristos goto fail; 198542542f5fSchristos 198642542f5fSchristos xcb_present_pixmap(XGetXCBConnection(dpy), 198742542f5fSchristos win, pixmap, 198842542f5fSchristos 0, /* sbc */ 198942542f5fSchristos 0, /* valid */ 199042542f5fSchristos 0, /* update */ 199142542f5fSchristos 0, /* x_off */ 199242542f5fSchristos 0, /* y_off */ 199342542f5fSchristos None, 199442542f5fSchristos None, /* wait fence */ 199542542f5fSchristos None, 199642542f5fSchristos XCB_PRESENT_OPTION_NONE, 199742542f5fSchristos 0, /* target msc */ 199842542f5fSchristos 0, /* divisor */ 199942542f5fSchristos 0, /* remainder */ 200042542f5fSchristos 0, NULL); 200142542f5fSchristos XFreePixmap(dpy, pixmap); 200242542f5fSchristos 200342542f5fSchristos XSync(dpy, True); 200442542f5fSchristos if (_x_error_occurred) 200542542f5fSchristos goto fail; 200642542f5fSchristos 200742542f5fSchristos ret = 0; 200842542f5fSchristosfail: 200942542f5fSchristos close(device); 201042542f5fSchristos return ret; 201142542f5fSchristos} 201242542f5fSchristos 201342542f5fSchristosstatic int has_present(Display *dpy) 201442542f5fSchristos{ 201542542f5fSchristos xcb_connection_t *c = XGetXCBConnection(dpy); 201642542f5fSchristos xcb_generic_error_t *error = NULL; 2017fe8aea9eSmrg void *reply; 2018fe8aea9eSmrg 2019fe8aea9eSmrg reply = xcb_xfixes_query_version_reply(c, 2020fe8aea9eSmrg xcb_xfixes_query_version(c, 2021fe8aea9eSmrg XCB_XFIXES_MAJOR_VERSION, 2022fe8aea9eSmrg XCB_XFIXES_MINOR_VERSION), 2023fe8aea9eSmrg &error); 2024fe8aea9eSmrg free(reply); 2025fe8aea9eSmrg free(error); 2026fe8aea9eSmrg if (reply == NULL) { 2027fe8aea9eSmrg fprintf(stderr, "XFixes not supported on %s\n", DisplayString(dpy)); 2028fe8aea9eSmrg return 0; 2029fe8aea9eSmrg } 2030fe8aea9eSmrg 2031fe8aea9eSmrg reply = xcb_dri3_query_version_reply(c, 2032fe8aea9eSmrg xcb_dri3_query_version(c, 2033fe8aea9eSmrg XCB_DRI3_MAJOR_VERSION, 2034fe8aea9eSmrg XCB_DRI3_MINOR_VERSION), 2035fe8aea9eSmrg &error); 2036fe8aea9eSmrg free(reply); 2037fe8aea9eSmrg free(error); 2038fe8aea9eSmrg if (reply == NULL) { 2039fe8aea9eSmrg fprintf(stderr, "DRI3 not supported on %s\n", DisplayString(dpy)); 2040fe8aea9eSmrg return 0; 2041fe8aea9eSmrg } 204242542f5fSchristos 204342542f5fSchristos reply = xcb_present_query_version_reply(c, 204442542f5fSchristos xcb_present_query_version(c, 204542542f5fSchristos XCB_PRESENT_MAJOR_VERSION, 204642542f5fSchristos XCB_PRESENT_MINOR_VERSION), 204742542f5fSchristos &error); 204842542f5fSchristos 204942542f5fSchristos free(reply); 205042542f5fSchristos free(error); 2051fe8aea9eSmrg if (reply == NULL) { 2052fe8aea9eSmrg fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy)); 2053fe8aea9eSmrg return 0; 2054fe8aea9eSmrg } 2055fe8aea9eSmrg 2056fe8aea9eSmrg return 1; 2057fe8aea9eSmrg} 2058fe8aea9eSmrg 2059fe8aea9eSmrgstatic int has_composite(Display *dpy) 2060fe8aea9eSmrg{ 2061fe8aea9eSmrg int event, error; 2062fe8aea9eSmrg int major, minor; 2063fe8aea9eSmrg 2064fe8aea9eSmrg if (!XCompositeQueryExtension(dpy, &event, &error)) 2065fe8aea9eSmrg return 0; 2066fe8aea9eSmrg 2067fe8aea9eSmrg XCompositeQueryVersion(dpy, &major, &minor); 206842542f5fSchristos 2069fe8aea9eSmrg return major > 0 || minor >= 4; 207042542f5fSchristos} 207142542f5fSchristos 207242542f5fSchristosint main(void) 207342542f5fSchristos{ 207442542f5fSchristos Display *dpy; 207542542f5fSchristos Window root; 2076fe8aea9eSmrg int dummy; 207742542f5fSchristos int error = 0; 207842542f5fSchristos uint64_t last_msc; 207942542f5fSchristos void *queue; 208042542f5fSchristos 208142542f5fSchristos dpy = XOpenDisplay(NULL); 208242542f5fSchristos if (dpy == NULL) 208342542f5fSchristos return 77; 208442542f5fSchristos 208542542f5fSchristos if (!has_present(dpy)) 208642542f5fSchristos return 77; 208742542f5fSchristos 2088fe8aea9eSmrg if (DPMSQueryExtension(dpy, &dummy, &dummy)) 2089fe8aea9eSmrg DPMSDisable(dpy); 2090fe8aea9eSmrg 209142542f5fSchristos root = DefaultRootWindow(dpy); 209242542f5fSchristos 209342542f5fSchristos signal(SIGALRM, SIG_IGN); 209442542f5fSchristos XSetErrorHandler(_check_error_handler); 209542542f5fSchristos 209642542f5fSchristos queue = setup_msc(dpy, root); 2097fe8aea9eSmrg last_msc = check_msc(dpy, root, queue, 0, NULL); 2098fe8aea9eSmrg 2099fe8aea9eSmrg error += test_future_msc(dpy, queue); 2100fe8aea9eSmrg last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2101fe8aea9eSmrg 2102fe8aea9eSmrg error += test_wrap_msc(dpy); 2103fe8aea9eSmrg last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2104fe8aea9eSmrg 2105fe8aea9eSmrg error += test_accuracy_msc(dpy, queue); 2106fe8aea9eSmrg last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2107fe8aea9eSmrg 2108fe8aea9eSmrg error += test_modulus_msc(dpy, queue); 2109fe8aea9eSmrg last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2110fe8aea9eSmrg 2111fe8aea9eSmrg error += test_exhaustion_msc(dpy, queue); 2112fe8aea9eSmrg last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2113fe8aea9eSmrg 2114fe8aea9eSmrg for (dummy = 0; dummy <= 3; dummy++) { 2115fe8aea9eSmrg Window win; 2116fe8aea9eSmrg uint64_t msc = 0; 2117fe8aea9eSmrg XSetWindowAttributes attr; 2118fe8aea9eSmrg Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy)); 2119fe8aea9eSmrg unsigned int width, height; 2120fe8aea9eSmrg unsigned border, depth; 2121fe8aea9eSmrg const char *phase; 2122fe8aea9eSmrg int x, y; 2123fe8aea9eSmrg void *Q; 2124fe8aea9eSmrg 2125fe8aea9eSmrg attr.override_redirect = 1; 2126fe8aea9eSmrg 2127fe8aea9eSmrg XGetGeometry(dpy, root, &win, &x, &y, 2128fe8aea9eSmrg &width, &height, &border, &depth); 2129fe8aea9eSmrg 2130fe8aea9eSmrg _x_error_occurred = 0; 2131fe8aea9eSmrg switch (dummy) { 2132fe8aea9eSmrg case 0: 2133fe8aea9eSmrg win = root; 2134fe8aea9eSmrg phase = "root"; 2135fe8aea9eSmrg break; 2136fe8aea9eSmrg case 1: 2137fe8aea9eSmrg win = XCreateWindow(dpy, root, 2138fe8aea9eSmrg 0, 0, width, height, 0, depth, 2139fe8aea9eSmrg InputOutput, visual, 2140fe8aea9eSmrg CWOverrideRedirect, &attr); 2141fe8aea9eSmrg phase = "fullscreen"; 2142fe8aea9eSmrg break; 2143fe8aea9eSmrg case 2: 2144fe8aea9eSmrg win = XCreateWindow(dpy, root, 2145fe8aea9eSmrg 0, 0, width/2, height/2, 0, depth, 2146fe8aea9eSmrg InputOutput, visual, 2147fe8aea9eSmrg CWOverrideRedirect, &attr); 2148fe8aea9eSmrg phase = "window"; 2149fe8aea9eSmrg break; 2150fe8aea9eSmrg case 3: 2151fe8aea9eSmrg if (!has_composite(dpy)) 2152fe8aea9eSmrg continue; 2153fe8aea9eSmrg 2154fe8aea9eSmrg win = XCreateWindow(dpy, root, 2155fe8aea9eSmrg 0, 0, width, height, 0, 2156fe8aea9eSmrg DefaultDepth(dpy, DefaultScreen(dpy)), 2157fe8aea9eSmrg InputOutput, 2158fe8aea9eSmrg DefaultVisual(dpy, DefaultScreen(dpy)), 2159fe8aea9eSmrg CWOverrideRedirect, &attr); 2160fe8aea9eSmrg XCompositeRedirectWindow(dpy, win, CompositeRedirectManual); 2161fe8aea9eSmrg phase = "composite"; 2162fe8aea9eSmrg break; 2163fe8aea9eSmrg 2164fe8aea9eSmrg default: 2165fe8aea9eSmrg phase = "broken"; 2166fe8aea9eSmrg win = root; 2167fe8aea9eSmrg abort(); 2168fe8aea9eSmrg break; 2169fe8aea9eSmrg } 2170fe8aea9eSmrg 2171fe8aea9eSmrg XMapWindow(dpy, win); 2172fe8aea9eSmrg XSync(dpy, True); 2173fe8aea9eSmrg if (_x_error_occurred) 2174fe8aea9eSmrg continue; 2175fe8aea9eSmrg 2176fe8aea9eSmrg Q = setup_msc(dpy, win); 2177fe8aea9eSmrg msc = check_msc(dpy, win, Q, msc, NULL); 217842542f5fSchristos 2179fe8aea9eSmrg error += test_whole(dpy, win, phase); 2180fe8aea9eSmrg msc = check_msc(dpy, win, Q, msc, NULL); 2181fe8aea9eSmrg 2182fe8aea9eSmrg error += test_double(dpy, win, phase, Q); 2183fe8aea9eSmrg msc = check_msc(dpy, win, Q, msc, NULL); 2184fe8aea9eSmrg 2185fe8aea9eSmrg error += test_future(dpy, win, phase, Q); 2186fe8aea9eSmrg msc = check_msc(dpy, win, Q, msc, NULL); 2187fe8aea9eSmrg 2188fe8aea9eSmrg error += test_accuracy(dpy, win, phase, Q); 2189fe8aea9eSmrg msc = check_msc(dpy, win, Q, msc, NULL); 2190fe8aea9eSmrg 2191fe8aea9eSmrg error += test_modulus(dpy, win, phase, Q); 2192fe8aea9eSmrg msc = check_msc(dpy, win, Q, msc, NULL); 2193fe8aea9eSmrg 2194fe8aea9eSmrg error += test_exhaustion(dpy, win, phase, Q); 2195fe8aea9eSmrg msc = check_msc(dpy, win, Q, msc, NULL); 2196fe8aea9eSmrg 2197fe8aea9eSmrg teardown_msc(dpy, Q); 2198fe8aea9eSmrg if (win != root) 2199fe8aea9eSmrg XDestroyWindow(dpy, win); 2200fe8aea9eSmrg } 220142542f5fSchristos 220242542f5fSchristos error += test_crtc(dpy, queue, last_msc); 2203fe8aea9eSmrg last_msc = check_msc(dpy, root, queue, last_msc, NULL); 220442542f5fSchristos 220542542f5fSchristos error += test_shm(dpy); 2206fe8aea9eSmrg last_msc = check_msc(dpy, root, queue, last_msc, NULL); 220742542f5fSchristos 220842542f5fSchristos error += test_dri3(dpy); 2209fe8aea9eSmrg last_msc = check_msc(dpy, root, queue, last_msc, NULL); 2210fe8aea9eSmrg 2211fe8aea9eSmrg error += test_dri3_tiling(dpy); 2212fe8aea9eSmrg last_msc = check_msc(dpy, root, queue, last_msc, NULL); 221342542f5fSchristos 221442542f5fSchristos teardown_msc(dpy, queue); 221542542f5fSchristos 2216fe8aea9eSmrg if (DPMSQueryExtension(dpy, &dummy, &dummy)) 2217fe8aea9eSmrg DPMSEnable(dpy); 221842542f5fSchristos return !!error; 221942542f5fSchristos} 2220