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