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