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