/* * 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 */ #include #include #include "glxclient.h" #include #include #ifdef GLX_USE_APPLEGL #include "apple/apple_glx.h" #include "apple/apple_visual.h" #endif #include "glxextensions.h" #include "util/debug.h" #include #include #include #ifdef DEBUG void __glXDumpDrawBuffer(struct glx_context * 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 const char __glXExtensionName[] = GLX_EXTENSION_NAME; static struct glx_display *glx_displays; static /* const */ char *error_list[] = { "GLXBadContext", "GLXBadContextState", "GLXBadDrawable", "GLXBadPixmap", "GLXBadContextTag", "GLXBadCurrentWindow", "GLXBadRenderRequest", "GLXBadLargeRequest", "GLXUnsupportedPrivateRequest", "GLXBadFBConfig", "GLXBadPbuffer", "GLXBadCurrentDrawable", "GLXBadWindow", "GLXBadProfileARB", }; #ifdef GLX_USE_APPLEGL static char *__glXErrorString(Display *dpy, int code, XExtCodes *codes, char *buf, int n); #endif static XEXT_GENERATE_ERROR_STRING(__glXErrorString, __glXExtensionName, __GLX_NUMBER_ERRORS, error_list) /* * 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) { struct glx_display *glx_dpy = __glXInitialize(dpy); if (glx_dpy == NULL) return False; switch ((wire->u.u.type & 0x7f) - glx_dpy->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; } case GLX_BufferSwapComplete: { GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event; xGLXBufferSwapComplete2 *awire = (xGLXBufferSwapComplete2 *)wire; struct glx_drawable *glxDraw = GetGLXDrawable(dpy, awire->drawable); if (!glxDraw) return False; aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire); aevent->send_event = (awire->type & 0x80) != 0; aevent->display = dpy; aevent->event_type = awire->event_type; aevent->drawable = glxDraw->xDrawable; aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo; aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo; /* Handle 32-Bit wire sbc wraparound in both directions to cope with out * of sequence 64-Bit sbc's */ if ((int64_t) awire->sbc < ((int64_t) glxDraw->lastEventSbc - 0x40000000)) glxDraw->eventSbcWrap += 0x100000000; if ((int64_t) awire->sbc > ((int64_t) glxDraw->lastEventSbc + 0x40000000)) glxDraw->eventSbcWrap -= 0x100000000; glxDraw->lastEventSbc = awire->sbc; aevent->sbc = awire->sbc + glxDraw->eventSbcWrap; return True; } 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) { struct glx_display *glx_dpy = __glXInitialize(dpy); if (glx_dpy == NULL) return 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(struct glx_display * priv) { struct glx_screen *psc; GLint i, screens; /* Free screen configuration information */ screens = ScreenCount(priv->dpy); for (i = 0; i < screens; i++) { psc = priv->screens[i]; glx_screen_cleanup(psc); #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) if (psc->driScreen) { psc->driScreen->destroyScreen(psc); } else { free(psc); } #else free(psc); #endif } free((char *) priv->screens); priv->screens = NULL; } static void glx_display_free(struct glx_display *priv) { struct glx_context *gc; gc = __glXGetCurrentContext(); if (priv->dpy == gc->currentDpy) { gc->vtable->destroy(gc); __glXSetCurrentContextNull(); } FreeScreenConfigs(priv); free((char *) priv->serverGLXvendor); free((char *) priv->serverGLXversion); __glxHashDestroy(priv->glXDrawHash); #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) __glxHashDestroy(priv->drawHash); /* Free the direct rendering per display data */ if (priv->driswDisplay) (*priv->driswDisplay->destroyDisplay) (priv->driswDisplay); priv->driswDisplay = NULL; #if defined (GLX_USE_DRM) if (priv->driDisplay) (*priv->driDisplay->destroyDisplay) (priv->driDisplay); priv->driDisplay = NULL; if (priv->dri2Display) (*priv->dri2Display->destroyDisplay) (priv->dri2Display); priv->dri2Display = NULL; if (priv->dri3Display) (*priv->dri3Display->destroyDisplay) (priv->dri3Display); priv->dri3Display = NULL; #endif /* GLX_USE_DRM */ #if defined(GLX_USE_WINDOWSGL) if (priv->windowsdriDisplay) (*priv->windowsdriDisplay->destroyDisplay) (priv->windowsdriDisplay); priv->windowsdriDisplay = NULL; #endif /* GLX_USE_WINDOWSGL */ #endif /* GLX_DIRECT_RENDERING && !GLX_USE_APPLEGL */ free((char *) priv); } static int __glXCloseDisplay(Display * dpy, XExtCodes * codes) { struct glx_display *priv, **prev; _XLockMutex(_Xglobal_lock); prev = &glx_displays; for (priv = glx_displays; priv; prev = &priv->next, priv = priv->next) { if (priv->dpy == dpy) { *prev = priv->next; break; } } _XUnlockMutex(_Xglobal_lock); if (priv != NULL) glx_display_free(priv); return 1; } /* ** 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) { 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) return GL_FALSE; 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; } /* * We don't want to enable this GLX_OML_swap_method in glxext.h, * because we can't support it. The X server writes it out though, * so we should handle it somehow, to avoid false warnings. */ enum { IGNORE_GLX_SWAP_METHOD_OML = 0x8060 }; static GLint convert_from_x_visual_type(int visualType) { static const int glx_visual_types[] = { [StaticGray] = GLX_STATIC_GRAY, [GrayScale] = GLX_GRAY_SCALE, [StaticColor] = GLX_STATIC_COLOR, [PseudoColor] = GLX_PSEUDO_COLOR, [TrueColor] = GLX_TRUE_COLOR, [DirectColor] = GLX_DIRECT_COLOR, }; if (visualType < ARRAY_SIZE(glx_visual_types)) return glx_visual_types[visualType]; return GLX_NONE; } /* * getVisualConfigs uses the !tagged_only path. * getFBConfigs uses the tagged_only path. */ _X_HIDDEN void __glXInitializeVisualConfigFromTags(struct glx_config * 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 = convert_from_x_visual_type(*bp++); config->renderType = *bp++ ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; 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++; #ifdef GLX_USE_APPLEGL /* AppleSGLX supports pixmap and pbuffers with all config. */ config->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; /* Unfortunately this can create an ABI compatibility problem. */ count -= 18; #else count -= __GLX_MIN_CONFIG_PROPS; #endif } /* ** 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) { long int tag = *bp++; switch (tag) { case GLX_RGBA: if (fbconfig_style_tags) config->renderType = *bp++ ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT; else config->renderType = GLX_RGBA_BIT; 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++; #ifdef GLX_USE_APPLEGL /* AppleSGLX supports pixmap and pbuffers with all config. */ config->drawableType |= GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; #endif break; case GLX_RENDER_TYPE: /* fbconfig render type bits */ 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; #ifndef GLX_USE_APPLEGL 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: if (*bp == GLX_SWAP_UNDEFINED_OML || *bp == GLX_SWAP_COPY_OML || *bp == GLX_SWAP_EXCHANGE_OML) { config->swapMethod = *bp++; } else { /* X servers with old HW drivers may return any value here, so * assume GLX_SWAP_METHOD_UNDEFINED. */ config->swapMethod = GLX_SWAP_UNDEFINED_OML; bp++; } break; #endif case GLX_SAMPLE_BUFFERS_SGIS: config->sampleBuffers = *bp++; break; case GLX_SAMPLES_SGIS: config->samples = *bp++; break; #ifdef GLX_USE_APPLEGL case IGNORE_GLX_SWAP_METHOD_OML: /* We ignore this tag. See the comment above this function. */ ++bp; break; #else 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; #endif case GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT: config->sRGBCapable = *bp++; break; case GLX_USE_GL: if (fbconfig_style_tags) bp++; break; case None: i = count; break; default: if(env_var_as_boolean("LIBGL_DIAGNOSTIC", false)) { long int tagvalue = *bp++; fprintf(stderr, "WARNING: unknown GLX tag from server: " "tag 0x%lx value 0x%lx\n", tag, tagvalue); } else { /* Ignore the unrecognized tag's value */ bp++; } break; } } /* The GLX_ARB_fbconfig_float spec says: * * "Note that floating point rendering is only supported for * GLXPbuffer drawables." */ if (config->renderType & (GLX_RGBA_FLOAT_BIT_ARB|GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT)) config->drawableType &= GLX_PBUFFER_BIT; } static struct glx_config * createConfigsFromProperties(Display * dpy, int nvisuals, int nprops, int screen, GLboolean tagged_only) { INT32 buf[__GLX_TOTAL_CONFIG], *props; unsigned prop_size; struct glx_config *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 = glx_config_create_list(nvisuals); if (!modes) return NULL; prop_size = nprops * __GLX_SIZE_INT32; if (prop_size <= sizeof(buf)) props = buf; else props = malloc(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); #ifdef GLX_USE_APPLEGL /* Older X servers don't send this so we default it here. */ m->drawableType = GLX_WINDOW_BIT; #else /* * The XQuartz 2.3.2.1 X server doesn't set this properly, so * set the proper bits here. * AppleSGLX supports windows, pixmaps, and pbuffers with all config. */ m->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; #endif /* Older X servers don't send this so we default it here. */ m->sRGBCapable = GL_FALSE; __glXInitializeVisualConfigFromTags(m, nprops, props, tagged_only, GL_TRUE); m->screen = screen; m = m->next; } if (props != buf) free(props); return modes; } static GLboolean getVisualConfigs(struct glx_screen *psc, struct glx_display *priv, int screen) { xGLXGetVisualConfigsReq *req; xGLXGetVisualConfigsReply reply; Display *dpy = priv->dpy; LockDisplay(dpy); 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(struct glx_screen *psc, struct glx_display *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); if (psc->serverGLXexts == NULL) { return GL_FALSE; } 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; } _X_HIDDEN Bool glx_screen_init(struct glx_screen *psc, int screen, struct glx_display * priv) { /* Initialize per screen dynamic client GLX extensions */ psc->ext_list_first_time = GL_TRUE; psc->scr = screen; psc->dpy = priv->dpy; psc->display = priv; if (!getVisualConfigs(psc, priv, screen)) return GL_FALSE; if (!getFBConfigs(psc, priv, screen)) return GL_FALSE; return GL_TRUE; } _X_HIDDEN void glx_screen_cleanup(struct glx_screen *psc) { if (psc->configs) { glx_config_destroy_list(psc->configs); free(psc->effectiveGLXexts); psc->configs = NULL; /* NOTE: just for paranoia */ } if (psc->visuals) { glx_config_destroy_list(psc->visuals); psc->visuals = NULL; /* NOTE: just for paranoia */ } free((char *) psc->serverGLXexts); } /* ** 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, struct glx_display * priv) { struct glx_screen *psc; GLint i, screens; /* ** First allocate memory for the array of per screen configs. */ screens = ScreenCount(dpy); priv->screens = malloc(screens * sizeof *priv->screens); if (!priv->screens) 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++) { psc = NULL; #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) #if defined(GLX_USE_DRM) #if defined(HAVE_DRI3) if (priv->dri3Display) psc = (*priv->dri3Display->createScreen) (i, priv); #endif /* HAVE_DRI3 */ if (psc == NULL && priv->dri2Display) psc = (*priv->dri2Display->createScreen) (i, priv); if (psc == NULL && priv->driDisplay) psc = (*priv->driDisplay->createScreen) (i, priv); #endif /* GLX_USE_DRM */ #ifdef GLX_USE_WINDOWSGL if (psc == NULL && priv->windowsdriDisplay) psc = (*priv->windowsdriDisplay->createScreen) (i, priv); #endif if (psc == NULL && priv->driswDisplay) psc = (*priv->driswDisplay->createScreen) (i, priv); #endif /* GLX_DIRECT_RENDERING && !GLX_USE_APPLEGL */ #if defined(GLX_USE_APPLEGL) if (psc == NULL) psc = applegl_create_screen(i, priv); #else if (psc == NULL) psc = indirect_create_screen(i, priv); #endif priv->screens[i] = psc; } SyncHandle(); return GL_TRUE; } /* ** Initialize the client side extension code. */ _X_HIDDEN struct glx_display * __glXInitialize(Display * dpy) { struct glx_display *dpyPriv, *d; #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) Bool glx_direct, glx_accel; #endif int i; _XLockMutex(_Xglobal_lock); for (dpyPriv = glx_displays; dpyPriv; dpyPriv = dpyPriv->next) { if (dpyPriv->dpy == dpy) { _XUnlockMutex(_Xglobal_lock); return dpyPriv; } } /* Drop the lock while we create the display private. */ _XUnlockMutex(_Xglobal_lock); dpyPriv = calloc(1, sizeof *dpyPriv); if (!dpyPriv) return NULL; dpyPriv->codes = XInitExtension(dpy, __glXExtensionName); if (!dpyPriv->codes) { free(dpyPriv); return NULL; } dpyPriv->dpy = dpy; dpyPriv->majorOpcode = dpyPriv->codes->major_opcode; dpyPriv->serverGLXvendor = 0x0; dpyPriv->serverGLXversion = 0x0; /* See if the versions are compatible. This GLX implementation does not * work with servers that only support GLX 1.0. */ if (!QueryVersion(dpy, dpyPriv->majorOpcode, &dpyPriv->majorVersion, &dpyPriv->minorVersion) || (dpyPriv->majorVersion == 1 && dpyPriv->minorVersion < 1)) { free(dpyPriv); return NULL; } for (i = 0; i < __GLX_NUMBER_EVENTS; i++) { XESetWireToEvent(dpy, dpyPriv->codes->first_event + i, __glXWireToEvent); XESetEventToWire(dpy, dpyPriv->codes->first_event + i, __glXEventToWire); } XESetCloseDisplay(dpy, dpyPriv->codes->extension, __glXCloseDisplay); XESetErrorString (dpy, dpyPriv->codes->extension, __glXErrorString); dpyPriv->glXDrawHash = __glxHashCreate(); #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) glx_direct = !env_var_as_boolean("LIBGL_ALWAYS_INDIRECT", false); glx_accel = !env_var_as_boolean("LIBGL_ALWAYS_SOFTWARE", false); dpyPriv->drawHash = __glxHashCreate(); /* ** 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 defined(GLX_USE_DRM) if (glx_direct && glx_accel) { #if defined(HAVE_DRI3) if (!env_var_as_boolean("LIBGL_DRI3_DISABLE", false)) dpyPriv->dri3Display = dri3_create_display(dpy); #endif /* HAVE_DRI3 */ dpyPriv->dri2Display = dri2CreateDisplay(dpy); dpyPriv->driDisplay = driCreateDisplay(dpy); } #endif /* GLX_USE_DRM */ if (glx_direct) dpyPriv->driswDisplay = driswCreateDisplay(dpy); #endif /* GLX_DIRECT_RENDERING && !GLX_USE_APPLEGL */ #ifdef GLX_USE_APPLEGL if (!applegl_create_display(dpyPriv)) { free(dpyPriv); return NULL; } #endif #ifdef GLX_USE_WINDOWSGL if (glx_direct && glx_accel) dpyPriv->windowsdriDisplay = driwindowsCreateDisplay(dpy); #endif if (!AllocAndFetchScreenConfigs(dpy, dpyPriv)) { free(dpyPriv); return NULL; } __glX_send_client_info(dpyPriv); /* Grab the lock again and add the dispay private, unless somebody * beat us to initializing on this display in the meantime. */ _XLockMutex(_Xglobal_lock); for (d = glx_displays; d; d = d->next) { if (d->dpy == dpy) { _XUnlockMutex(_Xglobal_lock); glx_display_free(dpyPriv); return d; } } dpyPriv->next = glx_displays; glx_displays = dpyPriv; _XUnlockMutex(_Xglobal_lock); 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) { struct glx_context *gc; struct glx_display *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(struct glx_context * ctx, GLubyte * pc) { Display *const dpy = ctx->currentDpy; xcb_connection_t *c = XGetXCBConnection(dpy); const GLint size = pc - ctx->buf; if ((dpy != NULL) && (size > 0)) { xcb_glx_render(c, ctx->currentContextTag, size, (const uint8_t *) ctx->buf); } /* 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(struct glx_context * gc, GLint requestNumber, GLint totalRequests, const GLvoid * data, GLint dataLen) { Display *dpy = gc->currentDpy; xcb_connection_t *c = XGetXCBConnection(dpy); xcb_glx_render_large(c, gc->currentContextTag, requestNumber, totalRequests, dataLen, data); } /** * 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(struct glx_context * 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(struct glx_context * 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