x11_screen.c revision 95f9e118fe7b02ab5d28550dabd8751e5fb15e3c
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 fd = open(xscr->dri_device, O_RDWR); 269 if (fd < 0) { 270 _eglLog(_EGL_WARNING, "failed to open %s", xscr->dri_device); 271 return -1; 272 } 273 274 memset(&magic, 0, sizeof(magic)); 275 if (drmGetMagic(fd, &magic)) { 276 _eglLog(_EGL_WARNING, "failed to get magic"); 277 close(fd); 278 return -1; 279 } 280 281 if (!DRI2Authenticate(xscr->dpy, 282 RootWindow(xscr->dpy, xscr->number), magic)) { 283 _eglLog(_EGL_WARNING, "failed to authenticate magic"); 284 close(fd); 285 return -1; 286 } 287 288 if (!x11_screen_init_glx(xscr)) { 289 _eglLog(_EGL_WARNING, "failed to initialize GLX"); 290 close(fd); 291 return -1; 292 } 293 if (xscr->glx_dpy->xscr) { 294 _eglLog(_EGL_WARNING, 295 "display is already managed by another x11 screen"); 296 close(fd); 297 return -1; 298 } 299 300 xscr->glx_dpy->xscr = xscr; 301 xscr->dri_invalidate_buffers = invalidate_buffers; 302 xscr->dri_user_data = user_data; 303 304 xscr->dri_fd = fd; 305 } 306 307 return xscr->dri_fd; 308} 309 310char * 311x11_screen_get_device_name(struct x11_screen *xscr) 312{ 313 return xscr->dri_device; 314} 315 316int 317x11_screen_authenticate(struct x11_screen *xscr, uint32_t id) 318{ 319 boolean authenticated; 320 321 authenticated = DRI2Authenticate(xscr->dpy, 322 RootWindow(xscr->dpy, xscr->number), id); 323 324 return authenticated ? 0 : -1; 325} 326 327/** 328 * Create/Destroy the DRI drawable. 329 */ 330void 331x11_drawable_enable_dri2(struct x11_screen *xscr, 332 Drawable drawable, boolean on) 333{ 334 if (on) 335 DRI2CreateDrawable(xscr->dpy, drawable); 336 else 337 DRI2DestroyDrawable(xscr->dpy, drawable); 338} 339 340/** 341 * Copy between buffers of the DRI2 drawable. 342 */ 343void 344x11_drawable_copy_buffers(struct x11_screen *xscr, Drawable drawable, 345 int x, int y, int width, int height, 346 int src_buf, int dst_buf) 347{ 348 XRectangle rect; 349 XserverRegion region; 350 351 rect.x = x; 352 rect.y = y; 353 rect.width = width; 354 rect.height = height; 355 356 region = XFixesCreateRegion(xscr->dpy, &rect, 1); 357 DRI2CopyRegion(xscr->dpy, drawable, region, dst_buf, src_buf); 358 XFixesDestroyRegion(xscr->dpy, region); 359} 360 361/** 362 * Get the buffers of the DRI2 drawable. The returned array should be freed. 363 */ 364struct x11_drawable_buffer * 365x11_drawable_get_buffers(struct x11_screen *xscr, Drawable drawable, 366 int *width, int *height, unsigned int *attachments, 367 boolean with_format, int num_ins, int *num_outs) 368{ 369 DRI2Buffer *dri2bufs; 370 371 if (with_format) 372 dri2bufs = DRI2GetBuffersWithFormat(xscr->dpy, drawable, width, height, 373 attachments, num_ins, num_outs); 374 else 375 dri2bufs = DRI2GetBuffers(xscr->dpy, drawable, width, height, 376 attachments, num_ins, num_outs); 377 378 return (struct x11_drawable_buffer *) dri2bufs; 379} 380 381/** 382 * Create a mode list of the given size. 383 */ 384__GLcontextModes * 385x11_context_modes_create(unsigned count) 386{ 387 const size_t size = sizeof(__GLcontextModes); 388 __GLcontextModes *base = NULL; 389 __GLcontextModes **next; 390 unsigned i; 391 392 next = &base; 393 for (i = 0; i < count; i++) { 394 *next = (__GLcontextModes *) CALLOC(1, size); 395 if (*next == NULL) { 396 x11_context_modes_destroy(base); 397 base = NULL; 398 break; 399 } 400 next = &((*next)->next); 401 } 402 403 return base; 404} 405 406/** 407 * Destroy a mode list. 408 */ 409void 410x11_context_modes_destroy(__GLcontextModes *modes) 411{ 412 while (modes != NULL) { 413 __GLcontextModes *next = modes->next; 414 FREE(modes); 415 modes = next; 416 } 417} 418 419/** 420 * Return the number of the modes in the mode list. 421 */ 422unsigned 423x11_context_modes_count(const __GLcontextModes *modes) 424{ 425 const __GLcontextModes *mode; 426 int count = 0; 427 for (mode = modes; mode; mode = mode->next) 428 count++; 429 return count; 430} 431 432extern void 433dri2InvalidateBuffers(Display *dpy, XID drawable); 434 435/** 436 * This is called from src/glx/dri2.c. 437 */ 438void 439dri2InvalidateBuffers(Display *dpy, XID drawable) 440{ 441 __GLXdisplayPrivate *priv = __glXInitialize(dpy); 442 struct x11_screen *xscr = NULL; 443 444 if (priv && priv->xscr) 445 xscr = priv->xscr; 446 if (!xscr || !xscr->dri_invalidate_buffers) 447 return; 448 449 xscr->dri_invalidate_buffers(xscr, drawable, xscr->dri_user_data); 450} 451 452extern unsigned 453dri2GetSwapEventType(Display *dpy, XID drawable); 454 455extern void * 456dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id); 457 458extern void * 459GetGLXDrawable(Display *dpy, XID drawable); 460 461/** 462 * This is also called from src/glx/dri2.c. 463 */ 464unsigned dri2GetSwapEventType(Display *dpy, XID drawable) 465{ 466 return 0; 467} 468 469void * 470dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 471{ 472 return NULL; 473} 474 475void * 476GetGLXDrawable(Display *dpy, XID drawable) 477{ 478 return NULL; 479} 480 481#endif /* GLX_DIRECT_RENDERING */ 482