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