| /** |
| * GLX initialization. Code based on glxext.c, glx_query.c, and |
| * glcontextmodes.c under src/glx/. The major difference is that DRI |
| * related code is stripped out. |
| * |
| * If the maintenance of this file takes too much time, we should consider |
| * refactoring glxext.c. |
| */ |
| |
| #include <assert.h> |
| #include <X11/Xlib.h> |
| #include <X11/Xproto.h> |
| #include <X11/Xlibint.h> |
| #include <X11/extensions/Xext.h> |
| #include <X11/extensions/extutil.h> |
| #include <sys/time.h> |
| |
| #include "GL/glxproto.h" |
| #include "GL/glxtokens.h" |
| #include "GL/gl.h" /* for GL types needed by __GLcontextModes */ |
| #include "glcore.h" /* for __GLcontextModes */ |
| |
| #include "glxinit.h" |
| |
| #ifdef GLX_DIRECT_RENDERING |
| |
| typedef struct GLXGenericGetString |
| { |
| CARD8 reqType; |
| CARD8 glxCode; |
| CARD16 length B16; |
| CARD32 for_whom B32; |
| CARD32 name B32; |
| } xGLXGenericGetStringReq; |
| |
| #define sz_xGLXGenericGetStringReq 12 |
| #define X_GLXGenericGetString 0 |
| |
| /* Extension required boiler plate */ |
| |
| static char *__glXExtensionName = GLX_EXTENSION_NAME; |
| static XExtensionInfo *__glXExtensionInfo = NULL; |
| |
| static int |
| __glXCloseDisplay(Display * dpy, XExtCodes * codes) |
| { |
| return XextRemoveDisplay(__glXExtensionInfo, dpy); |
| } |
| |
| static /* const */ XExtensionHooks __glXExtensionHooks = { |
| NULL, /* create_gc */ |
| NULL, /* copy_gc */ |
| NULL, /* flush_gc */ |
| NULL, /* free_gc */ |
| NULL, /* create_font */ |
| NULL, /* free_font */ |
| __glXCloseDisplay, /* close_display */ |
| NULL, /* wire_to_event */ |
| NULL, /* event_to_wire */ |
| NULL, /* error */ |
| NULL, /* error_string */ |
| }; |
| |
| static XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo, |
| __glXExtensionName, &__glXExtensionHooks, |
| __GLX_NUMBER_EVENTS, NULL) |
| |
| static GLint |
| _gl_convert_from_x_visual_type(int visualType) |
| { |
| #define NUM_VISUAL_TYPES 6 |
| static const int glx_visual_types[NUM_VISUAL_TYPES] = { |
| GLX_STATIC_GRAY, GLX_GRAY_SCALE, |
| GLX_STATIC_COLOR, GLX_PSEUDO_COLOR, |
| GLX_TRUE_COLOR, GLX_DIRECT_COLOR |
| }; |
| |
| return ((unsigned) visualType < NUM_VISUAL_TYPES) |
| ? glx_visual_types[visualType] : GLX_NONE; |
| } |
| |
| static void |
| _gl_context_modes_destroy(__GLcontextModes * modes) |
| { |
| while (modes != NULL) { |
| __GLcontextModes *const next = modes->next; |
| |
| Xfree(modes); |
| modes = next; |
| } |
| } |
| |
| static __GLcontextModes * |
| _gl_context_modes_create(unsigned count, size_t minimum_size) |
| { |
| const size_t size = (minimum_size > sizeof(__GLcontextModes)) |
| ? minimum_size : sizeof(__GLcontextModes); |
| __GLcontextModes *base = NULL; |
| __GLcontextModes **next; |
| unsigned i; |
| |
| next = &base; |
| for (i = 0; i < count; i++) { |
| *next = (__GLcontextModes *) Xmalloc(size); |
| if (*next == NULL) { |
| _gl_context_modes_destroy(base); |
| base = NULL; |
| break; |
| } |
| |
| memset(*next, 0, size); |
| (*next)->visualID = GLX_DONT_CARE; |
| (*next)->visualType = GLX_DONT_CARE; |
| (*next)->visualRating = GLX_NONE; |
| (*next)->transparentPixel = GLX_NONE; |
| (*next)->transparentRed = GLX_DONT_CARE; |
| (*next)->transparentGreen = GLX_DONT_CARE; |
| (*next)->transparentBlue = GLX_DONT_CARE; |
| (*next)->transparentAlpha = GLX_DONT_CARE; |
| (*next)->transparentIndex = GLX_DONT_CARE; |
| (*next)->xRenderable = GLX_DONT_CARE; |
| (*next)->fbconfigID = GLX_DONT_CARE; |
| (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML; |
| (*next)->bindToTextureRgb = GLX_DONT_CARE; |
| (*next)->bindToTextureRgba = GLX_DONT_CARE; |
| (*next)->bindToMipmapTexture = GLX_DONT_CARE; |
| (*next)->bindToTextureTargets = GLX_DONT_CARE; |
| (*next)->yInverted = GLX_DONT_CARE; |
| |
| next = &((*next)->next); |
| } |
| |
| return base; |
| } |
| |
| static char * |
| __glXQueryServerString(Display * dpy, int opcode, CARD32 screen, CARD32 name) |
| { |
| xGLXGenericGetStringReq *req; |
| xGLXSingleReply reply; |
| int length; |
| int numbytes; |
| char *buf; |
| CARD32 for_whom = screen; |
| CARD32 glxCode = X_GLXQueryServerString; |
| |
| |
| LockDisplay(dpy); |
| |
| |
| /* All of the GLX protocol requests for getting a string from the server |
| * look the same. The exact meaning of the for_whom field is usually |
| * either the screen number (for glXQueryServerString) or the context tag |
| * (for GLXSingle). |
| */ |
| |
| GetReq(GLXGenericGetString, req); |
| req->reqType = opcode; |
| req->glxCode = glxCode; |
| req->for_whom = for_whom; |
| req->name = name; |
| |
| _XReply(dpy, (xReply *) & reply, 0, False); |
| |
| length = reply.length * 4; |
| numbytes = reply.size; |
| |
| buf = (char *) Xmalloc(numbytes); |
| if (buf != NULL) { |
| _XRead(dpy, buf, numbytes); |
| length -= numbytes; |
| } |
| |
| _XEatData(dpy, length); |
| |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| |
| return buf; |
| } |
| |
| /************************************************************************/ |
| /* |
| ** Free the per screen configs data as well as the array of |
| ** __glXScreenConfigs. |
| */ |
| static void |
| FreeScreenConfigs(__GLXdisplayPrivate * priv) |
| { |
| __GLXscreenConfigs *psc; |
| GLint i, screens; |
| |
| /* Free screen configuration information */ |
| screens = ScreenCount(priv->dpy); |
| for (i = 0; i < screens; i++) { |
| psc = priv->screenConfigs[i]; |
| if (!psc) |
| continue; |
| if (psc->configs) { |
| _gl_context_modes_destroy(psc->configs); |
| psc->configs = NULL; /* NOTE: just for paranoia */ |
| } |
| Xfree((char *) psc->serverGLXexts); |
| } |
| XFree((char *) priv->screenConfigs); |
| priv->screenConfigs = NULL; |
| } |
| |
| /* |
| ** Release the private memory referred to in a display private |
| ** structure. The caller will free the extension structure. |
| */ |
| static int |
| __glXFreeDisplayPrivate(XExtData * extension) |
| { |
| __GLXdisplayPrivate *priv; |
| |
| priv = (__GLXdisplayPrivate *) extension->private_data; |
| FreeScreenConfigs(priv); |
| if (priv->serverGLXversion) |
| Xfree((char *) priv->serverGLXversion); |
| |
| Xfree((char *) priv); |
| return 0; |
| } |
| |
| /************************************************************************/ |
| |
| /* |
| ** Query the version of the GLX extension. This procedure works even if |
| ** the client extension is not completely set up. |
| */ |
| |
| #define GLX_MAJOR_VERSION 1 /* current version numbers */ |
| #define GLX_MINOR_VERSION 4 |
| |
| static Bool |
| QueryVersion(Display * dpy, int opcode, int *major, int *minor) |
| { |
| xGLXQueryVersionReq *req; |
| xGLXQueryVersionReply reply; |
| |
| /* Send the glXQueryVersion request */ |
| LockDisplay(dpy); |
| GetReq(GLXQueryVersion, req); |
| req->reqType = opcode; |
| req->glxCode = X_GLXQueryVersion; |
| req->majorVersion = GLX_MAJOR_VERSION; |
| req->minorVersion = GLX_MINOR_VERSION; |
| _XReply(dpy, (xReply *) & reply, 0, False); |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| |
| if (reply.majorVersion != GLX_MAJOR_VERSION) { |
| /* |
| ** The server does not support the same major release as this |
| ** client. |
| */ |
| return GL_FALSE; |
| } |
| *major = reply.majorVersion; |
| *minor = min(reply.minorVersion, GLX_MINOR_VERSION); |
| return GL_TRUE; |
| } |
| |
| #define __GLX_MIN_CONFIG_PROPS 18 |
| #define __GLX_MAX_CONFIG_PROPS 500 |
| #define __GLX_EXT_CONFIG_PROPS 10 |
| #define __GLX_TOTAL_CONFIG (__GLX_MIN_CONFIG_PROPS + \ |
| 2 * __GLX_EXT_CONFIG_PROPS) |
| |
| static void |
| __glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count, |
| const INT32 * bp, Bool tagged_only, |
| Bool fbconfig_style_tags) |
| { |
| int i; |
| |
| if (!tagged_only) { |
| /* Copy in the first set of properties */ |
| config->visualID = *bp++; |
| |
| config->visualType = _gl_convert_from_x_visual_type(*bp++); |
| |
| config->rgbMode = *bp++; |
| |
| config->redBits = *bp++; |
| config->greenBits = *bp++; |
| config->blueBits = *bp++; |
| config->alphaBits = *bp++; |
| config->accumRedBits = *bp++; |
| config->accumGreenBits = *bp++; |
| config->accumBlueBits = *bp++; |
| config->accumAlphaBits = *bp++; |
| |
| config->doubleBufferMode = *bp++; |
| config->stereoMode = *bp++; |
| |
| config->rgbBits = *bp++; |
| config->depthBits = *bp++; |
| config->stencilBits = *bp++; |
| config->numAuxBuffers = *bp++; |
| config->level = *bp++; |
| |
| count -= __GLX_MIN_CONFIG_PROPS; |
| } |
| |
| /* |
| ** Additional properties may be in a list at the end |
| ** of the reply. They are in pairs of property type |
| ** and property value. |
| */ |
| |
| #define FETCH_OR_SET(tag) \ |
| config-> tag = ( fbconfig_style_tags ) ? *bp++ : 1 |
| |
| for (i = 0; i < count; i += 2) { |
| switch (*bp++) { |
| case GLX_RGBA: |
| FETCH_OR_SET(rgbMode); |
| break; |
| case GLX_BUFFER_SIZE: |
| config->rgbBits = *bp++; |
| break; |
| case GLX_LEVEL: |
| config->level = *bp++; |
| break; |
| case GLX_DOUBLEBUFFER: |
| FETCH_OR_SET(doubleBufferMode); |
| break; |
| case GLX_STEREO: |
| FETCH_OR_SET(stereoMode); |
| break; |
| case GLX_AUX_BUFFERS: |
| config->numAuxBuffers = *bp++; |
| break; |
| case GLX_RED_SIZE: |
| config->redBits = *bp++; |
| break; |
| case GLX_GREEN_SIZE: |
| config->greenBits = *bp++; |
| break; |
| case GLX_BLUE_SIZE: |
| config->blueBits = *bp++; |
| break; |
| case GLX_ALPHA_SIZE: |
| config->alphaBits = *bp++; |
| break; |
| case GLX_DEPTH_SIZE: |
| config->depthBits = *bp++; |
| break; |
| case GLX_STENCIL_SIZE: |
| config->stencilBits = *bp++; |
| break; |
| case GLX_ACCUM_RED_SIZE: |
| config->accumRedBits = *bp++; |
| break; |
| case GLX_ACCUM_GREEN_SIZE: |
| config->accumGreenBits = *bp++; |
| break; |
| case GLX_ACCUM_BLUE_SIZE: |
| config->accumBlueBits = *bp++; |
| break; |
| case GLX_ACCUM_ALPHA_SIZE: |
| config->accumAlphaBits = *bp++; |
| break; |
| case GLX_VISUAL_CAVEAT_EXT: |
| config->visualRating = *bp++; |
| break; |
| case GLX_X_VISUAL_TYPE: |
| config->visualType = *bp++; |
| break; |
| case GLX_TRANSPARENT_TYPE: |
| config->transparentPixel = *bp++; |
| break; |
| case GLX_TRANSPARENT_INDEX_VALUE: |
| config->transparentIndex = *bp++; |
| break; |
| case GLX_TRANSPARENT_RED_VALUE: |
| config->transparentRed = *bp++; |
| break; |
| case GLX_TRANSPARENT_GREEN_VALUE: |
| config->transparentGreen = *bp++; |
| break; |
| case GLX_TRANSPARENT_BLUE_VALUE: |
| config->transparentBlue = *bp++; |
| break; |
| case GLX_TRANSPARENT_ALPHA_VALUE: |
| config->transparentAlpha = *bp++; |
| break; |
| case GLX_VISUAL_ID: |
| config->visualID = *bp++; |
| break; |
| case GLX_DRAWABLE_TYPE: |
| config->drawableType = *bp++; |
| break; |
| case GLX_RENDER_TYPE: |
| config->renderType = *bp++; |
| break; |
| case GLX_X_RENDERABLE: |
| config->xRenderable = *bp++; |
| break; |
| case GLX_FBCONFIG_ID: |
| config->fbconfigID = *bp++; |
| break; |
| case GLX_MAX_PBUFFER_WIDTH: |
| config->maxPbufferWidth = *bp++; |
| break; |
| case GLX_MAX_PBUFFER_HEIGHT: |
| config->maxPbufferHeight = *bp++; |
| break; |
| case GLX_MAX_PBUFFER_PIXELS: |
| config->maxPbufferPixels = *bp++; |
| break; |
| case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX: |
| config->optimalPbufferWidth = *bp++; |
| break; |
| case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX: |
| config->optimalPbufferHeight = *bp++; |
| break; |
| case GLX_VISUAL_SELECT_GROUP_SGIX: |
| config->visualSelectGroup = *bp++; |
| break; |
| case GLX_SWAP_METHOD_OML: |
| config->swapMethod = *bp++; |
| break; |
| case GLX_SAMPLE_BUFFERS_SGIS: |
| config->sampleBuffers = *bp++; |
| break; |
| case GLX_SAMPLES_SGIS: |
| config->samples = *bp++; |
| break; |
| case GLX_BIND_TO_TEXTURE_RGB_EXT: |
| config->bindToTextureRgb = *bp++; |
| break; |
| case GLX_BIND_TO_TEXTURE_RGBA_EXT: |
| config->bindToTextureRgba = *bp++; |
| break; |
| case GLX_BIND_TO_MIPMAP_TEXTURE_EXT: |
| config->bindToMipmapTexture = *bp++; |
| break; |
| case GLX_BIND_TO_TEXTURE_TARGETS_EXT: |
| config->bindToTextureTargets = *bp++; |
| break; |
| case GLX_Y_INVERTED_EXT: |
| config->yInverted = *bp++; |
| break; |
| case None: |
| i = count; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| config->renderType = |
| (config->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; |
| |
| config->haveAccumBuffer = ((config->accumRedBits + |
| config->accumGreenBits + |
| config->accumBlueBits + |
| config->accumAlphaBits) > 0); |
| config->haveDepthBuffer = (config->depthBits > 0); |
| config->haveStencilBuffer = (config->stencilBits > 0); |
| } |
| |
| static __GLcontextModes * |
| createConfigsFromProperties(Display * dpy, int nvisuals, int nprops, |
| int screen, GLboolean tagged_only) |
| { |
| INT32 buf[__GLX_TOTAL_CONFIG], *props; |
| unsigned prop_size; |
| __GLcontextModes *modes, *m; |
| int i; |
| |
| if (nprops == 0) |
| return NULL; |
| |
| /* FIXME: Is the __GLX_MIN_CONFIG_PROPS test correct for FBconfigs? */ |
| |
| /* Check number of properties */ |
| if (nprops < __GLX_MIN_CONFIG_PROPS || nprops > __GLX_MAX_CONFIG_PROPS) |
| return NULL; |
| |
| /* Allocate memory for our config structure */ |
| modes = _gl_context_modes_create(nvisuals, sizeof(__GLcontextModes)); |
| if (!modes) |
| return NULL; |
| |
| prop_size = nprops * __GLX_SIZE_INT32; |
| if (prop_size <= sizeof(buf)) |
| props = buf; |
| else |
| props = Xmalloc(prop_size); |
| |
| /* Read each config structure and convert it into our format */ |
| m = modes; |
| for (i = 0; i < nvisuals; i++) { |
| _XRead(dpy, (char *) props, prop_size); |
| /* Older X servers don't send this so we default it here. */ |
| m->drawableType = GLX_WINDOW_BIT; |
| __glXInitializeVisualConfigFromTags(m, nprops, props, |
| tagged_only, GL_TRUE); |
| m->screen = screen; |
| m = m->next; |
| } |
| |
| if (props != buf) |
| Xfree(props); |
| |
| return modes; |
| } |
| |
| static GLboolean |
| getFBConfigs(__GLXscreenConfigs *psc, __GLXdisplayPrivate *priv, int screen) |
| { |
| xGLXGetFBConfigsReq *fb_req; |
| xGLXGetFBConfigsSGIXReq *sgi_req; |
| xGLXVendorPrivateWithReplyReq *vpreq; |
| xGLXGetFBConfigsReply reply; |
| Display *dpy = priv->dpy; |
| |
| psc->serverGLXexts = |
| __glXQueryServerString(dpy, priv->majorOpcode, screen, GLX_EXTENSIONS); |
| |
| LockDisplay(dpy); |
| |
| psc->configs = NULL; |
| if (atof(priv->serverGLXversion) >= 1.3) { |
| GetReq(GLXGetFBConfigs, fb_req); |
| fb_req->reqType = priv->majorOpcode; |
| fb_req->glxCode = X_GLXGetFBConfigs; |
| fb_req->screen = screen; |
| } |
| else if (strstr(psc->serverGLXexts, "GLX_SGIX_fbconfig") != NULL) { |
| GetReqExtra(GLXVendorPrivateWithReply, |
| sz_xGLXGetFBConfigsSGIXReq + |
| sz_xGLXVendorPrivateWithReplyReq, vpreq); |
| sgi_req = (xGLXGetFBConfigsSGIXReq *) vpreq; |
| sgi_req->reqType = priv->majorOpcode; |
| sgi_req->glxCode = X_GLXVendorPrivateWithReply; |
| sgi_req->vendorCode = X_GLXvop_GetFBConfigsSGIX; |
| sgi_req->screen = screen; |
| } |
| else |
| goto out; |
| |
| if (!_XReply(dpy, (xReply *) & reply, 0, False)) |
| goto out; |
| |
| psc->configs = createConfigsFromProperties(dpy, |
| reply.numFBConfigs, |
| reply.numAttribs * 2, |
| screen, GL_TRUE); |
| |
| out: |
| UnlockDisplay(dpy); |
| return psc->configs != NULL; |
| } |
| |
| static GLboolean |
| AllocAndFetchScreenConfigs(Display * dpy, __GLXdisplayPrivate * priv) |
| { |
| __GLXscreenConfigs *psc; |
| GLint i, screens; |
| |
| /* |
| ** First allocate memory for the array of per screen configs. |
| */ |
| screens = ScreenCount(dpy); |
| priv->screenConfigs = Xmalloc(screens * sizeof *priv->screenConfigs); |
| if (!priv->screenConfigs) { |
| return GL_FALSE; |
| } |
| |
| priv->serverGLXversion = |
| __glXQueryServerString(dpy, priv->majorOpcode, 0, GLX_VERSION); |
| if (priv->serverGLXversion == NULL) { |
| FreeScreenConfigs(priv); |
| return GL_FALSE; |
| } |
| |
| for (i = 0; i < screens; i++) { |
| psc = Xcalloc(1, sizeof *psc); |
| if (!psc) |
| return GL_FALSE; |
| getFBConfigs(psc, priv, i); |
| priv->screenConfigs[i] = psc; |
| } |
| |
| SyncHandle(); |
| |
| return GL_TRUE; |
| } |
| |
| _X_HIDDEN __GLXdisplayPrivate * |
| __glXInitialize(Display * dpy) |
| { |
| XExtDisplayInfo *info = __glXFindDisplay(dpy); |
| XExtData **privList, *private, *found; |
| __GLXdisplayPrivate *dpyPriv; |
| XEDataObject dataObj; |
| int major, minor; |
| |
| if (!XextHasExtension(info)) |
| return NULL; |
| |
| /* See if a display private already exists. If so, return it */ |
| dataObj.display = dpy; |
| privList = XEHeadOfExtensionList(dataObj); |
| found = XFindOnExtensionList(privList, info->codes->extension); |
| if (found) |
| return (__GLXdisplayPrivate *) found->private_data; |
| |
| /* See if the versions are compatible */ |
| if (!QueryVersion(dpy, info->codes->major_opcode, &major, &minor)) |
| return NULL; |
| |
| /* |
| ** Allocate memory for all the pieces needed for this buffer. |
| */ |
| private = (XExtData *) Xmalloc(sizeof(XExtData)); |
| if (!private) |
| return NULL; |
| dpyPriv = (__GLXdisplayPrivate *) Xcalloc(1, sizeof(__GLXdisplayPrivate)); |
| if (!dpyPriv) { |
| Xfree(private); |
| return NULL; |
| } |
| |
| /* |
| ** Init the display private and then read in the screen config |
| ** structures from the server. |
| */ |
| dpyPriv->majorOpcode = info->codes->major_opcode; |
| dpyPriv->dpy = dpy; |
| |
| if (!AllocAndFetchScreenConfigs(dpy, dpyPriv)) { |
| Xfree(dpyPriv); |
| Xfree(private); |
| return NULL; |
| } |
| |
| /* |
| ** Fill in the private structure. This is the actual structure that |
| ** hangs off of the Display structure. Our private structure is |
| ** referred to by this structure. Got that? |
| */ |
| private->number = info->codes->extension; |
| private->next = 0; |
| private->free_private = __glXFreeDisplayPrivate; |
| private->private_data = (char *) dpyPriv; |
| XAddToExtensionList(privList, private); |
| |
| return dpyPriv; |
| } |
| |
| #endif /* GLX_DIRECT_RENDERING */ |