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