| /* |
| * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008) |
| * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice including the dates of first publication and |
| * either this permission notice or a reference to |
| * http://oss.sgi.com/projects/FreeB/ |
| * shall be included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF |
| * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| * |
| * Except as contained in this notice, the name of Silicon Graphics, Inc. |
| * shall not be used in advertising or otherwise to promote the sale, use or |
| * other dealings in this Software without prior written authorization from |
| * Silicon Graphics, Inc. |
| */ |
| |
| /** |
| * \file glxext.c |
| * GLX protocol interface boot-strap code. |
| * |
| * Direct rendering support added by Precision Insight, Inc. |
| * |
| * \author Kevin E. Martin <kevin@precisioninsight.com> |
| */ |
| |
| #include <assert.h> |
| #include "glxclient.h" |
| #include <X11/extensions/Xext.h> |
| #include <X11/extensions/extutil.h> |
| #include <X11/extensions/dri2proto.h> |
| #include "glxextensions.h" |
| #include "glcontextmodes.h" |
| |
| #ifdef USE_XCB |
| #include <X11/Xlib-xcb.h> |
| #include <xcb/xcb.h> |
| #include <xcb/glx.h> |
| #endif |
| |
| |
| #ifdef DEBUG |
| void __glXDumpDrawBuffer(__GLXcontext * ctx); |
| #endif |
| |
| /* |
| ** You can set this cell to 1 to force the gl drawing stuff to be |
| ** one command per packet |
| */ |
| _X_HIDDEN int __glXDebug = 0; |
| |
| /* Extension required boiler plate */ |
| |
| static char *__glXExtensionName = GLX_EXTENSION_NAME; |
| XExtensionInfo *__glXExtensionInfo = NULL; |
| |
| static /* const */ char *error_list[] = { |
| "GLXBadContext", |
| "GLXBadContextState", |
| "GLXBadDrawable", |
| "GLXBadPixmap", |
| "GLXBadContextTag", |
| "GLXBadCurrentWindow", |
| "GLXBadRenderRequest", |
| "GLXBadLargeRequest", |
| "GLXUnsupportedPrivateRequest", |
| "GLXBadFBConfig", |
| "GLXBadPbuffer", |
| "GLXBadCurrentDrawable", |
| "GLXBadWindow", |
| }; |
| |
| static int |
| __glXCloseDisplay(Display * dpy, XExtCodes * codes) |
| { |
| GLXContext gc; |
| |
| gc = __glXGetCurrentContext(); |
| if (dpy == gc->currentDpy) { |
| __glXSetCurrentContextNull(); |
| __glXFreeContext(gc); |
| } |
| |
| return XextRemoveDisplay(__glXExtensionInfo, dpy); |
| } |
| |
| |
| static |
| XEXT_GENERATE_ERROR_STRING(__glXErrorString, __glXExtensionName, |
| __GLX_NUMBER_ERRORS, error_list) |
| static Bool |
| __glXWireToEvent(Display *dpy, XEvent *event, xEvent *wire); |
| static Status |
| __glXEventToWire(Display *dpy, XEvent *event, xEvent *wire); |
| |
| 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 */ |
| __glXWireToEvent, /* wire_to_event */ |
| __glXEventToWire, /* event_to_wire */ |
| NULL, /* error */ |
| __glXErrorString, /* error_string */ |
| }; |
| |
| XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo, |
| __glXExtensionName, &__glXExtensionHooks, |
| __GLX_NUMBER_EVENTS, NULL) |
| |
| /* |
| * GLX events are a bit funky. We don't stuff the X event code into |
| * our user exposed (via XNextEvent) structure. Instead we use the GLX |
| * private event code namespace (and hope it doesn't conflict). Clients |
| * have to know that bit 15 in the event type field means they're getting |
| * a GLX event, and then handle the various sub-event types there, rather |
| * than simply checking the event code and handling it directly. |
| */ |
| |
| static Bool |
| __glXWireToEvent(Display *dpy, XEvent *event, xEvent *wire) |
| { |
| XExtDisplayInfo *info = __glXFindDisplay(dpy); |
| |
| XextCheckExtension(dpy, info, __glXExtensionName, False); |
| |
| switch ((wire->u.u.type & 0x7f) - info->codes->first_event) { |
| case GLX_PbufferClobber: |
| { |
| GLXPbufferClobberEvent *aevent = (GLXPbufferClobberEvent *)event; |
| xGLXPbufferClobberEvent *awire = (xGLXPbufferClobberEvent *)wire; |
| aevent->event_type = awire->type; |
| aevent->serial = awire->sequenceNumber; |
| aevent->event_type = awire->event_type; |
| aevent->draw_type = awire->draw_type; |
| aevent->drawable = awire->drawable; |
| aevent->buffer_mask = awire->buffer_mask; |
| aevent->aux_buffer = awire->aux_buffer; |
| aevent->x = awire->x; |
| aevent->y = awire->y; |
| aevent->width = awire->width; |
| aevent->height = awire->height; |
| aevent->count = awire->count; |
| return True; |
| } |
| /* No easy symbol to test for this, as GLX_BufferSwapComplete is |
| * defined in the local glx.h header, but the |
| * xGLXBufferSwapComplete typedef is only available in new versions |
| * of the external glxproto.h header, which doesn't have any |
| * testable versioning define. |
| * |
| * I'll use the related DRI2 define, in the hope that we won't |
| * receive these events unless we know how to ask for them: |
| */ |
| #ifdef X_DRI2SwapBuffers |
| case GLX_BufferSwapComplete: |
| { |
| GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event; |
| xGLXBufferSwapComplete *awire = (xGLXBufferSwapComplete *)wire; |
| aevent->event_type = awire->event_type; |
| aevent->drawable = awire->drawable; |
| aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo; |
| aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo; |
| aevent->sbc = ((CARD64)awire->sbc_hi << 32) | awire->sbc_lo; |
| return True; |
| } |
| #endif |
| default: |
| /* client doesn't support server event */ |
| break; |
| } |
| |
| return False; |
| } |
| |
| /* We don't actually support this. It doesn't make sense for clients to |
| * send each other GLX events. |
| */ |
| static Status |
| __glXEventToWire(Display *dpy, XEvent *event, xEvent *wire) |
| { |
| XExtDisplayInfo *info = __glXFindDisplay(dpy); |
| |
| XextCheckExtension(dpy, info, __glXExtensionName, False); |
| |
| switch (event->type) { |
| case GLX_DAMAGED: |
| break; |
| case GLX_SAVED: |
| break; |
| case GLX_EXCHANGE_COMPLETE_INTEL: |
| break; |
| case GLX_COPY_COMPLETE_INTEL: |
| break; |
| case GLX_FLIP_COMPLETE_INTEL: |
| break; |
| default: |
| /* client doesn't support server event */ |
| break; |
| } |
| |
| return Success; |
| } |
| |
| /************************************************************************/ |
| /* |
| ** 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 */ |
| psc = priv->screenConfigs; |
| screens = ScreenCount(priv->dpy); |
| for (i = 0; i < screens; i++, psc++) { |
| if (psc->configs) { |
| _gl_context_modes_destroy(psc->configs); |
| if (psc->effectiveGLXexts) |
| Xfree(psc->effectiveGLXexts); |
| psc->configs = NULL; /* NOTE: just for paranoia */ |
| } |
| if (psc->visuals) { |
| _gl_context_modes_destroy(psc->visuals); |
| psc->visuals = NULL; /* NOTE: just for paranoia */ |
| } |
| Xfree((char *) psc->serverGLXexts); |
| |
| #ifdef GLX_DIRECT_RENDERING |
| if (psc->driver_configs) { |
| unsigned int j; |
| for (j = 0; psc->driver_configs[j]; j++) |
| free((__DRIconfig *) psc->driver_configs[j]); |
| free(psc->driver_configs); |
| psc->driver_configs = NULL; |
| } |
| if (psc->driScreen) { |
| psc->driScreen->destroyScreen(psc); |
| __glxHashDestroy(psc->drawHash); |
| XFree(psc->driScreen); |
| psc->driScreen = NULL; |
| } |
| #endif |
| } |
| 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->serverGLXvendor) { |
| Xfree((char *) priv->serverGLXvendor); |
| priv->serverGLXvendor = 0x0; /* to protect against double free's */ |
| } |
| if (priv->serverGLXversion) { |
| Xfree((char *) priv->serverGLXversion); |
| priv->serverGLXversion = 0x0; /* to protect against double free's */ |
| } |
| |
| #ifdef GLX_DIRECT_RENDERING |
| /* Free the direct rendering per display data */ |
| if (priv->driswDisplay) |
| (*priv->driswDisplay->destroyDisplay) (priv->driswDisplay); |
| priv->driswDisplay = NULL; |
| |
| if (priv->driDisplay) |
| (*priv->driDisplay->destroyDisplay) (priv->driDisplay); |
| priv->driDisplay = NULL; |
| |
| if (priv->dri2Display) |
| (*priv->dri2Display->destroyDisplay) (priv->dri2Display); |
| priv->dri2Display = NULL; |
| #endif |
| |
| 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. |
| */ |
| static Bool |
| QueryVersion(Display * dpy, int opcode, int *major, int *minor) |
| { |
| #ifdef USE_XCB |
| xcb_connection_t *c = XGetXCBConnection(dpy); |
| xcb_glx_query_version_reply_t *reply = xcb_glx_query_version_reply(c, |
| xcb_glx_query_version |
| (c, |
| GLX_MAJOR_VERSION, |
| GLX_MINOR_VERSION), |
| NULL); |
| |
| if (reply->major_version != GLX_MAJOR_VERSION) { |
| free(reply); |
| return GL_FALSE; |
| } |
| *major = reply->major_version; |
| *minor = min(reply->minor_version, GLX_MINOR_VERSION); |
| free(reply); |
| return GL_TRUE; |
| #else |
| 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; |
| #endif /* USE_XCB */ |
| } |
| |
| |
| _X_HIDDEN 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: |
| /* Ignore the unrecognized tag's value */ |
| bp++; |
| 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 |
| getVisualConfigs(Display * dpy, __GLXdisplayPrivate * priv, int screen) |
| { |
| xGLXGetVisualConfigsReq *req; |
| __GLXscreenConfigs *psc; |
| xGLXGetVisualConfigsReply reply; |
| |
| LockDisplay(dpy); |
| |
| psc = priv->screenConfigs + screen; |
| psc->visuals = NULL; |
| GetReq(GLXGetVisualConfigs, req); |
| req->reqType = priv->majorOpcode; |
| req->glxCode = X_GLXGetVisualConfigs; |
| req->screen = screen; |
| |
| if (!_XReply(dpy, (xReply *) & reply, 0, False)) |
| goto out; |
| |
| psc->visuals = createConfigsFromProperties(dpy, |
| reply.numVisuals, |
| reply.numProps, |
| screen, GL_FALSE); |
| |
| out: |
| UnlockDisplay(dpy); |
| return psc->visuals != NULL; |
| } |
| |
| static GLboolean |
| getFBConfigs(Display * dpy, __GLXdisplayPrivate * priv, int screen) |
| { |
| xGLXGetFBConfigsReq *fb_req; |
| xGLXGetFBConfigsSGIXReq *sgi_req; |
| xGLXVendorPrivateWithReplyReq *vpreq; |
| xGLXGetFBConfigsReply reply; |
| __GLXscreenConfigs *psc; |
| |
| psc = priv->screenConfigs + screen; |
| 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; |
| } |
| |
| /* |
| ** Allocate the memory for the per screen configs for each screen. |
| ** If that works then fetch the per screen configs data. |
| */ |
| static Bool |
| AllocAndFetchScreenConfigs(Display * dpy, __GLXdisplayPrivate * priv) |
| { |
| __GLXscreenConfigs *psc; |
| GLint i, screens; |
| |
| /* |
| ** First allocate memory for the array of per screen configs. |
| */ |
| screens = ScreenCount(dpy); |
| psc = (__GLXscreenConfigs *) Xmalloc(screens * sizeof(__GLXscreenConfigs)); |
| if (!psc) { |
| return GL_FALSE; |
| } |
| memset(psc, 0, screens * sizeof(__GLXscreenConfigs)); |
| priv->screenConfigs = psc; |
| |
| 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++) { |
| getVisualConfigs(dpy, priv, i); |
| getFBConfigs(dpy, priv, i); |
| |
| #ifdef GLX_DIRECT_RENDERING |
| psc->scr = i; |
| psc->dpy = dpy; |
| psc->drawHash = __glxHashCreate(); |
| if (psc->drawHash == NULL) |
| continue; |
| |
| /* Initialize per screen dynamic client GLX extensions */ |
| psc->ext_list_first_time = GL_TRUE; |
| |
| if (priv->dri2Display) |
| psc->driScreen = (*priv->dri2Display->createScreen) (psc, i, priv); |
| |
| if (psc->driScreen == NULL && priv->driDisplay) |
| psc->driScreen = (*priv->driDisplay->createScreen) (psc, i, priv); |
| |
| if (psc->driScreen == NULL && priv->driswDisplay) |
| psc->driScreen = (*priv->driswDisplay->createScreen) (psc, i, priv); |
| |
| if (psc->driScreen == NULL) { |
| __glxHashDestroy(psc->drawHash); |
| psc->drawHash = NULL; |
| } |
| #endif |
| } |
| SyncHandle(); |
| return GL_TRUE; |
| } |
| |
| /* |
| ** Initialize the client side extension code. |
| */ |
| _X_HIDDEN __GLXdisplayPrivate * |
| __glXInitialize(Display * dpy) |
| { |
| XExtDisplayInfo *info = __glXFindDisplay(dpy); |
| XExtData **privList, *private, *found; |
| __GLXdisplayPrivate *dpyPriv; |
| XEDataObject dataObj; |
| int major, minor; |
| #ifdef GLX_DIRECT_RENDERING |
| Bool glx_direct, glx_accel; |
| #endif |
| |
| /* The one and only long long lock */ |
| __glXLock(); |
| |
| if (!XextHasExtension(info)) { |
| /* No GLX extension supported by this server. Oh well. */ |
| __glXUnlock(); |
| XMissingExtension(dpy, __glXExtensionName); |
| return 0; |
| } |
| |
| /* 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) { |
| __glXUnlock(); |
| return (__GLXdisplayPrivate *) found->private_data; |
| } |
| |
| /* See if the versions are compatible */ |
| if (!QueryVersion(dpy, info->codes->major_opcode, &major, &minor)) { |
| /* The client and server do not agree on versions. Punt. */ |
| __glXUnlock(); |
| return 0; |
| } |
| |
| /* |
| ** Allocate memory for all the pieces needed for this buffer. |
| */ |
| private = (XExtData *) Xmalloc(sizeof(XExtData)); |
| if (!private) { |
| __glXUnlock(); |
| return 0; |
| } |
| dpyPriv = (__GLXdisplayPrivate *) Xcalloc(1, sizeof(__GLXdisplayPrivate)); |
| if (!dpyPriv) { |
| __glXUnlock(); |
| Xfree((char *) private); |
| return 0; |
| } |
| |
| /* |
| ** Init the display private and then read in the screen config |
| ** structures from the server. |
| */ |
| dpyPriv->majorOpcode = info->codes->major_opcode; |
| dpyPriv->majorVersion = major; |
| dpyPriv->minorVersion = minor; |
| dpyPriv->dpy = dpy; |
| |
| dpyPriv->serverGLXvendor = 0x0; |
| dpyPriv->serverGLXversion = 0x0; |
| |
| #ifdef GLX_DIRECT_RENDERING |
| glx_direct = (getenv("LIBGL_ALWAYS_INDIRECT") == NULL); |
| glx_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL); |
| |
| /* |
| ** Initialize the direct rendering per display data and functions. |
| ** Note: This _must_ be done before calling any other DRI routines |
| ** (e.g., those called in AllocAndFetchScreenConfigs). |
| */ |
| if (glx_direct && glx_accel) { |
| dpyPriv->dri2Display = dri2CreateDisplay(dpy); |
| dpyPriv->driDisplay = driCreateDisplay(dpy); |
| } |
| if (glx_direct) |
| dpyPriv->driswDisplay = driswCreateDisplay(dpy); |
| #endif |
| |
| if (!AllocAndFetchScreenConfigs(dpy, dpyPriv)) { |
| __glXUnlock(); |
| Xfree((char *) dpyPriv); |
| Xfree((char *) private); |
| return 0; |
| } |
| |
| /* |
| ** 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); |
| |
| if (dpyPriv->majorVersion == 1 && dpyPriv->minorVersion >= 1) { |
| __glXClientInfo(dpy, dpyPriv->majorOpcode); |
| } |
| __glXUnlock(); |
| |
| return dpyPriv; |
| } |
| |
| /* |
| ** Setup for sending a GLX command on dpy. Make sure the extension is |
| ** initialized. Try to avoid calling __glXInitialize as its kinda slow. |
| */ |
| _X_HIDDEN CARD8 |
| __glXSetupForCommand(Display * dpy) |
| { |
| GLXContext gc; |
| __GLXdisplayPrivate *priv; |
| |
| /* If this thread has a current context, flush its rendering commands */ |
| gc = __glXGetCurrentContext(); |
| if (gc->currentDpy) { |
| /* Flush rendering buffer of the current context, if any */ |
| (void) __glXFlushRenderBuffer(gc, gc->pc); |
| |
| if (gc->currentDpy == dpy) { |
| /* Use opcode from gc because its right */ |
| return gc->majorOpcode; |
| } |
| else { |
| /* |
| ** Have to get info about argument dpy because it might be to |
| ** a different server |
| */ |
| } |
| } |
| |
| /* Forced to lookup extension via the slow initialize route */ |
| priv = __glXInitialize(dpy); |
| if (!priv) { |
| return 0; |
| } |
| return priv->majorOpcode; |
| } |
| |
| /** |
| * Flush the drawing command transport buffer. |
| * |
| * \param ctx Context whose transport buffer is to be flushed. |
| * \param pc Pointer to first unused buffer location. |
| * |
| * \todo |
| * Modify this function to use \c ctx->pc instead of the explicit |
| * \c pc parameter. |
| */ |
| _X_HIDDEN GLubyte * |
| __glXFlushRenderBuffer(__GLXcontext * ctx, GLubyte * pc) |
| { |
| Display *const dpy = ctx->currentDpy; |
| #ifdef USE_XCB |
| xcb_connection_t *c = XGetXCBConnection(dpy); |
| #else |
| xGLXRenderReq *req; |
| #endif /* USE_XCB */ |
| const GLint size = pc - ctx->buf; |
| |
| if ((dpy != NULL) && (size > 0)) { |
| #ifdef USE_XCB |
| xcb_glx_render(c, ctx->currentContextTag, size, |
| (const uint8_t *) ctx->buf); |
| #else |
| /* Send the entire buffer as an X request */ |
| LockDisplay(dpy); |
| GetReq(GLXRender, req); |
| req->reqType = ctx->majorOpcode; |
| req->glxCode = X_GLXRender; |
| req->contextTag = ctx->currentContextTag; |
| req->length += (size + 3) >> 2; |
| _XSend(dpy, (char *) ctx->buf, size); |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| #endif |
| } |
| |
| /* Reset pointer and return it */ |
| ctx->pc = ctx->buf; |
| return ctx->pc; |
| } |
| |
| |
| /** |
| * Send a portion of a GLXRenderLarge command to the server. The advantage of |
| * this function over \c __glXSendLargeCommand is that callers can use the |
| * data buffer in the GLX context and may be able to avoid allocating an |
| * extra buffer. The disadvantage is the clients will have to do more |
| * GLX protocol work (i.e., calculating \c totalRequests, etc.). |
| * |
| * \sa __glXSendLargeCommand |
| * |
| * \param gc GLX context |
| * \param requestNumber Which part of the whole command is this? The first |
| * request is 1. |
| * \param totalRequests How many requests will there be? |
| * \param data Command data. |
| * \param dataLen Size, in bytes, of the command data. |
| */ |
| _X_HIDDEN void |
| __glXSendLargeChunk(__GLXcontext * gc, GLint requestNumber, |
| GLint totalRequests, const GLvoid * data, GLint dataLen) |
| { |
| Display *dpy = gc->currentDpy; |
| #ifdef USE_XCB |
| xcb_connection_t *c = XGetXCBConnection(dpy); |
| xcb_glx_render_large(c, gc->currentContextTag, requestNumber, |
| totalRequests, dataLen, data); |
| #else |
| xGLXRenderLargeReq *req; |
| |
| if (requestNumber == 1) { |
| LockDisplay(dpy); |
| } |
| |
| GetReq(GLXRenderLarge, req); |
| req->reqType = gc->majorOpcode; |
| req->glxCode = X_GLXRenderLarge; |
| req->contextTag = gc->currentContextTag; |
| req->length += (dataLen + 3) >> 2; |
| req->requestNumber = requestNumber; |
| req->requestTotal = totalRequests; |
| req->dataBytes = dataLen; |
| Data(dpy, data, dataLen); |
| |
| if (requestNumber == totalRequests) { |
| UnlockDisplay(dpy); |
| SyncHandle(); |
| } |
| #endif /* USE_XCB */ |
| } |
| |
| |
| /** |
| * Send a command that is too large for the GLXRender protocol request. |
| * |
| * Send a large command, one that is too large for some reason to |
| * send using the GLXRender protocol request. One reason to send |
| * a large command is to avoid copying the data. |
| * |
| * \param ctx GLX context |
| * \param header Header data. |
| * \param headerLen Size, in bytes, of the header data. It is assumed that |
| * the header data will always be small enough to fit in |
| * a single X protocol packet. |
| * \param data Command data. |
| * \param dataLen Size, in bytes, of the command data. |
| */ |
| _X_HIDDEN void |
| __glXSendLargeCommand(__GLXcontext * ctx, |
| const GLvoid * header, GLint headerLen, |
| const GLvoid * data, GLint dataLen) |
| { |
| GLint maxSize; |
| GLint totalRequests, requestNumber; |
| |
| /* |
| ** Calculate the maximum amount of data can be stuffed into a single |
| ** packet. sz_xGLXRenderReq is added because bufSize is the maximum |
| ** packet size minus sz_xGLXRenderReq. |
| */ |
| maxSize = (ctx->bufSize + sz_xGLXRenderReq) - sz_xGLXRenderLargeReq; |
| totalRequests = 1 + (dataLen / maxSize); |
| if (dataLen % maxSize) |
| totalRequests++; |
| |
| /* |
| ** Send all of the command, except the large array, as one request. |
| */ |
| assert(headerLen <= maxSize); |
| __glXSendLargeChunk(ctx, 1, totalRequests, header, headerLen); |
| |
| /* |
| ** Send enough requests until the whole array is sent. |
| */ |
| for (requestNumber = 2; requestNumber <= (totalRequests - 1); |
| requestNumber++) { |
| __glXSendLargeChunk(ctx, requestNumber, totalRequests, data, maxSize); |
| data = (const GLvoid *) (((const GLubyte *) data) + maxSize); |
| dataLen -= maxSize; |
| assert(dataLen > 0); |
| } |
| |
| assert(dataLen <= maxSize); |
| __glXSendLargeChunk(ctx, requestNumber, totalRequests, data, dataLen); |
| } |
| |
| /************************************************************************/ |
| |
| #ifdef DEBUG |
| _X_HIDDEN void |
| __glXDumpDrawBuffer(__GLXcontext * ctx) |
| { |
| GLubyte *p = ctx->buf; |
| GLubyte *end = ctx->pc; |
| GLushort opcode, length; |
| |
| while (p < end) { |
| /* Fetch opcode */ |
| opcode = *((GLushort *) p); |
| length = *((GLushort *) (p + 2)); |
| printf("%2x: %5d: ", opcode, length); |
| length -= 4; |
| p += 4; |
| while (length > 0) { |
| printf("%08x ", *((unsigned *) p)); |
| p += 4; |
| length -= 4; |
| } |
| printf("\n"); |
| } |
| } |
| #endif |