Home | History | Annotate | Download | only in x11
      1 /**
      2  * GLX initialization.  Code based on glxext.c, glx_query.c, and
      3  * glcontextmodes.c under src/glx/.  The major difference is that DRI
      4  * related code is stripped out.
      5  *
      6  * If the maintenance of this file takes too much time, we should consider
      7  * refactoring glxext.c.
      8  */
      9 
     10 #include <assert.h>
     11 #include <X11/Xlib.h>
     12 #include <X11/Xproto.h>
     13 #include <X11/Xlibint.h>
     14 #include <X11/extensions/Xext.h>
     15 #include <X11/extensions/extutil.h>
     16 #include <sys/time.h>
     17 
     18 #include "GL/glxproto.h"
     19 #include "GL/glxtokens.h"
     20 #include "GL/gl.h" /* for GL types needed by __GLcontextModes */
     21 #include "glcore.h"  /* for __GLcontextModes */
     22 
     23 #include "glxinit.h"
     24 
     25 #ifdef GLX_DIRECT_RENDERING
     26 
     27 typedef struct GLXGenericGetString
     28 {
     29    CARD8 reqType;
     30    CARD8 glxCode;
     31    CARD16 length B16;
     32    CARD32 for_whom B32;
     33    CARD32 name B32;
     34 } xGLXGenericGetStringReq;
     35 
     36 #define sz_xGLXGenericGetStringReq 12
     37 #define X_GLXGenericGetString 0
     38 
     39 /* Extension required boiler plate */
     40 
     41 static char *__glXExtensionName = GLX_EXTENSION_NAME;
     42 static XExtensionInfo *__glXExtensionInfo = NULL;
     43 
     44 static int
     45 __glXCloseDisplay(Display * dpy, XExtCodes * codes)
     46 {
     47    return XextRemoveDisplay(__glXExtensionInfo, dpy);
     48 }
     49 
     50 static /* const */ XExtensionHooks __glXExtensionHooks = {
     51   NULL,                   /* create_gc */
     52   NULL,                   /* copy_gc */
     53   NULL,                   /* flush_gc */
     54   NULL,                   /* free_gc */
     55   NULL,                   /* create_font */
     56   NULL,                   /* free_font */
     57   __glXCloseDisplay,      /* close_display */
     58   NULL,                   /* wire_to_event */
     59   NULL,                   /* event_to_wire */
     60   NULL,                   /* error */
     61   NULL,                   /* error_string */
     62 };
     63 
     64 static XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo,
     65 				  __glXExtensionName, &__glXExtensionHooks,
     66 				  __GLX_NUMBER_EVENTS, NULL)
     67 
     68 static GLint
     69 _gl_convert_from_x_visual_type(int visualType)
     70 {
     71 #define NUM_VISUAL_TYPES   6
     72    static const int glx_visual_types[NUM_VISUAL_TYPES] = {
     73       GLX_STATIC_GRAY, GLX_GRAY_SCALE,
     74       GLX_STATIC_COLOR, GLX_PSEUDO_COLOR,
     75       GLX_TRUE_COLOR, GLX_DIRECT_COLOR
     76    };
     77 
     78    return ((unsigned) visualType < NUM_VISUAL_TYPES)
     79       ? glx_visual_types[visualType] : GLX_NONE;
     80 }
     81 
     82 static void
     83 _gl_context_modes_destroy(__GLcontextModes * modes)
     84 {
     85    while (modes != NULL) {
     86       __GLcontextModes *const next = modes->next;
     87 
     88       Xfree(modes);
     89       modes = next;
     90    }
     91 }
     92 
     93 static __GLcontextModes *
     94 _gl_context_modes_create(unsigned count, size_t minimum_size)
     95 {
     96    const size_t size = (minimum_size > sizeof(__GLcontextModes))
     97       ? minimum_size : sizeof(__GLcontextModes);
     98    __GLcontextModes *base = NULL;
     99    __GLcontextModes **next;
    100    unsigned i;
    101 
    102    next = &base;
    103    for (i = 0; i < count; i++) {
    104       *next = (__GLcontextModes *) Xmalloc(size);
    105       if (*next == NULL) {
    106          _gl_context_modes_destroy(base);
    107          base = NULL;
    108          break;
    109       }
    110 
    111       memset(*next, 0, size);
    112       (*next)->visualID = GLX_DONT_CARE;
    113       (*next)->visualType = GLX_DONT_CARE;
    114       (*next)->visualRating = GLX_NONE;
    115       (*next)->transparentPixel = GLX_NONE;
    116       (*next)->transparentRed = GLX_DONT_CARE;
    117       (*next)->transparentGreen = GLX_DONT_CARE;
    118       (*next)->transparentBlue = GLX_DONT_CARE;
    119       (*next)->transparentAlpha = GLX_DONT_CARE;
    120       (*next)->transparentIndex = GLX_DONT_CARE;
    121       (*next)->xRenderable = GLX_DONT_CARE;
    122       (*next)->fbconfigID = GLX_DONT_CARE;
    123       (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
    124       (*next)->bindToTextureRgb = GLX_DONT_CARE;
    125       (*next)->bindToTextureRgba = GLX_DONT_CARE;
    126       (*next)->bindToMipmapTexture = GLX_DONT_CARE;
    127       (*next)->bindToTextureTargets = GLX_DONT_CARE;
    128       (*next)->yInverted = GLX_DONT_CARE;
    129 
    130       next = &((*next)->next);
    131    }
    132 
    133    return base;
    134 }
    135 
    136 static char *
    137 __glXQueryServerString(Display * dpy, int opcode, CARD32 screen, CARD32 name)
    138 {
    139    xGLXGenericGetStringReq *req;
    140    xGLXSingleReply reply;
    141    int length;
    142    int numbytes;
    143    char *buf;
    144    CARD32 for_whom = screen;
    145    CARD32 glxCode = X_GLXQueryServerString;
    146 
    147 
    148    LockDisplay(dpy);
    149 
    150 
    151    /* All of the GLX protocol requests for getting a string from the server
    152     * look the same.  The exact meaning of the for_whom field is usually
    153     * either the screen number (for glXQueryServerString) or the context tag
    154     * (for GLXSingle).
    155     */
    156 
    157    GetReq(GLXGenericGetString, req);
    158    req->reqType = opcode;
    159    req->glxCode = glxCode;
    160    req->for_whom = for_whom;
    161    req->name = name;
    162 
    163    _XReply(dpy, (xReply *) & reply, 0, False);
    164 
    165    length = reply.length * 4;
    166    numbytes = reply.size;
    167 
    168    buf = (char *) Xmalloc(numbytes);
    169    if (buf != NULL) {
    170       _XRead(dpy, buf, numbytes);
    171       length -= numbytes;
    172    }
    173 
    174    _XEatData(dpy, length);
    175 
    176    UnlockDisplay(dpy);
    177    SyncHandle();
    178 
    179    return buf;
    180 }
    181 
    182 /************************************************************************/
    183 /*
    184 ** Free the per screen configs data as well as the array of
    185 ** __glXScreenConfigs.
    186 */
    187 static void
    188 FreeScreenConfigs(__GLXdisplayPrivate * priv)
    189 {
    190    __GLXscreenConfigs *psc;
    191    GLint i, screens;
    192 
    193    /* Free screen configuration information */
    194    screens = ScreenCount(priv->dpy);
    195    for (i = 0; i < screens; i++) {
    196       psc = priv->screenConfigs[i];
    197       if (!psc)
    198          continue;
    199       if (psc->configs) {
    200          _gl_context_modes_destroy(psc->configs);
    201          psc->configs = NULL;   /* NOTE: just for paranoia */
    202       }
    203       Xfree((char *) psc->serverGLXexts);
    204    }
    205    XFree((char *) priv->screenConfigs);
    206    priv->screenConfigs = NULL;
    207 }
    208 
    209 /*
    210 ** Release the private memory referred to in a display private
    211 ** structure.  The caller will free the extension structure.
    212 */
    213 static int
    214 __glXFreeDisplayPrivate(XExtData * extension)
    215 {
    216    __GLXdisplayPrivate *priv;
    217 
    218    priv = (__GLXdisplayPrivate *) extension->private_data;
    219    FreeScreenConfigs(priv);
    220    if (priv->serverGLXversion)
    221       Xfree((char *) priv->serverGLXversion);
    222 
    223    Xfree((char *) priv);
    224    return 0;
    225 }
    226 
    227 /************************************************************************/
    228 
    229 /*
    230 ** Query the version of the GLX extension.  This procedure works even if
    231 ** the client extension is not completely set up.
    232 */
    233 
    234 #define GLX_MAJOR_VERSION 1       /* current version numbers */
    235 #define GLX_MINOR_VERSION 4
    236 
    237 static Bool
    238 QueryVersion(Display * dpy, int opcode, int *major, int *minor)
    239 {
    240    xGLXQueryVersionReq *req;
    241    xGLXQueryVersionReply reply;
    242 
    243    /* Send the glXQueryVersion request */
    244    LockDisplay(dpy);
    245    GetReq(GLXQueryVersion, req);
    246    req->reqType = opcode;
    247    req->glxCode = X_GLXQueryVersion;
    248    req->majorVersion = GLX_MAJOR_VERSION;
    249    req->minorVersion = GLX_MINOR_VERSION;
    250    _XReply(dpy, (xReply *) & reply, 0, False);
    251    UnlockDisplay(dpy);
    252    SyncHandle();
    253 
    254    if (reply.majorVersion != GLX_MAJOR_VERSION) {
    255       /*
    256        ** The server does not support the same major release as this
    257        ** client.
    258        */
    259       return GL_FALSE;
    260    }
    261    *major = reply.majorVersion;
    262    *minor = min(reply.minorVersion, GLX_MINOR_VERSION);
    263    return GL_TRUE;
    264 }
    265 
    266 #define __GLX_MIN_CONFIG_PROPS	18
    267 #define __GLX_MAX_CONFIG_PROPS	500
    268 #define __GLX_EXT_CONFIG_PROPS 	10
    269 #define __GLX_TOTAL_CONFIG       (__GLX_MIN_CONFIG_PROPS +      \
    270                                     2 * __GLX_EXT_CONFIG_PROPS)
    271 
    272 static void
    273 __glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count,
    274                                     const INT32 * bp, Bool tagged_only,
    275                                     Bool fbconfig_style_tags)
    276 {
    277    int i;
    278 
    279    if (!tagged_only) {
    280       /* Copy in the first set of properties */
    281       config->visualID = *bp++;
    282 
    283       config->visualType = _gl_convert_from_x_visual_type(*bp++);
    284 
    285       config->rgbMode = *bp++;
    286 
    287       config->redBits = *bp++;
    288       config->greenBits = *bp++;
    289       config->blueBits = *bp++;
    290       config->alphaBits = *bp++;
    291       config->accumRedBits = *bp++;
    292       config->accumGreenBits = *bp++;
    293       config->accumBlueBits = *bp++;
    294       config->accumAlphaBits = *bp++;
    295 
    296       config->doubleBufferMode = *bp++;
    297       config->stereoMode = *bp++;
    298 
    299       config->rgbBits = *bp++;
    300       config->depthBits = *bp++;
    301       config->stencilBits = *bp++;
    302       config->numAuxBuffers = *bp++;
    303       config->level = *bp++;
    304 
    305       count -= __GLX_MIN_CONFIG_PROPS;
    306    }
    307 
    308    /*
    309     ** Additional properties may be in a list at the end
    310     ** of the reply.  They are in pairs of property type
    311     ** and property value.
    312     */
    313 
    314 #define FETCH_OR_SET(tag) \
    315     config-> tag = ( fbconfig_style_tags ) ? *bp++ : 1
    316 
    317    for (i = 0; i < count; i += 2) {
    318       switch (*bp++) {
    319       case GLX_RGBA:
    320          FETCH_OR_SET(rgbMode);
    321          break;
    322       case GLX_BUFFER_SIZE:
    323          config->rgbBits = *bp++;
    324          break;
    325       case GLX_LEVEL:
    326          config->level = *bp++;
    327          break;
    328       case GLX_DOUBLEBUFFER:
    329          FETCH_OR_SET(doubleBufferMode);
    330          break;
    331       case GLX_STEREO:
    332          FETCH_OR_SET(stereoMode);
    333          break;
    334       case GLX_AUX_BUFFERS:
    335          config->numAuxBuffers = *bp++;
    336          break;
    337       case GLX_RED_SIZE:
    338          config->redBits = *bp++;
    339          break;
    340       case GLX_GREEN_SIZE:
    341          config->greenBits = *bp++;
    342          break;
    343       case GLX_BLUE_SIZE:
    344          config->blueBits = *bp++;
    345          break;
    346       case GLX_ALPHA_SIZE:
    347          config->alphaBits = *bp++;
    348          break;
    349       case GLX_DEPTH_SIZE:
    350          config->depthBits = *bp++;
    351          break;
    352       case GLX_STENCIL_SIZE:
    353          config->stencilBits = *bp++;
    354          break;
    355       case GLX_ACCUM_RED_SIZE:
    356          config->accumRedBits = *bp++;
    357          break;
    358       case GLX_ACCUM_GREEN_SIZE:
    359          config->accumGreenBits = *bp++;
    360          break;
    361       case GLX_ACCUM_BLUE_SIZE:
    362          config->accumBlueBits = *bp++;
    363          break;
    364       case GLX_ACCUM_ALPHA_SIZE:
    365          config->accumAlphaBits = *bp++;
    366          break;
    367       case GLX_VISUAL_CAVEAT_EXT:
    368          config->visualRating = *bp++;
    369          break;
    370       case GLX_X_VISUAL_TYPE:
    371          config->visualType = *bp++;
    372          break;
    373       case GLX_TRANSPARENT_TYPE:
    374          config->transparentPixel = *bp++;
    375          break;
    376       case GLX_TRANSPARENT_INDEX_VALUE:
    377          config->transparentIndex = *bp++;
    378          break;
    379       case GLX_TRANSPARENT_RED_VALUE:
    380          config->transparentRed = *bp++;
    381          break;
    382       case GLX_TRANSPARENT_GREEN_VALUE:
    383          config->transparentGreen = *bp++;
    384          break;
    385       case GLX_TRANSPARENT_BLUE_VALUE:
    386          config->transparentBlue = *bp++;
    387          break;
    388       case GLX_TRANSPARENT_ALPHA_VALUE:
    389          config->transparentAlpha = *bp++;
    390          break;
    391       case GLX_VISUAL_ID:
    392          config->visualID = *bp++;
    393          break;
    394       case GLX_DRAWABLE_TYPE:
    395          config->drawableType = *bp++;
    396          break;
    397       case GLX_RENDER_TYPE:
    398          config->renderType = *bp++;
    399          break;
    400       case GLX_X_RENDERABLE:
    401          config->xRenderable = *bp++;
    402          break;
    403       case GLX_FBCONFIG_ID:
    404          config->fbconfigID = *bp++;
    405          break;
    406       case GLX_MAX_PBUFFER_WIDTH:
    407          config->maxPbufferWidth = *bp++;
    408          break;
    409       case GLX_MAX_PBUFFER_HEIGHT:
    410          config->maxPbufferHeight = *bp++;
    411          break;
    412       case GLX_MAX_PBUFFER_PIXELS:
    413          config->maxPbufferPixels = *bp++;
    414          break;
    415       case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX:
    416          config->optimalPbufferWidth = *bp++;
    417          break;
    418       case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX:
    419          config->optimalPbufferHeight = *bp++;
    420          break;
    421       case GLX_VISUAL_SELECT_GROUP_SGIX:
    422          config->visualSelectGroup = *bp++;
    423          break;
    424       case GLX_SWAP_METHOD_OML:
    425          config->swapMethod = *bp++;
    426          break;
    427       case GLX_SAMPLE_BUFFERS_SGIS:
    428          config->sampleBuffers = *bp++;
    429          break;
    430       case GLX_SAMPLES_SGIS:
    431          config->samples = *bp++;
    432          break;
    433       case GLX_BIND_TO_TEXTURE_RGB_EXT:
    434          config->bindToTextureRgb = *bp++;
    435          break;
    436       case GLX_BIND_TO_TEXTURE_RGBA_EXT:
    437          config->bindToTextureRgba = *bp++;
    438          break;
    439       case GLX_BIND_TO_MIPMAP_TEXTURE_EXT:
    440          config->bindToMipmapTexture = *bp++;
    441          break;
    442       case GLX_BIND_TO_TEXTURE_TARGETS_EXT:
    443          config->bindToTextureTargets = *bp++;
    444          break;
    445       case GLX_Y_INVERTED_EXT:
    446          config->yInverted = *bp++;
    447          break;
    448       case None:
    449          i = count;
    450          break;
    451       default:
    452          break;
    453       }
    454    }
    455 
    456    config->renderType =
    457       (config->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
    458 
    459    config->haveAccumBuffer = ((config->accumRedBits +
    460                                config->accumGreenBits +
    461                                config->accumBlueBits +
    462                                config->accumAlphaBits) > 0);
    463    config->haveDepthBuffer = (config->depthBits > 0);
    464    config->haveStencilBuffer = (config->stencilBits > 0);
    465 }
    466 
    467 static __GLcontextModes *
    468 createConfigsFromProperties(Display * dpy, int nvisuals, int nprops,
    469                             int screen, GLboolean tagged_only)
    470 {
    471    INT32 buf[__GLX_TOTAL_CONFIG], *props;
    472    unsigned prop_size;
    473    __GLcontextModes *modes, *m;
    474    int i;
    475 
    476    if (nprops == 0)
    477       return NULL;
    478 
    479    /* FIXME: Is the __GLX_MIN_CONFIG_PROPS test correct for FBconfigs? */
    480 
    481    /* Check number of properties */
    482    if (nprops < __GLX_MIN_CONFIG_PROPS || nprops > __GLX_MAX_CONFIG_PROPS)
    483       return NULL;
    484 
    485    /* Allocate memory for our config structure */
    486    modes = _gl_context_modes_create(nvisuals, sizeof(__GLcontextModes));
    487    if (!modes)
    488       return NULL;
    489 
    490    prop_size = nprops * __GLX_SIZE_INT32;
    491    if (prop_size <= sizeof(buf))
    492       props = buf;
    493    else
    494       props = Xmalloc(prop_size);
    495 
    496    /* Read each config structure and convert it into our format */
    497    m = modes;
    498    for (i = 0; i < nvisuals; i++) {
    499       _XRead(dpy, (char *) props, prop_size);
    500       /* Older X servers don't send this so we default it here. */
    501       m->drawableType = GLX_WINDOW_BIT;
    502       __glXInitializeVisualConfigFromTags(m, nprops, props,
    503                                      tagged_only, GL_TRUE);
    504       m->screen = screen;
    505       m = m->next;
    506    }
    507 
    508    if (props != buf)
    509       Xfree(props);
    510 
    511    return modes;
    512 }
    513 
    514 static GLboolean
    515 getFBConfigs(__GLXscreenConfigs *psc, __GLXdisplayPrivate *priv, int screen)
    516 {
    517    xGLXGetFBConfigsReq *fb_req;
    518    xGLXGetFBConfigsSGIXReq *sgi_req;
    519    xGLXVendorPrivateWithReplyReq *vpreq;
    520    xGLXGetFBConfigsReply reply;
    521    Display *dpy = priv->dpy;
    522 
    523    psc->serverGLXexts =
    524       __glXQueryServerString(dpy, priv->majorOpcode, screen, GLX_EXTENSIONS);
    525 
    526    LockDisplay(dpy);
    527 
    528    psc->configs = NULL;
    529    if (atof(priv->serverGLXversion) >= 1.3) {
    530       GetReq(GLXGetFBConfigs, fb_req);
    531       fb_req->reqType = priv->majorOpcode;
    532       fb_req->glxCode = X_GLXGetFBConfigs;
    533       fb_req->screen = screen;
    534    }
    535    else if (strstr(psc->serverGLXexts, "GLX_SGIX_fbconfig") != NULL) {
    536       GetReqExtra(GLXVendorPrivateWithReply,
    537                   sz_xGLXGetFBConfigsSGIXReq +
    538                   sz_xGLXVendorPrivateWithReplyReq, vpreq);
    539       sgi_req = (xGLXGetFBConfigsSGIXReq *) vpreq;
    540       sgi_req->reqType = priv->majorOpcode;
    541       sgi_req->glxCode = X_GLXVendorPrivateWithReply;
    542       sgi_req->vendorCode = X_GLXvop_GetFBConfigsSGIX;
    543       sgi_req->screen = screen;
    544    }
    545    else
    546       goto out;
    547 
    548    if (!_XReply(dpy, (xReply *) & reply, 0, False))
    549       goto out;
    550 
    551    psc->configs = createConfigsFromProperties(dpy,
    552                                               reply.numFBConfigs,
    553                                               reply.numAttribs * 2,
    554                                               screen, GL_TRUE);
    555 
    556  out:
    557    UnlockDisplay(dpy);
    558    return psc->configs != NULL;
    559 }
    560 
    561 static GLboolean
    562 AllocAndFetchScreenConfigs(Display * dpy, __GLXdisplayPrivate * priv)
    563 {
    564    __GLXscreenConfigs *psc;
    565    GLint i, screens;
    566 
    567    /*
    568     ** First allocate memory for the array of per screen configs.
    569     */
    570    screens = ScreenCount(dpy);
    571    priv->screenConfigs = Xmalloc(screens * sizeof *priv->screenConfigs);
    572    if (!priv->screenConfigs) {
    573       return GL_FALSE;
    574    }
    575 
    576    priv->serverGLXversion =
    577       __glXQueryServerString(dpy, priv->majorOpcode, 0, GLX_VERSION);
    578    if (priv->serverGLXversion == NULL) {
    579       FreeScreenConfigs(priv);
    580       return GL_FALSE;
    581    }
    582 
    583    for (i = 0; i < screens; i++) {
    584       psc = Xcalloc(1, sizeof *psc);
    585       if (!psc)
    586          return GL_FALSE;
    587       getFBConfigs(psc, priv, i);
    588       priv->screenConfigs[i] = psc;
    589    }
    590 
    591    SyncHandle();
    592 
    593    return GL_TRUE;
    594 }
    595 
    596 _X_HIDDEN __GLXdisplayPrivate *
    597 __glXInitialize(Display * dpy)
    598 {
    599    XExtDisplayInfo *info = __glXFindDisplay(dpy);
    600    XExtData **privList, *private, *found;
    601    __GLXdisplayPrivate *dpyPriv;
    602    XEDataObject dataObj;
    603    int major, minor;
    604 
    605    if (!XextHasExtension(info))
    606       return NULL;
    607 
    608    /* See if a display private already exists.  If so, return it */
    609    dataObj.display = dpy;
    610    privList = XEHeadOfExtensionList(dataObj);
    611    found = XFindOnExtensionList(privList, info->codes->extension);
    612    if (found)
    613       return (__GLXdisplayPrivate *) found->private_data;
    614 
    615    /* See if the versions are compatible */
    616    if (!QueryVersion(dpy, info->codes->major_opcode, &major, &minor))
    617       return NULL;
    618 
    619    /*
    620     ** Allocate memory for all the pieces needed for this buffer.
    621     */
    622    private = (XExtData *) Xmalloc(sizeof(XExtData));
    623    if (!private)
    624       return NULL;
    625    dpyPriv = (__GLXdisplayPrivate *) Xcalloc(1, sizeof(__GLXdisplayPrivate));
    626    if (!dpyPriv) {
    627       Xfree(private);
    628       return NULL;
    629    }
    630 
    631    /*
    632     ** Init the display private and then read in the screen config
    633     ** structures from the server.
    634     */
    635    dpyPriv->majorOpcode = info->codes->major_opcode;
    636    dpyPriv->dpy = dpy;
    637 
    638    if (!AllocAndFetchScreenConfigs(dpy, dpyPriv)) {
    639       Xfree(dpyPriv);
    640       Xfree(private);
    641       return NULL;
    642    }
    643 
    644    /*
    645     ** Fill in the private structure.  This is the actual structure that
    646     ** hangs off of the Display structure.  Our private structure is
    647     ** referred to by this structure.  Got that?
    648     */
    649    private->number = info->codes->extension;
    650    private->next = 0;
    651    private->free_private = __glXFreeDisplayPrivate;
    652    private->private_data = (char *) dpyPriv;
    653    XAddToExtensionList(privList, private);
    654 
    655    return dpyPriv;
    656 }
    657 
    658 #endif /* GLX_DIRECT_RENDERING */
    659