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