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