Home | History | Annotate | Download | only in glx
      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_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  */
     57 static void
     58 warn_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  */
     81 static void
     82 ChangeDrawableAttribute(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
    155 static GLenum
    156 determineTextureTarget(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 
    177 static GLenum
    178 determineTextureFormat(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 
    190 static GLboolean
    191 CreateDRIDrawable(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 
    221 static void
    222 DestroyDRIDrawable(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 
    239 static GLboolean
    240 CreateDRIDrawable(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 
    247 static void
    248 DestroyDRIDrawable(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  */
    269 static int
    270 GetDrawableAttribute(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 
    370 static void
    371 protocolDestroyDrawable(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  */
    394 static GLXDrawable
    395 CreateDrawable(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  */
    458 static void
    459 DestroyDrawable(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  */
    484 static GLXDrawable
    485 CreatePbuffer(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  */
    580 static void
    581 DestroyPbuffer(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
    630 glXCreateGLXPbufferSGIX(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
    645 glXCreatePbuffer(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
    720 glXDestroyPbuffer(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
    736 glXQueryDrawable(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
    785 glXQueryGLXPbufferSGIX(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
    796 glXSelectEvent(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
    829 glXGetSelectedEvent(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
    866 glXCreatePixmap(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
    886 glXCreateWindow(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
    921 glXDestroyPixmap(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
    934 glXDestroyWindow(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
    944 GLX_ALIAS_VOID(glXDestroyGLXPbufferSGIX,
    945                (Display * dpy, GLXPbufferSGIX pbuf),
    946                (dpy, pbuf), glXDestroyPbuffer)
    947 
    948 _X_EXPORT
    949 GLX_ALIAS_VOID(glXSelectEventSGIX,
    950                (Display * dpy, GLXDrawable drawable,
    951                 unsigned long mask), (dpy, drawable, mask), glXSelectEvent)
    952 
    953 _X_EXPORT
    954 GLX_ALIAS_VOID(glXGetSelectedEventSGIX,
    955                (Display * dpy, GLXDrawable drawable,
    956                 unsigned long *mask), (dpy, drawable, mask),
    957                glXGetSelectedEvent)
    958 #endif
    959