dri2-speed.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 "dri2.h" 53fe8aea9eSmrg 54fe8aea9eSmrgstatic int _x_error_occurred; 55fe8aea9eSmrg 56fe8aea9eSmrgstatic int 57fe8aea9eSmrg_check_error_handler(Display *display, 58fe8aea9eSmrg XErrorEvent *event) 59fe8aea9eSmrg{ 60fe8aea9eSmrg printf("X11 error from display %s, serial=%ld, error=%d, req=%d.%d\n", 61fe8aea9eSmrg DisplayString(display), 62fe8aea9eSmrg event->serial, 63fe8aea9eSmrg event->error_code, 64fe8aea9eSmrg event->request_code, 65fe8aea9eSmrg event->minor_code); 66fe8aea9eSmrg _x_error_occurred++; 67fe8aea9eSmrg return False; /* ignored */ 68fe8aea9eSmrg} 69fe8aea9eSmrg 70fe8aea9eSmrgstatic double elapsed(const struct timespec *start, 71fe8aea9eSmrg const struct timespec *end) 72fe8aea9eSmrg{ 73fe8aea9eSmrg return 1e6*(end->tv_sec - start->tv_sec) + (end->tv_nsec - start->tv_nsec)/1000; 74fe8aea9eSmrg} 75fe8aea9eSmrg 76fe8aea9eSmrgstatic void run(Display *dpy, Window win, const char *name) 77fe8aea9eSmrg{ 78fe8aea9eSmrg xcb_connection_t *c = XGetXCBConnection(dpy); 79fe8aea9eSmrg struct timespec start, end; 80fe8aea9eSmrg int n, completed = 0; 81fe8aea9eSmrg 82fe8aea9eSmrg _x_error_occurred = 0; 83fe8aea9eSmrg 84fe8aea9eSmrg clock_gettime(CLOCK_MONOTONIC, &start); 85fe8aea9eSmrg do { 86fe8aea9eSmrg for (n = 0; n < 1000; n++) { 87fe8aea9eSmrg unsigned int attachments[] = { DRI2BufferBackLeft }; 88fe8aea9eSmrg unsigned int seq[2]; 89fe8aea9eSmrg 90fe8aea9eSmrg seq[0] = xcb_dri2_swap_buffers_unchecked(c, win, 91fe8aea9eSmrg 0, 0, 0, 0, 0, 0).sequence; 92fe8aea9eSmrg 93fe8aea9eSmrg 94fe8aea9eSmrg seq[1] = xcb_dri2_get_buffers_unchecked(c, win, 95fe8aea9eSmrg 1, 1, attachments).sequence; 96fe8aea9eSmrg 97fe8aea9eSmrg xcb_flush(c); 98fe8aea9eSmrg xcb_discard_reply(c, seq[0]); 99fe8aea9eSmrg xcb_discard_reply(c, seq[1]); 100fe8aea9eSmrg completed++; 101fe8aea9eSmrg } 102fe8aea9eSmrg clock_gettime(CLOCK_MONOTONIC, &end); 103fe8aea9eSmrg } while (end.tv_sec < start.tv_sec + 10); 104fe8aea9eSmrg 105fe8aea9eSmrg XSync(dpy, True); 106fe8aea9eSmrg if (_x_error_occurred) 107fe8aea9eSmrg abort(); 108fe8aea9eSmrg 109fe8aea9eSmrg printf("%s: Completed %d swaps in %.1fs, %.3fus each (%.1f FPS)\n", 110fe8aea9eSmrg name, completed, elapsed(&start, &end) / 1000000, 111fe8aea9eSmrg elapsed(&start, &end) / completed, 112fe8aea9eSmrg completed / (elapsed(&start, &end) / 1000000)); 113fe8aea9eSmrg} 114fe8aea9eSmrg 115fe8aea9eSmrgstatic inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window) 116fe8aea9eSmrg{ 117fe8aea9eSmrg XRRScreenResources *res; 118fe8aea9eSmrg 119fe8aea9eSmrg res = XRRGetScreenResourcesCurrent(dpy, window); 120fe8aea9eSmrg if (res == NULL) 121fe8aea9eSmrg res = XRRGetScreenResources(dpy, window); 122fe8aea9eSmrg 123fe8aea9eSmrg return res; 124fe8aea9eSmrg} 125fe8aea9eSmrg 126fe8aea9eSmrgstatic XRRModeInfo *lookup_mode(XRRScreenResources *res, int id) 127fe8aea9eSmrg{ 128fe8aea9eSmrg int i; 129fe8aea9eSmrg 130fe8aea9eSmrg for (i = 0; i < res->nmode; i++) { 131fe8aea9eSmrg if (res->modes[i].id == id) 132fe8aea9eSmrg return &res->modes[i]; 133fe8aea9eSmrg } 134fe8aea9eSmrg 135fe8aea9eSmrg return NULL; 136fe8aea9eSmrg} 137fe8aea9eSmrg 138fe8aea9eSmrgstatic int dri2_open(Display *dpy) 139fe8aea9eSmrg{ 140fe8aea9eSmrg drm_auth_t auth; 141fe8aea9eSmrg char *driver, *device; 142fe8aea9eSmrg int fd; 143fe8aea9eSmrg 144fe8aea9eSmrg if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device)) 145fe8aea9eSmrg return -1; 146fe8aea9eSmrg 147fe8aea9eSmrg printf ("Connecting to %s driver on %s\n", driver, device); 148fe8aea9eSmrg 149fe8aea9eSmrg fd = open(device, O_RDWR); 150fe8aea9eSmrg if (fd < 0) 151fe8aea9eSmrg return -1; 152fe8aea9eSmrg 153fe8aea9eSmrg if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 154fe8aea9eSmrg return -1; 155fe8aea9eSmrg 156fe8aea9eSmrg if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic)) 157fe8aea9eSmrg return -1; 158fe8aea9eSmrg 159fe8aea9eSmrg return fd; 160fe8aea9eSmrg} 161fe8aea9eSmrg 162fe8aea9eSmrgstatic void fullscreen(Display *dpy, Window win) 163fe8aea9eSmrg{ 164fe8aea9eSmrg Atom atom = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); 165fe8aea9eSmrg XChangeProperty(dpy, win, 166fe8aea9eSmrg XInternAtom(dpy, "_NET_WM_STATE", False), 167fe8aea9eSmrg XA_ATOM, 32, PropModeReplace, 168fe8aea9eSmrg (unsigned char *)&atom, 1); 169fe8aea9eSmrg} 170fe8aea9eSmrg 171fe8aea9eSmrgstatic int has_composite(Display *dpy) 172fe8aea9eSmrg{ 173fe8aea9eSmrg int event, error; 174fe8aea9eSmrg int major, minor; 175fe8aea9eSmrg 176fe8aea9eSmrg if (!XDamageQueryExtension (dpy, &event, &error)) 177fe8aea9eSmrg return 0; 178fe8aea9eSmrg 179fe8aea9eSmrg if (!XCompositeQueryExtension(dpy, &event, &error)) 180fe8aea9eSmrg return 0; 181fe8aea9eSmrg 182fe8aea9eSmrg XCompositeQueryVersion(dpy, &major, &minor); 183fe8aea9eSmrg 184fe8aea9eSmrg return major > 0 || minor >= 4; 185fe8aea9eSmrg} 186fe8aea9eSmrg 187fe8aea9eSmrgint main(void) 188fe8aea9eSmrg{ 189fe8aea9eSmrg Display *dpy; 190fe8aea9eSmrg Window root, win; 191fe8aea9eSmrg XRRScreenResources *res; 192fe8aea9eSmrg XRRCrtcInfo **original_crtc; 193fe8aea9eSmrg XSetWindowAttributes attr; 194fe8aea9eSmrg int i, j, fd; 195fe8aea9eSmrg 196fe8aea9eSmrg attr.override_redirect = 1; 197fe8aea9eSmrg 198fe8aea9eSmrg dpy = XOpenDisplay(NULL); 199fe8aea9eSmrg if (dpy == NULL) 200fe8aea9eSmrg return 77; 201fe8aea9eSmrg 202fe8aea9eSmrg fd = dri2_open(dpy); 203fe8aea9eSmrg if (fd < 0) 204fe8aea9eSmrg return 77; 205fe8aea9eSmrg 206fe8aea9eSmrg if (DPMSQueryExtension(dpy, &i, &i)) 207fe8aea9eSmrg DPMSDisable(dpy); 208fe8aea9eSmrg 209fe8aea9eSmrg root = DefaultRootWindow(dpy); 210fe8aea9eSmrg 211fe8aea9eSmrg signal(SIGALRM, SIG_IGN); 212fe8aea9eSmrg XSetErrorHandler(_check_error_handler); 213fe8aea9eSmrg 214fe8aea9eSmrg res = NULL; 215fe8aea9eSmrg if (XRRQueryVersion(dpy, &i, &i)) 216fe8aea9eSmrg res = _XRRGetScreenResourcesCurrent(dpy, root); 217fe8aea9eSmrg if (res == NULL) 218fe8aea9eSmrg return 77; 219fe8aea9eSmrg 220fe8aea9eSmrg original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc); 221fe8aea9eSmrg for (i = 0; i < res->ncrtc; i++) 222fe8aea9eSmrg original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]); 223fe8aea9eSmrg 224fe8aea9eSmrg printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc); 225fe8aea9eSmrg for (i = 0; i < res->ncrtc; i++) 226fe8aea9eSmrg XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 227fe8aea9eSmrg 0, 0, None, RR_Rotate_0, NULL, 0); 228fe8aea9eSmrg 229fe8aea9eSmrg DRI2CreateDrawable(dpy, root); 230fe8aea9eSmrg DRI2SwapInterval(dpy, root, 0); 231fe8aea9eSmrg run(dpy, root, "off"); 232fe8aea9eSmrg XSync(dpy, True); 233fe8aea9eSmrg 234fe8aea9eSmrg for (i = 0; i < res->noutput; i++) { 235fe8aea9eSmrg XRROutputInfo *output; 236fe8aea9eSmrg XRRModeInfo *mode; 237fe8aea9eSmrg 238fe8aea9eSmrg output = XRRGetOutputInfo(dpy, res, res->outputs[i]); 239fe8aea9eSmrg if (output == NULL) 240fe8aea9eSmrg continue; 241fe8aea9eSmrg 242fe8aea9eSmrg mode = NULL; 243fe8aea9eSmrg if (res->nmode) 244fe8aea9eSmrg mode = lookup_mode(res, output->modes[0]); 245fe8aea9eSmrg 246fe8aea9eSmrg for (j = 0; mode && j < 2*output->ncrtc; j++) { 247fe8aea9eSmrg int c = j; 248fe8aea9eSmrg if (c >= output->ncrtc) 249fe8aea9eSmrg c = 2*output->ncrtc - j - 1; 250fe8aea9eSmrg 251fe8aea9eSmrg printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld: %dx%d\n", 252fe8aea9eSmrg i, c, (long)res->outputs[i], (long)output->crtcs[c], 253fe8aea9eSmrg mode->width, mode->height); 254fe8aea9eSmrg XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime, 255fe8aea9eSmrg 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1); 256fe8aea9eSmrg 257fe8aea9eSmrg run(dpy, root, "root"); 258fe8aea9eSmrg XSync(dpy, True); 259fe8aea9eSmrg 260fe8aea9eSmrg win = XCreateWindow(dpy, root, 261fe8aea9eSmrg 0, 0, mode->width, mode->height, 0, 262fe8aea9eSmrg DefaultDepth(dpy, DefaultScreen(dpy)), 263fe8aea9eSmrg InputOutput, 264fe8aea9eSmrg DefaultVisual(dpy, DefaultScreen(dpy)), 265fe8aea9eSmrg CWOverrideRedirect, &attr); 266fe8aea9eSmrg DRI2CreateDrawable(dpy, win); 267fe8aea9eSmrg DRI2SwapInterval(dpy, win, 0); 268fe8aea9eSmrg fullscreen(dpy, win); 269fe8aea9eSmrg XMapWindow(dpy, win); 270fe8aea9eSmrg run(dpy, win, "fullscreen"); 271fe8aea9eSmrg XDestroyWindow(dpy, win); 272fe8aea9eSmrg XSync(dpy, True); 273fe8aea9eSmrg 274fe8aea9eSmrg win = XCreateWindow(dpy, root, 275fe8aea9eSmrg 0, 0, mode->width, mode->height, 0, 276fe8aea9eSmrg DefaultDepth(dpy, DefaultScreen(dpy)), 277fe8aea9eSmrg InputOutput, 278fe8aea9eSmrg DefaultVisual(dpy, DefaultScreen(dpy)), 279fe8aea9eSmrg CWOverrideRedirect, &attr); 280fe8aea9eSmrg DRI2CreateDrawable(dpy, win); 281fe8aea9eSmrg DRI2SwapInterval(dpy, win, 0); 282fe8aea9eSmrg XMapWindow(dpy, win); 283fe8aea9eSmrg run(dpy, win, "windowed"); 284fe8aea9eSmrg XDestroyWindow(dpy, win); 285fe8aea9eSmrg XSync(dpy, True); 286fe8aea9eSmrg 287fe8aea9eSmrg if (has_composite(dpy)) { 288fe8aea9eSmrg Damage damage; 289fe8aea9eSmrg 290fe8aea9eSmrg _x_error_occurred = 0; 291fe8aea9eSmrg win = XCreateWindow(dpy, root, 292fe8aea9eSmrg 0, 0, mode->width, mode->height, 0, 293fe8aea9eSmrg DefaultDepth(dpy, DefaultScreen(dpy)), 294fe8aea9eSmrg InputOutput, 295fe8aea9eSmrg DefaultVisual(dpy, DefaultScreen(dpy)), 296fe8aea9eSmrg CWOverrideRedirect, &attr); 297fe8aea9eSmrg XCompositeRedirectWindow(dpy, win, CompositeRedirectManual); 298fe8aea9eSmrg damage = XDamageCreate(dpy, win, XDamageReportRawRectangles); 299fe8aea9eSmrg DRI2CreateDrawable(dpy, win); 300fe8aea9eSmrg DRI2SwapInterval(dpy, win, 0); 301fe8aea9eSmrg XMapWindow(dpy, win); 302fe8aea9eSmrg XSync(dpy, True); 303fe8aea9eSmrg if (!_x_error_occurred) 304fe8aea9eSmrg run(dpy, win, "composited"); 305fe8aea9eSmrg XDamageDestroy(dpy, damage); 306fe8aea9eSmrg XDestroyWindow(dpy, win); 307fe8aea9eSmrg XSync(dpy, True); 308fe8aea9eSmrg } 309fe8aea9eSmrg 310fe8aea9eSmrg win = XCreateWindow(dpy, root, 311fe8aea9eSmrg 0, 0, mode->width/2, mode->height/2, 0, 312fe8aea9eSmrg DefaultDepth(dpy, DefaultScreen(dpy)), 313fe8aea9eSmrg InputOutput, 314fe8aea9eSmrg DefaultVisual(dpy, DefaultScreen(dpy)), 315fe8aea9eSmrg CWOverrideRedirect, &attr); 316fe8aea9eSmrg DRI2CreateDrawable(dpy, win); 317fe8aea9eSmrg DRI2SwapInterval(dpy, win, 0); 318fe8aea9eSmrg XMapWindow(dpy, win); 319fe8aea9eSmrg run(dpy, win, "half"); 320fe8aea9eSmrg XDestroyWindow(dpy, win); 321fe8aea9eSmrg XSync(dpy, True); 322fe8aea9eSmrg 323fe8aea9eSmrg XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime, 324fe8aea9eSmrg 0, 0, None, RR_Rotate_0, NULL, 0); 325fe8aea9eSmrg } 326fe8aea9eSmrg 327fe8aea9eSmrg XRRFreeOutputInfo(output); 328fe8aea9eSmrg } 329fe8aea9eSmrg 330fe8aea9eSmrg for (i = 0; i < res->ncrtc; i++) 331fe8aea9eSmrg XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 332fe8aea9eSmrg original_crtc[i]->x, 333fe8aea9eSmrg original_crtc[i]->y, 334fe8aea9eSmrg original_crtc[i]->mode, 335fe8aea9eSmrg original_crtc[i]->rotation, 336fe8aea9eSmrg original_crtc[i]->outputs, 337fe8aea9eSmrg original_crtc[i]->noutput); 338fe8aea9eSmrg 339fe8aea9eSmrg if (DPMSQueryExtension(dpy, &i, &i)) 340fe8aea9eSmrg DPMSEnable(dpy); 341fe8aea9eSmrg return 0; 342fe8aea9eSmrg} 343