x11_screen.c revision 87290a383be2eeffef4407eeb17c1070d1122b2f
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#ifdef GLX_DIRECT_RENDERING 43 /* dummy base class */ 44 struct __GLXDRIdisplayRec base; 45#endif 46 47 Display *dpy; 48 int number; 49 50 /* 51 * This is used to fetch GLX visuals/fbconfigs. It steals code from GLX. 52 * It might be better to rewrite the part in Xlib or XCB. 53 */ 54 __GLXdisplayPrivate *glx_dpy; 55 56 int dri_major, dri_minor; 57 char *dri_driver; 58 char *dri_device; 59 int dri_fd; 60 61 x11_drawable_invalidate_buffers dri_invalidate_buffers; 62 void *dri_user_data; 63 64 XVisualInfo *visuals; 65 int num_visuals; 66 67 /* cached values for x11_drawable_get_depth */ 68 Drawable last_drawable; 69 unsigned int last_depth; 70}; 71 72 73/** 74 * Create a X11 screen. 75 */ 76struct x11_screen * 77x11_screen_create(Display *dpy, int screen) 78{ 79 struct x11_screen *xscr; 80 81 if (screen >= ScreenCount(dpy)) 82 return NULL; 83 84 xscr = CALLOC_STRUCT(x11_screen); 85 if (xscr) { 86 xscr->dpy = dpy; 87 xscr->number = screen; 88 89 xscr->dri_major = -1; 90 xscr->dri_fd = -1; 91 } 92 return xscr; 93} 94 95/** 96 * Destroy a X11 screen. 97 */ 98void 99x11_screen_destroy(struct x11_screen *xscr) 100{ 101 if (xscr->dri_fd >= 0) 102 close(xscr->dri_fd); 103 if (xscr->dri_driver) 104 Xfree(xscr->dri_driver); 105 if (xscr->dri_device) 106 Xfree(xscr->dri_device); 107 108#ifdef GLX_DIRECT_RENDERING 109 /* xscr->glx_dpy will be destroyed with the X display */ 110 if (xscr->glx_dpy) 111 xscr->glx_dpy->dri2Display = NULL; 112#endif 113 114 if (xscr->visuals) 115 XFree(xscr->visuals); 116 FREE(xscr); 117} 118 119#ifdef GLX_DIRECT_RENDERING 120 121static boolean 122x11_screen_init_dri2(struct x11_screen *xscr) 123{ 124 if (xscr->dri_major < 0) { 125 int eventBase, errorBase; 126 127 if (!DRI2QueryExtension(xscr->dpy, &eventBase, &errorBase) || 128 !DRI2QueryVersion(xscr->dpy, &xscr->dri_major, &xscr->dri_minor)) 129 xscr->dri_major = -1; 130 } 131 return (xscr->dri_major >= 0); 132} 133 134static boolean 135x11_screen_init_glx(struct x11_screen *xscr) 136{ 137 if (!xscr->glx_dpy) 138 xscr->glx_dpy = __glXInitialize(xscr->dpy); 139 return (xscr->glx_dpy != NULL); 140} 141 142#endif /* GLX_DIRECT_RENDERING */ 143 144/** 145 * Return true if the screen supports the extension. 146 */ 147boolean 148x11_screen_support(struct x11_screen *xscr, enum x11_screen_extension ext) 149{ 150 boolean supported = FALSE; 151 152 switch (ext) { 153 case X11_SCREEN_EXTENSION_XSHM: 154 supported = XShmQueryExtension(xscr->dpy); 155 break; 156#ifdef GLX_DIRECT_RENDERING 157 case X11_SCREEN_EXTENSION_GLX: 158 supported = x11_screen_init_glx(xscr); 159 break; 160 case X11_SCREEN_EXTENSION_DRI2: 161 supported = x11_screen_init_dri2(xscr); 162 break; 163#endif 164 default: 165 break; 166 } 167 168 return supported; 169} 170 171/** 172 * Return the X visuals. 173 */ 174const XVisualInfo * 175x11_screen_get_visuals(struct x11_screen *xscr, int *num_visuals) 176{ 177 if (!xscr->visuals) { 178 XVisualInfo vinfo_template; 179 vinfo_template.screen = xscr->number; 180 xscr->visuals = XGetVisualInfo(xscr->dpy, VisualScreenMask, 181 &vinfo_template, &xscr->num_visuals); 182 } 183 184 if (num_visuals) 185 *num_visuals = xscr->num_visuals; 186 return xscr->visuals; 187} 188 189/** 190 * Return the depth of a drawable. 191 * 192 * Unlike other drawable functions, the drawable needs not be a DRI2 drawable. 193 */ 194uint 195x11_drawable_get_depth(struct x11_screen *xscr, Drawable drawable) 196{ 197 unsigned int depth; 198 199 if (drawable != xscr->last_drawable) { 200 Window root; 201 int x, y; 202 unsigned int w, h, border; 203 Status ok; 204 205 ok = XGetGeometry(xscr->dpy, drawable, &root, 206 &x, &y, &w, &h, &border, &depth); 207 if (!ok) 208 depth = 0; 209 210 xscr->last_drawable = drawable; 211 xscr->last_depth = depth; 212 } 213 else { 214 depth = xscr->last_depth; 215 } 216 217 return depth; 218} 219 220#ifdef GLX_DIRECT_RENDERING 221 222/** 223 * Return the GLX fbconfigs. 224 */ 225const __GLcontextModes * 226x11_screen_get_glx_configs(struct x11_screen *xscr) 227{ 228 return (x11_screen_init_glx(xscr)) 229 ? xscr->glx_dpy->screenConfigs[xscr->number]->configs 230 : NULL; 231} 232 233/** 234 * Return the GLX visuals. 235 */ 236const __GLcontextModes * 237x11_screen_get_glx_visuals(struct x11_screen *xscr) 238{ 239 return (x11_screen_init_glx(xscr)) 240 ? xscr->glx_dpy->screenConfigs[xscr->number]->visuals 241 : NULL; 242} 243 244/** 245 * Probe the screen for the DRI2 driver name. 246 */ 247const char * 248x11_screen_probe_dri2(struct x11_screen *xscr, int *major, int *minor) 249{ 250 if (!x11_screen_init_dri2(xscr)) 251 return NULL; 252 253 /* get the driver name and the device name */ 254 if (!xscr->dri_driver) { 255 if (!DRI2Connect(xscr->dpy, RootWindow(xscr->dpy, xscr->number), 256 &xscr->dri_driver, &xscr->dri_device)) 257 xscr->dri_driver = xscr->dri_device = NULL; 258 } 259 if (major) 260 *major = xscr->dri_major; 261 if (minor) 262 *minor = xscr->dri_minor; 263 264 return xscr->dri_driver; 265} 266 267/** 268 * Enable DRI2 and returns the file descriptor of the DRM device. The file 269 * descriptor will be closed automatically when the screen is destoryed. 270 */ 271int 272x11_screen_enable_dri2(struct x11_screen *xscr, 273 x11_drawable_invalidate_buffers invalidate_buffers, 274 void *user_data) 275{ 276 if (xscr->dri_fd < 0) { 277 int fd; 278 drm_magic_t magic; 279 280 /* get the driver name and the device name first */ 281 if (!x11_screen_probe_dri2(xscr, NULL, NULL)) 282 return -1; 283 284 fd = open(xscr->dri_device, O_RDWR); 285 if (fd < 0) { 286 _eglLog(_EGL_WARNING, "failed to open %s", xscr->dri_device); 287 return -1; 288 } 289 290 memset(&magic, 0, sizeof(magic)); 291 if (drmGetMagic(fd, &magic)) { 292 _eglLog(_EGL_WARNING, "failed to get magic"); 293 close(fd); 294 return -1; 295 } 296 297 if (!DRI2Authenticate(xscr->dpy, 298 RootWindow(xscr->dpy, xscr->number), magic)) { 299 _eglLog(_EGL_WARNING, "failed to authenticate magic"); 300 close(fd); 301 return -1; 302 } 303 304 if (!x11_screen_init_glx(xscr)) { 305 _eglLog(_EGL_WARNING, "failed to initialize GLX"); 306 close(fd); 307 return -1; 308 } 309 if (xscr->glx_dpy->dri2Display) { 310 _eglLog(_EGL_WARNING, 311 "display is already managed by another x11 screen"); 312 close(fd); 313 return -1; 314 } 315 316 xscr->glx_dpy->dri2Display = (__GLXDRIdisplay *) xscr; 317 xscr->dri_invalidate_buffers = invalidate_buffers; 318 xscr->dri_user_data = user_data; 319 320 xscr->dri_fd = fd; 321 } 322 323 return xscr->dri_fd; 324} 325 326/** 327 * Create/Destroy the DRI drawable. 328 */ 329void 330x11_drawable_enable_dri2(struct x11_screen *xscr, 331 Drawable drawable, boolean on) 332{ 333 if (on) 334 DRI2CreateDrawable(xscr->dpy, drawable); 335 else 336 DRI2DestroyDrawable(xscr->dpy, drawable); 337} 338 339/** 340 * Copy between buffers of the DRI2 drawable. 341 */ 342void 343x11_drawable_copy_buffers(struct x11_screen *xscr, Drawable drawable, 344 int x, int y, int width, int height, 345 int src_buf, int dst_buf) 346{ 347 XRectangle rect; 348 XserverRegion region; 349 350 rect.x = x; 351 rect.y = y; 352 rect.width = width; 353 rect.height = height; 354 355 region = XFixesCreateRegion(xscr->dpy, &rect, 1); 356 DRI2CopyRegion(xscr->dpy, drawable, region, dst_buf, src_buf); 357 XFixesDestroyRegion(xscr->dpy, region); 358} 359 360/** 361 * Get the buffers of the DRI2 drawable. The returned array should be freed. 362 */ 363struct x11_drawable_buffer * 364x11_drawable_get_buffers(struct x11_screen *xscr, Drawable drawable, 365 int *width, int *height, unsigned int *attachments, 366 boolean with_format, int num_ins, int *num_outs) 367{ 368 DRI2Buffer *dri2bufs; 369 370 if (with_format) 371 dri2bufs = DRI2GetBuffersWithFormat(xscr->dpy, drawable, width, height, 372 attachments, num_ins, num_outs); 373 else 374 dri2bufs = DRI2GetBuffers(xscr->dpy, drawable, width, height, 375 attachments, num_ins, num_outs); 376 377 return (struct x11_drawable_buffer *) dri2bufs; 378} 379 380/** 381 * Create a mode list of the given size. 382 */ 383__GLcontextModes * 384x11_context_modes_create(unsigned count) 385{ 386 const size_t size = sizeof(__GLcontextModes); 387 __GLcontextModes *base = NULL; 388 __GLcontextModes **next; 389 unsigned i; 390 391 next = &base; 392 for (i = 0; i < count; i++) { 393 *next = (__GLcontextModes *) CALLOC(1, size); 394 if (*next == NULL) { 395 x11_context_modes_destroy(base); 396 base = NULL; 397 break; 398 } 399 next = &((*next)->next); 400 } 401 402 return base; 403} 404 405/** 406 * Destroy a mode list. 407 */ 408void 409x11_context_modes_destroy(__GLcontextModes *modes) 410{ 411 while (modes != NULL) { 412 __GLcontextModes *next = modes->next; 413 FREE(modes); 414 modes = next; 415 } 416} 417 418/** 419 * Return the number of the modes in the mode list. 420 */ 421unsigned 422x11_context_modes_count(const __GLcontextModes *modes) 423{ 424 const __GLcontextModes *mode; 425 int count = 0; 426 for (mode = modes; mode; mode = mode->next) 427 count++; 428 return count; 429} 430 431/** 432 * This is called from src/glx/dri2.c. 433 */ 434void 435dri2InvalidateBuffers(Display *dpy, XID drawable) 436{ 437 __GLXdisplayPrivate *priv = __glXInitialize(dpy); 438 struct x11_screen *xscr = NULL; 439 440 if (priv && priv->dri2Display) 441 xscr = (struct x11_screen *) priv->dri2Display; 442 if (!xscr || !xscr->dri_invalidate_buffers) 443 return; 444 445 xscr->dri_invalidate_buffers(xscr, drawable, xscr->dri_user_data); 446} 447 448#endif /* GLX_DIRECT_RENDERING */ 449