1/* 2 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 3 * Copyright © 2008 Red Hat, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Soft- 7 * ware"), to deal in the Software without restriction, including without 8 * limitation the rights to use, copy, modify, merge, publish, distribute, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, provided that the above copyright 11 * notice(s) and this permission notice appear in all copies of the Soft- 12 * ware and that both the above copyright notice(s) and this permission 13 * notice appear in supporting documentation. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 17 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 18 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 19 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 20 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 23 * MANCE OF THIS SOFTWARE. 24 * 25 * Except as contained in this notice, the name of a copyright holder shall 26 * not be used in advertising or otherwise to promote the sale, use or 27 * other dealings in this Software without prior written authorization of 28 * the copyright holder. 29 * 30 * Authors: 31 * Kevin E. Martin <kevin@precisioninsight.com> 32 * Brian Paul <brian@precisioninsight.com> 33 * Kristian Høgsberg (krh@redhat.com) 34 */ 35 36#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 37 38#include <unistd.h> 39#include <dlfcn.h> 40#include <stdarg.h> 41#include "glxclient.h" 42#include "dri_common.h" 43#include "loader.h" 44#include <X11/Xlib-xcb.h> 45#include <xcb/xproto.h> 46 47#ifndef RTLD_NOW 48#define RTLD_NOW 0 49#endif 50#ifndef RTLD_GLOBAL 51#define RTLD_GLOBAL 0 52#endif 53 54#ifndef GL_LIB_NAME 55#define GL_LIB_NAME "libGL.so.1" 56#endif 57 58/** 59 * Try to \c dlopen the named driver. 60 * 61 * This function adds the "_dri.so" suffix to the driver name and searches the 62 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in 63 * order to find the driver. 64 * 65 * \param driverName - a name like "i965", "radeon", "nouveau", etc. 66 * \param out_driver_handle - Address to return the resulting dlopen() handle. 67 * 68 * \returns 69 * The __DRIextension entrypoint table for the driver, or \c NULL if driver 70 * file not found. 71 */ 72_X_HIDDEN const __DRIextension ** 73driOpenDriver(const char *driverName, void **out_driver_handle) 74{ 75 void *glhandle; 76 77 /* Attempt to make sure libGL symbols will be visible to the driver */ 78 glhandle = dlopen(GL_LIB_NAME, RTLD_NOW | RTLD_GLOBAL); 79 80 static const char *search_path_vars[] = { 81 "LIBGL_DRIVERS_PATH", 82 "LIBGL_DRIVERS_DIR", /* deprecated */ 83 NULL 84 }; 85 86 const __DRIextension **extensions = 87 loader_open_driver(driverName, out_driver_handle, search_path_vars); 88 89 if (glhandle) 90 dlclose(glhandle); 91 92 return extensions; 93} 94 95#define __ATTRIB(attrib, field) \ 96 { attrib, offsetof(struct glx_config, field) } 97 98static const struct 99{ 100 unsigned int attrib, offset; 101} attribMap[] = { 102 __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits), 103 __ATTRIB(__DRI_ATTRIB_LEVEL, level), 104 __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits), 105 __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits), 106 __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits), 107 __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits), 108 __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits), 109 __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits), 110 __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits), 111 __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits), 112 __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits), 113 __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits), 114 __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers), 115 __ATTRIB(__DRI_ATTRIB_SAMPLES, samples), 116 __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode), 117 __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode), 118 __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers), 119 __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod), 120 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb), 121 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba), 122 __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture), 123 __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted), 124 __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable) 125}; 126 127static int 128scalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value) 129{ 130 unsigned glxValue, i; 131 132 for (i = 0; i < ARRAY_SIZE(attribMap); i++) 133 if (attribMap[i].attrib == attrib) { 134 glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset); 135 return glxValue == GLX_DONT_CARE || glxValue == value; 136 } 137 138 return GL_TRUE; /* Is a non-existing attribute equal to value? */ 139} 140 141static int 142driConfigEqual(const __DRIcoreExtension *core, 143 struct glx_config *config, const __DRIconfig *driConfig) 144{ 145 unsigned int attrib, value, glxValue; 146 int i; 147 148 i = 0; 149 while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) { 150 switch (attrib) { 151 case __DRI_ATTRIB_RENDER_TYPE: 152 glxValue = 0; 153 if (value & __DRI_ATTRIB_RGBA_BIT) { 154 glxValue |= GLX_RGBA_BIT; 155 } 156 if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) { 157 glxValue |= GLX_COLOR_INDEX_BIT; 158 } 159 if (value & __DRI_ATTRIB_FLOAT_BIT) { 160 glxValue |= GLX_RGBA_FLOAT_BIT_ARB; 161 } 162 if (value & __DRI_ATTRIB_UNSIGNED_FLOAT_BIT) { 163 glxValue |= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT; 164 } 165 if (glxValue != config->renderType) 166 return GL_FALSE; 167 break; 168 169 case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS: 170 glxValue = 0; 171 if (value & __DRI_ATTRIB_TEXTURE_1D_BIT) 172 glxValue |= GLX_TEXTURE_1D_BIT_EXT; 173 if (value & __DRI_ATTRIB_TEXTURE_2D_BIT) 174 glxValue |= GLX_TEXTURE_2D_BIT_EXT; 175 if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT) 176 glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT; 177 if (config->bindToTextureTargets != GLX_DONT_CARE && 178 glxValue != config->bindToTextureTargets) 179 return GL_FALSE; 180 break; 181 182 case __DRI_ATTRIB_SWAP_METHOD: 183 if (value == __DRI_ATTRIB_SWAP_EXCHANGE) 184 glxValue = GLX_SWAP_EXCHANGE_OML; 185 else if (value == __DRI_ATTRIB_SWAP_COPY) 186 glxValue = GLX_SWAP_COPY_OML; 187 else 188 glxValue = GLX_SWAP_UNDEFINED_OML; 189 190 if (!scalarEqual(config, attrib, glxValue)) 191 return GL_FALSE; 192 193 break; 194 195 /* Nerf some attributes we can safely ignore if the server claims to 196 * support them but the driver does not. 197 */ 198 case __DRI_ATTRIB_CONFIG_CAVEAT: 199 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) 200 glxValue = GLX_NON_CONFORMANT_CONFIG; 201 else if (value & __DRI_ATTRIB_SLOW_BIT) 202 glxValue = GLX_SLOW_CONFIG; 203 else 204 glxValue = GLX_NONE; 205 if (glxValue != config->visualRating) { 206 if (config->visualRating == GLX_NONE) { 207 static int warned; 208 if (!warned) { 209 DebugMessageF("Not downgrading visual rating\n"); 210 warned = 1; 211 } 212 } else { 213 return GL_FALSE; 214 } 215 } 216 break; 217 218 case __DRI_ATTRIB_AUX_BUFFERS: 219 if (!scalarEqual(config, attrib, value)) { 220 static int warned; 221 if (!warned) { 222 DebugMessageF("Disabling server's aux buffer support\n"); 223 warned = 1; 224 } 225 config->numAuxBuffers = 0; 226 } 227 break; 228 229 case __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE: 230 if (!scalarEqual(config, attrib, value)) { 231 static int warned; 232 if (!warned) { 233 DebugMessageF("Disabling server's tfp mipmap support\n"); 234 warned = 1; 235 } 236 config->bindToMipmapTexture = 0; 237 } 238 break; 239 240 default: 241 if (!scalarEqual(config, attrib, value)) 242 return GL_FALSE; 243 } 244 } 245 246 return GL_TRUE; 247} 248 249static struct glx_config * 250createDriMode(const __DRIcoreExtension * core, 251 struct glx_config *config, const __DRIconfig **driConfigs) 252{ 253 __GLXDRIconfigPrivate *driConfig; 254 int i; 255 256 for (i = 0; driConfigs[i]; i++) { 257 if (driConfigEqual(core, config, driConfigs[i])) 258 break; 259 } 260 261 if (driConfigs[i] == NULL) 262 return NULL; 263 264 driConfig = malloc(sizeof *driConfig); 265 if (driConfig == NULL) 266 return NULL; 267 268 driConfig->base = *config; 269 driConfig->driConfig = driConfigs[i]; 270 271 return &driConfig->base; 272} 273 274_X_HIDDEN struct glx_config * 275driConvertConfigs(const __DRIcoreExtension * core, 276 struct glx_config *configs, const __DRIconfig **driConfigs) 277{ 278 struct glx_config head, *tail, *m; 279 280 tail = &head; 281 head.next = NULL; 282 for (m = configs; m; m = m->next) { 283 tail->next = createDriMode(core, m, driConfigs); 284 if (tail->next == NULL) { 285 /* no matching dri config for m */ 286 continue; 287 } 288 289 290 tail = tail->next; 291 } 292 293 return head.next; 294} 295 296_X_HIDDEN void 297driDestroyConfigs(const __DRIconfig **configs) 298{ 299 int i; 300 301 for (i = 0; configs[i]; i++) 302 free((__DRIconfig *) configs[i]); 303 free(configs); 304} 305 306static struct glx_config * 307driInferDrawableConfig(struct glx_screen *psc, GLXDrawable draw) 308{ 309 unsigned int fbconfig = 0; 310 xcb_get_window_attributes_cookie_t cookie = { 0 }; 311 xcb_get_window_attributes_reply_t *attr = NULL; 312 xcb_connection_t *conn = XGetXCBConnection(psc->dpy); 313 314 /* In practice here, either the XID is a bare Window or it was created 315 * by some other client. First let's see if the X server can tell us 316 * the answer. Xorg first added GLX_EXT_no_config_context in 1.20, where 317 * this usually works except for bare Windows that haven't been made 318 * current yet. 319 */ 320 if (__glXGetDrawableAttribute(psc->dpy, draw, GLX_FBCONFIG_ID, &fbconfig)) { 321 return glx_config_find_fbconfig(psc->configs, fbconfig); 322 } 323 324 /* Well this had better be a Window then. Figure out its visual and 325 * then find the corresponding GLX visual. 326 */ 327 cookie = xcb_get_window_attributes(conn, draw); 328 attr = xcb_get_window_attributes_reply(conn, cookie, NULL); 329 330 if (attr) { 331 uint32_t vid = attr->visual; 332 free(attr); 333 return glx_config_find_visual(psc->visuals, vid); 334 } 335 336 return NULL; 337} 338 339_X_HIDDEN __GLXDRIdrawable * 340driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable) 341{ 342 Display *dpy = gc->psc->dpy; 343 struct glx_display *const priv = __glXInitialize(dpy); 344 __GLXDRIdrawable *pdraw; 345 struct glx_screen *psc; 346 struct glx_config *config = gc->config; 347 unsigned int type; 348 349 if (priv == NULL) 350 return NULL; 351 352 if (glxDrawable == None) 353 return NULL; 354 355 psc = priv->screens[gc->screen]; 356 if (priv->drawHash == NULL) 357 return NULL; 358 359 if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) { 360 /* Resurrected, so remove from the alive-query-set if exist. */ 361 _mesa_set_remove_key(priv->zombieGLXDrawable, pdraw); 362 363 pdraw->refcount ++; 364 return pdraw; 365 } 366 367 /* if this is a no-config context, infer the fbconfig from the drawable */ 368 if (config == NULL) 369 config = driInferDrawableConfig(gc->psc, glxDrawable); 370 if (config == NULL) 371 return NULL; 372 373 /* We can't find this GLX drawable above because it's either: 374 * 375 * 1. An X window ID instead of a GLX window ID. This could happend when 376 * glXMakeCurrent() is passed an X window directly instead of creating 377 * GLXWindow with glXCreateWindow() first. 378 * 379 * 2. A GLXPbuffer created on other display: 380 * 381 * From the GLX spec: 382 * 383 * Like other drawable types, GLXPbuffers are shared; any client which 384 * knows the associated XID can use a GLXPbuffer. 385 * 386 * So client other than the creator of this GLXPbuffer could use its 387 * XID to do something like glXMakeCurrent(). I can't find explicite 388 * statement in GLX spec that also allow GLXWindow and GLXPixmap. 389 * 390 * But even GLXWindow and GLXPixmap is allowed, currently client other 391 * than the GLX drawable creator has no way to find which X drawable 392 * (window or pixmap) this GLX drawable uses, except the GLXPbuffer 393 * case which use the same XID for both X pixmap and GLX drawable. 394 */ 395 396 /* Infer the GLX drawable type. */ 397 if (__glXGetDrawableAttribute(dpy, glxDrawable, GLX_DRAWABLE_TYPE, &type)) { 398 /* Xserver may support query with raw X11 window. */ 399 if (type == GLX_PIXMAP_BIT) { 400 ErrorMessageF("GLXPixmap drawable type is not supported\n"); 401 return NULL; 402 } 403 } else { 404 /* Xserver may not implement GLX_DRAWABLE_TYPE query yet. */ 405 type = GLX_PBUFFER_BIT | GLX_WINDOW_BIT; 406 } 407 408 pdraw = psc->driScreen->createDrawable(psc, glxDrawable, glxDrawable, 409 type, config); 410 411 if (pdraw == NULL) { 412 ErrorMessageF("failed to create drawable\n"); 413 return NULL; 414 } 415 416 if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) { 417 (*pdraw->destroyDrawable) (pdraw); 418 return NULL; 419 } 420 /* This sure does look suspicious, doesn't it? We're on this path because 421 * this is a naked Window. GLX 1.3 drawables have an explicit creation 422 * step (setting refcount to 1), and those we would have found in the 423 * hash lookup above, bumped their refcount for the bind_context we're 424 * being called for, and then returned. But since we just created the 425 * internal naked-Window state, we need to account for both here. 426 */ 427 pdraw->refcount = 2; 428 429 return pdraw; 430} 431 432static int 433discardGLXBadDrawableHandler(Display *display, xError *err, XExtCodes *codes, 434 int *ret_code) 435{ 436 int code = codes->first_error + GLXBadDrawable; 437 438 /* Only discard error which is expected. */ 439 if (err->majorCode == codes->major_opcode && 440 err->minorCode == X_GLXGetDrawableAttributes && 441 /* newer xserver use GLXBadDrawable, old one use BadDrawable */ 442 (err->errorCode == code || err->errorCode == BadDrawable)) { 443 *ret_code = 1; 444 return 1; 445 } 446 447 return 0; 448} 449 450static void 451checkServerGLXDrawableAlive(const struct glx_display *priv) 452{ 453 ErrorType old = XESetError(priv->dpy, priv->codes.extension, 454 discardGLXBadDrawableHandler); 455 456 set_foreach(priv->zombieGLXDrawable, entry) { 457 __GLXDRIdrawable *pdraw = (__GLXDRIdrawable *)entry->key; 458 GLXDrawable drawable = pdraw->drawable; 459 unsigned int dummy; 460 461 /* Fail to query, so the window has been closed. Release the GLXDrawable. */ 462 if (!__glXGetDrawableAttribute(priv->dpy, drawable, GLX_WIDTH, &dummy)) { 463 pdraw->destroyDrawable(pdraw); 464 __glxHashDelete(priv->drawHash, drawable); 465 _mesa_set_remove(priv->zombieGLXDrawable, entry); 466 } 467 } 468 469 XESetError(priv->dpy, priv->codes.extension, old); 470} 471 472static void 473releaseDrawable(const struct glx_display *priv, GLXDrawable drawable) 474{ 475 __GLXDRIdrawable *pdraw; 476 477 if (__glxHashLookup(priv->drawHash, drawable, (void *) &pdraw) == 0) { 478 /* Only native window and pbuffer have same GLX and X11 drawable ID. */ 479 if (pdraw->drawable == pdraw->xDrawable) { 480 pdraw->refcount --; 481 /* If pbuffer's refcount reaches 0, it must be imported from other 482 * display. Because pbuffer created from this display will always 483 * hold the last refcount until destroy the GLXPbuffer object. 484 */ 485 if (pdraw->refcount == 0) { 486 if (pdraw->psc->keep_native_window_glx_drawable) { 487 checkServerGLXDrawableAlive(priv); 488 _mesa_set_add(priv->zombieGLXDrawable, pdraw); 489 } else { 490 pdraw->destroyDrawable(pdraw); 491 __glxHashDelete(priv->drawHash, drawable); 492 } 493 } 494 } 495 } 496} 497 498_X_HIDDEN void 499driReleaseDrawables(struct glx_context *gc) 500{ 501 const struct glx_display *priv = (gc && gc->psc) ? gc->psc->display : NULL; 502 503 if (priv == NULL) 504 return; 505 506 releaseDrawable(priv, gc->currentDrawable); 507 releaseDrawable(priv, gc->currentReadable); 508 509 gc->currentDrawable = None; 510 gc->currentReadable = None; 511 512} 513 514_X_HIDDEN int 515dri_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs, 516 struct dri_ctx_attribs *dca) 517{ 518 unsigned i; 519 uint32_t profile = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; 520 521 dca->major_ver = 1; 522 dca->minor_ver = 0; 523 dca->render_type = GLX_RGBA_TYPE; 524 dca->reset = __DRI_CTX_RESET_NO_NOTIFICATION; 525 dca->release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH; 526 dca->flags = 0; 527 dca->api = __DRI_API_OPENGL; 528 dca->no_error = 0; 529 530 if (num_attribs == 0) 531 return __DRI_CTX_ERROR_SUCCESS; 532 533 /* This is actually an internal error, but what the heck. */ 534 if (attribs == NULL) 535 return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 536 537 for (i = 0; i < num_attribs; i++) { 538 switch (attribs[i * 2]) { 539 case GLX_CONTEXT_MAJOR_VERSION_ARB: 540 dca->major_ver = attribs[i * 2 + 1]; 541 break; 542 case GLX_CONTEXT_MINOR_VERSION_ARB: 543 dca->minor_ver = attribs[i * 2 + 1]; 544 break; 545 case GLX_CONTEXT_FLAGS_ARB: 546 dca->flags = attribs[i * 2 + 1]; 547 break; 548 case GLX_CONTEXT_OPENGL_NO_ERROR_ARB: 549 dca->no_error = attribs[i * 2 + 1]; 550 break; 551 case GLX_CONTEXT_PROFILE_MASK_ARB: 552 profile = attribs[i * 2 + 1]; 553 break; 554 case GLX_RENDER_TYPE: 555 dca->render_type = attribs[i * 2 + 1]; 556 break; 557 case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB: 558 switch (attribs[i * 2 + 1]) { 559 case GLX_NO_RESET_NOTIFICATION_ARB: 560 dca->reset = __DRI_CTX_RESET_NO_NOTIFICATION; 561 break; 562 case GLX_LOSE_CONTEXT_ON_RESET_ARB: 563 dca->reset = __DRI_CTX_RESET_LOSE_CONTEXT; 564 break; 565 default: 566 return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 567 } 568 break; 569 case GLX_CONTEXT_RELEASE_BEHAVIOR_ARB: 570 switch (attribs[i * 2 + 1]) { 571 case GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB: 572 dca->release = __DRI_CTX_RELEASE_BEHAVIOR_NONE; 573 break; 574 case GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB: 575 dca->release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH; 576 break; 577 default: 578 return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 579 } 580 break; 581 case GLX_SCREEN: 582 /* Implies GLX_EXT_no_config_context */ 583 dca->render_type = GLX_DONT_CARE; 584 break; 585 default: 586 /* If an unknown attribute is received, fail. 587 */ 588 return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 589 } 590 } 591 592 switch (profile) { 593 case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: 594 /* This is the default value, but there are no profiles before OpenGL 595 * 3.2. The GLX_ARB_create_context_profile spec says: 596 * 597 * "If the requested OpenGL version is less than 3.2, 598 * GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality 599 * of the context is determined solely by the requested version." 600 */ 601 dca->api = (dca->major_ver > 3 || (dca->major_ver == 3 && dca->minor_ver >= 2)) 602 ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL; 603 break; 604 case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: 605 dca->api = __DRI_API_OPENGL; 606 break; 607 case GLX_CONTEXT_ES_PROFILE_BIT_EXT: 608 if (dca->major_ver >= 3) 609 dca->api = __DRI_API_GLES3; 610 else if (dca->major_ver == 2 && dca->minor_ver == 0) 611 dca->api = __DRI_API_GLES2; 612 else if (dca->major_ver == 1 && dca->minor_ver < 2) 613 dca->api = __DRI_API_GLES; 614 else { 615 return __DRI_CTX_ERROR_BAD_API; 616 } 617 break; 618 default: 619 return __DRI_CTX_ERROR_BAD_API; 620 } 621 622 /* Unknown flag value */ 623 if (dca->flags & ~(__DRI_CTX_FLAG_DEBUG | 624 __DRI_CTX_FLAG_FORWARD_COMPATIBLE | 625 __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS | 626 __DRI_CTX_FLAG_RESET_ISOLATION)) 627 return __DRI_CTX_ERROR_UNKNOWN_FLAG; 628 629 /* There are no forward-compatible contexts before OpenGL 3.0. The 630 * GLX_ARB_create_context spec says: 631 * 632 * "Forward-compatible contexts are defined only for OpenGL versions 633 * 3.0 and later." 634 */ 635 if (dca->major_ver < 3 && (dca->flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) 636 return __DRI_CTX_ERROR_BAD_FLAG; 637 638 if (dca->major_ver >= 3 && dca->render_type == GLX_COLOR_INDEX_TYPE) 639 return __DRI_CTX_ERROR_BAD_FLAG; 640 641 /* The KHR_no_error specs say: 642 * 643 * Requires OpenGL ES 2.0 or OpenGL 2.0. 644 */ 645 if (dca->no_error && dca->major_ver < 2) 646 return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 647 648 /* The GLX_ARB_create_context_no_error specs say: 649 * 650 * BadMatch is generated if the GLX_CONTEXT_OPENGL_NO_ERROR_ARB is TRUE at 651 * the same time as a debug or robustness context is specified. 652 * 653 */ 654 if (dca->no_error && ((dca->flags & __DRI_CTX_FLAG_DEBUG) || 655 (dca->flags & __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS))) 656 return __DRI_CTX_ERROR_BAD_FLAG; 657 658 return __DRI_CTX_ERROR_SUCCESS; 659} 660 661struct glx_context * 662dri_common_create_context(struct glx_screen *base, 663 struct glx_config *config_base, 664 struct glx_context *shareList, 665 int renderType) 666{ 667 unsigned int error; 668 uint32_t attribs[2] = { GLX_RENDER_TYPE, renderType }; 669 670 return base->vtable->create_context_attribs(base, config_base, shareList, 671 1, attribs, &error); 672} 673 674 675/* 676 * Given a display pointer and screen number, determine the name of 677 * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc). 678 * Return True for success, False for failure. 679 */ 680static Bool 681driGetDriverName(Display * dpy, int scrNum, char **driverName) 682{ 683 struct glx_screen *glx_screen = GetGLXScreenConfigs(dpy, scrNum); 684 685 if (!glx_screen || !glx_screen->vtable->get_driver_name) 686 return False; 687 688 *driverName = glx_screen->vtable->get_driver_name(glx_screen); 689 return True; 690} 691 692/* 693 * Exported function for querying the DRI driver for a given screen. 694 * 695 * The returned char pointer points to a static array that will be 696 * overwritten by subsequent calls. 697 */ 698_GLX_PUBLIC const char * 699glXGetScreenDriver(Display * dpy, int scrNum) 700{ 701 static char ret[32]; 702 char *driverName; 703 704 if (driGetDriverName(dpy, scrNum, &driverName)) { 705 int len; 706 if (!driverName) 707 return NULL; 708 len = strlen(driverName); 709 if (len >= 31) 710 return NULL; 711 memcpy(ret, driverName, len + 1); 712 free(driverName); 713 return ret; 714 } 715 return NULL; 716} 717 718/* glXGetDriverConfig must return a pointer with a static lifetime. To avoid 719 * keeping drivers loaded and other leaks, we keep a cache of results here that 720 * is cleared by an atexit handler. 721 */ 722struct driver_config_entry { 723 struct driver_config_entry *next; 724 char *driverName; 725 char *config; 726}; 727 728static pthread_mutex_t driver_config_mutex = PTHREAD_MUTEX_INITIALIZER; 729static struct driver_config_entry *driver_config_cache = NULL; 730 731/* Called as an atexit function. Otherwise, this would have to be called with 732 * driver_config_mutex locked. 733 */ 734static void 735clear_driver_config_cache() 736{ 737 while (driver_config_cache) { 738 struct driver_config_entry *e = driver_config_cache; 739 driver_config_cache = e->next; 740 741 free(e->driverName); 742 free(e->config); 743 free(e); 744 } 745} 746 747static char * 748get_driver_config(const char *driverName) 749{ 750 void *handle; 751 char *config = NULL; 752 const __DRIextension **extensions = driOpenDriver(driverName, &handle); 753 if (extensions) { 754 for (int i = 0; extensions[i]; i++) { 755 if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) != 0) 756 continue; 757 758 __DRIconfigOptionsExtension *ext = 759 (__DRIconfigOptionsExtension *)extensions[i]; 760 761 if (ext->base.version >= 2) 762 config = ext->getXml(driverName); 763 else 764 config = strdup(ext->xml); 765 766 break; 767 } 768 } 769 770 if (!config) { 771 /* Fall back to the old method */ 772 config = dlsym(handle, "__driConfigOptions"); 773 if (config) 774 config = strdup(config); 775 } 776 777 dlclose(handle); 778 779 return config; 780} 781 782/* 783 * Exported function for obtaining a driver's option list (UTF-8 encoded XML). 784 * 785 * The returned char pointer points directly into the driver. Therefore 786 * it should be treated as a constant. 787 * 788 * If the driver was not found or does not support configuration NULL is 789 * returned. 790 */ 791_GLX_PUBLIC const char * 792glXGetDriverConfig(const char *driverName) 793{ 794 struct driver_config_entry *e; 795 796 pthread_mutex_lock(&driver_config_mutex); 797 798 for (e = driver_config_cache; e; e = e->next) { 799 if (strcmp(e->driverName, driverName) == 0) 800 goto out; 801 } 802 803 e = malloc(sizeof(*e)); 804 if (!e) 805 goto out; 806 807 e->config = get_driver_config(driverName); 808 e->driverName = strdup(driverName); 809 if (!e->config || !e->driverName) { 810 free(e->config); 811 free(e->driverName); 812 free(e); 813 e = NULL; 814 goto out; 815 } 816 817 e->next = driver_config_cache; 818 driver_config_cache = e; 819 820 if (!e->next) 821 atexit(clear_driver_config_cache); 822 823out: 824 pthread_mutex_unlock(&driver_config_mutex); 825 826 return e ? e->config : NULL; 827} 828 829#endif /* GLX_DIRECT_RENDERING */ 830