dri_common.c revision bf69ce37f0dcbb479078ee676d5100ac63e20750
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_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 "tdfx", "i810", "mga", 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 glx_config_destroy_list(configs); 344 345 return head.next; 346} 347 348_X_HIDDEN void 349driDestroyConfigs(const __DRIconfig **configs) 350{ 351 int i; 352 353 for (i = 0; configs[i]; i++) 354 free((__DRIconfig *) configs[i]); 355 free(configs); 356} 357 358_X_HIDDEN __GLXDRIdrawable * 359driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable) 360{ 361 struct glx_display *const priv = __glXInitialize(gc->psc->dpy); 362 __GLXDRIdrawable *pdraw; 363 struct glx_screen *psc; 364 365 if (priv == NULL) 366 return NULL; 367 368 psc = priv->screens[gc->screen]; 369 if (priv->drawHash == NULL) 370 return NULL; 371 372 if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) { 373 pdraw->refcount ++; 374 return pdraw; 375 } 376 377 pdraw = psc->driScreen->createDrawable(psc, glxDrawable, 378 glxDrawable, gc->config); 379 if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) { 380 (*pdraw->destroyDrawable) (pdraw); 381 return NULL; 382 } 383 pdraw->refcount = 1; 384 385 return pdraw; 386} 387 388_X_HIDDEN void 389driReleaseDrawables(struct glx_context *gc) 390{ 391 struct glx_display *const priv = __glXInitialize(gc->psc->dpy); 392 __GLXDRIdrawable *pdraw; 393 394 if (priv == NULL) 395 return; 396 397 if (__glxHashLookup(priv->drawHash, 398 gc->currentDrawable, (void *) &pdraw) == 0) { 399 if (pdraw->drawable == pdraw->xDrawable) { 400 pdraw->refcount --; 401 if (pdraw->refcount == 0) { 402 (*pdraw->destroyDrawable)(pdraw); 403 __glxHashDelete(priv->drawHash, gc->currentDrawable); 404 } 405 } 406 } 407 408 if (__glxHashLookup(priv->drawHash, 409 gc->currentReadable, (void *) &pdraw) == 0) { 410 if (pdraw->drawable == pdraw->xDrawable) { 411 pdraw->refcount --; 412 if (pdraw->refcount == 0) { 413 (*pdraw->destroyDrawable)(pdraw); 414 __glxHashDelete(priv->drawHash, gc->currentReadable); 415 } 416 } 417 } 418 419 gc->currentDrawable = None; 420 gc->currentReadable = None; 421 422} 423 424#endif /* GLX_DIRECT_RENDERING */ 425