1/* 2 * Mesa 3-D graphics library 3 * Version: 7.8 4 * 5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 */ 25 26#include <unistd.h> 27#include <fcntl.h> 28#include <sys/types.h> 29#include <sys/stat.h> 30#include <xf86drm.h> 31#include <X11/Xlibint.h> 32#include <X11/extensions/XShm.h> 33 34#include "util/u_memory.h" 35#include "egllog.h" 36 37#include "x11_screen.h" 38#include "dri2.h" 39#include "glxinit.h" 40 41struct x11_screen { 42 Display *dpy; 43 int number; 44 45 /* 46 * This is used to fetch GLX visuals/fbconfigs. It steals code from GLX. 47 * It might be better to rewrite the part in Xlib or XCB. 48 */ 49 __GLXdisplayPrivate *glx_dpy; 50 51 int dri_major, dri_minor; 52 char *dri_driver; 53 char *dri_device; 54 int dri_fd; 55 56 x11_drawable_invalidate_buffers dri_invalidate_buffers; 57 void *dri_user_data; 58 59 XVisualInfo *visuals; 60 int num_visuals; 61 62 /* cached values for x11_drawable_get_depth */ 63 Drawable last_drawable; 64 unsigned int last_depth; 65}; 66 67 68/** 69 * Create a X11 screen. 70 */ 71struct x11_screen * 72x11_screen_create(Display *dpy, int screen) 73{ 74 struct x11_screen *xscr; 75 76 if (screen >= ScreenCount(dpy)) 77 return NULL; 78 79 xscr = CALLOC_STRUCT(x11_screen); 80 if (xscr) { 81 xscr->dpy = dpy; 82 xscr->number = screen; 83 84 xscr->dri_major = -1; 85 xscr->dri_fd = -1; 86 } 87 return xscr; 88} 89 90/** 91 * Destroy a X11 screen. 92 */ 93void 94x11_screen_destroy(struct x11_screen *xscr) 95{ 96 if (xscr->dri_fd >= 0) 97 close(xscr->dri_fd); 98 if (xscr->dri_driver) 99 Xfree(xscr->dri_driver); 100 if (xscr->dri_device) 101 Xfree(xscr->dri_device); 102 103#ifdef GLX_DIRECT_RENDERING 104 /* xscr->glx_dpy will be destroyed with the X display */ 105 if (xscr->glx_dpy) 106 xscr->glx_dpy->xscr = NULL; 107#endif 108 109 if (xscr->visuals) 110 XFree(xscr->visuals); 111 FREE(xscr); 112} 113 114#ifdef GLX_DIRECT_RENDERING 115 116static boolean 117x11_screen_init_dri2(struct x11_screen *xscr) 118{ 119 if (xscr->dri_major < 0) { 120 int eventBase, errorBase; 121 122 if (!DRI2QueryExtension(xscr->dpy, &eventBase, &errorBase) || 123 !DRI2QueryVersion(xscr->dpy, &xscr->dri_major, &xscr->dri_minor)) 124 xscr->dri_major = -1; 125 } 126 return (xscr->dri_major >= 0); 127} 128 129static boolean 130x11_screen_init_glx(struct x11_screen *xscr) 131{ 132 if (!xscr->glx_dpy) 133 xscr->glx_dpy = __glXInitialize(xscr->dpy); 134 return (xscr->glx_dpy != NULL); 135} 136 137#endif /* GLX_DIRECT_RENDERING */ 138 139/** 140 * Return true if the screen supports the extension. 141 */ 142boolean 143x11_screen_support(struct x11_screen *xscr, enum x11_screen_extension ext) 144{ 145 boolean supported = FALSE; 146 147 switch (ext) { 148 case X11_SCREEN_EXTENSION_XSHM: 149 supported = XShmQueryExtension(xscr->dpy); 150 break; 151#ifdef GLX_DIRECT_RENDERING 152 case X11_SCREEN_EXTENSION_GLX: 153 supported = x11_screen_init_glx(xscr); 154 break; 155 case X11_SCREEN_EXTENSION_DRI2: 156 supported = x11_screen_init_dri2(xscr); 157 break; 158#endif 159 default: 160 break; 161 } 162 163 return supported; 164} 165 166/** 167 * Return the X visuals. 168 */ 169const XVisualInfo * 170x11_screen_get_visuals(struct x11_screen *xscr, int *num_visuals) 171{ 172 if (!xscr->visuals) { 173 XVisualInfo vinfo_template; 174 vinfo_template.screen = xscr->number; 175 xscr->visuals = XGetVisualInfo(xscr->dpy, VisualScreenMask, 176 &vinfo_template, &xscr->num_visuals); 177 } 178 179 if (num_visuals) 180 *num_visuals = xscr->num_visuals; 181 return xscr->visuals; 182} 183 184/** 185 * Return the depth of a drawable. 186 * 187 * Unlike other drawable functions, the drawable needs not be a DRI2 drawable. 188 */ 189uint 190x11_drawable_get_depth(struct x11_screen *xscr, Drawable drawable) 191{ 192 unsigned int depth; 193 194 if (drawable != xscr->last_drawable) { 195 Window root; 196 int x, y; 197 unsigned int w, h, border; 198 Status ok; 199 200 ok = XGetGeometry(xscr->dpy, drawable, &root, 201 &x, &y, &w, &h, &border, &depth); 202 if (!ok) 203 depth = 0; 204 205 xscr->last_drawable = drawable; 206 xscr->last_depth = depth; 207 } 208 else { 209 depth = xscr->last_depth; 210 } 211 212 return depth; 213} 214 215#ifdef GLX_DIRECT_RENDERING 216 217/** 218 * Return the GLX fbconfigs. 219 */ 220const __GLcontextModes * 221x11_screen_get_glx_configs(struct x11_screen *xscr) 222{ 223 return (x11_screen_init_glx(xscr)) 224 ? xscr->glx_dpy->screenConfigs[xscr->number]->configs 225 : NULL; 226} 227 228/** 229 * Probe the screen for the DRI2 driver name. 230 */ 231const char * 232x11_screen_probe_dri2(struct x11_screen *xscr, int *major, int *minor) 233{ 234 if (!x11_screen_init_dri2(xscr)) 235 return NULL; 236 237 /* get the driver name and the device name */ 238 if (!xscr->dri_driver) { 239 if (!DRI2Connect(xscr->dpy, RootWindow(xscr->dpy, xscr->number), 240 &xscr->dri_driver, &xscr->dri_device)) 241 xscr->dri_driver = xscr->dri_device = NULL; 242 } 243 if (major) 244 *major = xscr->dri_major; 245 if (minor) 246 *minor = xscr->dri_minor; 247 248 return xscr->dri_driver; 249} 250 251/** 252 * Enable DRI2 and returns the file descriptor of the DRM device. The file 253 * descriptor will be closed automatically when the screen is destoryed. 254 */ 255int 256x11_screen_enable_dri2(struct x11_screen *xscr, 257 x11_drawable_invalidate_buffers invalidate_buffers, 258 void *user_data) 259{ 260 if (xscr->dri_fd < 0) { 261 int fd; 262 drm_magic_t magic; 263 264 /* get the driver name and the device name first */ 265 if (!x11_screen_probe_dri2(xscr, NULL, NULL)) 266 return -1; 267 268#ifdef O_CLOEXEC 269 fd = open(xscr->dri_device, O_RDWR | O_CLOEXEC); 270 if (fd == -1 && errno == EINVAL) 271#endif 272 { 273 fd = open(xscr->dri_device, O_RDWR); 274 if (fd != -1) 275 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 276 } 277 if (fd < 0) { 278 _eglLog(_EGL_WARNING, "failed to open %s", xscr->dri_device); 279 return -1; 280 } 281 282 memset(&magic, 0, sizeof(magic)); 283 if (drmGetMagic(fd, &magic)) { 284 _eglLog(_EGL_WARNING, "failed to get magic"); 285 close(fd); 286 return -1; 287 } 288 289 if (!DRI2Authenticate(xscr->dpy, 290 RootWindow(xscr->dpy, xscr->number), magic)) { 291 _eglLog(_EGL_WARNING, "failed to authenticate magic"); 292 close(fd); 293 return -1; 294 } 295 296 if (!x11_screen_init_glx(xscr)) { 297 _eglLog(_EGL_WARNING, "failed to initialize GLX"); 298 close(fd); 299 return -1; 300 } 301 if (xscr->glx_dpy->xscr) { 302 _eglLog(_EGL_WARNING, 303 "display is already managed by another x11 screen"); 304 close(fd); 305 return -1; 306 } 307 308 xscr->glx_dpy->xscr = xscr; 309 xscr->dri_invalidate_buffers = invalidate_buffers; 310 xscr->dri_user_data = user_data; 311 312 xscr->dri_fd = fd; 313 } 314 315 return xscr->dri_fd; 316} 317 318char * 319x11_screen_get_device_name(struct x11_screen *xscr) 320{ 321 return xscr->dri_device; 322} 323 324int 325x11_screen_authenticate(struct x11_screen *xscr, uint32_t id) 326{ 327 boolean authenticated; 328 329 authenticated = DRI2Authenticate(xscr->dpy, 330 RootWindow(xscr->dpy, xscr->number), id); 331 332 return authenticated ? 0 : -1; 333} 334 335/** 336 * Create/Destroy the DRI drawable. 337 */ 338void 339x11_drawable_enable_dri2(struct x11_screen *xscr, 340 Drawable drawable, boolean on) 341{ 342 if (on) 343 DRI2CreateDrawable(xscr->dpy, drawable); 344 else 345 DRI2DestroyDrawable(xscr->dpy, drawable); 346} 347 348/** 349 * Copy between buffers of the DRI2 drawable. 350 */ 351void 352x11_drawable_copy_buffers_region(struct x11_screen *xscr, Drawable drawable, 353 int num_rects, const int *rects, 354 int src_buf, int dst_buf) 355{ 356 XserverRegion region; 357 XRectangle *rectangles = CALLOC(num_rects, sizeof(XRectangle)); 358 359 for (int i = 0; i < num_rects; i++) { 360 rectangles[i].x = rects[i * 4 + 0]; 361 rectangles[i].y = rects[i * 4 + 1]; 362 rectangles[i].width = rects[i * 4 + 2]; 363 rectangles[i].height = rects[i * 4 + 3]; 364 } 365 366 region = XFixesCreateRegion(xscr->dpy, rectangles, num_rects); 367 DRI2CopyRegion(xscr->dpy, drawable, region, dst_buf, src_buf); 368 XFixesDestroyRegion(xscr->dpy, region); 369 FREE(rectangles); 370} 371 372/** 373 * Get the buffers of the DRI2 drawable. The returned array should be freed. 374 */ 375struct x11_drawable_buffer * 376x11_drawable_get_buffers(struct x11_screen *xscr, Drawable drawable, 377 int *width, int *height, unsigned int *attachments, 378 boolean with_format, int num_ins, int *num_outs) 379{ 380 DRI2Buffer *dri2bufs; 381 382 if (with_format) 383 dri2bufs = DRI2GetBuffersWithFormat(xscr->dpy, drawable, width, height, 384 attachments, num_ins, num_outs); 385 else 386 dri2bufs = DRI2GetBuffers(xscr->dpy, drawable, width, height, 387 attachments, num_ins, num_outs); 388 389 return (struct x11_drawable_buffer *) dri2bufs; 390} 391 392/** 393 * Create a mode list of the given size. 394 */ 395__GLcontextModes * 396x11_context_modes_create(unsigned count) 397{ 398 const size_t size = sizeof(__GLcontextModes); 399 __GLcontextModes *base = NULL; 400 __GLcontextModes **next; 401 unsigned i; 402 403 next = &base; 404 for (i = 0; i < count; i++) { 405 *next = (__GLcontextModes *) CALLOC(1, size); 406 if (*next == NULL) { 407 x11_context_modes_destroy(base); 408 base = NULL; 409 break; 410 } 411 next = &((*next)->next); 412 } 413 414 return base; 415} 416 417/** 418 * Destroy a mode list. 419 */ 420void 421x11_context_modes_destroy(__GLcontextModes *modes) 422{ 423 while (modes != NULL) { 424 __GLcontextModes *next = modes->next; 425 FREE(modes); 426 modes = next; 427 } 428} 429 430/** 431 * Return the number of the modes in the mode list. 432 */ 433unsigned 434x11_context_modes_count(const __GLcontextModes *modes) 435{ 436 const __GLcontextModes *mode; 437 int count = 0; 438 for (mode = modes; mode; mode = mode->next) 439 count++; 440 return count; 441} 442 443extern void 444dri2InvalidateBuffers(Display *dpy, XID drawable); 445 446/** 447 * This is called from src/glx/dri2.c. 448 */ 449void 450dri2InvalidateBuffers(Display *dpy, XID drawable) 451{ 452 __GLXdisplayPrivate *priv = __glXInitialize(dpy); 453 struct x11_screen *xscr = NULL; 454 455 if (priv && priv->xscr) 456 xscr = priv->xscr; 457 if (!xscr || !xscr->dri_invalidate_buffers) 458 return; 459 460 xscr->dri_invalidate_buffers(xscr, drawable, xscr->dri_user_data); 461} 462 463extern unsigned 464dri2GetSwapEventType(Display *dpy, XID drawable); 465 466extern void * 467dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id); 468 469extern void * 470GetGLXDrawable(Display *dpy, XID drawable); 471 472/** 473 * This is also called from src/glx/dri2.c. 474 */ 475unsigned dri2GetSwapEventType(Display *dpy, XID drawable) 476{ 477 return 0; 478} 479 480void * 481dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 482{ 483 return NULL; 484} 485 486void * 487GetGLXDrawable(Display *dpy, XID drawable) 488{ 489 return NULL; 490} 491 492#endif /* GLX_DIRECT_RENDERING */ 493