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