1/* 2 * Copyright (c) 2014 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 */ 24 25#include <X11/Xlib.h> 26#include <X11/Xlib-xcb.h> 27#include <X11/xshmfence.h> 28#include <xcb/xcb.h> 29#include <xcb/dri3.h> 30#include <xcb/sync.h> 31#include <unistd.h> 32#include <stdlib.h> 33 34#include "dri3.h" 35 36Pixmap dri3_create_pixmap(Display *dpy, 37 Drawable draw, 38 int width, int height, int depth, 39 int fd, int bpp, int stride, int size) 40{ 41 xcb_connection_t *c = XGetXCBConnection(dpy); 42 if (fd >= 0) { 43 xcb_pixmap_t pixmap = xcb_generate_id(c); 44 xcb_dri3_pixmap_from_buffer(c, pixmap, draw, size, width, height, stride, depth, bpp, fd); 45 return pixmap; 46 } 47 return 0; 48} 49 50int dri3_create_fd(Display *dpy, 51 Pixmap pixmap, 52 int *stride) 53{ 54 xcb_connection_t *c = XGetXCBConnection(dpy); 55 xcb_dri3_buffer_from_pixmap_cookie_t cookie; 56 xcb_dri3_buffer_from_pixmap_reply_t *reply; 57 58 cookie = xcb_dri3_buffer_from_pixmap(c, pixmap); 59 reply = xcb_dri3_buffer_from_pixmap_reply(c, cookie, NULL); 60 if (!reply) 61 return -1; 62 63 if (reply->nfd != 1) 64 return -1; 65 66 *stride = reply->stride; 67 return xcb_dri3_buffer_from_pixmap_reply_fds(c, reply)[0]; 68} 69 70int dri3_create_fence(Display *dpy, Pixmap pixmap, struct dri3_fence *fence) 71{ 72 xcb_connection_t *c = XGetXCBConnection(dpy); 73 struct dri3_fence f; 74 int fd; 75 76 fd = xshmfence_alloc_shm(); 77 if (fd < 0) 78 return -1; 79 80 f.addr = xshmfence_map_shm(fd); 81 if (f.addr == NULL) { 82 close(fd); 83 return -1; 84 } 85 86 f.xid = xcb_generate_id(c); 87 xcb_dri3_fence_from_fd(c, pixmap, f.xid, 0, fd); 88 89 *fence = f; 90 return 0; 91} 92 93void dri3_fence_sync(Display *dpy, struct dri3_fence *fence) 94{ 95 xcb_connection_t *c = XGetXCBConnection(dpy); 96 97 xshmfence_reset(fence->addr); 98 99 xcb_sync_trigger_fence(c, fence->xid); 100 xcb_flush(c); 101 102 xshmfence_await(fence->addr); 103} 104 105void dri3_fence_free(Display *dpy, struct dri3_fence *fence) 106{ 107 xcb_connection_t *c = XGetXCBConnection(dpy); 108 109 xshmfence_unmap_shm(fence->addr); 110 xcb_sync_destroy_fence(c, fence->xid); 111} 112 113static void dri3_query_version(xcb_connection_t *c, int *major, int *minor) 114{ 115 xcb_dri3_query_version_reply_t *reply; 116 117 reply = xcb_dri3_query_version_reply(c, 118 xcb_dri3_query_version(c, 119 XCB_DRI3_MAJOR_VERSION, 120 XCB_DRI3_MINOR_VERSION), 121 NULL); 122 if (reply != NULL) { 123 *major = reply->major_version; 124 *minor = reply->minor_version; 125 free(reply); 126 } 127} 128 129static int dri3_exists(xcb_connection_t *c) 130{ 131 const xcb_query_extension_reply_t *ext; 132 int major, minor; 133 134 major = minor = -1; 135 136 ext = xcb_get_extension_data(c, &xcb_dri3_id); 137 if (ext != NULL && ext->present) 138 dri3_query_version(c, &major, &minor); 139 140 return major >= 0; 141} 142 143int dri3_open__full(Display *dpy, Window root, unsigned provider) 144{ 145 xcb_connection_t *c = XGetXCBConnection(dpy); 146 xcb_dri3_open_cookie_t cookie; 147 xcb_dri3_open_reply_t *reply; 148 149 if (!dri3_exists(c)) 150 return -1; 151 152 cookie = xcb_dri3_open(c, root, provider); 153 reply = xcb_dri3_open_reply(c, cookie, NULL); 154 155 if (!reply) 156 return -1; 157 158 if (reply->nfd != 1) 159 return -1; 160 161 return xcb_dri3_open_reply_fds(c, reply)[0]; 162} 163 164int dri3_open(Display *dpy) 165{ 166 return dri3_open__full(dpy, RootWindow(dpy, DefaultScreen(dpy)), None); 167} 168