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