dri_common.c revision 16887d042a917fa4773e4d853f50051b54e9948c
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 227static int 228scalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value) 229{ 230 unsigned int glxValue; 231 int i; 232 233 for (i = 0; i < ARRAY_SIZE(attribMap); i++) 234 if (attribMap[i].attrib == attrib) { 235 glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset); 236 return glxValue == GLX_DONT_CARE || glxValue == value; 237 } 238 239 return GL_TRUE; /* Is a non-existing attribute equal to value? */ 240} 241 242static int 243driConfigEqual(const __DRIcoreExtension *core, 244 struct glx_config *config, const __DRIconfig *driConfig) 245{ 246 unsigned int attrib, value, glxValue; 247 int i; 248 249 i = 0; 250 while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) { 251 switch (attrib) { 252 case __DRI_ATTRIB_RENDER_TYPE: 253 glxValue = 0; 254 if (value & __DRI_ATTRIB_RGBA_BIT) { 255 glxValue |= GLX_RGBA_BIT; 256 } 257 else if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) { 258 glxValue |= GLX_COLOR_INDEX_BIT; 259 } 260 if (glxValue != config->renderType) 261 return GL_FALSE; 262 break; 263 264 case __DRI_ATTRIB_CONFIG_CAVEAT: 265 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) 266 glxValue = GLX_NON_CONFORMANT_CONFIG; 267 else if (value & __DRI_ATTRIB_SLOW_BIT) 268 glxValue = GLX_SLOW_CONFIG; 269 else 270 glxValue = GLX_NONE; 271 if (glxValue != config->visualRating) 272 return GL_FALSE; 273 break; 274 275 case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS: 276 glxValue = 0; 277 if (value & __DRI_ATTRIB_TEXTURE_1D_BIT) 278 glxValue |= GLX_TEXTURE_1D_BIT_EXT; 279 if (value & __DRI_ATTRIB_TEXTURE_2D_BIT) 280 glxValue |= GLX_TEXTURE_2D_BIT_EXT; 281 if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT) 282 glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT; 283 if (config->bindToTextureTargets != GLX_DONT_CARE && 284 glxValue != config->bindToTextureTargets) 285 return GL_FALSE; 286 break; 287 288 default: 289 if (!scalarEqual(config, attrib, value)) 290 return GL_FALSE; 291 } 292 } 293 294 return GL_TRUE; 295} 296 297static struct glx_config * 298createDriMode(const __DRIcoreExtension * core, 299 struct glx_config *config, const __DRIconfig **driConfigs) 300{ 301 __GLXDRIconfigPrivate *driConfig; 302 int i; 303 304 for (i = 0; driConfigs[i]; i++) { 305 if (driConfigEqual(core, config, driConfigs[i])) 306 break; 307 } 308 309 if (driConfigs[i] == NULL) 310 return NULL; 311 312 driConfig = Xmalloc(sizeof *driConfig); 313 if (driConfig == NULL) 314 return NULL; 315 316 driConfig->base = *config; 317 driConfig->driConfig = driConfigs[i]; 318 319 return &driConfig->base; 320} 321 322_X_HIDDEN struct glx_config * 323driConvertConfigs(const __DRIcoreExtension * core, 324 struct glx_config *configs, const __DRIconfig **driConfigs) 325{ 326 struct glx_config head, *tail, *m; 327 328 tail = &head; 329 head.next = NULL; 330 for (m = configs; m; m = m->next) { 331 tail->next = createDriMode(core, m, driConfigs); 332 if (tail->next == NULL) { 333 /* no matching dri config for m */ 334 continue; 335 } 336 337 338 tail = tail->next; 339 } 340 341 glx_config_destroy_list(configs); 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 return pdraw; 372 373 pdraw = psc->driScreen->createDrawable(psc, glxDrawable, 374 glxDrawable, gc->config); 375 if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) { 376 (*pdraw->destroyDrawable) (pdraw); 377 return NULL; 378 } 379 380 return pdraw; 381} 382 383_X_HIDDEN void 384driReleaseDrawables(struct glx_context *gc) 385{ 386 struct glx_display *const priv = __glXInitialize(gc->psc->dpy); 387 __GLXDRIdrawable *pdraw; 388 389 if (priv == NULL) 390 return; 391 392 if (__glxHashLookup(priv->drawHash, 393 gc->currentDrawable, (void *) &pdraw) == 0) { 394 if (pdraw->drawable == pdraw->xDrawable) 395 (*pdraw->destroyDrawable)(pdraw); 396 __glxHashDelete(priv->drawHash, gc->currentDrawable); 397 } 398 399 if (gc->currentDrawable != gc->currentReadable && 400 __glxHashLookup(priv->drawHash, 401 gc->currentReadable, (void *) &pdraw) == 0) { 402 if (pdraw->drawable == pdraw->xDrawable) 403 (*pdraw->destroyDrawable)(pdraw); 404 __glxHashDelete(priv->drawHash, gc->currentReadable); 405 } 406} 407 408#endif /* GLX_DIRECT_RENDERING */ 409