1428d7b3dSmrg#include <stdint.h> 2428d7b3dSmrg#include <stdio.h> 3428d7b3dSmrg#include <stdlib.h> 4428d7b3dSmrg 5428d7b3dSmrg#include <X11/Xlib.h> 6428d7b3dSmrg#include <X11/Xutil.h> 7428d7b3dSmrg#include <X11/extensions/Xfixes.h> 8428d7b3dSmrg#include <X11/extensions/Xrandr.h> 9428d7b3dSmrg#include <unistd.h> 10428d7b3dSmrg#include <fcntl.h> 11428d7b3dSmrg#include <string.h> 12428d7b3dSmrg#include <time.h> 13428d7b3dSmrg 14428d7b3dSmrg#include <xf86drm.h> 15428d7b3dSmrg#include <drm.h> 16428d7b3dSmrg 17428d7b3dSmrg#include "dri2.h" 18428d7b3dSmrg 19428d7b3dSmrg#define COUNT 60 20428d7b3dSmrg 21428d7b3dSmrgstatic inline XRRScreenResources *_XRRGetScreenResourcesCurrent(Display *dpy, Window window) 22428d7b3dSmrg{ 23428d7b3dSmrg XRRScreenResources *res; 24428d7b3dSmrg 25428d7b3dSmrg res = XRRGetScreenResourcesCurrent(dpy, window); 26428d7b3dSmrg if (res == NULL) 27428d7b3dSmrg res = XRRGetScreenResources(dpy, window); 28428d7b3dSmrg 29428d7b3dSmrg return res; 30428d7b3dSmrg} 31428d7b3dSmrg 32428d7b3dSmrgstatic XRRModeInfo *lookup_mode(XRRScreenResources *res, int id) 33428d7b3dSmrg{ 34428d7b3dSmrg int i; 35428d7b3dSmrg 36428d7b3dSmrg for (i = 0; i < res->nmode; i++) { 37428d7b3dSmrg if (res->modes[i].id == id) 38428d7b3dSmrg return &res->modes[i]; 39428d7b3dSmrg } 40428d7b3dSmrg 41428d7b3dSmrg return NULL; 42428d7b3dSmrg} 43428d7b3dSmrg 44428d7b3dSmrgstatic int dri2_open(Display *dpy) 45428d7b3dSmrg{ 46428d7b3dSmrg drm_auth_t auth; 47428d7b3dSmrg char *driver, *device; 48428d7b3dSmrg int fd; 49428d7b3dSmrg 50428d7b3dSmrg if (!DRI2Connect(dpy, DefaultRootWindow(dpy), &driver, &device)) 51428d7b3dSmrg return -1; 52428d7b3dSmrg 53428d7b3dSmrg printf ("Connecting to %s driver on %s\n", driver, device); 54428d7b3dSmrg 55428d7b3dSmrg fd = open(device, O_RDWR); 56428d7b3dSmrg if (fd < 0) 57428d7b3dSmrg return -1; 58428d7b3dSmrg 59428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth)) 60428d7b3dSmrg return -1; 61428d7b3dSmrg 62428d7b3dSmrg if (!DRI2Authenticate(dpy, DefaultRootWindow(dpy), auth.magic)) 63428d7b3dSmrg return -1; 64428d7b3dSmrg 65428d7b3dSmrg return fd; 66428d7b3dSmrg} 67428d7b3dSmrg 68428d7b3dSmrgstatic void dri2_copy_swap(Display *dpy, Drawable d, 69428d7b3dSmrg int width, int height, int has_front) 70428d7b3dSmrg{ 71428d7b3dSmrg XRectangle rect; 72428d7b3dSmrg XserverRegion region; 73428d7b3dSmrg 74428d7b3dSmrg rect.x = 0; 75428d7b3dSmrg rect.y = 0; 76428d7b3dSmrg rect.width = width; 77428d7b3dSmrg rect.height = height; 78428d7b3dSmrg 79428d7b3dSmrg region = XFixesCreateRegion(dpy, &rect, 1); 80428d7b3dSmrg DRI2CopyRegion(dpy, d, region, DRI2BufferFrontLeft, DRI2BufferBackLeft); 81428d7b3dSmrg if (has_front) 82428d7b3dSmrg DRI2CopyRegion(dpy, d, region, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 83428d7b3dSmrg XFixesDestroyRegion(dpy, region); 84428d7b3dSmrg} 85428d7b3dSmrg 86428d7b3dSmrgstatic double elapsed(const struct timespec *start, 87428d7b3dSmrg const struct timespec *end) 88428d7b3dSmrg{ 89428d7b3dSmrg return (end->tv_sec - start->tv_sec) + 90428d7b3dSmrg 1e-9*(end->tv_nsec - start->tv_nsec); 91428d7b3dSmrg} 92428d7b3dSmrg 93428d7b3dSmrgstatic uint64_t check_msc(Display *dpy, Window win, uint64_t last_msc) 94428d7b3dSmrg{ 95428d7b3dSmrg uint64_t current_msc, current_ust, current_sbc; 96428d7b3dSmrg DRI2GetMSC(dpy, win, ¤t_ust, ¤t_msc, ¤t_sbc); 97428d7b3dSmrg if (current_msc < last_msc) { 98428d7b3dSmrg printf("Invalid MSC: was %llu, now %llu\n", 99428d7b3dSmrg (long long)last_msc, (long long)current_msc); 100428d7b3dSmrg } 101428d7b3dSmrg return current_msc; 102428d7b3dSmrg} 103428d7b3dSmrg 104428d7b3dSmrgstatic void run(Display *dpy, int width, int height, 105428d7b3dSmrg unsigned int *attachments, int nattachments, 106428d7b3dSmrg const char *name) 107428d7b3dSmrg{ 108428d7b3dSmrg Window win; 109428d7b3dSmrg XSetWindowAttributes attr; 110428d7b3dSmrg int count; 111428d7b3dSmrg DRI2Buffer *buffers; 112428d7b3dSmrg struct timespec start, end; 113428d7b3dSmrg uint64_t msc; 114428d7b3dSmrg 115428d7b3dSmrg /* Be nasty and install a fullscreen window on top so that we 116428d7b3dSmrg * can guarantee we do not get clipped by children. 117428d7b3dSmrg */ 118428d7b3dSmrg attr.override_redirect = 1; 119428d7b3dSmrg win = XCreateWindow(dpy, DefaultRootWindow(dpy), 120428d7b3dSmrg 0, 0, width, height, 0, 121428d7b3dSmrg DefaultDepth(dpy, DefaultScreen(dpy)), 122428d7b3dSmrg InputOutput, 123428d7b3dSmrg DefaultVisual(dpy, DefaultScreen(dpy)), 124428d7b3dSmrg CWOverrideRedirect, &attr); 125428d7b3dSmrg XMapWindow(dpy, win); 126428d7b3dSmrg 127428d7b3dSmrg DRI2CreateDrawable(dpy, win); 128428d7b3dSmrg msc = check_msc(dpy, win, 0); 129428d7b3dSmrg 130428d7b3dSmrg buffers = DRI2GetBuffers(dpy, win, &width, &height, 131428d7b3dSmrg attachments, nattachments, &count); 132428d7b3dSmrg if (count != nattachments) 133428d7b3dSmrg return; 134428d7b3dSmrg 135428d7b3dSmrg msc = check_msc(dpy, win, msc); 136428d7b3dSmrg clock_gettime(CLOCK_MONOTONIC, &start); 137428d7b3dSmrg for (count = 0; count < COUNT; count++) 138428d7b3dSmrg DRI2SwapBuffers(dpy, win, 0, 0, 0); 139428d7b3dSmrg msc = check_msc(dpy, win, msc); 140428d7b3dSmrg clock_gettime(CLOCK_MONOTONIC, &end); 141428d7b3dSmrg printf("%d %s (%dx%d) swaps in %fs.\n", 142428d7b3dSmrg count, name, width, height, elapsed(&start, &end)); 143428d7b3dSmrg 144428d7b3dSmrg msc = check_msc(dpy, win, msc); 145428d7b3dSmrg clock_gettime(CLOCK_MONOTONIC, &start); 146428d7b3dSmrg for (count = 0; count < COUNT; count++) 147428d7b3dSmrg dri2_copy_swap(dpy, win, width, height, nattachments == 2); 148428d7b3dSmrg msc = check_msc(dpy, win, msc); 149428d7b3dSmrg clock_gettime(CLOCK_MONOTONIC, &end); 150428d7b3dSmrg 151428d7b3dSmrg printf("%d %s (%dx%d) blits in %fs.\n", 152428d7b3dSmrg count, name, width, height, elapsed(&start, &end)); 153428d7b3dSmrg 154428d7b3dSmrg DRI2SwapInterval(dpy, win, 0); 155428d7b3dSmrg 156428d7b3dSmrg msc = check_msc(dpy, win, msc); 157428d7b3dSmrg clock_gettime(CLOCK_MONOTONIC, &start); 158428d7b3dSmrg for (count = 0; count < COUNT; count++) 159428d7b3dSmrg DRI2SwapBuffers(dpy, win, 0, 0, 0); 160428d7b3dSmrg msc = check_msc(dpy, win, msc); 161428d7b3dSmrg clock_gettime(CLOCK_MONOTONIC, &end); 162428d7b3dSmrg printf("%d %s (%dx%d) vblank=0 swaps in %fs.\n", 163428d7b3dSmrg count, name, width, height, elapsed(&start, &end)); 164428d7b3dSmrg 165428d7b3dSmrg XDestroyWindow(dpy, win); 166428d7b3dSmrg free(buffers); 167428d7b3dSmrg 168428d7b3dSmrg XSync(dpy, 1); 169428d7b3dSmrg} 170428d7b3dSmrg 171428d7b3dSmrgint main(void) 172428d7b3dSmrg{ 173428d7b3dSmrg Display *dpy; 174428d7b3dSmrg int i, j, fd; 175428d7b3dSmrg unsigned int attachments[] = { 176428d7b3dSmrg DRI2BufferBackLeft, 177428d7b3dSmrg DRI2BufferFrontLeft, 178428d7b3dSmrg }; 179428d7b3dSmrg XRRScreenResources *res; 180428d7b3dSmrg XRRCrtcInfo **original_crtc; 181428d7b3dSmrg Window root; 182428d7b3dSmrg uint64_t last_msc; 183428d7b3dSmrg 184428d7b3dSmrg dpy = XOpenDisplay(NULL); 185428d7b3dSmrg if (dpy == NULL) 186428d7b3dSmrg return 77; 187428d7b3dSmrg 188428d7b3dSmrg if (!XRRQueryVersion(dpy, &i, &j)) 189428d7b3dSmrg return 77; 190428d7b3dSmrg 191428d7b3dSmrg fd = dri2_open(dpy); 192428d7b3dSmrg if (fd < 0) 193428d7b3dSmrg return 1; 194428d7b3dSmrg 195428d7b3dSmrg root = DefaultRootWindow(dpy); 196428d7b3dSmrg DRI2CreateDrawable(dpy, root); 197428d7b3dSmrg 198428d7b3dSmrg res = _XRRGetScreenResourcesCurrent(dpy, root); 199428d7b3dSmrg if (res == NULL) 200428d7b3dSmrg return 1; 201428d7b3dSmrg 202428d7b3dSmrg original_crtc = malloc(sizeof(XRRCrtcInfo *)*res->ncrtc); 203428d7b3dSmrg for (i = 0; i < res->ncrtc; i++) 204428d7b3dSmrg original_crtc[i] = XRRGetCrtcInfo(dpy, res, res->crtcs[i]); 205428d7b3dSmrg 206428d7b3dSmrg printf("noutput=%d, ncrtc=%d\n", res->noutput, res->ncrtc); 207428d7b3dSmrg last_msc = check_msc(dpy, root, 0); 208428d7b3dSmrg for (i = 0; i < res->ncrtc; i++) 209428d7b3dSmrg XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 210428d7b3dSmrg 0, 0, None, RR_Rotate_0, NULL, 0); 211428d7b3dSmrg last_msc = check_msc(dpy, root, last_msc); 212428d7b3dSmrg 213428d7b3dSmrg for (i = 0; i < res->noutput; i++) { 214428d7b3dSmrg XRROutputInfo *output; 215428d7b3dSmrg XRRModeInfo *mode; 216428d7b3dSmrg 217428d7b3dSmrg output = XRRGetOutputInfo(dpy, res, res->outputs[i]); 218428d7b3dSmrg if (output == NULL) 219428d7b3dSmrg continue; 220428d7b3dSmrg 221428d7b3dSmrg mode = NULL; 222428d7b3dSmrg if (res->nmode) 223428d7b3dSmrg mode = lookup_mode(res, output->modes[0]); 224428d7b3dSmrg 225428d7b3dSmrg for (j = 0; mode && j < 2*output->ncrtc; j++) { 226428d7b3dSmrg int c = j; 227428d7b3dSmrg if (c >= output->ncrtc) 228428d7b3dSmrg c = 2*output->ncrtc - j - 1; 229428d7b3dSmrg 230428d7b3dSmrg printf("[%d, %d] -- OUTPUT:%ld, CRTC:%ld\n", 231428d7b3dSmrg i, c, (long)res->outputs[i], (long)output->crtcs[c]); 232428d7b3dSmrg last_msc = check_msc(dpy, root, last_msc); 233428d7b3dSmrg XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime, 234428d7b3dSmrg 0, 0, output->modes[0], RR_Rotate_0, &res->outputs[i], 1); 235428d7b3dSmrg last_msc = check_msc(dpy, root, last_msc); 236428d7b3dSmrg 237428d7b3dSmrg run(dpy, mode->width, mode->height, attachments, 1, "fullscreen"); 238428d7b3dSmrg run(dpy, mode->width, mode->height, attachments, 2, "fullscreen (with front)"); 239428d7b3dSmrg 240428d7b3dSmrg run(dpy, mode->width/2, mode->height/2, attachments, 1, "windowed"); 241428d7b3dSmrg run(dpy, mode->width/2, mode->height/2, attachments, 2, "windowed (with front)"); 242428d7b3dSmrg 243428d7b3dSmrg last_msc = check_msc(dpy, root, last_msc); 244428d7b3dSmrg XRRSetCrtcConfig(dpy, res, output->crtcs[c], CurrentTime, 245428d7b3dSmrg 0, 0, None, RR_Rotate_0, NULL, 0); 246428d7b3dSmrg last_msc = check_msc(dpy, root, last_msc); 247428d7b3dSmrg } 248428d7b3dSmrg 249428d7b3dSmrg XRRFreeOutputInfo(output); 250428d7b3dSmrg } 251428d7b3dSmrg 252428d7b3dSmrg for (i = 0; i < res->ncrtc; i++) 253428d7b3dSmrg XRRSetCrtcConfig(dpy, res, res->crtcs[i], CurrentTime, 254428d7b3dSmrg original_crtc[i]->x, 255428d7b3dSmrg original_crtc[i]->y, 256428d7b3dSmrg original_crtc[i]->mode, 257428d7b3dSmrg original_crtc[i]->rotation, 258428d7b3dSmrg original_crtc[i]->outputs, 259428d7b3dSmrg original_crtc[i]->noutput); 260428d7b3dSmrg return 0; 261428d7b3dSmrg} 262