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 407 if (pdraw == NULL) { 408 ErrorMessageF("failed to create drawable\n"); 409 return NULL; 410 } 411 412 if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) { 413 (*pdraw->destroyDrawable) (pdraw); 414 return NULL; 415 } 416 pdraw->refcount = 1; 417 418 return pdraw; 419} 420 421_X_HIDDEN void 422driReleaseDrawables(struct glx_context *gc) 423{ 424 const struct glx_display *priv = gc->psc->display; 425 __GLXDRIdrawable *pdraw; 426 427 if (priv == NULL) 428 return; 429 430 if (__glxHashLookup(priv->drawHash, 431 gc->currentDrawable, (void *) &pdraw) == 0) { 432 if (pdraw->drawable == pdraw->xDrawable) { 433 pdraw->refcount --; 434 if (pdraw->refcount == 0) { 435 (*pdraw->destroyDrawable)(pdraw); 436 __glxHashDelete(priv->drawHash, gc->currentDrawable); 437 } 438 } 439 } 440 441 if (__glxHashLookup(priv->drawHash, 442 gc->currentReadable, (void *) &pdraw) == 0) { 443 if (pdraw->drawable == pdraw->xDrawable) { 444 pdraw->refcount --; 445 if (pdraw->refcount == 0) { 446 (*pdraw->destroyDrawable)(pdraw); 447 __glxHashDelete(priv->drawHash, gc->currentReadable); 448 } 449 } 450 } 451 452 gc->currentDrawable = None; 453 gc->currentReadable = None; 454 455} 456 457_X_HIDDEN bool 458dri2_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs, 459 unsigned *major_ver, unsigned *minor_ver, 460 uint32_t *flags, unsigned *api, int *reset, 461 unsigned *error) 462{ 463 unsigned i; 464 bool got_profile = false; 465 uint32_t profile; 466 int render_type = GLX_RGBA_TYPE; 467 468 if (num_attribs == 0) { 469 *api = __DRI_API_OPENGL; 470 return true; 471 } 472 473 /* This is actually an internal error, but what the heck. 474 */ 475 if (attribs == NULL) { 476 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 477 return false; 478 } 479 480 *major_ver = 1; 481 *minor_ver = 0; 482 *reset = __DRI_CTX_RESET_NO_NOTIFICATION; 483 484 for (i = 0; i < num_attribs; i++) { 485 switch (attribs[i * 2]) { 486 case GLX_CONTEXT_MAJOR_VERSION_ARB: 487 *major_ver = attribs[i * 2 + 1]; 488 break; 489 case GLX_CONTEXT_MINOR_VERSION_ARB: 490 *minor_ver = attribs[i * 2 + 1]; 491 break; 492 case GLX_CONTEXT_FLAGS_ARB: 493 *flags = attribs[i * 2 + 1]; 494 break; 495 case GLX_CONTEXT_PROFILE_MASK_ARB: 496 profile = attribs[i * 2 + 1]; 497 got_profile = true; 498 break; 499 case GLX_RENDER_TYPE: 500 render_type = attribs[i * 2 + 1]; 501 break; 502 case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB: 503 switch (attribs[i * 2 + 1]) { 504 case GLX_NO_RESET_NOTIFICATION_ARB: 505 *reset = __DRI_CTX_RESET_NO_NOTIFICATION; 506 break; 507 case GLX_LOSE_CONTEXT_ON_RESET_ARB: 508 *reset = __DRI_CTX_RESET_LOSE_CONTEXT; 509 break; 510 default: 511 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 512 return false; 513 } 514 break; 515 default: 516 /* If an unknown attribute is received, fail. 517 */ 518 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 519 return false; 520 } 521 } 522 523 *api = __DRI_API_OPENGL; 524 if (!got_profile) { 525 if (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2)) 526 *api = __DRI_API_OPENGL_CORE; 527 } else { 528 switch (profile) { 529 case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: 530 /* There are no profiles before OpenGL 3.2. The 531 * GLX_ARB_create_context_profile spec says: 532 * 533 * "If the requested OpenGL version is less than 3.2, 534 * GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality 535 * of the context is determined solely by the requested version." 536 */ 537 *api = (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2)) 538 ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL; 539 break; 540 case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: 541 *api = __DRI_API_OPENGL; 542 break; 543 case GLX_CONTEXT_ES2_PROFILE_BIT_EXT: 544 *api = __DRI_API_GLES2; 545 break; 546 default: 547 *error = __DRI_CTX_ERROR_BAD_API; 548 return false; 549 } 550 } 551 552 /* Unknown flag value. 553 */ 554 if (*flags & ~(__DRI_CTX_FLAG_DEBUG | __DRI_CTX_FLAG_FORWARD_COMPATIBLE 555 | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)) { 556 *error = __DRI_CTX_ERROR_UNKNOWN_FLAG; 557 return false; 558 } 559 560 /* There are no forward-compatible contexts before OpenGL 3.0. The 561 * GLX_ARB_create_context spec says: 562 * 563 * "Forward-compatible contexts are defined only for OpenGL versions 564 * 3.0 and later." 565 */ 566 if (*major_ver < 3 && (*flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) { 567 *error = __DRI_CTX_ERROR_BAD_FLAG; 568 return false; 569 } 570 571 if (*major_ver >= 3 && render_type == GLX_COLOR_INDEX_TYPE) { 572 *error = __DRI_CTX_ERROR_BAD_FLAG; 573 return false; 574 } 575 576 /* The GLX_EXT_create_context_es2_profile spec says: 577 * 578 * "... If the version requested is 2.0, and the 579 * GLX_CONTEXT_ES2_PROFILE_BIT_EXT bit is set in the 580 * GLX_CONTEXT_PROFILE_MASK_ARB attribute (see below), then the context 581 * returned will implement OpenGL ES 2.0. This is the only way in which 582 * an implementation may request an OpenGL ES 2.0 context." 583 */ 584 if (*api == __DRI_API_GLES2 && (*major_ver != 2 || *minor_ver != 0)) { 585 *error = __DRI_CTX_ERROR_BAD_API; 586 return false; 587 } 588 589 *error = __DRI_CTX_ERROR_SUCCESS; 590 return true; 591} 592 593#endif /* GLX_DIRECT_RENDERING */ 594