dri_common.c revision b45f77dc4c9662a774c19db764bb8f95c4f61073
1ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch/* 2ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 3ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * Copyright © 2008 Red Hat, Inc. 4ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * 5ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * Permission is hereby granted, free of charge, to any person obtaining a 6ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * copy of this software and associated documentation files (the "Soft- 7ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * ware"), to deal in the Software without restriction, including without 8ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * limitation the rights to use, copy, modify, merge, publish, distribute, 9ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * and/or sell copies of the Software, and to permit persons to whom the 10ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * Software is furnished to do so, provided that the above copyright 11ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * notice(s) and this permission notice appear in all copies of the Soft- 12ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * ware and that both the above copyright notice(s) and this permission 13ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * notice appear in supporting documentation. 14ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * 15ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 17ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 19ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 20ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 23ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * MANCE OF THIS SOFTWARE. 240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * 250f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * Except as contained in this notice, the name of a copyright holder shall 260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) * not be used in advertising or otherwise to promote the sale, use or 27ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * other dealings in this Software without prior written authorization of 28ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * the copyright holder. 29ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * 30ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * Authors: 31ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch * 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_X_HIDDEN void 52InfoMessageF(const char *f, ...) 53{ 54 va_list args; 55 const char *env; 56 57 if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) { 58 fprintf(stderr, "libGL: "); 59 va_start(args, f); 60 vfprintf(stderr, f, args); 61 va_end(args); 62 } 63} 64 65/** 66 * Print error to stderr, unless LIBGL_DEBUG=="quiet". 67 */ 68_X_HIDDEN void 69ErrorMessageF(const char *f, ...) 70{ 71 va_list args; 72 const char *env; 73 74 if ((env = getenv("LIBGL_DEBUG")) && !strstr(env, "quiet")) { 75 fprintf(stderr, "libGL error: "); 76 va_start(args, f); 77 vfprintf(stderr, f, args); 78 va_end(args); 79 } 80} 81 82#ifndef DEFAULT_DRIVER_DIR 83/* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */ 84#define DEFAULT_DRIVER_DIR "/usr/local/lib/dri" 85#endif 86 87/** 88 * Try to \c dlopen the named driver. 89 * 90 * This function adds the "_dri.so" suffix to the driver name and searches the 91 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in 92 * order to find the driver. 93 * 94 * \param driverName - a name like "i965", "radeon", "nouveau", etc. 95 * 96 * \returns 97 * A handle from \c dlopen, or \c NULL if driver file not found. 98 */ 99_X_HIDDEN void * 100driOpenDriver(const char *driverName) 101{ 102 void *glhandle, *handle; 103 const char *libPaths, *p, *next; 104 char realDriverName[200]; 105 int len; 106 107 /* Attempt to make sure libGL symbols will be visible to the driver */ 108 glhandle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL); 109 110 libPaths = NULL; 111 if (geteuid() == getuid()) { 112 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */ 113 libPaths = getenv("LIBGL_DRIVERS_PATH"); 114 if (!libPaths) 115 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */ 116 } 117 if (libPaths == NULL) 118 libPaths = DEFAULT_DRIVER_DIR; 119 120 handle = NULL; 121 for (p = libPaths; *p; p = next) { 122 next = strchr(p, ':'); 123 if (next == NULL) { 124 len = strlen(p); 125 next = p + len; 126 } 127 else { 128 len = next - p; 129 next++; 130 } 131 132#ifdef GLX_USE_TLS 133 snprintf(realDriverName, sizeof realDriverName, 134 "%.*s/tls/%s_dri.so", len, p, driverName); 135 InfoMessageF("OpenDriver: trying %s\n", realDriverName); 136 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); 137#endif 138 139 if (handle == NULL) { 140 snprintf(realDriverName, sizeof realDriverName, 141 "%.*s/%s_dri.so", len, p, driverName); 142 InfoMessageF("OpenDriver: trying %s\n", realDriverName); 143 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL); 144 } 145 146 if (handle != NULL) 147 break; 148 else 149 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror()); 150 } 151 152 if (!handle) 153 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName); 154 155 if (glhandle) 156 dlclose(glhandle); 157 158 return handle; 159} 160 161static GLboolean 162__driGetMSCRate(__DRIdrawable *draw, 163 int32_t * numerator, int32_t * denominator, 164 void *loaderPrivate) 165{ 166 __GLXDRIdrawable *glxDraw = loaderPrivate; 167 168 return __glxGetMscRate(glxDraw, numerator, denominator); 169} 170 171_X_HIDDEN const __DRIsystemTimeExtension systemTimeExtension = { 172 {__DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION}, 173 __glXGetUST, 174 __driGetMSCRate 175}; 176 177#define __ATTRIB(attrib, field) \ 178 { attrib, offsetof(struct glx_config, field) } 179 180static const struct 181{ 182 unsigned int attrib, offset; 183} attribMap[] = { 184 __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits), 185 __ATTRIB(__DRI_ATTRIB_LEVEL, level), 186 __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits), 187 __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits), 188 __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits), 189 __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits), 190 __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits), 191 __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits), 192 __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits), 193 __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits), 194 __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits), 195 __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits), 196 __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers), 197 __ATTRIB(__DRI_ATTRIB_SAMPLES, samples), 198 __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode), 199 __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode), 200 __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers), 201#if 0 202 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel), 203 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentIndex), 204 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed), 205 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen), 206 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue), 207 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha), 208 __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask), 209 __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask), 210 __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask), 211 __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask), 212#endif 213 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth), 214 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight), 215 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels), 216 __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth), 217 __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight), 218#if 0 219 __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod), 220#endif 221__ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb), 222 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba), 223 __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, 224 bindToMipmapTexture), 225 __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted), 226 __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable) 227}; 228 229static int 230scalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value) 231{ 232 unsigned int glxValue; 233 int i; 234 235 for (i = 0; i < ARRAY_SIZE(attribMap); i++) 236 if (attribMap[i].attrib == attrib) { 237 glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset); 238 return glxValue == GLX_DONT_CARE || glxValue == value; 239 } 240 241 return GL_TRUE; /* Is a non-existing attribute equal to value? */ 242} 243 244static int 245driConfigEqual(const __DRIcoreExtension *core, 246 struct glx_config *config, const __DRIconfig *driConfig) 247{ 248 unsigned int attrib, value, glxValue; 249 int i; 250 251 i = 0; 252 while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) { 253 switch (attrib) { 254 case __DRI_ATTRIB_RENDER_TYPE: 255 glxValue = 0; 256 if (value & __DRI_ATTRIB_RGBA_BIT) { 257 glxValue |= GLX_RGBA_BIT; 258 } 259 else if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) { 260 glxValue |= GLX_COLOR_INDEX_BIT; 261 } 262 if (glxValue != config->renderType) 263 return GL_FALSE; 264 break; 265 266 case __DRI_ATTRIB_CONFIG_CAVEAT: 267 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) 268 glxValue = GLX_NON_CONFORMANT_CONFIG; 269 else if (value & __DRI_ATTRIB_SLOW_BIT) 270 glxValue = GLX_SLOW_CONFIG; 271 else 272 glxValue = GLX_NONE; 273 if (glxValue != config->visualRating) 274 return GL_FALSE; 275 break; 276 277 case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS: 278 glxValue = 0; 279 if (value & __DRI_ATTRIB_TEXTURE_1D_BIT) 280 glxValue |= GLX_TEXTURE_1D_BIT_EXT; 281 if (value & __DRI_ATTRIB_TEXTURE_2D_BIT) 282 glxValue |= GLX_TEXTURE_2D_BIT_EXT; 283 if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT) 284 glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT; 285 if (config->bindToTextureTargets != GLX_DONT_CARE && 286 glxValue != config->bindToTextureTargets) 287 return GL_FALSE; 288 break; 289 290 default: 291 if (!scalarEqual(config, attrib, value)) 292 return GL_FALSE; 293 } 294 } 295 296 return GL_TRUE; 297} 298 299static struct glx_config * 300createDriMode(const __DRIcoreExtension * core, 301 struct glx_config *config, const __DRIconfig **driConfigs) 302{ 303 __GLXDRIconfigPrivate *driConfig; 304 int i; 305 306 for (i = 0; driConfigs[i]; i++) { 307 if (driConfigEqual(core, config, driConfigs[i])) 308 break; 309 } 310 311 if (driConfigs[i] == NULL) 312 return NULL; 313 314 driConfig = Xmalloc(sizeof *driConfig); 315 if (driConfig == NULL) 316 return NULL; 317 318 driConfig->base = *config; 319 driConfig->driConfig = driConfigs[i]; 320 321 return &driConfig->base; 322} 323 324_X_HIDDEN struct glx_config * 325driConvertConfigs(const __DRIcoreExtension * core, 326 struct glx_config *configs, const __DRIconfig **driConfigs) 327{ 328 struct glx_config head, *tail, *m; 329 330 tail = &head; 331 head.next = NULL; 332 for (m = configs; m; m = m->next) { 333 tail->next = createDriMode(core, m, driConfigs); 334 if (tail->next == NULL) { 335 /* no matching dri config for m */ 336 continue; 337 } 338 339 340 tail = tail->next; 341 } 342 343 return head.next; 344} 345 346_X_HIDDEN void 347driDestroyConfigs(const __DRIconfig **configs) 348{ 349 int i; 350 351 for (i = 0; configs[i]; i++) 352 free((__DRIconfig *) configs[i]); 353 free(configs); 354} 355 356_X_HIDDEN __GLXDRIdrawable * 357driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable) 358{ 359 struct glx_display *const priv = __glXInitialize(gc->psc->dpy); 360 __GLXDRIdrawable *pdraw; 361 struct glx_screen *psc; 362 363 if (priv == NULL) 364 return NULL; 365 366 psc = priv->screens[gc->screen]; 367 if (priv->drawHash == NULL) 368 return NULL; 369 370 if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) { 371 pdraw->refcount ++; 372 return pdraw; 373 } 374 375 pdraw = psc->driScreen->createDrawable(psc, glxDrawable, 376 glxDrawable, gc->config); 377 if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) { 378 (*pdraw->destroyDrawable) (pdraw); 379 return NULL; 380 } 381 pdraw->refcount = 1; 382 383 return pdraw; 384} 385 386_X_HIDDEN void 387driReleaseDrawables(struct glx_context *gc) 388{ 389 const struct glx_display *priv = gc->psc->display; 390 __GLXDRIdrawable *pdraw; 391 392 if (priv == NULL) 393 return; 394 395 if (__glxHashLookup(priv->drawHash, 396 gc->currentDrawable, (void *) &pdraw) == 0) { 397 if (pdraw->drawable == pdraw->xDrawable) { 398 pdraw->refcount --; 399 if (pdraw->refcount == 0) { 400 (*pdraw->destroyDrawable)(pdraw); 401 __glxHashDelete(priv->drawHash, gc->currentDrawable); 402 } 403 } 404 } 405 406 if (__glxHashLookup(priv->drawHash, 407 gc->currentReadable, (void *) &pdraw) == 0) { 408 if (pdraw->drawable == pdraw->xDrawable) { 409 pdraw->refcount --; 410 if (pdraw->refcount == 0) { 411 (*pdraw->destroyDrawable)(pdraw); 412 __glxHashDelete(priv->drawHash, gc->currentReadable); 413 } 414 } 415 } 416 417 gc->currentDrawable = None; 418 gc->currentReadable = None; 419 420} 421 422_X_HIDDEN bool 423dri2_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs, 424 unsigned *major_ver, unsigned *minor_ver, 425 uint32_t *flags, unsigned *api, unsigned *error) 426{ 427 unsigned i; 428 bool got_profile = false; 429 uint32_t profile; 430 int render_type = GLX_RGBA_TYPE; 431 432 if (num_attribs == 0) 433 return true; 434 435 /* This is actually an internal error, but what the heck. 436 */ 437 if (attribs == NULL) { 438 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 439 return false; 440 } 441 442 *major_ver = 1; 443 *minor_ver = 0; 444 445 for (i = 0; i < num_attribs; i++) { 446 switch (attribs[i * 2]) { 447 case GLX_CONTEXT_MAJOR_VERSION_ARB: 448 *major_ver = attribs[i * 2 + 1]; 449 break; 450 case GLX_CONTEXT_MINOR_VERSION_ARB: 451 *minor_ver = attribs[i * 2 + 1]; 452 break; 453 case GLX_CONTEXT_FLAGS_ARB: 454 *flags = attribs[i * 2 + 1]; 455 break; 456 case GLX_CONTEXT_PROFILE_MASK_ARB: 457 profile = attribs[i * 2 + 1]; 458 got_profile = true; 459 break; 460 case GLX_RENDER_TYPE: 461 render_type = attribs[i * 2 + 1]; 462 break; 463 default: 464 /* If an unknown attribute is received, fail. 465 */ 466 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 467 return false; 468 } 469 } 470 471 *api = __DRI_API_OPENGL; 472 if (!got_profile) { 473 if (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2)) 474 *api = __DRI_API_OPENGL_CORE; 475 } else { 476 switch (profile) { 477 case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: 478 /* There are no profiles before OpenGL 3.2. The 479 * GLX_ARB_create_context_profile spec says: 480 * 481 * "If the requested OpenGL version is less than 3.2, 482 * GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality 483 * of the context is determined solely by the requested version." 484 */ 485 *api = (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2)) 486 ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL; 487 break; 488 case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: 489 *api = __DRI_API_OPENGL; 490 break; 491 default: 492 *error = __DRI_CTX_ERROR_BAD_API; 493 return false; 494 } 495 } 496 497 /* Unknown flag value. 498 */ 499 if (*flags & ~(__DRI_CTX_FLAG_DEBUG | __DRI_CTX_FLAG_FORWARD_COMPATIBLE)) { 500 *error = __DRI_CTX_ERROR_UNKNOWN_FLAG; 501 return false; 502 } 503 504 /* There are no forward-compatible contexts before OpenGL 3.0. The 505 * GLX_ARB_create_context spec says: 506 * 507 * "Forward-compatible contexts are defined only for OpenGL versions 508 * 3.0 and later." 509 */ 510 if (*major_ver < 3 && (*flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) { 511 *error = __DRI_CTX_ERROR_BAD_FLAG; 512 return false; 513 } 514 515 if (*major_ver >= 3 && render_type == GLX_COLOR_INDEX_TYPE) { 516 *error = __DRI_CTX_ERROR_BAD_FLAG; 517 return false; 518 } 519 520 *error = __DRI_CTX_ERROR_SUCCESS; 521 return true; 522} 523 524#endif /* GLX_DIRECT_RENDERING */ 525