dri2-swap.c revision fe8aea9e
1fe8aea9eSmrg/* 2fe8aea9eSmrg * Copyright (c) 2015 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/Xatom.h> 31fe8aea9eSmrg#include <X11/Xlib-xcb.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/Xdamage.h> 38fe8aea9eSmrg#include <X11/extensions/Xrandr.h> 39fe8aea9eSmrg#include <xcb/xcb.h> 40fe8aea9eSmrg#include <xcb/dri2.h> 41fe8aea9eSmrg#include <xf86drm.h> 42fe8aea9eSmrg 43fe8aea9eSmrg#include <stdio.h> 44fe8aea9eSmrg#include <string.h> 45fe8aea9eSmrg#include <fcntl.h> 46fe8aea9eSmrg#include <unistd.h> 47fe8aea9eSmrg#include <assert.h> 48fe8aea9eSmrg#include <errno.h> 49fe8aea9eSmrg#include <setjmp.h> 50fe8aea9eSmrg#include <signal.h> 51fe8aea9eSmrg 52fe8aea9eSmrg#include <X11/Xlibint.h> 53fe8aea9eSmrg#include <X11/extensions/Xext.h> 54fe8aea9eSmrg#include <X11/extensions/extutil.h> 55fe8aea9eSmrg#include <X11/extensions/dri2proto.h> 56fe8aea9eSmrg#include <X11/extensions/dri2tokens.h> 57fe8aea9eSmrg#include <X11/extensions/Xfixes.h> 58fe8aea9eSmrg 59fe8aea9eSmrgstatic char dri2ExtensionName[] = DRI2_NAME; 60fe8aea9eSmrgstatic XExtensionInfo *dri2Info; 61fe8aea9eSmrgstatic XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info) 62fe8aea9eSmrg 63fe8aea9eSmrgstatic Bool 64fe8aea9eSmrgDRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire); 65fe8aea9eSmrgstatic Status 66fe8aea9eSmrgDRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire); 67fe8aea9eSmrgstatic int 68fe8aea9eSmrgDRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code); 69fe8aea9eSmrg 70fe8aea9eSmrgstatic /* const */ XExtensionHooks dri2ExtensionHooks = { 71fe8aea9eSmrg NULL, /* create_gc */ 72fe8aea9eSmrg NULL, /* copy_gc */ 73fe8aea9eSmrg NULL, /* flush_gc */ 74fe8aea9eSmrg NULL, /* free_gc */ 75fe8aea9eSmrg NULL, /* create_font */ 76fe8aea9eSmrg NULL, /* free_font */ 77fe8aea9eSmrg DRI2CloseDisplay, /* close_display */ 78fe8aea9eSmrg DRI2WireToEvent, /* wire_to_event */ 79fe8aea9eSmrg DRI2EventToWire, /* event_to_wire */ 80fe8aea9eSmrg DRI2Error, /* error */ 81fe8aea9eSmrg NULL, /* error_string */ 82fe8aea9eSmrg}; 83fe8aea9eSmrg 84fe8aea9eSmrgstatic XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay, 85fe8aea9eSmrg dri2Info, 86fe8aea9eSmrg dri2ExtensionName, 87fe8aea9eSmrg &dri2ExtensionHooks, 88fe8aea9eSmrg 0, NULL) 89fe8aea9eSmrg 90fe8aea9eSmrgstatic Bool 91fe8aea9eSmrgDRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire) 92fe8aea9eSmrg{ 93fe8aea9eSmrg XExtDisplayInfo *info = DRI2FindDisplay(dpy); 94fe8aea9eSmrg 95fe8aea9eSmrg XextCheckExtension(dpy, info, dri2ExtensionName, False); 96fe8aea9eSmrg 97fe8aea9eSmrg switch ((wire->u.u.type & 0x7f) - info->codes->first_event) { 98fe8aea9eSmrg#ifdef X_DRI2SwapBuffers 99fe8aea9eSmrg case DRI2_BufferSwapComplete: 100fe8aea9eSmrg return False; 101fe8aea9eSmrg#endif 102fe8aea9eSmrg#ifdef DRI2_InvalidateBuffers 103fe8aea9eSmrg case DRI2_InvalidateBuffers: 104fe8aea9eSmrg return False; 105fe8aea9eSmrg#endif 106fe8aea9eSmrg default: 107fe8aea9eSmrg /* client doesn't support server event */ 108fe8aea9eSmrg break; 109fe8aea9eSmrg } 110fe8aea9eSmrg 111fe8aea9eSmrg return False; 112fe8aea9eSmrg} 113fe8aea9eSmrg 114fe8aea9eSmrg/* We don't actually support this. It doesn't make sense for clients to 115fe8aea9eSmrg * send each other DRI2 events. 116fe8aea9eSmrg */ 117fe8aea9eSmrgstatic Status 118fe8aea9eSmrgDRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire) 119fe8aea9eSmrg{ 120fe8aea9eSmrg XExtDisplayInfo *info = DRI2FindDisplay(dpy); 121fe8aea9eSmrg 122fe8aea9eSmrg XextCheckExtension(dpy, info, dri2ExtensionName, False); 123fe8aea9eSmrg 124fe8aea9eSmrg switch (event->type) { 125fe8aea9eSmrg default: 126fe8aea9eSmrg /* client doesn't support server event */ 127fe8aea9eSmrg break; 128fe8aea9eSmrg } 129fe8aea9eSmrg 130fe8aea9eSmrg return Success; 131fe8aea9eSmrg} 132fe8aea9eSmrg 133fe8aea9eSmrgstatic int 134fe8aea9eSmrgDRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code) 135fe8aea9eSmrg{ 136fe8aea9eSmrg if (err->majorCode == codes->major_opcode && 137fe8aea9eSmrg err->errorCode == BadDrawable && 138fe8aea9eSmrg err->minorCode == X_DRI2CopyRegion) 139fe8aea9eSmrg return True; 140fe8aea9eSmrg 141fe8aea9eSmrg /* If the X drawable was destroyed before the GLX drawable, the 142fe8aea9eSmrg * DRI2 drawble will be gone by the time we call 143fe8aea9eSmrg * DRI2DestroyDrawable. So just ignore BadDrawable here. */ 144fe8aea9eSmrg if (err->majorCode == codes->major_opcode && 145fe8aea9eSmrg err->errorCode == BadDrawable && 146fe8aea9eSmrg err->minorCode == X_DRI2DestroyDrawable) 147fe8aea9eSmrg return True; 148fe8aea9eSmrg 149fe8aea9eSmrg /* If the server is non-local DRI2Connect will raise BadRequest. 150fe8aea9eSmrg * Swallow this so that DRI2Connect can signal this in its return code */ 151fe8aea9eSmrg if (err->majorCode == codes->major_opcode && 152fe8aea9eSmrg err->minorCode == X_DRI2Connect && 153fe8aea9eSmrg err->errorCode == BadRequest) { 154fe8aea9eSmrg *ret_code = False; 155fe8aea9eSmrg return True; 156fe8aea9eSmrg } 157fe8aea9eSmrg 158fe8aea9eSmrg return False; 159fe8aea9eSmrg} 160fe8aea9eSmrg 161fe8aea9eSmrgstatic Bool 162fe8aea9eSmrgDRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase) 163fe8aea9eSmrg{ 164fe8aea9eSmrg XExtDisplayInfo *info = DRI2FindDisplay(dpy); 165fe8aea9eSmrg 166fe8aea9eSmrg if (XextHasExtension(info)) { 167fe8aea9eSmrg *eventBase = info->codes->first_event; 168fe8aea9eSmrg *errorBase = info->codes->first_error; 169fe8aea9eSmrg return True; 170fe8aea9eSmrg } 171fe8aea9eSmrg 172fe8aea9eSmrg return False; 173fe8aea9eSmrg} 174fe8aea9eSmrg 175fe8aea9eSmrgstatic Bool 176fe8aea9eSmrgDRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName) 177fe8aea9eSmrg{ 178fe8aea9eSmrg XExtDisplayInfo *info = DRI2FindDisplay(dpy); 179fe8aea9eSmrg xDRI2ConnectReply rep; 180fe8aea9eSmrg xDRI2ConnectReq *req; 181fe8aea9eSmrg 182fe8aea9eSmrg XextCheckExtension(dpy, info, dri2ExtensionName, False); 183fe8aea9eSmrg 184fe8aea9eSmrg LockDisplay(dpy); 185fe8aea9eSmrg GetReq(DRI2Connect, req); 186fe8aea9eSmrg req->reqType = info->codes->major_opcode; 187fe8aea9eSmrg req->dri2ReqType = X_DRI2Connect; 188fe8aea9eSmrg req->window = window; 189fe8aea9eSmrg req->driverType = DRI2DriverDRI; 190fe8aea9eSmrg if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 191fe8aea9eSmrg UnlockDisplay(dpy); 192fe8aea9eSmrg SyncHandle(); 193fe8aea9eSmrg return False; 194fe8aea9eSmrg } 195fe8aea9eSmrg 196fe8aea9eSmrg if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) { 197fe8aea9eSmrg UnlockDisplay(dpy); 198fe8aea9eSmrg SyncHandle(); 199fe8aea9eSmrg return False; 200fe8aea9eSmrg } 201fe8aea9eSmrg 202fe8aea9eSmrg *driverName = Xmalloc(rep.driverNameLength + 1); 203fe8aea9eSmrg if (*driverName == NULL) { 204fe8aea9eSmrg _XEatData(dpy, 205fe8aea9eSmrg ((rep.driverNameLength + 3) & ~3) + 206fe8aea9eSmrg ((rep.deviceNameLength + 3) & ~3)); 207fe8aea9eSmrg UnlockDisplay(dpy); 208fe8aea9eSmrg SyncHandle(); 209fe8aea9eSmrg return False; 210fe8aea9eSmrg } 211fe8aea9eSmrg _XReadPad(dpy, *driverName, rep.driverNameLength); 212fe8aea9eSmrg (*driverName)[rep.driverNameLength] = '\0'; 213fe8aea9eSmrg 214fe8aea9eSmrg *deviceName = Xmalloc(rep.deviceNameLength + 1); 215fe8aea9eSmrg if (*deviceName == NULL) { 216fe8aea9eSmrg Xfree(*driverName); 217fe8aea9eSmrg _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3)); 218fe8aea9eSmrg UnlockDisplay(dpy); 219fe8aea9eSmrg SyncHandle(); 220fe8aea9eSmrg return False; 221fe8aea9eSmrg } 222fe8aea9eSmrg _XReadPad(dpy, *deviceName, rep.deviceNameLength); 223fe8aea9eSmrg (*deviceName)[rep.deviceNameLength] = '\0'; 224fe8aea9eSmrg 225fe8aea9eSmrg UnlockDisplay(dpy); 226fe8aea9eSmrg SyncHandle(); 227fe8aea9eSmrg 228fe8aea9eSmrg return True; 229fe8aea9eSmrg} 230fe8aea9eSmrg 231fe8aea9eSmrgstatic Bool 232fe8aea9eSmrgDRI2Authenticate(Display * dpy, XID window, unsigned int magic) 233fe8aea9eSmrg{ 234fe8aea9eSmrg XExtDisplayInfo *info = DRI2FindDisplay(dpy); 235fe8aea9eSmrg xDRI2AuthenticateReq *req; 236fe8aea9eSmrg xDRI2AuthenticateReply rep; 237fe8aea9eSmrg 238fe8aea9eSmrg XextCheckExtension(dpy, info, dri2ExtensionName, False); 239fe8aea9eSmrg 240fe8aea9eSmrg LockDisplay(dpy); 241fe8aea9eSmrg GetReq(DRI2Authenticate, req); 242fe8aea9eSmrg req->reqType = info->codes->major_opcode; 243fe8aea9eSmrg req->dri2ReqType = X_DRI2Authenticate; 244fe8aea9eSmrg req->window = window; 245fe8aea9eSmrg req->magic = magic; 246fe8aea9eSmrg 247fe8aea9eSmrg if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { 248fe8aea9eSmrg UnlockDisplay(dpy); 249fe8aea9eSmrg SyncHandle(); 250fe8aea9eSmrg return False; 251fe8aea9eSmrg } 252fe8aea9eSmrg 253fe8aea9eSmrg UnlockDisplay(dpy); 254fe8aea9eSmrg SyncHandle(); 255fe8aea9eSmrg 256fe8aea9eSmrg return rep.authenticated; 257fe8aea9eSmrg} 258fe8aea9eSmrg 259fe8aea9eSmrgstatic void 260fe8aea9eSmrgDRI2CreateDrawable(Display * dpy, XID drawable) 261fe8aea9eSmrg{ 262fe8aea9eSmrg XExtDisplayInfo *info = DRI2FindDisplay(dpy); 263fe8aea9eSmrg xDRI2CreateDrawableReq *req; 264fe8aea9eSmrg 265fe8aea9eSmrg XextSimpleCheckExtension(dpy, info, dri2ExtensionName); 266fe8aea9eSmrg 267fe8aea9eSmrg LockDisplay(dpy); 268fe8aea9eSmrg GetReq(DRI2CreateDrawable, req); 269fe8aea9eSmrg req->reqType = info->codes->major_opcode; 270fe8aea9eSmrg req->dri2ReqType = X_DRI2CreateDrawable; 271fe8aea9eSmrg req->drawable = drawable; 272fe8aea9eSmrg UnlockDisplay(dpy); 273fe8aea9eSmrg SyncHandle(); 274fe8aea9eSmrg} 275fe8aea9eSmrg 276fe8aea9eSmrgstatic void DRI2SwapInterval(Display *dpy, XID drawable, int interval) 277fe8aea9eSmrg{ 278fe8aea9eSmrg XExtDisplayInfo *info = DRI2FindDisplay(dpy); 279fe8aea9eSmrg xDRI2SwapIntervalReq *req; 280fe8aea9eSmrg 281fe8aea9eSmrg XextSimpleCheckExtension (dpy, info, dri2ExtensionName); 282fe8aea9eSmrg 283fe8aea9eSmrg LockDisplay(dpy); 284fe8aea9eSmrg GetReq(DRI2SwapInterval, req); 285fe8aea9eSmrg req->reqType = info->codes->major_opcode; 286fe8aea9eSmrg req->dri2ReqType = X_DRI2SwapInterval; 287fe8aea9eSmrg req->drawable = drawable; 288fe8aea9eSmrg req->interval = interval; 289fe8aea9eSmrg UnlockDisplay(dpy); 290fe8aea9eSmrg SyncHandle(); 291fe8aea9eSmrg} 292fe8aea9eSmrg 293fe8aea9eSmrgstatic int _x_error_occurred; 294fe8aea9eSmrg 295fe8aea9eSmrgstatic int 296fe8aea9eSmrg_check_error_handler(Display *display, 297fe8aea9eSmrg XErrorEvent *event) 298fe8aea9eSmrg{ 299fe8aea9eSmrg fprintf(stderr, 300fe8aea9eSmrg "X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n", 301fe8aea9eSmrg DisplayString(display), 302fe8aea9eSmrg event->serial, 303fe8aea9eSmrg event->error_code, 304fe8aea9eSmrg event->request_code, 305fe8aea9eSmrg event->minor_code); 306fe8aea9eSmrg _x_error_occurred++; 307fe8aea9eSmrg return False; /* ignored */ 308fe8aea9eSmrg} 309fe8aea9eSmrg 310fe8aea9eSmrgstatic double elapsed(const struct timespec *start, 311fe8aea9eSmrg const struct timespec *end) 312fe8aea9eSmrg{ 313fe8aea9eSmrg return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000; 314fe8aea9eSmrg} 315fe8aea9eSmrg 316fe8aea9eSmrgstatic void run(Display *dpy, Window win) 317fe8aea9eSmrg{ 318fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 319fe8aea9eSmrg struct timespec start, end; 320fe8aea9eSmrg int n, completed = 0; 321fe8aea9eSmrg 322fe8aea9eSmrg clock_gettime(CLOCK_MONOTONIC, &start); 323fe8aea9eSmrg do { 324fe8aea9eSmrg for (n = 0; n < 1000; n++) { 325fe8aea9eSmrg unsigned int attachments[] = { DRI2BufferBackLeft }; 326fe8aea9eSmrg unsigned int seq[2]; 327fe8aea9eSmrg 328fe8aea9eSmrg seq[0] = xcb_dri2_swap_buffers_unchecked(c, win, 329fe8aea9eSmrg 0, 0, 0, 0, 0, 0).sequence; 330fe8aea9eSmrg 331fe8aea9eSmrg 332fe8aea9eSmrg seq[1] = xcb_dri2_get_buffers_unchecked(c, win, 333fe8aea9eSmrg 1, 1, attachments).sequence; 334fe8aea9eSmrg 335fe8aea9eSmrg xcb_flush(c); 336fe8aea9eSmrg xcb_discard_reply(c, seq[0]); 337fe8aea9eSmrg xcb_discard_reply(c, seq[1]); 338fe8aea9eSmrg completed++; 339fe8aea9eSmrg } 340fe8aea9eSmrg clock_gettime(CLOCK_MONOTONIC, &end); 341fe8aea9eSmrg } while (end.tv_sec < start.tv_sec + 10); 342fe8aea9eSmrg 343fe8aea9eSmrg printf("%f\n", completed / (elapsed(&start, &end) / 1000000)); 344fe8aea9eSmrg} 345fe8aea9eSmrg 346fe8aea9eSmrgstatic inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window) 347fe8aea9eSmrg{ 348fe8aea9eSmrg XRRScreenResources *res; 349fe8aea9eSmrg 350fe8aea9eSmrg res = XRRGetScreenResourcesCurrent(dpy, window); 351fe8aea9eSmrg if (res == NULL) 352fe8aea9eSmrg res = XRRGetScreenResources(dpy, window); 353fe8aea9eSmrg 354fe8aea9eSmrg return res; 355fe8aea9eSmrg} 356fe8aea9eSmrg 357fe8aea9eSmrgstatic XRRModeInfo *lookup_mode(XRRScreenResources *res, int id) 358fe8aea9eSmrg{ 359fe8aea9eSmrg int i; 360fe8aea9eSmrg 361fe8aea9eSmrg for (i = 0; i < res->nmode; i++) { 362fe8aea9eSmrg if (res->modes[i].id == id) 363fe8aea9eSmrg return &res->modes[i]; 364fe8aea9eSmrg } 365fe8aea9eSmrg 366fe8aea9eSmrg return NULL; 367fe8aea9eSmrg} 368fe8aea9eSmrg 369fe8aea9eSmrgstatic int dri2_open(Display *dpy) 370fe8aea9eSmrg{ 371fe8aea9eSmrg drm_auth_t auth; 372fe8aea9eSmrg char *driver, *device; 373fe8aea9eSmrg int fd; 374fe8aea9eSmrg 375fe8aea9eSmrg if (!DRI2QueryExtension(dpy, &fd, &fd)) 376fe8aea9eSmrg return -1; 377fe8aea9eSmrg 378fe8aea9eSmrg if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device)) 379fe8aea9eSmrg return -1; 380fe8aea9eSmrg 381fe8aea9eSmrg fd = open(device, O_RDWR); 382fe8aea9eSmrg if (fd < 0) 383fe8aea9eSmrg return -1; 384fe8aea9eSmrg 385fe8aea9eSmrg if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 386fe8aea9eSmrg return -1; 387fe8aea9eSmrg 388fe8aea9eSmrg if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic)) 389fe8aea9eSmrg return -1; 390fe8aea9eSmrg 391fe8aea9eSmrg return fd; 392fe8aea9eSmrg} 393fe8aea9eSmrg 394fe8aea9eSmrgstatic void fullscreen(Display *dpy, Window win) 395fe8aea9eSmrg{ 396fe8aea9eSmrg Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); 397fe8aea9eSmrg XChangeProperty(dpy, win, 398fe8aea9eSmrg XInternAtom(dpy, "_NET_WM_STATE", False), 399fe8aea9eSmrg XA_ATOM, 32, PropModeReplace, 400fe8aea9eSmrg (unsigned char *)&atom, 1); 401fe8aea9eSmrg} 402fe8aea9eSmrg 403fe8aea9eSmrgstatic int has_composite(Display *dpy) 404fe8aea9eSmrg{ 405fe8aea9eSmrg int event, error; 406fe8aea9eSmrg int major, minor; 407fe8aea9eSmrg 408fe8aea9eSmrg if (!XDamageQueryExtension (dpy, &event, &error)) 409fe8aea9eSmrg return 0; 410fe8aea9eSmrg 411fe8aea9eSmrg if (!XCompositeQueryExtension(dpy, &event, &error)) 412fe8aea9eSmrg return 0; 413fe8aea9eSmrg 414fe8aea9eSmrg XCompositeQueryVersion(dpy, &major, &minor); 415fe8aea9eSmrg 416fe8aea9eSmrg return major > 0 || minor >= 4; 417fe8aea9eSmrg} 418fe8aea9eSmrg 419fe8aea9eSmrgint main(int argc, char **argv) 420fe8aea9eSmrg{ 421fe8aea9eSmrg Display *dpy; 422fe8aea9eSmrg Window root, win; 423fe8aea9eSmrg XRRScreenResources *res; 424fe8aea9eSmrg XRRCrtcInfo **original_crtc; 425fe8aea9eSmrg XSetWindowAttributes attr; 426fe8aea9eSmrg enum window { ROOT, FULLSCREEN, WINDOW } w = FULLSCREEN; 427fe8aea9eSmrg enum visible {REDIRECTED, NORMAL } v = NORMAL; 428fe8aea9eSmrg enum display { OFF, ON } d = OFF; 429fe8aea9eSmrg int width, height; 430fe8aea9eSmrg int i, fd; 431fe8aea9eSmrg int c; 432fe8aea9eSmrg 433fe8aea9eSmrg while ((c = getopt(argc, argv, "d:v:w:")) != -1) { 434fe8aea9eSmrg switch (c) { 435fe8aea9eSmrg case 'd': 436fe8aea9eSmrg if (strcmp(optarg, "off") == 0) 437fe8aea9eSmrg d = OFF; 438fe8aea9eSmrg else if (strcmp(optarg, "on") == 0) 439fe8aea9eSmrg d = ON; 440fe8aea9eSmrg else 441fe8aea9eSmrg abort(); 442fe8aea9eSmrg break; 443fe8aea9eSmrg 444fe8aea9eSmrg case 'v': 445fe8aea9eSmrg if (strcmp(optarg, "redirected") == 0) 446fe8aea9eSmrg v = REDIRECTED; 447fe8aea9eSmrg else if (strcmp(optarg, "normal") == 0) 448fe8aea9eSmrg v = NORMAL; 449fe8aea9eSmrg else 450fe8aea9eSmrg abort(); 451fe8aea9eSmrg break; 452fe8aea9eSmrg 453fe8aea9eSmrg case 'w': 454fe8aea9eSmrg if (strcmp(optarg, "fullscreen") == 0) 455fe8aea9eSmrg w = FULLSCREEN; 456fe8aea9eSmrg else if (strcmp(optarg, "window") == 0) 457fe8aea9eSmrg w = WINDOW; 458fe8aea9eSmrg else if (strcmp(optarg, "root") == 0) 459fe8aea9eSmrg w = ROOT; 460fe8aea9eSmrg else 461fe8aea9eSmrg abort(); 462fe8aea9eSmrg break; 463fe8aea9eSmrg } 464fe8aea9eSmrg } 465fe8aea9eSmrg 466fe8aea9eSmrg attr.override_redirect = 1; 467fe8aea9eSmrg 468fe8aea9eSmrg dpy = XOpenDisplay(NULL); 469fe8aea9eSmrg if (dpy == NULL) 470fe8aea9eSmrg return 77; 471fe8aea9eSmrg 472fe8aea9eSmrg width = DisplayWidth(dpy, DefaultScreen(dpy)); 473fe8aea9eSmrg height = DisplayHeight(dpy, DefaultScreen(dpy)); 474fe8aea9eSmrg 475fe8aea9eSmrg fd = dri2_open(dpy); 476fe8aea9eSmrg if (fd < 0) 477fe8aea9eSmrg return 77; 478fe8aea9eSmrg 479fe8aea9eSmrg if (DPMSQueryExtension(dpy, &i, &i)) 480fe8aea9eSmrg DPMSDisable(dpy); 481fe8aea9eSmrg 482fe8aea9eSmrg root = DefaultRootWindow(dpy); 483fe8aea9eSmrg 484fe8aea9eSmrg signal(SIGALRM, SIG_IGN); 485fe8aea9eSmrg XSetErrorHandler(_check_error_handler); 486fe8aea9eSmrg 487fe8aea9eSmrg res = NULL; 488fe8aea9eSmrg if (XRRQueryVersion(dpy, &i, &i)) 489fe8aea9eSmrg res = _XRRGetScreenResourcesCurrent(dpy, root); 490fe8aea9eSmrg if (res == NULL) 491fe8aea9eSmrg return 77; 492fe8aea9eSmrg 493fe8aea9eSmrg if (v == REDIRECTED && !has_composite(dpy)) 494fe8aea9eSmrg return 77; 495fe8aea9eSmrg 496fe8aea9eSmrg original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc); 497fe8aea9eSmrg for (i = 0; i < res->ncrtc; i++) 498fe8aea9eSmrg original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]); 499fe8aea9eSmrg 500fe8aea9eSmrg for (i = 0; i < res->ncrtc; i++) 501fe8aea9eSmrg XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 502fe8aea9eSmrg 0, 0, None, RR_Rotate_0, NULL, 0); 503fe8aea9eSmrg 504fe8aea9eSmrg DRI2CreateDrawable(dpy, root); 505fe8aea9eSmrg DRI2SwapInterval(dpy, root, 0); 506fe8aea9eSmrg 507fe8aea9eSmrg if (d != OFF) { 508fe8aea9eSmrg for (i = 0; i < res->noutput; i++) { 509fe8aea9eSmrg XRROutputInfo *output; 510fe8aea9eSmrg XRRModeInfo *mode; 511fe8aea9eSmrg 512fe8aea9eSmrg output = XRRGetOutputInfo(dpy, res, res->outputs[i]); 513fe8aea9eSmrg if (output == NULL) 514fe8aea9eSmrg continue; 515fe8aea9eSmrg 516fe8aea9eSmrg mode = NULL; 517fe8aea9eSmrg if (res->nmode) 518fe8aea9eSmrg mode = lookup_mode(res, output->modes[0]); 519fe8aea9eSmrg if (mode == NULL) 520fe8aea9eSmrg continue; 521fe8aea9eSmrg 522fe8aea9eSmrg XRRSetCrtcConfig(dpy, res, output->crtcs[0], CurrentTime, 523fe8aea9eSmrg 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1); 524fe8aea9eSmrg width = mode->width; 525fe8aea9eSmrg height = mode->height; 526fe8aea9eSmrg break; 527fe8aea9eSmrg } 528fe8aea9eSmrg if (i == res->noutput) { 529fe8aea9eSmrg _x_error_occurred = 77; 530fe8aea9eSmrg goto restore; 531fe8aea9eSmrg } 532fe8aea9eSmrg } 533fe8aea9eSmrg 534fe8aea9eSmrg if (w == ROOT) { 535fe8aea9eSmrg run(dpy, root); 536fe8aea9eSmrg } else if (w == FULLSCREEN) { 537fe8aea9eSmrg win = XCreateWindow(dpy, root, 538fe8aea9eSmrg 0, 0, width, height, 0, 539fe8aea9eSmrg DefaultDepth(dpy, DefaultScreen(dpy)), 540fe8aea9eSmrg InputOutput, 541fe8aea9eSmrg DefaultVisual(dpy, DefaultScreen(dpy)), 542fe8aea9eSmrg CWOverrideRedirect, &attr); 543fe8aea9eSmrg DRI2CreateDrawable(dpy, win); 544fe8aea9eSmrg DRI2SwapInterval(dpy, win, 0); 545fe8aea9eSmrg if (v == REDIRECTED) { 546fe8aea9eSmrg XCompositeRedirectWindow(dpy, win, CompositeRedirectManual); 547fe8aea9eSmrg XDamageCreate(dpy, win, XDamageReportRawRectangles); 548fe8aea9eSmrg } else 549fe8aea9eSmrg fullscreen(dpy, win); 550fe8aea9eSmrg XMapWindow(dpy, win); 551fe8aea9eSmrg run(dpy, win); 552fe8aea9eSmrg } else if (w == WINDOW) { 553fe8aea9eSmrg win = XCreateWindow(dpy, root, 554fe8aea9eSmrg 0, 0, width/2, height/2, 0, 555fe8aea9eSmrg DefaultDepth(dpy, DefaultScreen(dpy)), 556fe8aea9eSmrg InputOutput, 557fe8aea9eSmrg DefaultVisual(dpy, DefaultScreen(dpy)), 558fe8aea9eSmrg CWOverrideRedirect, &attr); 559fe8aea9eSmrg DRI2CreateDrawable(dpy, win); 560fe8aea9eSmrg DRI2SwapInterval(dpy, win, 0); 561fe8aea9eSmrg if (v == REDIRECTED) { 562fe8aea9eSmrg XCompositeRedirectWindow(dpy, win, CompositeRedirectManual); 563fe8aea9eSmrg XDamageCreate(dpy, win, XDamageReportRawRectangles); 564fe8aea9eSmrg } 565fe8aea9eSmrg XMapWindow(dpy, win); 566fe8aea9eSmrg run(dpy, win); 567fe8aea9eSmrg } 568fe8aea9eSmrg 569fe8aea9eSmrgrestore: 570fe8aea9eSmrg for (i = 0; i < res->ncrtc; i++) 571fe8aea9eSmrg XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 572fe8aea9eSmrg 0, 0, None, RR_Rotate_0, NULL, 0); 573fe8aea9eSmrg 574fe8aea9eSmrg for (i = 0; i < res->ncrtc; i++) 575fe8aea9eSmrg XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 576fe8aea9eSmrg original_crtc[i]->x, 577fe8aea9eSmrg original_crtc[i]->y, 578fe8aea9eSmrg original_crtc[i]->mode, 579fe8aea9eSmrg original_crtc[i]->rotation, 580fe8aea9eSmrg original_crtc[i]->outputs, 581fe8aea9eSmrg original_crtc[i]->noutput); 582fe8aea9eSmrg 583fe8aea9eSmrg if (DPMSQueryExtension(dpy, &i, &i)) 584fe8aea9eSmrg DPMSEnable(dpy); 585fe8aea9eSmrg 586fe8aea9eSmrg XSync(dpy, True); 587fe8aea9eSmrg return _x_error_occurred; 588fe8aea9eSmrg} 589