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 (at) precisioninsight.com> 32 * Brian Paul <brian (at) precisioninsight.com> 33 * Kristian Hgsberg (krh (at) 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 45 #ifndef RTLD_NOW 46 #define RTLD_NOW 0 47 #endif 48 #ifndef RTLD_GLOBAL 49 #define RTLD_GLOBAL 0 50 #endif 51 52 _X_HIDDEN void 53 dri_message(int level, const char *f, ...) 54 { 55 va_list args; 56 int threshold = _LOADER_WARNING; 57 const char *libgl_debug; 58 59 libgl_debug = getenv("LIBGL_DEBUG"); 60 if (libgl_debug) { 61 if (strstr(libgl_debug, "quiet")) 62 threshold = _LOADER_FATAL; 63 else if (strstr(libgl_debug, "verbose")) 64 threshold = _LOADER_DEBUG; 65 } 66 67 /* Note that the _LOADER_* levels are lower numbers for more severe. */ 68 if (level <= threshold) { 69 fprintf(stderr, "libGL%s: ", level <= _LOADER_WARNING ? " error" : ""); 70 va_start(args, f); 71 vfprintf(stderr, f, args); 72 va_end(args); 73 } 74 } 75 76 #ifndef GL_LIB_NAME 77 #define GL_LIB_NAME "libGL.so.1" 78 #endif 79 80 #ifndef DEFAULT_DRIVER_DIR 81 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */ 82 #define DEFAULT_DRIVER_DIR "/usr/local/lib/dri" 83 #endif 84 85 /** 86 * Try to \c dlopen the named driver. 87 * 88 * This function adds the "_dri.so" suffix to the driver name and searches the 89 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in 90 * order to find the driver. 91 * 92 * \param driverName - a name like "i965", "radeon", "nouveau", etc. 93 * 94 * \returns 95 * A handle from \c dlopen, or \c NULL if driver file not found. 96 */ 97 _X_HIDDEN void * 98 driOpenDriver(const char *driverName) 99 { 100 void *glhandle, *handle; 101 const char *libPaths, *p, *next; 102 char realDriverName[200]; 103 int len; 104 105 /* Attempt to make sure libGL symbols will be visible to the driver */ 106 glhandle = dlopen(GL_LIB_NAME, RTLD_NOW | RTLD_GLOBAL); 107 108 libPaths = NULL; 109 if (geteuid() == getuid()) { 110 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */ 111 libPaths = getenv("LIBGL_DRIVERS_PATH"); 112 if (!libPaths) 113 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */ 114 } 115 if (libPaths == NULL) 116 libPaths = DEFAULT_DRIVER_DIR; 117 118 handle = NULL; 119 for (p = libPaths; *p; p = next) { 120 next = strchr(p, ':'); 121 if (next == NULL) { 122 len = strlen(p); 123 next = p + len; 124 } 125 else { 126 len = next - p; 127 next++; 128 } 129 130 #ifdef GLX_USE_TLS 131 snprintf(realDriverName, sizeof realDriverName, 132 "%.*s/tls/%s_dri.so", len, p, driverName); 133 InfoMessageF("OpenDriver: trying %s\n", realDriverName); 134 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); 135 #endif 136 137 if (handle == NULL) { 138 snprintf(realDriverName, sizeof realDriverName, 139 "%.*s/%s_dri.so", len, p, driverName); 140 InfoMessageF("OpenDriver: trying %s\n", realDriverName); 141 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); 142 } 143 144 if (handle != NULL) 145 break; 146 else 147 InfoMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror()); 148 } 149 150 if (!handle) 151 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName); 152 153 if (glhandle) 154 dlclose(glhandle); 155 156 return handle; 157 } 158 159 _X_HIDDEN const __DRIextension ** 160 driGetDriverExtensions(void *handle, const char *driver_name) 161 { 162 const __DRIextension **extensions = NULL; 163 const __DRIextension **(*get_extensions)(void); 164 char *get_extensions_name = loader_get_extensions_name(driver_name); 165 166 if (get_extensions_name) { 167 get_extensions = dlsym(handle, get_extensions_name); 168 if (get_extensions) { 169 free(get_extensions_name); 170 return get_extensions(); 171 } else { 172 InfoMessageF("driver does not expose %s(): %s\n", 173 get_extensions_name, dlerror()); 174 free(get_extensions_name); 175 } 176 } 177 178 extensions = dlsym(handle, __DRI_DRIVER_EXTENSIONS); 179 if (extensions == NULL) { 180 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 181 return NULL; 182 } 183 184 return extensions; 185 } 186 187 static GLboolean 188 __driGetMSCRate(__DRIdrawable *draw, 189 int32_t * numerator, int32_t * denominator, 190 void *loaderPrivate) 191 { 192 __GLXDRIdrawable *glxDraw = loaderPrivate; 193 194 return __glxGetMscRate(glxDraw->psc, numerator, denominator); 195 } 196 197 _X_HIDDEN const __DRIsystemTimeExtension systemTimeExtension = { 198 .base = {__DRI_SYSTEM_TIME, 1 }, 199 200 .getUST = __glXGetUST, 201 .getMSCRate = __driGetMSCRate 202 }; 203 204 #define __ATTRIB(attrib, field) \ 205 { attrib, offsetof(struct glx_config, field) } 206 207 static const struct 208 { 209 unsigned int attrib, offset; 210 } attribMap[] = { 211 __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits), 212 __ATTRIB(__DRI_ATTRIB_LEVEL, level), 213 __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits), 214 __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits), 215 __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits), 216 __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits), 217 __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits), 218 __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits), 219 __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits), 220 __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits), 221 __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits), 222 __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits), 223 __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers), 224 __ATTRIB(__DRI_ATTRIB_SAMPLES, samples), 225 __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode), 226 __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode), 227 __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers), 228 #if 0 229 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel), 230 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentIndex), 231 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed), 232 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen), 233 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue), 234 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha), 235 __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask), 236 __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask), 237 __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask), 238 __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask), 239 #endif 240 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth), 241 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight), 242 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels), 243 __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth), 244 __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight), 245 #if 0 246 __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod), 247 #endif 248 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb), 249 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba), 250 __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, 251 bindToMipmapTexture), 252 __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted), 253 __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable) 254 }; 255 256 static int 257 scalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value) 258 { 259 unsigned glxValue, i; 260 261 for (i = 0; i < ARRAY_SIZE(attribMap); i++) 262 if (attribMap[i].attrib == attrib) { 263 glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset); 264 return glxValue == GLX_DONT_CARE || glxValue == value; 265 } 266 267 return GL_TRUE; /* Is a non-existing attribute equal to value? */ 268 } 269 270 static int 271 driConfigEqual(const __DRIcoreExtension *core, 272 struct glx_config *config, const __DRIconfig *driConfig) 273 { 274 unsigned int attrib, value, glxValue; 275 int i; 276 277 i = 0; 278 while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) { 279 switch (attrib) { 280 case __DRI_ATTRIB_RENDER_TYPE: 281 glxValue = 0; 282 if (value & __DRI_ATTRIB_RGBA_BIT) { 283 glxValue |= GLX_RGBA_BIT; 284 } 285 if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) { 286 glxValue |= GLX_COLOR_INDEX_BIT; 287 } 288 if (value & __DRI_ATTRIB_FLOAT_BIT) { 289 glxValue |= GLX_RGBA_FLOAT_BIT_ARB; 290 } 291 if (value & __DRI_ATTRIB_UNSIGNED_FLOAT_BIT) { 292 glxValue |= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT; 293 } 294 if (glxValue != config->renderType) 295 return GL_FALSE; 296 break; 297 298 case __DRI_ATTRIB_CONFIG_CAVEAT: 299 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) 300 glxValue = GLX_NON_CONFORMANT_CONFIG; 301 else if (value & __DRI_ATTRIB_SLOW_BIT) 302 glxValue = GLX_SLOW_CONFIG; 303 else 304 glxValue = GLX_NONE; 305 if (glxValue != config->visualRating) 306 return GL_FALSE; 307 break; 308 309 case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS: 310 glxValue = 0; 311 if (value & __DRI_ATTRIB_TEXTURE_1D_BIT) 312 glxValue |= GLX_TEXTURE_1D_BIT_EXT; 313 if (value & __DRI_ATTRIB_TEXTURE_2D_BIT) 314 glxValue |= GLX_TEXTURE_2D_BIT_EXT; 315 if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT) 316 glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT; 317 if (config->bindToTextureTargets != GLX_DONT_CARE && 318 glxValue != config->bindToTextureTargets) 319 return GL_FALSE; 320 break; 321 322 default: 323 if (!scalarEqual(config, attrib, value)) 324 return GL_FALSE; 325 } 326 } 327 328 return GL_TRUE; 329 } 330 331 static struct glx_config * 332 createDriMode(const __DRIcoreExtension * core, 333 struct glx_config *config, const __DRIconfig **driConfigs) 334 { 335 __GLXDRIconfigPrivate *driConfig; 336 int i; 337 338 for (i = 0; driConfigs[i]; i++) { 339 if (driConfigEqual(core, config, driConfigs[i])) 340 break; 341 } 342 343 if (driConfigs[i] == NULL) 344 return NULL; 345 346 driConfig = malloc(sizeof *driConfig); 347 if (driConfig == NULL) 348 return NULL; 349 350 driConfig->base = *config; 351 driConfig->driConfig = driConfigs[i]; 352 353 return &driConfig->base; 354 } 355 356 _X_HIDDEN struct glx_config * 357 driConvertConfigs(const __DRIcoreExtension * core, 358 struct glx_config *configs, const __DRIconfig **driConfigs) 359 { 360 struct glx_config head, *tail, *m; 361 362 tail = &head; 363 head.next = NULL; 364 for (m = configs; m; m = m->next) { 365 tail->next = createDriMode(core, m, driConfigs); 366 if (tail->next == NULL) { 367 /* no matching dri config for m */ 368 continue; 369 } 370 371 372 tail = tail->next; 373 } 374 375 return head.next; 376 } 377 378 _X_HIDDEN void 379 driDestroyConfigs(const __DRIconfig **configs) 380 { 381 int i; 382 383 for (i = 0; configs[i]; i++) 384 free((__DRIconfig *) configs[i]); 385 free(configs); 386 } 387 388 _X_HIDDEN __GLXDRIdrawable * 389 driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable) 390 { 391 struct glx_display *const priv = __glXInitialize(gc->psc->dpy); 392 __GLXDRIdrawable *pdraw; 393 struct glx_screen *psc; 394 395 if (priv == NULL) 396 return NULL; 397 398 if (glxDrawable == None) 399 return NULL; 400 401 psc = priv->screens[gc->screen]; 402 if (priv->drawHash == NULL) 403 return NULL; 404 405 if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) { 406 pdraw->refcount ++; 407 return pdraw; 408 } 409 410 pdraw = psc->driScreen->createDrawable(psc, glxDrawable, 411 glxDrawable, gc->config); 412 413 if (pdraw == NULL) { 414 ErrorMessageF("failed to create drawable\n"); 415 return NULL; 416 } 417 418 if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) { 419 (*pdraw->destroyDrawable) (pdraw); 420 return NULL; 421 } 422 pdraw->refcount = 1; 423 424 return pdraw; 425 } 426 427 _X_HIDDEN void 428 driReleaseDrawables(struct glx_context *gc) 429 { 430 const struct glx_display *priv = gc->psc->display; 431 __GLXDRIdrawable *pdraw; 432 433 if (priv == NULL) 434 return; 435 436 if (__glxHashLookup(priv->drawHash, 437 gc->currentDrawable, (void *) &pdraw) == 0) { 438 if (pdraw->drawable == pdraw->xDrawable) { 439 pdraw->refcount --; 440 if (pdraw->refcount == 0) { 441 (*pdraw->destroyDrawable)(pdraw); 442 __glxHashDelete(priv->drawHash, gc->currentDrawable); 443 } 444 } 445 } 446 447 if (__glxHashLookup(priv->drawHash, 448 gc->currentReadable, (void *) &pdraw) == 0) { 449 if (pdraw->drawable == pdraw->xDrawable) { 450 pdraw->refcount --; 451 if (pdraw->refcount == 0) { 452 (*pdraw->destroyDrawable)(pdraw); 453 __glxHashDelete(priv->drawHash, gc->currentReadable); 454 } 455 } 456 } 457 458 gc->currentDrawable = None; 459 gc->currentReadable = None; 460 461 } 462 463 _X_HIDDEN bool 464 dri2_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs, 465 unsigned *major_ver, unsigned *minor_ver, 466 uint32_t *render_type, uint32_t *flags, unsigned *api, 467 int *reset, unsigned *error) 468 { 469 unsigned i; 470 bool got_profile = false; 471 uint32_t profile; 472 473 *major_ver = 1; 474 *minor_ver = 0; 475 *render_type = GLX_RGBA_TYPE; 476 *reset = __DRI_CTX_RESET_NO_NOTIFICATION; 477 *flags = 0; 478 *api = __DRI_API_OPENGL; 479 480 if (num_attribs == 0) { 481 return true; 482 } 483 484 /* This is actually an internal error, but what the heck. 485 */ 486 if (attribs == NULL) { 487 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 488 return false; 489 } 490 491 for (i = 0; i < num_attribs; i++) { 492 switch (attribs[i * 2]) { 493 case GLX_CONTEXT_MAJOR_VERSION_ARB: 494 *major_ver = attribs[i * 2 + 1]; 495 break; 496 case GLX_CONTEXT_MINOR_VERSION_ARB: 497 *minor_ver = attribs[i * 2 + 1]; 498 break; 499 case GLX_CONTEXT_FLAGS_ARB: 500 *flags = attribs[i * 2 + 1]; 501 break; 502 case GLX_CONTEXT_PROFILE_MASK_ARB: 503 profile = attribs[i * 2 + 1]; 504 got_profile = true; 505 break; 506 case GLX_RENDER_TYPE: 507 *render_type = attribs[i * 2 + 1]; 508 break; 509 case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB: 510 switch (attribs[i * 2 + 1]) { 511 case GLX_NO_RESET_NOTIFICATION_ARB: 512 *reset = __DRI_CTX_RESET_NO_NOTIFICATION; 513 break; 514 case GLX_LOSE_CONTEXT_ON_RESET_ARB: 515 *reset = __DRI_CTX_RESET_LOSE_CONTEXT; 516 break; 517 default: 518 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 519 return false; 520 } 521 break; 522 default: 523 /* If an unknown attribute is received, fail. 524 */ 525 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 526 return false; 527 } 528 } 529 530 if (!got_profile) { 531 if (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2)) 532 *api = __DRI_API_OPENGL_CORE; 533 } else { 534 switch (profile) { 535 case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: 536 /* There are no profiles before OpenGL 3.2. The 537 * GLX_ARB_create_context_profile spec says: 538 * 539 * "If the requested OpenGL version is less than 3.2, 540 * GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality 541 * of the context is determined solely by the requested version." 542 */ 543 *api = (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2)) 544 ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL; 545 break; 546 case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: 547 *api = __DRI_API_OPENGL; 548 break; 549 case GLX_CONTEXT_ES_PROFILE_BIT_EXT: 550 if (*major_ver >= 3) 551 *api = __DRI_API_GLES3; 552 else if (*major_ver == 2 && *minor_ver == 0) 553 *api = __DRI_API_GLES2; 554 else if (*major_ver == 1 && *minor_ver < 2) 555 *api = __DRI_API_GLES; 556 else { 557 *error = __DRI_CTX_ERROR_BAD_API; 558 return false; 559 } 560 break; 561 default: 562 *error = __DRI_CTX_ERROR_BAD_API; 563 return false; 564 } 565 } 566 567 /* Unknown flag value. 568 */ 569 if (*flags & ~(__DRI_CTX_FLAG_DEBUG | __DRI_CTX_FLAG_FORWARD_COMPATIBLE 570 | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)) { 571 *error = __DRI_CTX_ERROR_UNKNOWN_FLAG; 572 return false; 573 } 574 575 /* There are no forward-compatible contexts before OpenGL 3.0. The 576 * GLX_ARB_create_context spec says: 577 * 578 * "Forward-compatible contexts are defined only for OpenGL versions 579 * 3.0 and later." 580 */ 581 if (*major_ver < 3 && (*flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) { 582 *error = __DRI_CTX_ERROR_BAD_FLAG; 583 return false; 584 } 585 586 if (*major_ver >= 3 && *render_type == GLX_COLOR_INDEX_TYPE) { 587 *error = __DRI_CTX_ERROR_BAD_FLAG; 588 return false; 589 } 590 591 *error = __DRI_CTX_ERROR_SUCCESS; 592 return true; 593 } 594 595 #endif /* GLX_DIRECT_RENDERING */ 596