glxinit.c revision 6e8897ff9f90601ebf6eed500ad942c11b54d1f7
1/** 2 * GLX initialization. Code based on glxext.c, glx_query.c, and 3 * glcontextmodes.c under src/glx/. The major difference is that DRI 4 * related code is stripped out. 5 * 6 * If the maintenance of this file takes too much time, we should consider 7 * refactoring glxext.c. 8 */ 9 10#include <assert.h> 11#include <X11/Xlib.h> 12#include <X11/Xproto.h> 13#include <X11/extensions/Xext.h> 14#include <X11/extensions/extutil.h> 15#include <sys/time.h> 16 17#include "glxinit.h" 18 19typedef struct GLXGenericGetString 20{ 21 CARD8 reqType; 22 CARD8 glxCode; 23 CARD16 length B16; 24 CARD32 for_whom B32; 25 CARD32 name B32; 26} xGLXGenericGetStringReq; 27 28#define sz_xGLXGenericGetStringReq 12 29#define X_GLXGenericGetString 0 30 31/* Extension required boiler plate */ 32 33static char *__glXExtensionName = GLX_EXTENSION_NAME; 34static XExtensionInfo *__glXExtensionInfo = NULL; 35 36static int 37__glXCloseDisplay(Display * dpy, XExtCodes * codes) 38{ 39 return XextRemoveDisplay(__glXExtensionInfo, dpy); 40} 41 42static /* const */ XExtensionHooks __glXExtensionHooks = { 43 NULL, /* create_gc */ 44 NULL, /* copy_gc */ 45 NULL, /* flush_gc */ 46 NULL, /* free_gc */ 47 NULL, /* create_font */ 48 NULL, /* free_font */ 49 __glXCloseDisplay, /* close_display */ 50 NULL, /* wire_to_event */ 51 NULL, /* event_to_wire */ 52 NULL, /* error */ 53 NULL, /* error_string */ 54}; 55 56XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo, 57 __glXExtensionName, &__glXExtensionHooks, 58 __GLX_NUMBER_EVENTS, NULL) 59 60static GLint 61_gl_convert_from_x_visual_type(int visualType) 62{ 63#define NUM_VISUAL_TYPES 6 64 static const int glx_visual_types[NUM_VISUAL_TYPES] = { 65 GLX_STATIC_GRAY, GLX_GRAY_SCALE, 66 GLX_STATIC_COLOR, GLX_PSEUDO_COLOR, 67 GLX_TRUE_COLOR, GLX_DIRECT_COLOR 68 }; 69 70 return ((unsigned) visualType < NUM_VISUAL_TYPES) 71 ? glx_visual_types[visualType] : GLX_NONE; 72} 73 74static __GLcontextModes * 75_gl_context_modes_create(unsigned count, size_t minimum_size) 76{ 77 const size_t size = (minimum_size > sizeof(__GLcontextModes)) 78 ? minimum_size : sizeof(__GLcontextModes); 79 __GLcontextModes *base = NULL; 80 __GLcontextModes **next; 81 unsigned i; 82 83 next = &base; 84 for (i = 0; i < count; i++) { 85 *next = (__GLcontextModes *) Xmalloc(size); 86 if (*next == NULL) { 87 _gl_context_modes_destroy(base); 88 base = NULL; 89 break; 90 } 91 92 memset(*next, 0, size); 93 (*next)->visualID = GLX_DONT_CARE; 94 (*next)->visualType = GLX_DONT_CARE; 95 (*next)->visualRating = GLX_NONE; 96 (*next)->transparentPixel = GLX_NONE; 97 (*next)->transparentRed = GLX_DONT_CARE; 98 (*next)->transparentGreen = GLX_DONT_CARE; 99 (*next)->transparentBlue = GLX_DONT_CARE; 100 (*next)->transparentAlpha = GLX_DONT_CARE; 101 (*next)->transparentIndex = GLX_DONT_CARE; 102 (*next)->xRenderable = GLX_DONT_CARE; 103 (*next)->fbconfigID = GLX_DONT_CARE; 104 (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML; 105 (*next)->bindToTextureRgb = GLX_DONT_CARE; 106 (*next)->bindToTextureRgba = GLX_DONT_CARE; 107 (*next)->bindToMipmapTexture = GLX_DONT_CARE; 108 (*next)->bindToTextureTargets = GLX_DONT_CARE; 109 (*next)->yInverted = GLX_DONT_CARE; 110 111 next = &((*next)->next); 112 } 113 114 return base; 115} 116 117_X_HIDDEN void 118_gl_context_modes_destroy(__GLcontextModes * modes) 119{ 120 while (modes != NULL) { 121 __GLcontextModes *const next = modes->next; 122 123 Xfree(modes); 124 modes = next; 125 } 126} 127 128_X_HIDDEN char * 129__glXQueryServerString(Display * dpy, int opcode, CARD32 screen, CARD32 name) 130{ 131 xGLXGenericGetStringReq *req; 132 xGLXSingleReply reply; 133 int length; 134 int numbytes; 135 char *buf; 136 CARD32 for_whom = screen; 137 CARD32 glxCode = X_GLXQueryServerString; 138 139 140 LockDisplay(dpy); 141 142 143 /* All of the GLX protocol requests for getting a string from the server 144 * look the same. The exact meaning of the for_whom field is usually 145 * either the screen number (for glXQueryServerString) or the context tag 146 * (for GLXSingle). 147 */ 148 149 GetReq(GLXGenericGetString, req); 150 req->reqType = opcode; 151 req->glxCode = glxCode; 152 req->for_whom = for_whom; 153 req->name = name; 154 155 _XReply(dpy, (xReply *) & reply, 0, False); 156 157 length = reply.length * 4; 158 numbytes = reply.size; 159 160 buf = (char *) Xmalloc(numbytes); 161 if (buf != NULL) { 162 _XRead(dpy, buf, numbytes); 163 length -= numbytes; 164 } 165 166 _XEatData(dpy, length); 167 168 UnlockDisplay(dpy); 169 SyncHandle(); 170 171 return buf; 172} 173 174/************************************************************************/ 175/* 176** Free the per screen configs data as well as the array of 177** __glXScreenConfigs. 178*/ 179static void 180FreeScreenConfigs(__GLXdisplayPrivate * priv) 181{ 182 __GLXscreenConfigs *psc; 183 GLint i, screens; 184 185 /* Free screen configuration information */ 186 psc = priv->screenConfigs; 187 screens = ScreenCount(priv->dpy); 188 for (i = 0; i < screens; i++, psc++) { 189 if (psc->configs) { 190 _gl_context_modes_destroy(psc->configs); 191 psc->configs = NULL; /* NOTE: just for paranoia */ 192 } 193 if (psc->visuals) { 194 _gl_context_modes_destroy(psc->visuals); 195 psc->visuals = NULL; /* NOTE: just for paranoia */ 196 } 197 Xfree((char *) psc->serverGLXexts); 198 } 199 XFree((char *) priv->screenConfigs); 200 priv->screenConfigs = NULL; 201} 202 203/* 204** Release the private memory referred to in a display private 205** structure. The caller will free the extension structure. 206*/ 207static int 208__glXFreeDisplayPrivate(XExtData * extension) 209{ 210 __GLXdisplayPrivate *priv; 211 212 priv = (__GLXdisplayPrivate *) extension->private_data; 213 FreeScreenConfigs(priv); 214 if (priv->serverGLXvendor) { 215 Xfree((char *) priv->serverGLXvendor); 216 priv->serverGLXvendor = 0x0; /* to protect against double free's */ 217 } 218 if (priv->serverGLXversion) { 219 Xfree((char *) priv->serverGLXversion); 220 priv->serverGLXversion = 0x0; /* to protect against double free's */ 221 } 222 223 Xfree((char *) priv); 224 return 0; 225} 226 227/************************************************************************/ 228 229/* 230** Query the version of the GLX extension. This procedure works even if 231** the client extension is not completely set up. 232*/ 233static Bool 234QueryVersion(Display * dpy, int opcode, int *major, int *minor) 235{ 236 xGLXQueryVersionReq *req; 237 xGLXQueryVersionReply reply; 238 239 /* Send the glXQueryVersion request */ 240 LockDisplay(dpy); 241 GetReq(GLXQueryVersion, req); 242 req->reqType = opcode; 243 req->glxCode = X_GLXQueryVersion; 244 req->majorVersion = GLX_MAJOR_VERSION; 245 req->minorVersion = GLX_MINOR_VERSION; 246 _XReply(dpy, (xReply *) & reply, 0, False); 247 UnlockDisplay(dpy); 248 SyncHandle(); 249 250 if (reply.majorVersion != GLX_MAJOR_VERSION) { 251 /* 252 ** The server does not support the same major release as this 253 ** client. 254 */ 255 return GL_FALSE; 256 } 257 *major = reply.majorVersion; 258 *minor = min(reply.minorVersion, GLX_MINOR_VERSION); 259 return GL_TRUE; 260} 261 262_X_HIDDEN void 263__glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count, 264 const INT32 * bp, Bool tagged_only, 265 Bool fbconfig_style_tags) 266{ 267 int i; 268 269 if (!tagged_only) { 270 /* Copy in the first set of properties */ 271 config->visualID = *bp++; 272 273 config->visualType = _gl_convert_from_x_visual_type(*bp++); 274 275 config->rgbMode = *bp++; 276 277 config->redBits = *bp++; 278 config->greenBits = *bp++; 279 config->blueBits = *bp++; 280 config->alphaBits = *bp++; 281 config->accumRedBits = *bp++; 282 config->accumGreenBits = *bp++; 283 config->accumBlueBits = *bp++; 284 config->accumAlphaBits = *bp++; 285 286 config->doubleBufferMode = *bp++; 287 config->stereoMode = *bp++; 288 289 config->rgbBits = *bp++; 290 config->depthBits = *bp++; 291 config->stencilBits = *bp++; 292 config->numAuxBuffers = *bp++; 293 config->level = *bp++; 294 295 count -= __GLX_MIN_CONFIG_PROPS; 296 } 297 298 /* 299 ** Additional properties may be in a list at the end 300 ** of the reply. They are in pairs of property type 301 ** and property value. 302 */ 303 304#define FETCH_OR_SET(tag) \ 305 config-> tag = ( fbconfig_style_tags ) ? *bp++ : 1 306 307 for (i = 0; i < count; i += 2) { 308 switch (*bp++) { 309 case GLX_RGBA: 310 FETCH_OR_SET(rgbMode); 311 break; 312 case GLX_BUFFER_SIZE: 313 config->rgbBits = *bp++; 314 break; 315 case GLX_LEVEL: 316 config->level = *bp++; 317 break; 318 case GLX_DOUBLEBUFFER: 319 FETCH_OR_SET(doubleBufferMode); 320 break; 321 case GLX_STEREO: 322 FETCH_OR_SET(stereoMode); 323 break; 324 case GLX_AUX_BUFFERS: 325 config->numAuxBuffers = *bp++; 326 break; 327 case GLX_RED_SIZE: 328 config->redBits = *bp++; 329 break; 330 case GLX_GREEN_SIZE: 331 config->greenBits = *bp++; 332 break; 333 case GLX_BLUE_SIZE: 334 config->blueBits = *bp++; 335 break; 336 case GLX_ALPHA_SIZE: 337 config->alphaBits = *bp++; 338 break; 339 case GLX_DEPTH_SIZE: 340 config->depthBits = *bp++; 341 break; 342 case GLX_STENCIL_SIZE: 343 config->stencilBits = *bp++; 344 break; 345 case GLX_ACCUM_RED_SIZE: 346 config->accumRedBits = *bp++; 347 break; 348 case GLX_ACCUM_GREEN_SIZE: 349 config->accumGreenBits = *bp++; 350 break; 351 case GLX_ACCUM_BLUE_SIZE: 352 config->accumBlueBits = *bp++; 353 break; 354 case GLX_ACCUM_ALPHA_SIZE: 355 config->accumAlphaBits = *bp++; 356 break; 357 case GLX_VISUAL_CAVEAT_EXT: 358 config->visualRating = *bp++; 359 break; 360 case GLX_X_VISUAL_TYPE: 361 config->visualType = *bp++; 362 break; 363 case GLX_TRANSPARENT_TYPE: 364 config->transparentPixel = *bp++; 365 break; 366 case GLX_TRANSPARENT_INDEX_VALUE: 367 config->transparentIndex = *bp++; 368 break; 369 case GLX_TRANSPARENT_RED_VALUE: 370 config->transparentRed = *bp++; 371 break; 372 case GLX_TRANSPARENT_GREEN_VALUE: 373 config->transparentGreen = *bp++; 374 break; 375 case GLX_TRANSPARENT_BLUE_VALUE: 376 config->transparentBlue = *bp++; 377 break; 378 case GLX_TRANSPARENT_ALPHA_VALUE: 379 config->transparentAlpha = *bp++; 380 break; 381 case GLX_VISUAL_ID: 382 config->visualID = *bp++; 383 break; 384 case GLX_DRAWABLE_TYPE: 385 config->drawableType = *bp++; 386 break; 387 case GLX_RENDER_TYPE: 388 config->renderType = *bp++; 389 break; 390 case GLX_X_RENDERABLE: 391 config->xRenderable = *bp++; 392 break; 393 case GLX_FBCONFIG_ID: 394 config->fbconfigID = *bp++; 395 break; 396 case GLX_MAX_PBUFFER_WIDTH: 397 config->maxPbufferWidth = *bp++; 398 break; 399 case GLX_MAX_PBUFFER_HEIGHT: 400 config->maxPbufferHeight = *bp++; 401 break; 402 case GLX_MAX_PBUFFER_PIXELS: 403 config->maxPbufferPixels = *bp++; 404 break; 405 case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX: 406 config->optimalPbufferWidth = *bp++; 407 break; 408 case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX: 409 config->optimalPbufferHeight = *bp++; 410 break; 411 case GLX_VISUAL_SELECT_GROUP_SGIX: 412 config->visualSelectGroup = *bp++; 413 break; 414 case GLX_SWAP_METHOD_OML: 415 config->swapMethod = *bp++; 416 break; 417 case GLX_SAMPLE_BUFFERS_SGIS: 418 config->sampleBuffers = *bp++; 419 break; 420 case GLX_SAMPLES_SGIS: 421 config->samples = *bp++; 422 break; 423 case GLX_BIND_TO_TEXTURE_RGB_EXT: 424 config->bindToTextureRgb = *bp++; 425 break; 426 case GLX_BIND_TO_TEXTURE_RGBA_EXT: 427 config->bindToTextureRgba = *bp++; 428 break; 429 case GLX_BIND_TO_MIPMAP_TEXTURE_EXT: 430 config->bindToMipmapTexture = *bp++; 431 break; 432 case GLX_BIND_TO_TEXTURE_TARGETS_EXT: 433 config->bindToTextureTargets = *bp++; 434 break; 435 case GLX_Y_INVERTED_EXT: 436 config->yInverted = *bp++; 437 break; 438 case None: 439 i = count; 440 break; 441 default: 442 break; 443 } 444 } 445 446 config->renderType = 447 (config->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; 448 449 config->haveAccumBuffer = ((config->accumRedBits + 450 config->accumGreenBits + 451 config->accumBlueBits + 452 config->accumAlphaBits) > 0); 453 config->haveDepthBuffer = (config->depthBits > 0); 454 config->haveStencilBuffer = (config->stencilBits > 0); 455} 456 457static __GLcontextModes * 458createConfigsFromProperties(Display * dpy, int nvisuals, int nprops, 459 int screen, GLboolean tagged_only) 460{ 461 INT32 buf[__GLX_TOTAL_CONFIG], *props; 462 unsigned prop_size; 463 __GLcontextModes *modes, *m; 464 int i; 465 466 if (nprops == 0) 467 return NULL; 468 469 /* FIXME: Is the __GLX_MIN_CONFIG_PROPS test correct for FBconfigs? */ 470 471 /* Check number of properties */ 472 if (nprops < __GLX_MIN_CONFIG_PROPS || nprops > __GLX_MAX_CONFIG_PROPS) 473 return NULL; 474 475 /* Allocate memory for our config structure */ 476 modes = _gl_context_modes_create(nvisuals, sizeof(__GLcontextModes)); 477 if (!modes) 478 return NULL; 479 480 prop_size = nprops * __GLX_SIZE_INT32; 481 if (prop_size <= sizeof(buf)) 482 props = buf; 483 else 484 props = Xmalloc(prop_size); 485 486 /* Read each config structure and convert it into our format */ 487 m = modes; 488 for (i = 0; i < nvisuals; i++) { 489 _XRead(dpy, (char *) props, prop_size); 490 /* Older X servers don't send this so we default it here. */ 491 m->drawableType = GLX_WINDOW_BIT; 492 __glXInitializeVisualConfigFromTags(m, nprops, props, 493 tagged_only, GL_TRUE); 494 m->screen = screen; 495 m = m->next; 496 } 497 498 if (props != buf) 499 Xfree(props); 500 501 return modes; 502} 503 504static GLboolean 505getVisualConfigs(Display * dpy, __GLXdisplayPrivate * priv, int screen) 506{ 507 xGLXGetVisualConfigsReq *req; 508 __GLXscreenConfigs *psc; 509 xGLXGetVisualConfigsReply reply; 510 511 LockDisplay(dpy); 512 513 psc = priv->screenConfigs + screen; 514 psc->visuals = NULL; 515 GetReq(GLXGetVisualConfigs, req); 516 req->reqType = priv->majorOpcode; 517 req->glxCode = X_GLXGetVisualConfigs; 518 req->screen = screen; 519 520 if (!_XReply(dpy, (xReply *) & reply, 0, False)) 521 goto out; 522 523 psc->visuals = createConfigsFromProperties(dpy, 524 reply.numVisuals, 525 reply.numProps, 526 screen, GL_FALSE); 527 528 out: 529 UnlockDisplay(dpy); 530 return psc->visuals != NULL; 531} 532 533static GLboolean 534getFBConfigs(Display * dpy, __GLXdisplayPrivate * priv, int screen) 535{ 536 xGLXGetFBConfigsReq *fb_req; 537 xGLXGetFBConfigsSGIXReq *sgi_req; 538 xGLXVendorPrivateWithReplyReq *vpreq; 539 xGLXGetFBConfigsReply reply; 540 __GLXscreenConfigs *psc; 541 542 psc = priv->screenConfigs + screen; 543 psc->serverGLXexts = 544 __glXQueryServerString(dpy, priv->majorOpcode, screen, GLX_EXTENSIONS); 545 546 LockDisplay(dpy); 547 548 psc->configs = NULL; 549 if (atof(priv->serverGLXversion) >= 1.3) { 550 GetReq(GLXGetFBConfigs, fb_req); 551 fb_req->reqType = priv->majorOpcode; 552 fb_req->glxCode = X_GLXGetFBConfigs; 553 fb_req->screen = screen; 554 } 555 else if (strstr(psc->serverGLXexts, "GLX_SGIX_fbconfig") != NULL) { 556 GetReqExtra(GLXVendorPrivateWithReply, 557 sz_xGLXGetFBConfigsSGIXReq + 558 sz_xGLXVendorPrivateWithReplyReq, vpreq); 559 sgi_req = (xGLXGetFBConfigsSGIXReq *) vpreq; 560 sgi_req->reqType = priv->majorOpcode; 561 sgi_req->glxCode = X_GLXVendorPrivateWithReply; 562 sgi_req->vendorCode = X_GLXvop_GetFBConfigsSGIX; 563 sgi_req->screen = screen; 564 } 565 else 566 goto out; 567 568 if (!_XReply(dpy, (xReply *) & reply, 0, False)) 569 goto out; 570 571 psc->configs = createConfigsFromProperties(dpy, 572 reply.numFBConfigs, 573 reply.numAttribs * 2, 574 screen, GL_TRUE); 575 576 out: 577 UnlockDisplay(dpy); 578 return psc->configs != NULL; 579} 580 581static GLboolean 582AllocAndFetchScreenConfigs(Display * dpy, __GLXdisplayPrivate * priv) 583{ 584 __GLXscreenConfigs *psc; 585 GLint i, screens; 586 587 /* 588 ** First allocate memory for the array of per screen configs. 589 */ 590 screens = ScreenCount(dpy); 591 psc = (__GLXscreenConfigs *) Xmalloc(screens * sizeof(__GLXscreenConfigs)); 592 if (!psc) { 593 return GL_FALSE; 594 } 595 memset(psc, 0, screens * sizeof(__GLXscreenConfigs)); 596 priv->screenConfigs = psc; 597 598 priv->serverGLXversion = 599 __glXQueryServerString(dpy, priv->majorOpcode, 0, GLX_VERSION); 600 if (priv->serverGLXversion == NULL) { 601 FreeScreenConfigs(priv); 602 return GL_FALSE; 603 } 604 605 for (i = 0; i < screens; i++, psc++) { 606 getFBConfigs(dpy, priv, i); 607 getVisualConfigs(dpy, priv, i); 608 psc->scr = i; 609 psc->dpy = dpy; 610 } 611 612 SyncHandle(); 613 614 return GL_TRUE; 615} 616 617_X_HIDDEN __GLXdisplayPrivate * 618__glXInitialize(Display * dpy) 619{ 620 XExtDisplayInfo *info = __glXFindDisplay(dpy); 621 XExtData **privList, *private, *found; 622 __GLXdisplayPrivate *dpyPriv; 623 XEDataObject dataObj; 624 int major, minor; 625 626 if (!XextHasExtension(info)) 627 return NULL; 628 629 /* See if a display private already exists. If so, return it */ 630 dataObj.display = dpy; 631 privList = XEHeadOfExtensionList(dataObj); 632 found = XFindOnExtensionList(privList, info->codes->extension); 633 if (found) 634 return (__GLXdisplayPrivate *) found->private_data; 635 636 /* See if the versions are compatible */ 637 if (!QueryVersion(dpy, info->codes->major_opcode, &major, &minor)) 638 return NULL; 639 640 /* 641 ** Allocate memory for all the pieces needed for this buffer. 642 */ 643 private = (XExtData *) Xmalloc(sizeof(XExtData)); 644 if (!private) 645 return NULL; 646 dpyPriv = (__GLXdisplayPrivate *) Xcalloc(1, sizeof(__GLXdisplayPrivate)); 647 if (!dpyPriv) { 648 Xfree(private); 649 return NULL; 650 } 651 652 /* 653 ** Init the display private and then read in the screen config 654 ** structures from the server. 655 */ 656 dpyPriv->majorOpcode = info->codes->major_opcode; 657 dpyPriv->majorVersion = major; 658 dpyPriv->minorVersion = minor; 659 dpyPriv->dpy = dpy; 660 661 dpyPriv->serverGLXvendor = NULL; 662 dpyPriv->serverGLXversion = NULL; 663 664 if (!AllocAndFetchScreenConfigs(dpy, dpyPriv)) { 665 Xfree(dpyPriv); 666 Xfree(private); 667 return NULL; 668 } 669 670 /* 671 ** Fill in the private structure. This is the actual structure that 672 ** hangs off of the Display structure. Our private structure is 673 ** referred to by this structure. Got that? 674 */ 675 private->number = info->codes->extension; 676 private->next = 0; 677 private->free_private = __glXFreeDisplayPrivate; 678 private->private_data = (char *) dpyPriv; 679 XAddToExtensionList(privList, private); 680 681 return dpyPriv; 682} 683