1fe8aea9eSmrg/* 2fe8aea9eSmrg * Copyright (c) 2014 Intel Corporation 3fe8aea9eSmrg * 4fe8aea9eSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5fe8aea9eSmrg * copy of this software and associated documentation files (the "Software"), 6fe8aea9eSmrg * to deal in the Software without restriction, including without limitation 7fe8aea9eSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8fe8aea9eSmrg * and/or sell copies of the Software, and to permit persons to whom the 9fe8aea9eSmrg * Software is furnished to do so, subject to the following conditions: 10fe8aea9eSmrg * 11fe8aea9eSmrg * The above copyright notice and this permission notice (including the next 12fe8aea9eSmrg * paragraph) shall be included in all copies or substantial portions of the 13fe8aea9eSmrg * Software. 14fe8aea9eSmrg * 15fe8aea9eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16fe8aea9eSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17fe8aea9eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18fe8aea9eSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19fe8aea9eSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20fe8aea9eSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21fe8aea9eSmrg * SOFTWARE. 22fe8aea9eSmrg * 23fe8aea9eSmrg */ 24fe8aea9eSmrg 25fe8aea9eSmrg#ifdef HAVE_CONFIG_H 26fe8aea9eSmrg#include "config.h" 27fe8aea9eSmrg#endif 28fe8aea9eSmrg 29fe8aea9eSmrg#include <X11/Xlib.h> 30fe8aea9eSmrg#include <X11/Xlib-xcb.h> 31fe8aea9eSmrg#include <X11/xshmfence.h> 32fe8aea9eSmrg#include <X11/Xutil.h> 33fe8aea9eSmrg#include <X11/Xlibint.h> 34fe8aea9eSmrg#include <X11/extensions/dpms.h> 35fe8aea9eSmrg#include <X11/extensions/randr.h> 36fe8aea9eSmrg#include <X11/extensions/Xcomposite.h> 37fe8aea9eSmrg#include <X11/extensions/Xrandr.h> 38fe8aea9eSmrg#include <X11/extensions/Xrender.h> 39fe8aea9eSmrg#include <X11/extensions/XShm.h> 40fe8aea9eSmrg#if HAVE_X11_EXTENSIONS_SHMPROTO_H 41fe8aea9eSmrg#include <X11/extensions/shmproto.h> 42fe8aea9eSmrg#elif HAVE_X11_EXTENSIONS_SHMSTR_H 43fe8aea9eSmrg#include <X11/extensions/shmstr.h> 44fe8aea9eSmrg#else 45fe8aea9eSmrg#error Failed to find the right header for X11 MIT-SHM protocol definitions 46fe8aea9eSmrg#endif 47fe8aea9eSmrg#include <xcb/xcb.h> 48fe8aea9eSmrg#include <xcb/present.h> 49fe8aea9eSmrg#include <xcb/xfixes.h> 50fe8aea9eSmrg#include <xcb/dri3.h> 51fe8aea9eSmrg#include <xf86drm.h> 52fe8aea9eSmrg#include <i915_drm.h> 53fe8aea9eSmrg 54fe8aea9eSmrg#include <stdio.h> 55fe8aea9eSmrg#include <string.h> 56fe8aea9eSmrg#include <fcntl.h> 57fe8aea9eSmrg#include <unistd.h> 58fe8aea9eSmrg#include <assert.h> 59fe8aea9eSmrg#include <errno.h> 60fe8aea9eSmrg#include <setjmp.h> 61fe8aea9eSmrg#include <signal.h> 62fe8aea9eSmrg 63fe8aea9eSmrg#include <sys/mman.h> 64fe8aea9eSmrg#include <sys/ipc.h> 65fe8aea9eSmrg#include <sys/shm.h> 66fe8aea9eSmrg#include <pciaccess.h> 67fe8aea9eSmrg 68fe8aea9eSmrg#include "dri3.h" 69fe8aea9eSmrg 70fe8aea9eSmrgstatic int _x_error_occurred; 71fe8aea9eSmrgstatic uint32_t stamp; 72fe8aea9eSmrg 73fe8aea9eSmrgstatic int 74fe8aea9eSmrg_check_error_handler(Display *display, 75fe8aea9eSmrg XErrorEvent *event) 76fe8aea9eSmrg{ 77fe8aea9eSmrg printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n", 78fe8aea9eSmrg DisplayString(display), 79fe8aea9eSmrg event->serial, 80fe8aea9eSmrg event->error_code, 81fe8aea9eSmrg event->request_code, 82fe8aea9eSmrg event->minor_code); 83fe8aea9eSmrg _x_error_occurred++; 84fe8aea9eSmrg return False; /* ignored */ 85fe8aea9eSmrg} 86fe8aea9eSmrg 87fe8aea9eSmrgstatic int has_composite(Display *dpy) 88fe8aea9eSmrg{ 89fe8aea9eSmrg int event, error; 90fe8aea9eSmrg int major, minor; 91fe8aea9eSmrg 92fe8aea9eSmrg if (!XCompositeQueryExtension(dpy, &event, &error)) 93fe8aea9eSmrg return 0; 94fe8aea9eSmrg 95fe8aea9eSmrg XCompositeQueryVersion(dpy, &major, &minor); 96fe8aea9eSmrg 97fe8aea9eSmrg return major > 0 || minor >= 4; 98fe8aea9eSmrg} 99fe8aea9eSmrg 100fe8aea9eSmrgstatic void *setup_msc(Display *dpy, Window win) 101fe8aea9eSmrg{ 102fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 103fe8aea9eSmrg xcb_void_cookie_t cookie; 104fe8aea9eSmrg uint32_t id = xcb_generate_id(c); 105fe8aea9eSmrg xcb_generic_error_t *error; 106fe8aea9eSmrg void *q; 107fe8aea9eSmrg 108fe8aea9eSmrg cookie = xcb_present_select_input_checked(c, id, win, XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY); 109fe8aea9eSmrg q = xcb_register_for_special_xge(c, &xcb_present_id, id, &stamp); 110fe8aea9eSmrg 111fe8aea9eSmrg error = xcb_request_check(c, cookie); 112fe8aea9eSmrg assert(error == NULL); 113fe8aea9eSmrg 114fe8aea9eSmrg return q; 115fe8aea9eSmrg} 116fe8aea9eSmrg 117fe8aea9eSmrgstatic void teardown_msc(Display *dpy, void *q) 118fe8aea9eSmrg{ 119fe8aea9eSmrg xcb_unregister_for_special_event(XGetXCBConnection(dpy), q); 120fe8aea9eSmrg} 121fe8aea9eSmrg 122fe8aea9eSmrgstatic uint64_t wait_vblank(Display *dpy, Window win) 123fe8aea9eSmrg{ 124fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 125fe8aea9eSmrg static uint32_t serial = 1; 126fe8aea9eSmrg uint64_t msc = 0; 127fe8aea9eSmrg int complete = 0; 128fe8aea9eSmrg void *q; 129fe8aea9eSmrg 130fe8aea9eSmrg if (win == 0) 131fe8aea9eSmrg win = DefaultRootWindow(dpy); 132fe8aea9eSmrg 133fe8aea9eSmrg q = setup_msc(dpy, win); 134fe8aea9eSmrg 135fe8aea9eSmrg xcb_present_notify_msc(c, win, serial ^ 0xdeadbeef, 0, 1, 0); 136fe8aea9eSmrg xcb_flush(c); 137fe8aea9eSmrg 138fe8aea9eSmrg do { 139fe8aea9eSmrg xcb_present_complete_notify_event_t *ce; 140fe8aea9eSmrg xcb_generic_event_t *ev; 141fe8aea9eSmrg 142fe8aea9eSmrg ev = xcb_wait_for_special_event(c, q); 143fe8aea9eSmrg if (ev == NULL) 144fe8aea9eSmrg break; 145fe8aea9eSmrg 146fe8aea9eSmrg ce = (xcb_present_complete_notify_event_t *)ev; 147fe8aea9eSmrg if (ce->kind == XCB_PRESENT_COMPLETE_KIND_NOTIFY_MSC && 148fe8aea9eSmrg ce->serial == (serial ^ 0xdeadbeef)) { 149fe8aea9eSmrg msc = ce->msc; 150fe8aea9eSmrg complete = 1; 151fe8aea9eSmrg } 152fe8aea9eSmrg free(ev); 153fe8aea9eSmrg } while (!complete); 154fe8aea9eSmrg 155fe8aea9eSmrg if (++serial == 0) 156fe8aea9eSmrg serial = 1; 157fe8aea9eSmrg 158fe8aea9eSmrg teardown_msc(dpy, q); 159fe8aea9eSmrg 160fe8aea9eSmrg return msc; 161fe8aea9eSmrg} 162fe8aea9eSmrg 163fe8aea9eSmrgstatic int test_basic(Display *dpy, int dummy) 164fe8aea9eSmrg{ 165fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 166fe8aea9eSmrg XSetWindowAttributes attr; 167fe8aea9eSmrg Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy)); 168fe8aea9eSmrg Pixmap pixmap; 169fe8aea9eSmrg struct dri3_fence fence; 170fe8aea9eSmrg Window root, win; 171fe8aea9eSmrg unsigned int width, height; 172fe8aea9eSmrg unsigned border, depth; 173fe8aea9eSmrg int x, y, ret = 1; 174fe8aea9eSmrg const char *phase; 175fe8aea9eSmrg uint64_t msc; 176fe8aea9eSmrg 177fe8aea9eSmrg root = DefaultRootWindow(dpy); 178fe8aea9eSmrg XGetGeometry(dpy, root, 179fe8aea9eSmrg &win, &x, &y, 180fe8aea9eSmrg &width, &height, &border, &depth); 181fe8aea9eSmrg 182fe8aea9eSmrg _x_error_occurred = 0; 183fe8aea9eSmrg attr.override_redirect = 1; 184fe8aea9eSmrg switch (dummy) { 185fe8aea9eSmrg case 0: 186fe8aea9eSmrg win = root; 187fe8aea9eSmrg phase = "root"; 188fe8aea9eSmrg break; 189fe8aea9eSmrg case 1: 190fe8aea9eSmrg win = XCreateWindow(dpy, root, 191fe8aea9eSmrg 0, 0, width, height, 0, depth, 192fe8aea9eSmrg InputOutput, visual, 193fe8aea9eSmrg CWOverrideRedirect, &attr); 194fe8aea9eSmrg phase = "fullscreen"; 195fe8aea9eSmrg break; 196fe8aea9eSmrg case 2: 197fe8aea9eSmrg width /= 2; 198fe8aea9eSmrg height /= 2; 199fe8aea9eSmrg win = XCreateWindow(dpy, root, 200fe8aea9eSmrg 0, 0, width, height, 0, depth, 201fe8aea9eSmrg InputOutput, visual, 202fe8aea9eSmrg CWOverrideRedirect, &attr); 203fe8aea9eSmrg phase = "window"; 204fe8aea9eSmrg break; 205fe8aea9eSmrg case 3: 206fe8aea9eSmrg if (!has_composite(dpy)) 207fe8aea9eSmrg return 0; 208fe8aea9eSmrg 209fe8aea9eSmrg win = XCreateWindow(dpy, root, 210fe8aea9eSmrg 0, 0, width, height, 0, 211fe8aea9eSmrg DefaultDepth(dpy, DefaultScreen(dpy)), 212fe8aea9eSmrg InputOutput, 213fe8aea9eSmrg DefaultVisual(dpy, DefaultScreen(dpy)), 214fe8aea9eSmrg CWOverrideRedirect, &attr); 215fe8aea9eSmrg XCompositeRedirectWindow(dpy, win, CompositeRedirectManual); 216fe8aea9eSmrg phase = "composite"; 217fe8aea9eSmrg break; 218fe8aea9eSmrg 219fe8aea9eSmrg default: 220fe8aea9eSmrg phase = "broken"; 221fe8aea9eSmrg win = root; 222fe8aea9eSmrg abort(); 223fe8aea9eSmrg break; 224fe8aea9eSmrg } 225fe8aea9eSmrg 226fe8aea9eSmrg XMapWindow(dpy, win); 227fe8aea9eSmrg XSync(dpy, True); 228fe8aea9eSmrg if (_x_error_occurred) 229fe8aea9eSmrg return 1; 230fe8aea9eSmrg 231fe8aea9eSmrg if (dri3_create_fence(dpy, win, &fence)) 232fe8aea9eSmrg return 0; 233fe8aea9eSmrg 234fe8aea9eSmrg printf("%s: Testing basic flip: %dx%d\n", phase, width, height); 235fe8aea9eSmrg fflush(stdout); 236fe8aea9eSmrg _x_error_occurred = 0; 237fe8aea9eSmrg 238fe8aea9eSmrg xshmfence_reset(fence.addr); 239fe8aea9eSmrg msc = wait_vblank(dpy, win); 240fe8aea9eSmrg 241fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 242fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 0, 243fe8aea9eSmrg 0, /* valid */ 244fe8aea9eSmrg 0, /* update */ 245fe8aea9eSmrg 0, /* x_off */ 246fe8aea9eSmrg 0, /* y_off */ 247fe8aea9eSmrg None, 248fe8aea9eSmrg None, /* wait fence */ 249fe8aea9eSmrg fence.xid, 250fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 251fe8aea9eSmrg (msc + 64) & -64, /* target msc */ 252fe8aea9eSmrg 64, /* divisor */ 253fe8aea9eSmrg 32, /* remainder */ 254fe8aea9eSmrg 0, NULL); 255fe8aea9eSmrg XFreePixmap(dpy, pixmap); 256fe8aea9eSmrg 257fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 258fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 0, 259fe8aea9eSmrg 0, /* valid */ 260fe8aea9eSmrg 0, /* update */ 261fe8aea9eSmrg 0, /* x_off */ 262fe8aea9eSmrg 0, /* y_off */ 263fe8aea9eSmrg None, 264fe8aea9eSmrg None, /* wait fence */ 265fe8aea9eSmrg None, /* sync fence */ 266fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 267fe8aea9eSmrg (msc + 64) & -64, /* target msc */ 268fe8aea9eSmrg 64, /* divisor */ 269fe8aea9eSmrg 48, /* remainder */ 270fe8aea9eSmrg 0, NULL); 271fe8aea9eSmrg XFreePixmap(dpy, pixmap); 272fe8aea9eSmrg XDestroyWindow(dpy, win); 273fe8aea9eSmrg XFlush(dpy); 274fe8aea9eSmrg 275fe8aea9eSmrg ret = !!xshmfence_await(fence.addr); 276fe8aea9eSmrg dri3_fence_free(dpy, &fence); 277fe8aea9eSmrg 278fe8aea9eSmrg XSync(dpy, True); 279fe8aea9eSmrg ret += !!_x_error_occurred; 280fe8aea9eSmrg 281fe8aea9eSmrg return ret; 282fe8aea9eSmrg} 283fe8aea9eSmrg 284fe8aea9eSmrgstatic int test_race(Display *dpy, int dummy) 285fe8aea9eSmrg{ 286fe8aea9eSmrg Display *mgr = XOpenDisplay(NULL); 287fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 288fe8aea9eSmrg XSetWindowAttributes attr; 289fe8aea9eSmrg Visual *visual = DefaultVisual(dpy, DefaultScreen(dpy)); 290fe8aea9eSmrg Pixmap pixmap; 291fe8aea9eSmrg struct dri3_fence fence; 292fe8aea9eSmrg Window root, win; 293fe8aea9eSmrg unsigned int width, height; 294fe8aea9eSmrg unsigned border, depth; 295fe8aea9eSmrg int x, y, ret = 1; 296fe8aea9eSmrg const char *phase; 297fe8aea9eSmrg uint64_t msc; 298fe8aea9eSmrg 299fe8aea9eSmrg root = DefaultRootWindow(dpy); 300fe8aea9eSmrg XGetGeometry(dpy, root, 301fe8aea9eSmrg &win, &x, &y, 302fe8aea9eSmrg &width, &height, &border, &depth); 303fe8aea9eSmrg 304fe8aea9eSmrg _x_error_occurred = 0; 305fe8aea9eSmrg attr.override_redirect = 1; 306fe8aea9eSmrg switch (dummy) { 307fe8aea9eSmrg case 0: 308fe8aea9eSmrg win = root; 309fe8aea9eSmrg phase = "root"; 310fe8aea9eSmrg break; 311fe8aea9eSmrg case 1: 312fe8aea9eSmrg win = XCreateWindow(dpy, root, 313fe8aea9eSmrg 0, 0, width, height, 0, depth, 314fe8aea9eSmrg InputOutput, visual, 315fe8aea9eSmrg CWOverrideRedirect, &attr); 316fe8aea9eSmrg phase = "fullscreen"; 317fe8aea9eSmrg break; 318fe8aea9eSmrg case 2: 319fe8aea9eSmrg width /= 2; 320fe8aea9eSmrg height /= 2; 321fe8aea9eSmrg win = XCreateWindow(dpy, root, 322fe8aea9eSmrg 0, 0, width, height, 0, depth, 323fe8aea9eSmrg InputOutput, visual, 324fe8aea9eSmrg CWOverrideRedirect, &attr); 325fe8aea9eSmrg phase = "window"; 326fe8aea9eSmrg break; 327fe8aea9eSmrg case 3: 328fe8aea9eSmrg if (!has_composite(dpy)) 329fe8aea9eSmrg return 0; 330fe8aea9eSmrg 331fe8aea9eSmrg win = XCreateWindow(dpy, root, 332fe8aea9eSmrg 0, 0, width, height, 0, 333fe8aea9eSmrg DefaultDepth(dpy, DefaultScreen(dpy)), 334fe8aea9eSmrg InputOutput, 335fe8aea9eSmrg DefaultVisual(dpy, DefaultScreen(dpy)), 336fe8aea9eSmrg CWOverrideRedirect, &attr); 337fe8aea9eSmrg XCompositeRedirectWindow(dpy, win, CompositeRedirectManual); 338fe8aea9eSmrg phase = "composite"; 339fe8aea9eSmrg break; 340fe8aea9eSmrg 341fe8aea9eSmrg default: 342fe8aea9eSmrg phase = "broken"; 343fe8aea9eSmrg win = root; 344fe8aea9eSmrg abort(); 345fe8aea9eSmrg break; 346fe8aea9eSmrg } 347fe8aea9eSmrg 348fe8aea9eSmrg XMapWindow(dpy, win); 349fe8aea9eSmrg XSync(dpy, True); 350fe8aea9eSmrg if (_x_error_occurred) 351fe8aea9eSmrg return 1; 352fe8aea9eSmrg 353fe8aea9eSmrg if (dri3_create_fence(dpy, win, &fence)) 354fe8aea9eSmrg return 0; 355fe8aea9eSmrg 356fe8aea9eSmrg printf("%s: Testing race with manager: %dx%d\n", phase, width, height); 357fe8aea9eSmrg fflush(stdout); 358fe8aea9eSmrg _x_error_occurred = 0; 359fe8aea9eSmrg 360fe8aea9eSmrg xshmfence_reset(fence.addr); 361fe8aea9eSmrg msc = wait_vblank(dpy, win); 362fe8aea9eSmrg 363fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 364fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 0, 365fe8aea9eSmrg 0, /* valid */ 366fe8aea9eSmrg 0, /* update */ 367fe8aea9eSmrg 0, /* x_off */ 368fe8aea9eSmrg 0, /* y_off */ 369fe8aea9eSmrg None, 370fe8aea9eSmrg None, /* wait fence */ 371fe8aea9eSmrg fence.xid, 372fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 373fe8aea9eSmrg (msc + 64) & -64, /* target msc */ 374fe8aea9eSmrg 64, /* divisor */ 375fe8aea9eSmrg 32, /* remainder */ 376fe8aea9eSmrg 0, NULL); 377fe8aea9eSmrg XFreePixmap(dpy, pixmap); 378fe8aea9eSmrg 379fe8aea9eSmrg XFlush(dpy); 380fe8aea9eSmrg XDestroyWindow(mgr, win); 381fe8aea9eSmrg XFlush(mgr); 382fe8aea9eSmrg 383fe8aea9eSmrg pixmap = XCreatePixmap(dpy, win, width, height, depth); 384fe8aea9eSmrg xcb_present_pixmap(c, win, pixmap, 0, 385fe8aea9eSmrg 0, /* valid */ 386fe8aea9eSmrg 0, /* update */ 387fe8aea9eSmrg 0, /* x_off */ 388fe8aea9eSmrg 0, /* y_off */ 389fe8aea9eSmrg None, 390fe8aea9eSmrg None, /* wait fence */ 391fe8aea9eSmrg None, /* sync fence */ 392fe8aea9eSmrg XCB_PRESENT_OPTION_NONE, 393fe8aea9eSmrg (msc + 64) & -64, /* target msc */ 394fe8aea9eSmrg 64, /* divisor */ 395fe8aea9eSmrg 48, /* remainder */ 396fe8aea9eSmrg 0, NULL); 397fe8aea9eSmrg XFreePixmap(dpy, pixmap); 398fe8aea9eSmrg XFlush(dpy); 399fe8aea9eSmrg 400fe8aea9eSmrg ret = !!xshmfence_await(fence.addr); 401fe8aea9eSmrg dri3_fence_free(dpy, &fence); 402fe8aea9eSmrg 403fe8aea9eSmrg XSync(dpy, True); 404fe8aea9eSmrg ret += !!_x_error_occurred; 405fe8aea9eSmrg 406fe8aea9eSmrg XCloseDisplay(mgr); 407fe8aea9eSmrg 408fe8aea9eSmrg return ret; 409fe8aea9eSmrg} 410fe8aea9eSmrg 411fe8aea9eSmrgstatic int has_present(Display *dpy) 412fe8aea9eSmrg{ 413fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 414fe8aea9eSmrg xcb_generic_error_t *error = NULL; 415fe8aea9eSmrg void *reply; 416fe8aea9eSmrg 417fe8aea9eSmrg reply = xcb_xfixes_query_version_reply(c, 418fe8aea9eSmrg xcb_xfixes_query_version(c, 419fe8aea9eSmrg XCB_XFIXES_MAJOR_VERSION, 420fe8aea9eSmrg XCB_XFIXES_MINOR_VERSION), 421fe8aea9eSmrg &error); 422fe8aea9eSmrg free(reply); 423fe8aea9eSmrg free(error); 424fe8aea9eSmrg if (reply == NULL) { 425fe8aea9eSmrg fprintf(stderr, "XFixes not supported on %s\n", DisplayString(dpy)); 426fe8aea9eSmrg return 0; 427fe8aea9eSmrg } 428fe8aea9eSmrg 429fe8aea9eSmrg reply = xcb_dri3_query_version_reply(c, 430fe8aea9eSmrg xcb_dri3_query_version(c, 431fe8aea9eSmrg XCB_DRI3_MAJOR_VERSION, 432fe8aea9eSmrg XCB_DRI3_MINOR_VERSION), 433fe8aea9eSmrg &error); 434fe8aea9eSmrg free(reply); 435fe8aea9eSmrg free(error); 436fe8aea9eSmrg if (reply == NULL) { 437fe8aea9eSmrg fprintf(stderr, "DRI3 not supported on %s\n", DisplayString(dpy)); 438fe8aea9eSmrg return 0; 439fe8aea9eSmrg } 440fe8aea9eSmrg 441fe8aea9eSmrg reply = xcb_present_query_version_reply(c, 442fe8aea9eSmrg xcb_present_query_version(c, 443fe8aea9eSmrg XCB_PRESENT_MAJOR_VERSION, 444fe8aea9eSmrg XCB_PRESENT_MINOR_VERSION), 445fe8aea9eSmrg &error); 446fe8aea9eSmrg 447fe8aea9eSmrg free(reply); 448fe8aea9eSmrg free(error); 449fe8aea9eSmrg if (reply == NULL) { 450fe8aea9eSmrg fprintf(stderr, "Present not supported on %s\n", DisplayString(dpy)); 451fe8aea9eSmrg return 0; 452fe8aea9eSmrg } 453fe8aea9eSmrg 454fe8aea9eSmrg return 1; 455fe8aea9eSmrg} 456fe8aea9eSmrg 457fe8aea9eSmrgint main(void) 458fe8aea9eSmrg{ 459fe8aea9eSmrg Display *dpy; 460fe8aea9eSmrg int dummy; 461fe8aea9eSmrg int error = 0; 462fe8aea9eSmrg 463fe8aea9eSmrg dpy = XOpenDisplay(NULL); 464fe8aea9eSmrg if (dpy == NULL) 465fe8aea9eSmrg return 77; 466fe8aea9eSmrg 467fe8aea9eSmrg if (!has_present(dpy)) 468fe8aea9eSmrg return 77; 469fe8aea9eSmrg 470fe8aea9eSmrg if (DPMSQueryExtension(dpy, &dummy, &dummy)) 471fe8aea9eSmrg DPMSDisable(dpy); 472fe8aea9eSmrg 473fe8aea9eSmrg signal(SIGALRM, SIG_IGN); 474fe8aea9eSmrg XSetErrorHandler(_check_error_handler); 475fe8aea9eSmrg 476fe8aea9eSmrg for (dummy = 0; dummy <= 3; dummy++) { 477fe8aea9eSmrg error += test_basic(dpy, dummy); 478fe8aea9eSmrg error += test_race(dpy, dummy); 479fe8aea9eSmrg } 480fe8aea9eSmrg 481fe8aea9eSmrg if (DPMSQueryExtension(dpy, &dummy, &dummy)) 482fe8aea9eSmrg DPMSEnable(dpy); 483fe8aea9eSmrg return !!error; 484fe8aea9eSmrg} 485