1 /* 2 * Mesa 3-D graphics library 3 * Version: 7.8 4 * 5 * Copyright (C) 2009-2010 Chia-I Wu <olv (at) 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 41 struct 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 */ 71 struct x11_screen * 72 x11_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 */ 93 void 94 x11_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 116 static boolean 117 x11_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 129 static boolean 130 x11_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 */ 142 boolean 143 x11_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 */ 169 const XVisualInfo * 170 x11_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 */ 189 uint 190 x11_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 */ 220 const __GLcontextModes * 221 x11_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 */ 231 const char * 232 x11_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 */ 255 int 256 x11_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 318 char * 319 x11_screen_get_device_name(struct x11_screen *xscr) 320 { 321 return xscr->dri_device; 322 } 323 324 int 325 x11_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 */ 338 void 339 x11_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 */ 351 void 352 x11_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 */ 375 struct x11_drawable_buffer * 376 x11_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 * 396 x11_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 */ 420 void 421 x11_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 */ 433 unsigned 434 x11_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 443 extern void 444 dri2InvalidateBuffers(Display *dpy, XID drawable); 445 446 /** 447 * This is called from src/glx/dri2.c. 448 */ 449 void 450 dri2InvalidateBuffers(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 463 extern unsigned 464 dri2GetSwapEventType(Display *dpy, XID drawable); 465 466 extern void * 467 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id); 468 469 extern void * 470 GetGLXDrawable(Display *dpy, XID drawable); 471 472 /** 473 * This is also called from src/glx/dri2.c. 474 */ 475 unsigned dri2GetSwapEventType(Display *dpy, XID drawable) 476 { 477 return 0; 478 } 479 480 void * 481 dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 482 { 483 return NULL; 484 } 485 486 void * 487 GetGLXDrawable(Display *dpy, XID drawable) 488 { 489 return NULL; 490 } 491 492 #endif /* GLX_DIRECT_RENDERING */ 493