1 /* 2 * (C) Copyright IBM Corporation 2004 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * on the rights to use, copy, modify, merge, publish, distribute, sub 9 * license, and/or sell copies of the Software, and to permit persons to whom 10 * the Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25 /** 26 * \file glx_pbuffer.c 27 * Implementation of pbuffer related functions. 28 * 29 * \author Ian Romanick <idr (at) us.ibm.com> 30 */ 31 32 #include <inttypes.h> 33 #include "glxclient.h" 34 #include <X11/extensions/extutil.h> 35 #include <X11/extensions/Xext.h> 36 #include <assert.h> 37 #include <string.h> 38 #include "glxextensions.h" 39 40 #ifdef GLX_USE_APPLEGL 41 #include <pthread.h> 42 #include "apple/apple_glx_drawable.h" 43 #endif 44 45 #include "glx_error.h" 46 47 #define WARN_ONCE_GLX_1_3(a, b) { \ 48 static int warned=1; \ 49 if(warned) { \ 50 warn_GLX_1_3((a), b ); \ 51 warned=0; \ 52 } \ 53 } 54 55 /** 56 * Emit a warning when clients use GLX 1.3 functions on pre-1.3 systems. 57 */ 58 static void 59 warn_GLX_1_3(Display * dpy, const char *function_name) 60 { 61 struct glx_display *priv = __glXInitialize(dpy); 62 63 if (priv && priv->minorVersion < 3) { 64 fprintf(stderr, 65 "WARNING: Application calling GLX 1.3 function \"%s\" " 66 "when GLX 1.3 is not supported! This is an application bug!\n", 67 function_name); 68 } 69 } 70 71 #ifndef GLX_USE_APPLEGL 72 /** 73 * Change a drawable's attribute. 74 * 75 * This function is used to implement \c glXSelectEvent and 76 * \c glXSelectEventSGIX. 77 * 78 * \note 79 * This function dynamically determines whether to use the SGIX_pbuffer 80 * version of the protocol or the GLX 1.3 version of the protocol. 81 */ 82 static void 83 ChangeDrawableAttribute(Display * dpy, GLXDrawable drawable, 84 const CARD32 * attribs, size_t num_attribs) 85 { 86 struct glx_display *priv = __glXInitialize(dpy); 87 #ifdef GLX_DIRECT_RENDERING 88 __GLXDRIdrawable *pdraw; 89 #endif 90 CARD32 *output; 91 CARD8 opcode; 92 int i; 93 94 if ((priv == NULL) || (dpy == NULL) || (drawable == 0)) { 95 return; 96 } 97 98 opcode = __glXSetupForCommand(dpy); 99 if (!opcode) 100 return; 101 102 LockDisplay(dpy); 103 104 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { 105 xGLXChangeDrawableAttributesReq *req; 106 107 GetReqExtra(GLXChangeDrawableAttributes, 8 * num_attribs, req); 108 output = (CARD32 *) (req + 1); 109 110 req->reqType = opcode; 111 req->glxCode = X_GLXChangeDrawableAttributes; 112 req->drawable = drawable; 113 req->numAttribs = (CARD32) num_attribs; 114 } 115 else { 116 xGLXVendorPrivateWithReplyReq *vpreq; 117 118 GetReqExtra(GLXVendorPrivateWithReply, 8 + (8 * num_attribs), vpreq); 119 output = (CARD32 *) (vpreq + 1); 120 121 vpreq->reqType = opcode; 122 vpreq->glxCode = X_GLXVendorPrivateWithReply; 123 vpreq->vendorCode = X_GLXvop_ChangeDrawableAttributesSGIX; 124 125 output[0] = (CARD32) drawable; 126 output[1] = num_attribs; 127 output += 2; 128 } 129 130 (void) memcpy(output, attribs, sizeof(CARD32) * 2 * num_attribs); 131 132 UnlockDisplay(dpy); 133 SyncHandle(); 134 135 #ifdef GLX_DIRECT_RENDERING 136 pdraw = GetGLXDRIDrawable(dpy, drawable); 137 138 if (!pdraw) 139 return; 140 141 for (i = 0; i < num_attribs; i++) { 142 switch(attribs[i * 2]) { 143 case GLX_EVENT_MASK: 144 /* Keep a local copy for masking out DRI2 proto events as needed */ 145 pdraw->eventMask = attribs[i * 2 + 1]; 146 break; 147 } 148 } 149 #endif 150 151 return; 152 } 153 154 155 #ifdef GLX_DIRECT_RENDERING 156 static GLenum 157 determineTextureTarget(const int *attribs, int numAttribs) 158 { 159 GLenum target = 0; 160 int i; 161 162 for (i = 0; i < numAttribs; i++) { 163 if (attribs[2 * i] == GLX_TEXTURE_TARGET_EXT) { 164 switch (attribs[2 * i + 1]) { 165 case GLX_TEXTURE_2D_EXT: 166 target = GL_TEXTURE_2D; 167 break; 168 case GLX_TEXTURE_RECTANGLE_EXT: 169 target = GL_TEXTURE_RECTANGLE_ARB; 170 break; 171 } 172 } 173 } 174 175 return target; 176 } 177 178 static GLenum 179 determineTextureFormat(const int *attribs, int numAttribs) 180 { 181 int i; 182 183 for (i = 0; i < numAttribs; i++) { 184 if (attribs[2 * i] == GLX_TEXTURE_FORMAT_EXT) 185 return attribs[2 * i + 1]; 186 } 187 188 return 0; 189 } 190 191 static GLboolean 192 CreateDRIDrawable(Display *dpy, struct glx_config *config, 193 XID drawable, XID glxdrawable, 194 const int *attrib_list, size_t num_attribs) 195 { 196 struct glx_display *const priv = __glXInitialize(dpy); 197 __GLXDRIdrawable *pdraw; 198 struct glx_screen *psc; 199 200 if (priv == NULL) { 201 fprintf(stderr, "failed to create drawable\n"); 202 return GL_FALSE; 203 } 204 205 psc = priv->screens[config->screen]; 206 if (psc->driScreen == NULL) 207 return GL_TRUE; 208 209 pdraw = psc->driScreen->createDrawable(psc, drawable, 210 glxdrawable, config); 211 if (pdraw == NULL) { 212 fprintf(stderr, "failed to create drawable\n"); 213 return GL_FALSE; 214 } 215 216 if (__glxHashInsert(priv->drawHash, glxdrawable, pdraw)) { 217 (*pdraw->destroyDrawable) (pdraw); 218 return GL_FALSE; 219 } 220 221 pdraw->textureTarget = determineTextureTarget(attrib_list, num_attribs); 222 pdraw->textureFormat = determineTextureFormat(attrib_list, num_attribs); 223 224 return GL_TRUE; 225 } 226 227 static void 228 DestroyDRIDrawable(Display *dpy, GLXDrawable drawable, int destroy_xdrawable) 229 { 230 struct glx_display *const priv = __glXInitialize(dpy); 231 __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable); 232 XID xid; 233 234 if (priv != NULL && pdraw != NULL) { 235 xid = pdraw->xDrawable; 236 (*pdraw->destroyDrawable) (pdraw); 237 __glxHashDelete(priv->drawHash, drawable); 238 if (destroy_xdrawable) 239 XFreePixmap(priv->dpy, xid); 240 } 241 } 242 243 #else 244 245 static GLboolean 246 CreateDRIDrawable(Display *dpy, const struct glx_config * fbconfig, 247 XID drawable, XID glxdrawable, 248 const int *attrib_list, size_t num_attribs) 249 { 250 return GL_TRUE; 251 } 252 253 static void 254 DestroyDRIDrawable(Display *dpy, GLXDrawable drawable, int destroy_xdrawable) 255 { 256 } 257 258 #endif 259 260 /** 261 * Get a drawable's attribute. 262 * 263 * This function is used to implement \c glXGetSelectedEvent and 264 * \c glXGetSelectedEventSGIX. 265 * 266 * \note 267 * This function dynamically determines whether to use the SGIX_pbuffer 268 * version of the protocol or the GLX 1.3 version of the protocol. 269 * 270 * \todo 271 * The number of attributes returned is likely to be small, probably less than 272 * 10. Given that, this routine should try to use an array on the stack to 273 * capture the reply rather than always calling Xmalloc. 274 */ 275 static int 276 GetDrawableAttribute(Display * dpy, GLXDrawable drawable, 277 int attribute, unsigned int *value) 278 { 279 struct glx_display *priv; 280 xGLXGetDrawableAttributesReply reply; 281 CARD32 *data; 282 CARD8 opcode; 283 unsigned int length; 284 unsigned int i; 285 unsigned int num_attributes; 286 GLboolean use_glx_1_3; 287 288 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 289 __GLXDRIdrawable *pdraw; 290 #endif 291 292 if (dpy == NULL) 293 return 0; 294 295 /* Page 38 (page 52 of the PDF) of glxencode1.3.pdf says: 296 * 297 * "If drawable is not a valid GLX drawable, a GLXBadDrawable error is 298 * generated." 299 */ 300 if (drawable == 0) { 301 __glXSendError(dpy, GLXBadDrawable, 0, X_GLXGetDrawableAttributes, false); 302 return 0; 303 } 304 305 priv = __glXInitialize(dpy); 306 if (priv == NULL) 307 return 0; 308 309 use_glx_1_3 = ((priv->majorVersion > 1) || (priv->minorVersion >= 3)); 310 311 *value = 0; 312 313 314 opcode = __glXSetupForCommand(dpy); 315 if (!opcode) 316 return 0; 317 318 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 319 pdraw = GetGLXDRIDrawable(dpy, drawable); 320 321 if (attribute == GLX_BACK_BUFFER_AGE_EXT) { 322 struct glx_context *gc = __glXGetCurrentContext(); 323 struct glx_screen *psc; 324 325 /* The GLX_EXT_buffer_age spec says: 326 * 327 * "If querying GLX_BACK_BUFFER_AGE_EXT and <draw> is not bound to 328 * the calling thread's current context a GLXBadDrawable error is 329 * generated." 330 */ 331 if (pdraw == NULL || gc == &dummyContext || gc->currentDpy != dpy || 332 (gc->currentDrawable != drawable && 333 gc->currentReadable != drawable)) { 334 __glXSendError(dpy, GLXBadDrawable, drawable, 335 X_GLXGetDrawableAttributes, false); 336 return 0; 337 } 338 339 psc = pdraw->psc; 340 341 if (psc->driScreen->getBufferAge != NULL) 342 *value = psc->driScreen->getBufferAge(pdraw); 343 344 return 0; 345 } 346 #endif 347 348 LockDisplay(dpy); 349 350 if (use_glx_1_3) { 351 xGLXGetDrawableAttributesReq *req; 352 353 GetReq(GLXGetDrawableAttributes, req); 354 req->reqType = opcode; 355 req->glxCode = X_GLXGetDrawableAttributes; 356 req->drawable = drawable; 357 } 358 else { 359 xGLXVendorPrivateWithReplyReq *vpreq; 360 361 GetReqExtra(GLXVendorPrivateWithReply, 4, vpreq); 362 data = (CARD32 *) (vpreq + 1); 363 data[0] = (CARD32) drawable; 364 365 vpreq->reqType = opcode; 366 vpreq->glxCode = X_GLXVendorPrivateWithReply; 367 vpreq->vendorCode = X_GLXvop_GetDrawableAttributesSGIX; 368 } 369 370 _XReply(dpy, (xReply *) & reply, 0, False); 371 372 if (reply.type == X_Error) { 373 UnlockDisplay(dpy); 374 SyncHandle(); 375 return 0; 376 } 377 378 length = reply.length; 379 if (length) { 380 num_attributes = (use_glx_1_3) ? reply.numAttribs : length / 2; 381 data = malloc(length * sizeof(CARD32)); 382 if (data == NULL) { 383 /* Throw data on the floor */ 384 _XEatData(dpy, length); 385 } 386 else { 387 _XRead(dpy, (char *) data, length * sizeof(CARD32)); 388 389 /* Search the set of returned attributes for the attribute requested by 390 * the caller. 391 */ 392 for (i = 0; i < num_attributes; i++) { 393 if (data[i * 2] == attribute) { 394 *value = data[(i * 2) + 1]; 395 break; 396 } 397 } 398 399 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 400 if (pdraw != NULL) { 401 if (!pdraw->textureTarget) 402 pdraw->textureTarget = 403 determineTextureTarget((const int *) data, num_attributes); 404 if (!pdraw->textureFormat) 405 pdraw->textureFormat = 406 determineTextureFormat((const int *) data, num_attributes); 407 } 408 #endif 409 410 free(data); 411 } 412 } 413 414 UnlockDisplay(dpy); 415 SyncHandle(); 416 417 return 0; 418 } 419 420 static void 421 protocolDestroyDrawable(Display *dpy, GLXDrawable drawable, CARD32 glxCode) 422 { 423 xGLXDestroyPbufferReq *req; 424 CARD8 opcode; 425 426 opcode = __glXSetupForCommand(dpy); 427 if (!opcode) 428 return; 429 430 LockDisplay(dpy); 431 432 GetReq(GLXDestroyPbuffer, req); 433 req->reqType = opcode; 434 req->glxCode = glxCode; 435 req->pbuffer = (GLXPbuffer) drawable; 436 437 UnlockDisplay(dpy); 438 SyncHandle(); 439 } 440 441 /** 442 * Create a non-pbuffer GLX drawable. 443 */ 444 static GLXDrawable 445 CreateDrawable(Display *dpy, struct glx_config *config, 446 Drawable drawable, const int *attrib_list, CARD8 glxCode) 447 { 448 xGLXCreateWindowReq *req; 449 struct glx_drawable *glxDraw; 450 CARD32 *data; 451 unsigned int i; 452 CARD8 opcode; 453 GLXDrawable xid; 454 455 i = 0; 456 if (attrib_list) { 457 while (attrib_list[i * 2] != None) 458 i++; 459 } 460 461 opcode = __glXSetupForCommand(dpy); 462 if (!opcode) 463 return None; 464 465 glxDraw = malloc(sizeof(*glxDraw)); 466 if (!glxDraw) 467 return None; 468 469 LockDisplay(dpy); 470 GetReqExtra(GLXCreateWindow, 8 * i, req); 471 data = (CARD32 *) (req + 1); 472 473 req->reqType = opcode; 474 req->glxCode = glxCode; 475 req->screen = config->screen; 476 req->fbconfig = config->fbconfigID; 477 req->window = drawable; 478 req->glxwindow = xid = XAllocID(dpy); 479 req->numAttribs = i; 480 481 if (attrib_list) 482 memcpy(data, attrib_list, 8 * i); 483 484 UnlockDisplay(dpy); 485 SyncHandle(); 486 487 if (InitGLXDrawable(dpy, glxDraw, drawable, xid)) { 488 free(glxDraw); 489 return None; 490 } 491 492 if (!CreateDRIDrawable(dpy, config, drawable, xid, attrib_list, i)) { 493 if (glxCode == X_GLXCreatePixmap) 494 glxCode = X_GLXDestroyPixmap; 495 else 496 glxCode = X_GLXDestroyWindow; 497 protocolDestroyDrawable(dpy, xid, glxCode); 498 xid = None; 499 } 500 501 return xid; 502 } 503 504 505 /** 506 * Destroy a non-pbuffer GLX drawable. 507 */ 508 static void 509 DestroyDrawable(Display * dpy, GLXDrawable drawable, CARD32 glxCode) 510 { 511 if ((dpy == NULL) || (drawable == 0)) { 512 return; 513 } 514 515 protocolDestroyDrawable(dpy, drawable, glxCode); 516 517 DestroyGLXDrawable(dpy, drawable); 518 DestroyDRIDrawable(dpy, drawable, GL_FALSE); 519 520 return; 521 } 522 523 524 /** 525 * Create a pbuffer. 526 * 527 * This function is used to implement \c glXCreatePbuffer and 528 * \c glXCreateGLXPbufferSGIX. 529 * 530 * \note 531 * This function dynamically determines whether to use the SGIX_pbuffer 532 * version of the protocol or the GLX 1.3 version of the protocol. 533 */ 534 static GLXDrawable 535 CreatePbuffer(Display * dpy, struct glx_config *config, 536 unsigned int width, unsigned int height, 537 const int *attrib_list, GLboolean size_in_attribs) 538 { 539 struct glx_display *priv = __glXInitialize(dpy); 540 GLXDrawable id = 0; 541 CARD32 *data; 542 CARD8 opcode; 543 unsigned int i; 544 Pixmap pixmap; 545 GLboolean glx_1_3 = GL_FALSE; 546 547 if (priv == NULL) 548 return None; 549 550 i = 0; 551 if (attrib_list) { 552 while (attrib_list[i * 2]) 553 i++; 554 } 555 556 opcode = __glXSetupForCommand(dpy); 557 if (!opcode) 558 return None; 559 560 LockDisplay(dpy); 561 id = XAllocID(dpy); 562 563 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { 564 xGLXCreatePbufferReq *req; 565 unsigned int extra = (size_in_attribs) ? 0 : 2; 566 567 glx_1_3 = GL_TRUE; 568 569 GetReqExtra(GLXCreatePbuffer, (8 * (i + extra)), req); 570 data = (CARD32 *) (req + 1); 571 572 req->reqType = opcode; 573 req->glxCode = X_GLXCreatePbuffer; 574 req->screen = config->screen; 575 req->fbconfig = config->fbconfigID; 576 req->pbuffer = id; 577 req->numAttribs = i + extra; 578 579 if (!size_in_attribs) { 580 data[(2 * i) + 0] = GLX_PBUFFER_WIDTH; 581 data[(2 * i) + 1] = width; 582 data[(2 * i) + 2] = GLX_PBUFFER_HEIGHT; 583 data[(2 * i) + 3] = height; 584 data += 4; 585 } 586 } 587 else { 588 xGLXVendorPrivateReq *vpreq; 589 590 GetReqExtra(GLXVendorPrivate, 20 + (8 * i), vpreq); 591 data = (CARD32 *) (vpreq + 1); 592 593 vpreq->reqType = opcode; 594 vpreq->glxCode = X_GLXVendorPrivate; 595 vpreq->vendorCode = X_GLXvop_CreateGLXPbufferSGIX; 596 597 data[0] = config->screen; 598 data[1] = config->fbconfigID; 599 data[2] = id; 600 data[3] = width; 601 data[4] = height; 602 data += 5; 603 } 604 605 (void) memcpy(data, attrib_list, sizeof(CARD32) * 2 * i); 606 607 UnlockDisplay(dpy); 608 SyncHandle(); 609 610 pixmap = XCreatePixmap(dpy, RootWindow(dpy, config->screen), 611 width, height, config->rgbBits); 612 613 if (!CreateDRIDrawable(dpy, config, pixmap, id, attrib_list, i)) { 614 CARD32 o = glx_1_3 ? X_GLXDestroyPbuffer : X_GLXvop_DestroyGLXPbufferSGIX; 615 XFreePixmap(dpy, pixmap); 616 protocolDestroyDrawable(dpy, id, o); 617 id = None; 618 } 619 620 return id; 621 } 622 623 /** 624 * Destroy a pbuffer. 625 * 626 * This function is used to implement \c glXDestroyPbuffer and 627 * \c glXDestroyGLXPbufferSGIX. 628 * 629 * \note 630 * This function dynamically determines whether to use the SGIX_pbuffer 631 * version of the protocol or the GLX 1.3 version of the protocol. 632 */ 633 static void 634 DestroyPbuffer(Display * dpy, GLXDrawable drawable) 635 { 636 struct glx_display *priv = __glXInitialize(dpy); 637 CARD8 opcode; 638 639 if ((priv == NULL) || (dpy == NULL) || (drawable == 0)) { 640 return; 641 } 642 643 opcode = __glXSetupForCommand(dpy); 644 if (!opcode) 645 return; 646 647 LockDisplay(dpy); 648 649 if ((priv->majorVersion > 1) || (priv->minorVersion >= 3)) { 650 xGLXDestroyPbufferReq *req; 651 652 GetReq(GLXDestroyPbuffer, req); 653 req->reqType = opcode; 654 req->glxCode = X_GLXDestroyPbuffer; 655 req->pbuffer = (GLXPbuffer) drawable; 656 } 657 else { 658 xGLXVendorPrivateWithReplyReq *vpreq; 659 CARD32 *data; 660 661 GetReqExtra(GLXVendorPrivateWithReply, 4, vpreq); 662 data = (CARD32 *) (vpreq + 1); 663 664 data[0] = (CARD32) drawable; 665 666 vpreq->reqType = opcode; 667 vpreq->glxCode = X_GLXVendorPrivateWithReply; 668 vpreq->vendorCode = X_GLXvop_DestroyGLXPbufferSGIX; 669 } 670 671 UnlockDisplay(dpy); 672 SyncHandle(); 673 674 DestroyDRIDrawable(dpy, drawable, GL_TRUE); 675 676 return; 677 } 678 679 /** 680 * Create a new pbuffer. 681 */ 682 _GLX_PUBLIC GLXPbufferSGIX 683 glXCreateGLXPbufferSGIX(Display * dpy, GLXFBConfigSGIX config, 684 unsigned int width, unsigned int height, 685 int *attrib_list) 686 { 687 return (GLXPbufferSGIX) CreatePbuffer(dpy, (struct glx_config *) config, 688 width, height, 689 attrib_list, GL_FALSE); 690 } 691 692 #endif /* GLX_USE_APPLEGL */ 693 694 /** 695 * Create a new pbuffer. 696 */ 697 _GLX_PUBLIC GLXPbuffer 698 glXCreatePbuffer(Display * dpy, GLXFBConfig config, const int *attrib_list) 699 { 700 int i, width, height; 701 #ifdef GLX_USE_APPLEGL 702 GLXPbuffer result; 703 int errorcode; 704 #endif 705 706 width = 0; 707 height = 0; 708 709 WARN_ONCE_GLX_1_3(dpy, __func__); 710 711 #ifdef GLX_USE_APPLEGL 712 for (i = 0; attrib_list[i]; ++i) { 713 switch (attrib_list[i]) { 714 case GLX_PBUFFER_WIDTH: 715 width = attrib_list[i + 1]; 716 ++i; 717 break; 718 719 case GLX_PBUFFER_HEIGHT: 720 height = attrib_list[i + 1]; 721 ++i; 722 break; 723 724 case GLX_LARGEST_PBUFFER: 725 /* This is a hint we should probably handle, but how? */ 726 ++i; 727 break; 728 729 case GLX_PRESERVED_CONTENTS: 730 /* The contents are always preserved with AppleSGLX with CGL. */ 731 ++i; 732 break; 733 734 default: 735 return None; 736 } 737 } 738 739 if (apple_glx_pbuffer_create(dpy, config, width, height, &errorcode, 740 &result)) { 741 /* 742 * apple_glx_pbuffer_create only sets the errorcode to core X11 743 * errors. 744 */ 745 __glXSendError(dpy, errorcode, 0, X_GLXCreatePbuffer, true); 746 747 return None; 748 } 749 750 return result; 751 #else 752 for (i = 0; attrib_list[i * 2]; i++) { 753 switch (attrib_list[i * 2]) { 754 case GLX_PBUFFER_WIDTH: 755 width = attrib_list[i * 2 + 1]; 756 break; 757 case GLX_PBUFFER_HEIGHT: 758 height = attrib_list[i * 2 + 1]; 759 break; 760 } 761 } 762 763 return (GLXPbuffer) CreatePbuffer(dpy, (struct glx_config *) config, 764 width, height, attrib_list, GL_TRUE); 765 #endif 766 } 767 768 769 /** 770 * Destroy an existing pbuffer. 771 */ 772 _GLX_PUBLIC void 773 glXDestroyPbuffer(Display * dpy, GLXPbuffer pbuf) 774 { 775 #ifdef GLX_USE_APPLEGL 776 if (apple_glx_pbuffer_destroy(dpy, pbuf)) { 777 __glXSendError(dpy, GLXBadPbuffer, pbuf, X_GLXDestroyPbuffer, false); 778 } 779 #else 780 DestroyPbuffer(dpy, pbuf); 781 #endif 782 } 783 784 785 /** 786 * Query an attribute of a drawable. 787 */ 788 _GLX_PUBLIC void 789 glXQueryDrawable(Display * dpy, GLXDrawable drawable, 790 int attribute, unsigned int *value) 791 { 792 WARN_ONCE_GLX_1_3(dpy, __func__); 793 #ifdef GLX_USE_APPLEGL 794 Window root; 795 int x, y; 796 unsigned int width, height, bd, depth; 797 798 if (apple_glx_pixmap_query(drawable, attribute, value)) 799 return; /*done */ 800 801 if (apple_glx_pbuffer_query(drawable, attribute, value)) 802 return; /*done */ 803 804 /* 805 * The OpenGL spec states that we should report GLXBadDrawable if 806 * the drawable is invalid, however doing so would require that we 807 * use XSetErrorHandler(), which is known to not be thread safe. 808 * If we use a round-trip call to validate the drawable, there could 809 * be a race, so instead we just opt in favor of letting the 810 * XGetGeometry request fail with a GetGeometry request X error 811 * rather than GLXBadDrawable, in what is hoped to be a rare 812 * case of an invalid drawable. In practice most and possibly all 813 * X11 apps using GLX shouldn't notice a difference. 814 */ 815 if (XGetGeometry 816 (dpy, drawable, &root, &x, &y, &width, &height, &bd, &depth)) { 817 switch (attribute) { 818 case GLX_WIDTH: 819 *value = width; 820 break; 821 822 case GLX_HEIGHT: 823 *value = height; 824 break; 825 } 826 } 827 #else 828 GetDrawableAttribute(dpy, drawable, attribute, value); 829 #endif 830 } 831 832 833 #ifndef GLX_USE_APPLEGL 834 /** 835 * Query an attribute of a pbuffer. 836 */ 837 _GLX_PUBLIC int 838 glXQueryGLXPbufferSGIX(Display * dpy, GLXPbufferSGIX drawable, 839 int attribute, unsigned int *value) 840 { 841 return GetDrawableAttribute(dpy, drawable, attribute, value); 842 } 843 #endif 844 845 /** 846 * Select the event mask for a drawable. 847 */ 848 _GLX_PUBLIC void 849 glXSelectEvent(Display * dpy, GLXDrawable drawable, unsigned long mask) 850 { 851 #ifdef GLX_USE_APPLEGL 852 XWindowAttributes xwattr; 853 854 if (apple_glx_pbuffer_set_event_mask(drawable, mask)) 855 return; /*done */ 856 857 /* 858 * The spec allows a window, but currently there are no valid 859 * events for a window, so do nothing. 860 */ 861 if (XGetWindowAttributes(dpy, drawable, &xwattr)) 862 return; /*done */ 863 /* The drawable seems to be invalid. Report an error. */ 864 865 __glXSendError(dpy, GLXBadDrawable, drawable, 866 X_GLXChangeDrawableAttributes, false); 867 #else 868 CARD32 attribs[2]; 869 870 attribs[0] = (CARD32) GLX_EVENT_MASK; 871 attribs[1] = (CARD32) mask; 872 873 ChangeDrawableAttribute(dpy, drawable, attribs, 1); 874 #endif 875 } 876 877 878 /** 879 * Get the selected event mask for a drawable. 880 */ 881 _GLX_PUBLIC void 882 glXGetSelectedEvent(Display * dpy, GLXDrawable drawable, unsigned long *mask) 883 { 884 #ifdef GLX_USE_APPLEGL 885 XWindowAttributes xwattr; 886 887 if (apple_glx_pbuffer_get_event_mask(drawable, mask)) 888 return; /*done */ 889 890 /* 891 * The spec allows a window, but currently there are no valid 892 * events for a window, so do nothing, but set the mask to 0. 893 */ 894 if (XGetWindowAttributes(dpy, drawable, &xwattr)) { 895 /* The window is valid, so set the mask to 0. */ 896 *mask = 0; 897 return; /*done */ 898 } 899 /* The drawable seems to be invalid. Report an error. */ 900 901 __glXSendError(dpy, GLXBadDrawable, drawable, X_GLXGetDrawableAttributes, 902 true); 903 #else 904 unsigned int value; 905 906 907 /* The non-sense with value is required because on LP64 platforms 908 * sizeof(unsigned int) != sizeof(unsigned long). On little-endian 909 * we could just type-cast the pointer, but why? 910 */ 911 912 GetDrawableAttribute(dpy, drawable, GLX_EVENT_MASK_SGIX, &value); 913 *mask = value; 914 #endif 915 } 916 917 918 _GLX_PUBLIC GLXPixmap 919 glXCreatePixmap(Display * dpy, GLXFBConfig config, Pixmap pixmap, 920 const int *attrib_list) 921 { 922 WARN_ONCE_GLX_1_3(dpy, __func__); 923 924 #ifdef GLX_USE_APPLEGL 925 const struct glx_config *modes = (const struct glx_config *) config; 926 927 if (apple_glx_pixmap_create(dpy, modes->screen, pixmap, modes)) 928 return None; 929 930 return pixmap; 931 #else 932 return CreateDrawable(dpy, (struct glx_config *) config, 933 (Drawable) pixmap, attrib_list, X_GLXCreatePixmap); 934 #endif 935 } 936 937 938 _GLX_PUBLIC GLXWindow 939 glXCreateWindow(Display * dpy, GLXFBConfig config, Window win, 940 const int *attrib_list) 941 { 942 WARN_ONCE_GLX_1_3(dpy, __func__); 943 #ifdef GLX_USE_APPLEGL 944 XWindowAttributes xwattr; 945 XVisualInfo *visinfo; 946 947 (void) attrib_list; /*unused according to GLX 1.4 */ 948 949 XGetWindowAttributes(dpy, win, &xwattr); 950 951 visinfo = glXGetVisualFromFBConfig(dpy, config); 952 953 if (NULL == visinfo) { 954 __glXSendError(dpy, GLXBadFBConfig, 0, X_GLXCreateWindow, false); 955 return None; 956 } 957 958 if (visinfo->visualid != XVisualIDFromVisual(xwattr.visual)) { 959 __glXSendError(dpy, BadMatch, 0, X_GLXCreateWindow, true); 960 return None; 961 } 962 963 free(visinfo); 964 965 return win; 966 #else 967 return CreateDrawable(dpy, (struct glx_config *) config, 968 (Drawable) win, attrib_list, X_GLXCreateWindow); 969 #endif 970 } 971 972 973 _GLX_PUBLIC void 974 glXDestroyPixmap(Display * dpy, GLXPixmap pixmap) 975 { 976 WARN_ONCE_GLX_1_3(dpy, __func__); 977 #ifdef GLX_USE_APPLEGL 978 if (apple_glx_pixmap_destroy(dpy, pixmap)) 979 __glXSendError(dpy, GLXBadPixmap, pixmap, X_GLXDestroyPixmap, false); 980 #else 981 DestroyDrawable(dpy, (GLXDrawable) pixmap, X_GLXDestroyPixmap); 982 #endif 983 } 984 985 986 _GLX_PUBLIC void 987 glXDestroyWindow(Display * dpy, GLXWindow win) 988 { 989 WARN_ONCE_GLX_1_3(dpy, __func__); 990 #ifndef GLX_USE_APPLEGL 991 DestroyDrawable(dpy, (GLXDrawable) win, X_GLXDestroyWindow); 992 #endif 993 } 994 995 _GLX_PUBLIC 996 GLX_ALIAS_VOID(glXDestroyGLXPbufferSGIX, 997 (Display * dpy, GLXPbufferSGIX pbuf), 998 (dpy, pbuf), glXDestroyPbuffer) 999 1000 _GLX_PUBLIC 1001 GLX_ALIAS_VOID(glXSelectEventSGIX, 1002 (Display * dpy, GLXDrawable drawable, 1003 unsigned long mask), (dpy, drawable, mask), glXSelectEvent) 1004 1005 _GLX_PUBLIC 1006 GLX_ALIAS_VOID(glXGetSelectedEventSGIX, 1007 (Display * dpy, GLXDrawable drawable, 1008 unsigned long *mask), (dpy, drawable, mask), 1009 glXGetSelectedEvent) 1010