/* * 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. */ #ifdef HAVE_DIX_CONFIG_H #include #endif #include #include #include "glxserver.h" #include #include #include #include #include "glxutil.h" #include "glxext.h" #include "glapitable.h" #include "glapi.h" #include "glthread.h" #include "dispatch.h" #include "indirect_dispatch.h" #include "indirect_table.h" #include "indirect_util.h" _X_HIDDEN int validGlxScreen(ClientPtr client, int screen, __GLXscreen ** pGlxScreen, int *err) { /* ** Check if screen exists. */ if (screen < 0 || screen >= screenInfo.numScreens) { client->errorValue = screen; *err = BadValue; return FALSE; } *pGlxScreen = glxGetScreen(screenInfo.screens[screen]); return TRUE; } _X_HIDDEN int validGlxFBConfig(ClientPtr client, __GLXscreen * pGlxScreen, XID id, __GLXconfig ** config, int *err) { __GLXconfig *m; for (m = pGlxScreen->fbconfigs; m != NULL; m = m->next) if (m->fbconfigID == id) { *config = m; return TRUE; } client->errorValue = id; *err = __glXError(GLXBadFBConfig); return FALSE; } static int validGlxVisual(ClientPtr client, __GLXscreen * pGlxScreen, XID id, __GLXconfig ** config, int *err) { int i; for (i = 0; i < pGlxScreen->numVisuals; i++) if (pGlxScreen->visuals[i]->visualID == id) { *config = pGlxScreen->visuals[i]; return TRUE; } client->errorValue = id; *err = BadValue; return FALSE; } static int validGlxFBConfigForWindow(ClientPtr client, __GLXconfig * config, DrawablePtr pDraw, int *err) { ScreenPtr pScreen = pDraw->pScreen; VisualPtr pVisual = NULL; XID vid; int i; vid = wVisual((WindowPtr) pDraw); for (i = 0; i < pScreen->numVisuals; i++) { if (pScreen->visuals[i].vid == vid) { pVisual = &pScreen->visuals[i]; break; } } /* FIXME: What exactly should we check here... */ if (pVisual->class != glxConvertToXVisualType(config->visualType) || !(config->drawableType & GLX_WINDOW_BIT)) { client->errorValue = pDraw->id; *err = BadMatch; return FALSE; } return TRUE; } _X_HIDDEN int validGlxContext(ClientPtr client, XID id, int access_mode, __GLXcontext ** context, int *err) { *err = dixLookupResourceByType((pointer *) context, id, __glXContextRes, client, access_mode); if (*err != Success || (*context)->idExists == GL_FALSE) { client->errorValue = id; if (*err == BadValue || *err == Success) *err = __glXError(GLXBadContext); return FALSE; } return TRUE; } static int validGlxDrawable(ClientPtr client, XID id, int type, int access_mode, __GLXdrawable ** drawable, int *err) { int rc; rc = dixLookupResourceByType((pointer *) drawable, id, __glXDrawableRes, client, access_mode); if (rc != Success && rc != BadValue) { *err = rc; client->errorValue = id; return FALSE; } /* If the ID of the glx drawable we looked up doesn't match the id * we looked for, it's because we looked it up under the X * drawable ID (see DoCreateGLXDrawable). */ if (rc == BadValue || (*drawable)->drawId != id || (type != GLX_DRAWABLE_ANY && type != (*drawable)->type)) { client->errorValue = id; switch (type) { case GLX_DRAWABLE_WINDOW: *err = __glXError(GLXBadWindow); return FALSE; case GLX_DRAWABLE_PIXMAP: *err = __glXError(GLXBadPixmap); return FALSE; case GLX_DRAWABLE_PBUFFER: *err = __glXError(GLXBadPbuffer); return FALSE; case GLX_DRAWABLE_ANY: *err = __glXError(GLXBadDrawable); return FALSE; } } return TRUE; } void __glXContextDestroy(__GLXcontext * context) { __glXFlushContextCache(); } static void __glXdirectContextDestroy(__GLXcontext * context) { __glXContextDestroy(context); free(context); } _X_HIDDEN __GLXcontext * __glXdirectContextCreate(__GLXscreen * screen, __GLXconfig * modes, __GLXcontext * shareContext) { __GLXcontext *context; context = calloc(1, sizeof(__GLXcontext)); if (context == NULL) return NULL; context->destroy = __glXdirectContextDestroy; return context; } void FlushContext(__GLXcontext * cx) { CALL_Flush(GET_DISPATCH(), ()); cx->hasUnflushedCommands = GL_FALSE; } /** * Create a GL context with the given properties. This routine is used * to implement \c glXCreateContext, \c glXCreateNewContext, and * \c glXCreateContextWithConfigSGIX. This works becuase of the hack way * that GLXFBConfigs are implemented. Basically, the FBConfigID is the * same as the VisualID. */ static int DoCreateContext(__GLXclientState * cl, GLXContextID gcId, GLXContextID shareList, __GLXconfig * config, __GLXscreen * pGlxScreen, GLboolean isDirect) { ClientPtr client = cl->client; __GLXcontext *glxc, *shareglxc; int err; LEGAL_NEW_RESOURCE(gcId, client); /* ** Find the display list space that we want to share. ** ** NOTE: In a multithreaded X server, we would need to keep a reference ** count for each display list so that if one client detroyed a list that ** another client was using, the list would not really be freed until it ** was no longer in use. Since this sample implementation has no support ** for multithreaded servers, we don't do this. */ if (shareList == None) { shareglxc = 0; } else { if (!validGlxContext(client, shareList, DixReadAccess, &shareglxc, &err)) return err; /* Page 26 (page 32 of the PDF) of the GLX 1.4 spec says: * * "The server context state for all sharing contexts must exist * in a single address space or a BadMatch error is generated." * * If the share context is indirect, force the new context to also be * indirect. If the shard context is direct but the new context * cannot be direct, generate BadMatch. */ if (shareglxc->isDirect && !isDirect) { client->errorValue = shareList; return BadMatch; } else if (!shareglxc->isDirect) { /* ** Create an indirect context regardless of what the client asked ** for; this way we can share display list space with shareList. */ isDirect = GL_FALSE; } } /* ** Allocate memory for the new context */ if (!isDirect) { /* Without any attributes, the only error that the driver should be * able to generate is BadAlloc. As result, just drop the error * returned from the driver on the floor. */ glxc = pGlxScreen->createContext(pGlxScreen, config, shareglxc, 0, NULL, &err); } else glxc = __glXdirectContextCreate(pGlxScreen, config, shareglxc); if (!glxc) { return BadAlloc; } /* Initialize the GLXcontext structure. */ glxc->pGlxScreen = pGlxScreen; glxc->config = config; glxc->id = gcId; glxc->share_id = shareList; glxc->idExists = GL_TRUE; glxc->isCurrent = GL_FALSE; glxc->isDirect = isDirect; glxc->hasUnflushedCommands = GL_FALSE; glxc->renderMode = GL_RENDER; glxc->feedbackBuf = NULL; glxc->feedbackBufSize = 0; glxc->selectBuf = NULL; glxc->selectBufSize = 0; glxc->drawPriv = NULL; glxc->readPriv = NULL; /* The GLX_ARB_create_context_robustness spec says: * * "The default value for GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB * is GLX_NO_RESET_NOTIFICATION_ARB." * * Without using glXCreateContextAttribsARB, there is no way to specify a * non-default reset notification strategy. */ glxc->resetNotificationStrategy = GLX_NO_RESET_NOTIFICATION_ARB; /* Add the new context to the various global tables of GLX contexts. */ if (!__glXAddContext(glxc)) { (*glxc->destroy) (glxc); client->errorValue = gcId; return BadAlloc; } return Success; } int __glXDisp_CreateContext(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; __GLXconfig *config; __GLXscreen *pGlxScreen; int err; REQUEST_SIZE_MATCH(xGLXCreateContextReq); if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) return err; if (!validGlxVisual(cl->client, pGlxScreen, req->visual, &config, &err)) return err; return DoCreateContext(cl, req->context, req->shareList, config, pGlxScreen, req->isDirect); } int __glXDisp_CreateNewContext(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc; __GLXconfig *config; __GLXscreen *pGlxScreen; int err; REQUEST_SIZE_MATCH(xGLXCreateNewContextReq); if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) return err; if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err)) return err; return DoCreateContext(cl, req->context, req->shareList, config, pGlxScreen, req->isDirect); } int __glXDisp_CreateContextWithConfigSGIX(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXCreateContextWithConfigSGIXReq *req = (xGLXCreateContextWithConfigSGIXReq *) pc; __GLXconfig *config; __GLXscreen *pGlxScreen; int err; REQUEST_SIZE_MATCH(xGLXCreateContextWithConfigSGIXReq); if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) return err; if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err)) return err; return DoCreateContext(cl, req->context, req->shareList, config, pGlxScreen, req->isDirect); } int __glXDisp_DestroyContext(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc; __GLXcontext *glxc; int err; REQUEST_SIZE_MATCH(xGLXDestroyContextReq); if (!validGlxContext(cl->client, req->context, DixDestroyAccess, &glxc, &err)) return err; glxc->idExists = GL_FALSE; if (!glxc->isCurrent) FreeResourceByType(req->context, __glXContextRes, FALSE); return Success; } /* * This will return "deleted" contexts, ie, where idExists is GL_FALSE. * Contrast validGlxContext, which will not. We're cheating here and * using the XID as the context tag, which is fine as long as we defer * actually destroying the context until it's no longer referenced, and * block clients from trying to MakeCurrent on contexts that are on the * way to destruction. Notice that DoMakeCurrent calls validGlxContext * for new contexts but __glXLookupContextByTag for previous contexts. */ __GLXcontext * __glXLookupContextByTag(__GLXclientState * cl, GLXContextTag tag) { __GLXcontext *ret; if (dixLookupResourceByType((void **) &ret, tag, __glXContextRes, cl->client, DixUseAccess) == Success) return ret; return NULL; } /*****************************************************************************/ static void StopUsingContext(__GLXcontext * glxc) { if (glxc) { if (glxc == __glXLastContext) { /* Tell server GL library */ __glXLastContext = 0; } glxc->isCurrent = GL_FALSE; if (!glxc->idExists) { FreeResourceByType(glxc->id, __glXContextRes, FALSE); } } } static void StartUsingContext(__GLXclientState * cl, __GLXcontext * glxc) { glxc->isCurrent = GL_TRUE; __glXLastContext = glxc; } /** * This is a helper function to handle the legacy (pre GLX 1.3) cases * where passing an X window to glXMakeCurrent is valid. Given a * resource ID, look up the GLX drawable if available, otherwise, make * sure it's an X window and create a GLX drawable one the fly. */ static __GLXdrawable * __glXGetDrawable(__GLXcontext * glxc, GLXDrawable drawId, ClientPtr client, int *error) { DrawablePtr pDraw; __GLXdrawable *pGlxDraw; int rc; if (validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY, DixWriteAccess, &pGlxDraw, &rc)) { if (glxc != NULL && pGlxDraw->config != glxc->config) { client->errorValue = drawId; *error = BadMatch; return NULL; } return pGlxDraw; } /* No active context and an unknown drawable, bail. */ if (glxc == NULL) { client->errorValue = drawId; *error = BadMatch; return NULL; } /* The drawId wasn't a GLX drawable. Make sure it's a window and * create a GLXWindow for it. Check that the drawable screen * matches the context screen and that the context fbconfig is * compatible with the window visual. */ rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixGetAttrAccess); if (rc != Success || pDraw->type != DRAWABLE_WINDOW) { client->errorValue = drawId; *error = __glXError(GLXBadDrawable); return NULL; } if (pDraw->pScreen != glxc->pGlxScreen->pScreen) { client->errorValue = pDraw->pScreen->myNum; *error = BadMatch; return NULL; } if (!validGlxFBConfigForWindow(client, glxc->config, pDraw, error)) return NULL; pGlxDraw = glxc->pGlxScreen->createDrawable(client, glxc->pGlxScreen, pDraw, drawId, GLX_DRAWABLE_WINDOW, drawId, glxc->config); /* since we are creating the drawablePrivate, drawId should be new */ if (!AddResource(drawId, __glXDrawableRes, pGlxDraw)) { pGlxDraw->destroy(pGlxDraw); *error = BadAlloc; return NULL; } return pGlxDraw; } /*****************************************************************************/ /* ** Make an OpenGL context and drawable current. */ static int DoMakeCurrent(__GLXclientState * cl, GLXDrawable drawId, GLXDrawable readId, GLXContextID contextId, GLXContextTag tag) { ClientPtr client = cl->client; xGLXMakeCurrentReply reply; __GLXcontext *glxc, *prevglxc; __GLXdrawable *drawPriv = NULL; __GLXdrawable *readPriv = NULL; int error; GLuint mask; /* ** If one is None and the other isn't, it's a bad match. */ mask = (drawId == None) ? (1 << 0) : 0; mask |= (readId == None) ? (1 << 1) : 0; mask |= (contextId == None) ? (1 << 2) : 0; if ((mask != 0x00) && (mask != 0x07)) { return BadMatch; } /* ** Lookup old context. If we have one, it must be in a usable state. */ if (tag != 0) { prevglxc = __glXLookupContextByTag(cl, tag); if (!prevglxc) { /* ** Tag for previous context is invalid. */ return __glXError(GLXBadContextTag); } if (prevglxc->renderMode != GL_RENDER) { /* Oops. Not in render mode render. */ client->errorValue = prevglxc->id; return __glXError(GLXBadContextState); } } else { prevglxc = 0; } /* ** Lookup new context. It must not be current for someone else. */ if (contextId != None) { int status; if (!validGlxContext(client, contextId, DixUseAccess, &glxc, &error)) return error; if ((glxc != prevglxc) && glxc->isCurrent) { /* Context is current to somebody else */ return BadAccess; } assert(drawId != None); assert(readId != None); drawPriv = __glXGetDrawable(glxc, drawId, client, &status); if (drawPriv == NULL) return status; readPriv = __glXGetDrawable(glxc, readId, client, &status); if (readPriv == NULL) return status; } else { /* Switching to no context. Ignore new drawable. */ glxc = 0; drawPriv = 0; readPriv = 0; } if (prevglxc) { /* ** Flush the previous context if needed. */ if (prevglxc->hasUnflushedCommands) { if (__glXForceCurrent(cl, tag, (int *) &error)) { CALL_Flush(GET_DISPATCH(), ()); prevglxc->hasUnflushedCommands = GL_FALSE; } else { return error; } } /* ** Make the previous context not current. */ if (!(*prevglxc->loseCurrent) (prevglxc)) { return __glXError(GLXBadContext); } __glXFlushContextCache(); if (!prevglxc->isDirect) { prevglxc->drawPriv = NULL; prevglxc->readPriv = NULL; } } if ((glxc != 0) && !glxc->isDirect) { glxc->drawPriv = drawPriv; glxc->readPriv = readPriv; /* make the context current */ if (!(*glxc->makeCurrent) (glxc)) { glxc->drawPriv = NULL; glxc->readPriv = NULL; return __glXError(GLXBadContext); } glxc->isCurrent = GL_TRUE; } StopUsingContext(prevglxc); reply = (xGLXMakeCurrentReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = 0, .contextTag = 0 }; if (glxc) { StartUsingContext(cl, glxc); reply.contextTag = glxc->id; } if (client->swapped) { __glXSwapMakeCurrentReply(client, &reply); } else { WriteToClient(client, sz_xGLXMakeCurrentReply, &reply); } return Success; } int __glXDisp_MakeCurrent(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc; REQUEST_SIZE_MATCH(xGLXMakeCurrentReq); return DoMakeCurrent(cl, req->drawable, req->drawable, req->context, req->oldContextTag); } int __glXDisp_MakeContextCurrent(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) pc; REQUEST_SIZE_MATCH(xGLXMakeContextCurrentReq); return DoMakeCurrent(cl, req->drawable, req->readdrawable, req->context, req->oldContextTag); } int __glXDisp_MakeCurrentReadSGI(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) pc; REQUEST_SIZE_MATCH(xGLXMakeCurrentReadSGIReq); return DoMakeCurrent(cl, req->drawable, req->readable, req->context, req->oldContextTag); } int __glXDisp_IsDirect(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc; xGLXIsDirectReply reply; __GLXcontext *glxc; int err; REQUEST_SIZE_MATCH(xGLXIsDirectReq); if (!validGlxContext(cl->client, req->context, DixReadAccess, &glxc, &err)) return err; reply = (xGLXIsDirectReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = 0, .isDirect = glxc->isDirect }; if (client->swapped) { __glXSwapIsDirectReply(client, &reply); } else { WriteToClient(client, sz_xGLXIsDirectReply, &reply); } return Success; } int __glXDisp_QueryVersion(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc; xGLXQueryVersionReply reply; GLuint major, minor; REQUEST_SIZE_MATCH(xGLXQueryVersionReq); major = req->majorVersion; minor = req->minorVersion; (void) major; (void) minor; /* ** Server should take into consideration the version numbers sent by the ** client if it wants to work with older clients; however, in this ** implementation the server just returns its version number. */ reply = (xGLXQueryVersionReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = 0, .majorVersion = glxMajorVersion, .minorVersion = glxMinorVersion }; if (client->swapped) { __glXSwapQueryVersionReply(client, &reply); } else { WriteToClient(client, sz_xGLXQueryVersionReply, &reply); } return Success; } int __glXDisp_WaitGL(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXWaitGLReq *req = (xGLXWaitGLReq *) pc; GLXContextTag tag; __GLXcontext *glxc = NULL; int error; REQUEST_SIZE_MATCH(xGLXWaitGLReq); tag = req->contextTag; if (tag) { glxc = __glXLookupContextByTag(cl, tag); if (!glxc) return __glXError(GLXBadContextTag); if (!__glXForceCurrent(cl, req->contextTag, &error)) return error; CALL_Finish(GET_DISPATCH(), ()); } if (glxc && glxc->drawPriv->waitGL) (*glxc->drawPriv->waitGL) (glxc->drawPriv); return Success; } int __glXDisp_WaitX(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXWaitXReq *req = (xGLXWaitXReq *) pc; GLXContextTag tag; __GLXcontext *glxc = NULL; int error; REQUEST_SIZE_MATCH(xGLXWaitXReq); tag = req->contextTag; if (tag) { glxc = __glXLookupContextByTag(cl, tag); if (!glxc) return __glXError(GLXBadContextTag); if (!__glXForceCurrent(cl, req->contextTag, &error)) return error; } if (glxc && glxc->drawPriv->waitX) (*glxc->drawPriv->waitX) (glxc->drawPriv); return Success; } int __glXDisp_CopyContext(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc; GLXContextID source; GLXContextID dest; GLXContextTag tag; unsigned long mask; __GLXcontext *src, *dst; int error; REQUEST_SIZE_MATCH(xGLXCopyContextReq); source = req->source; dest = req->dest; tag = req->contextTag; mask = req->mask; if (!validGlxContext(cl->client, source, DixReadAccess, &src, &error)) return error; if (!validGlxContext(cl->client, dest, DixWriteAccess, &dst, &error)) return error; /* ** They must be in the same address space, and same screen. ** NOTE: no support for direct rendering contexts here. */ if (src->isDirect || dst->isDirect || (src->pGlxScreen != dst->pGlxScreen)) { client->errorValue = source; return BadMatch; } /* ** The destination context must not be current for any client. */ if (dst->isCurrent) { client->errorValue = dest; return BadAccess; } if (tag) { __GLXcontext *tagcx = __glXLookupContextByTag(cl, tag); if (!tagcx) { return __glXError(GLXBadContextTag); } if (tagcx != src) { /* ** This would be caused by a faulty implementation of the client ** library. */ return BadMatch; } /* ** In this case, glXCopyContext is in both GL and X streams, in terms ** of sequentiality. */ if (__glXForceCurrent(cl, tag, &error)) { /* ** Do whatever is needed to make sure that all preceding requests ** in both streams are completed before the copy is executed. */ CALL_Finish(GET_DISPATCH(), ()); tagcx->hasUnflushedCommands = GL_FALSE; } else { return error; } } /* ** Issue copy. The only reason for failure is a bad mask. */ if (!(*dst->copy) (dst, src, mask)) { client->errorValue = mask; return BadValue; } return Success; } enum { GLX_VIS_CONFIG_UNPAIRED = 18, GLX_VIS_CONFIG_PAIRED = 20 }; enum { GLX_VIS_CONFIG_TOTAL = GLX_VIS_CONFIG_UNPAIRED + GLX_VIS_CONFIG_PAIRED }; int __glXDisp_GetVisualConfigs(__GLXclientState * cl, GLbyte * pc) { xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) pc; ClientPtr client = cl->client; xGLXGetVisualConfigsReply reply; __GLXscreen *pGlxScreen; __GLXconfig *modes; CARD32 buf[GLX_VIS_CONFIG_TOTAL]; int p, i, err; __GLX_DECLARE_SWAP_VARIABLES; __GLX_DECLARE_SWAP_ARRAY_VARIABLES; REQUEST_SIZE_MATCH(xGLXGetVisualConfigsReq); if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) return err; reply = (xGLXGetVisualConfigsReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = (pGlxScreen->numVisuals * __GLX_SIZE_CARD32 * GLX_VIS_CONFIG_TOTAL) >> 2, .numVisuals = pGlxScreen->numVisuals, .numProps = GLX_VIS_CONFIG_TOTAL }; if (client->swapped) { __GLX_SWAP_SHORT(&reply.sequenceNumber); __GLX_SWAP_INT(&reply.length); __GLX_SWAP_INT(&reply.numVisuals); __GLX_SWAP_INT(&reply.numProps); } WriteToClient(client, sz_xGLXGetVisualConfigsReply, &reply); for (i = 0; i < pGlxScreen->numVisuals; i++) { modes = pGlxScreen->visuals[i]; p = 0; buf[p++] = modes->visualID; buf[p++] = glxConvertToXVisualType(modes->visualType); buf[p++] = (modes->renderType & GLX_RGBA_BIT) ? GL_TRUE : GL_FALSE; buf[p++] = modes->redBits; buf[p++] = modes->greenBits; buf[p++] = modes->blueBits; buf[p++] = modes->alphaBits; buf[p++] = modes->accumRedBits; buf[p++] = modes->accumGreenBits; buf[p++] = modes->accumBlueBits; buf[p++] = modes->accumAlphaBits; buf[p++] = modes->doubleBufferMode; buf[p++] = modes->stereoMode; buf[p++] = modes->rgbBits; buf[p++] = modes->depthBits; buf[p++] = modes->stencilBits; buf[p++] = modes->numAuxBuffers; buf[p++] = modes->level; assert(p == GLX_VIS_CONFIG_UNPAIRED); /* ** Add token/value pairs for extensions. */ buf[p++] = GLX_VISUAL_CAVEAT_EXT; buf[p++] = modes->visualRating; buf[p++] = GLX_TRANSPARENT_TYPE; buf[p++] = modes->transparentPixel; buf[p++] = GLX_TRANSPARENT_RED_VALUE; buf[p++] = modes->transparentRed; buf[p++] = GLX_TRANSPARENT_GREEN_VALUE; buf[p++] = modes->transparentGreen; buf[p++] = GLX_TRANSPARENT_BLUE_VALUE; buf[p++] = modes->transparentBlue; buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE; buf[p++] = modes->transparentAlpha; buf[p++] = GLX_TRANSPARENT_INDEX_VALUE; buf[p++] = modes->transparentIndex; buf[p++] = GLX_SAMPLES_SGIS; buf[p++] = modes->samples; buf[p++] = GLX_SAMPLE_BUFFERS_SGIS; buf[p++] = modes->sampleBuffers; buf[p++] = 0; /* copy over visualSelectGroup (GLX_VISUAL_SELECT_GROUP_SGIX)? */ buf[p++] = 0; assert(p == GLX_VIS_CONFIG_TOTAL); if (client->swapped) { __GLX_SWAP_INT_ARRAY(buf, p); } WriteToClient(client, __GLX_SIZE_CARD32 * p, buf); } return Success; } #define __GLX_TOTAL_FBCONFIG_ATTRIBS (36) #define __GLX_FBCONFIG_ATTRIBS_LENGTH (__GLX_TOTAL_FBCONFIG_ATTRIBS * 2) /** * Send the set of GLXFBConfigs to the client. There is not currently * and interface into the driver on the server-side to get GLXFBConfigs, * so we "invent" some based on the \c __GLXvisualConfig structures that * the driver does supply. * * The reply format for both \c glXGetFBConfigs and \c glXGetFBConfigsSGIX * is the same, so this routine pulls double duty. */ static int DoGetFBConfigs(__GLXclientState * cl, unsigned screen) { ClientPtr client = cl->client; xGLXGetFBConfigsReply reply; __GLXscreen *pGlxScreen; CARD32 buf[__GLX_FBCONFIG_ATTRIBS_LENGTH]; int p, err; __GLXconfig *modes; __GLX_DECLARE_SWAP_VARIABLES; __GLX_DECLARE_SWAP_ARRAY_VARIABLES; if (!validGlxScreen(cl->client, screen, &pGlxScreen, &err)) return err; reply = (xGLXGetFBConfigsReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = __GLX_FBCONFIG_ATTRIBS_LENGTH * pGlxScreen->numFBConfigs, .numFBConfigs = pGlxScreen->numFBConfigs, .numAttribs = __GLX_TOTAL_FBCONFIG_ATTRIBS }; if (client->swapped) { __GLX_SWAP_SHORT(&reply.sequenceNumber); __GLX_SWAP_INT(&reply.length); __GLX_SWAP_INT(&reply.numFBConfigs); __GLX_SWAP_INT(&reply.numAttribs); } WriteToClient(client, sz_xGLXGetFBConfigsReply, &reply); for (modes = pGlxScreen->fbconfigs; modes != NULL; modes = modes->next) { p = 0; #define WRITE_PAIR(tag,value) \ do { buf[p++] = tag ; buf[p++] = value ; } while( 0 ) WRITE_PAIR(GLX_VISUAL_ID, modes->visualID); WRITE_PAIR(GLX_FBCONFIG_ID, modes->fbconfigID); WRITE_PAIR(GLX_X_RENDERABLE, GL_TRUE); WRITE_PAIR(GLX_RGBA, (modes->renderType & GLX_RGBA_BIT) ? GL_TRUE : GL_FALSE); WRITE_PAIR(GLX_RENDER_TYPE, modes->renderType); WRITE_PAIR(GLX_DOUBLEBUFFER, modes->doubleBufferMode); WRITE_PAIR(GLX_STEREO, modes->stereoMode); WRITE_PAIR(GLX_BUFFER_SIZE, modes->rgbBits); WRITE_PAIR(GLX_LEVEL, modes->level); WRITE_PAIR(GLX_AUX_BUFFERS, modes->numAuxBuffers); WRITE_PAIR(GLX_RED_SIZE, modes->redBits); WRITE_PAIR(GLX_GREEN_SIZE, modes->greenBits); WRITE_PAIR(GLX_BLUE_SIZE, modes->blueBits); WRITE_PAIR(GLX_ALPHA_SIZE, modes->alphaBits); WRITE_PAIR(GLX_ACCUM_RED_SIZE, modes->accumRedBits); WRITE_PAIR(GLX_ACCUM_GREEN_SIZE, modes->accumGreenBits); WRITE_PAIR(GLX_ACCUM_BLUE_SIZE, modes->accumBlueBits); WRITE_PAIR(GLX_ACCUM_ALPHA_SIZE, modes->accumAlphaBits); WRITE_PAIR(GLX_DEPTH_SIZE, modes->depthBits); WRITE_PAIR(GLX_STENCIL_SIZE, modes->stencilBits); WRITE_PAIR(GLX_X_VISUAL_TYPE, modes->visualType); WRITE_PAIR(GLX_CONFIG_CAVEAT, modes->visualRating); WRITE_PAIR(GLX_TRANSPARENT_TYPE, modes->transparentPixel); WRITE_PAIR(GLX_TRANSPARENT_RED_VALUE, modes->transparentRed); WRITE_PAIR(GLX_TRANSPARENT_GREEN_VALUE, modes->transparentGreen); WRITE_PAIR(GLX_TRANSPARENT_BLUE_VALUE, modes->transparentBlue); WRITE_PAIR(GLX_TRANSPARENT_ALPHA_VALUE, modes->transparentAlpha); WRITE_PAIR(GLX_TRANSPARENT_INDEX_VALUE, modes->transparentIndex); WRITE_PAIR(GLX_SWAP_METHOD_OML, modes->swapMethod); WRITE_PAIR(GLX_SAMPLES_SGIS, modes->samples); WRITE_PAIR(GLX_SAMPLE_BUFFERS_SGIS, modes->sampleBuffers); /* GLX_VISUAL_SELECT_GROUP_SGIX ? */ WRITE_PAIR(GLX_DRAWABLE_TYPE, modes->drawableType); WRITE_PAIR(GLX_BIND_TO_TEXTURE_RGB_EXT, modes->bindToTextureRgb); WRITE_PAIR(GLX_BIND_TO_TEXTURE_RGBA_EXT, modes->bindToTextureRgba); WRITE_PAIR(GLX_BIND_TO_MIPMAP_TEXTURE_EXT, modes->bindToMipmapTexture); WRITE_PAIR(GLX_BIND_TO_TEXTURE_TARGETS_EXT, modes->bindToTextureTargets); if (client->swapped) { __GLX_SWAP_INT_ARRAY(buf, __GLX_FBCONFIG_ATTRIBS_LENGTH); } WriteToClient(client, __GLX_SIZE_CARD32 * __GLX_FBCONFIG_ATTRIBS_LENGTH, (char *) buf); } return Success; } int __glXDisp_GetFBConfigs(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXGetFBConfigsReq *req = (xGLXGetFBConfigsReq *) pc; REQUEST_SIZE_MATCH(xGLXGetFBConfigsReq); return DoGetFBConfigs(cl, req->screen); } int __glXDisp_GetFBConfigsSGIX(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *) pc; /* work around mesa bug, don't use REQUEST_SIZE_MATCH */ REQUEST_AT_LEAST_SIZE(xGLXGetFBConfigsSGIXReq); return DoGetFBConfigs(cl, req->screen); } GLboolean __glXDrawableInit(__GLXdrawable * drawable, __GLXscreen * screen, DrawablePtr pDraw, int type, XID drawId, __GLXconfig * config) { drawable->pDraw = pDraw; drawable->type = type; drawable->drawId = drawId; drawable->config = config; drawable->eventMask = 0; return GL_TRUE; } void __glXDrawableRelease(__GLXdrawable * drawable) { } static int DoCreateGLXDrawable(ClientPtr client, __GLXscreen * pGlxScreen, __GLXconfig * config, DrawablePtr pDraw, XID drawableId, XID glxDrawableId, int type) { __GLXdrawable *pGlxDraw; if (pGlxScreen->pScreen != pDraw->pScreen) return BadMatch; pGlxDraw = pGlxScreen->createDrawable(client, pGlxScreen, pDraw, drawableId, type, glxDrawableId, config); if (pGlxDraw == NULL) return BadAlloc; if (!AddResource(glxDrawableId, __glXDrawableRes, pGlxDraw)) { pGlxDraw->destroy(pGlxDraw); return BadAlloc; } /* * Windows aren't refcounted, so track both the X and the GLX window * so we get called regardless of destruction order. */ if (drawableId != glxDrawableId && type == GLX_DRAWABLE_WINDOW && !AddResource(pDraw->id, __glXDrawableRes, pGlxDraw)) { pGlxDraw->destroy(pGlxDraw); return BadAlloc; } return Success; } static int DoCreateGLXPixmap(ClientPtr client, __GLXscreen * pGlxScreen, __GLXconfig * config, XID drawableId, XID glxDrawableId) { DrawablePtr pDraw; int err; LEGAL_NEW_RESOURCE(glxDrawableId, client); err = dixLookupDrawable(&pDraw, drawableId, client, 0, DixAddAccess); if (err != Success) { client->errorValue = drawableId; return err; } if (pDraw->type != DRAWABLE_PIXMAP) { client->errorValue = drawableId; return BadPixmap; } err = DoCreateGLXDrawable(client, pGlxScreen, config, pDraw, drawableId, glxDrawableId, GLX_DRAWABLE_PIXMAP); ((PixmapPtr) pDraw)->refcnt++; return err; } static void determineTextureTarget(ClientPtr client, XID glxDrawableID, CARD32 *attribs, CARD32 numAttribs) { GLenum target = 0; GLenum format = 0; int i, err; __GLXdrawable *pGlxDraw; if (!validGlxDrawable(client, glxDrawableID, GLX_DRAWABLE_PIXMAP, DixWriteAccess, &pGlxDraw, &err)) /* We just added it in CreatePixmap, so we should never get here. */ return; for (i = 0; i < numAttribs; i++) { if (attribs[2 * i] == GLX_TEXTURE_TARGET_EXT) { switch (attribs[2 * i + 1]) { case GLX_TEXTURE_2D_EXT: target = GL_TEXTURE_2D; break; case GLX_TEXTURE_RECTANGLE_EXT: target = GL_TEXTURE_RECTANGLE_ARB; break; } } if (attribs[2 * i] == GLX_TEXTURE_FORMAT_EXT) format = attribs[2 * i + 1]; } if (!target) { int w = pGlxDraw->pDraw->width, h = pGlxDraw->pDraw->height; if (h & (h - 1) || w & (w - 1)) target = GL_TEXTURE_RECTANGLE_ARB; else target = GL_TEXTURE_2D; } pGlxDraw->target = target; pGlxDraw->format = format; } int __glXDisp_CreateGLXPixmap(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXCreateGLXPixmapReq *req = (xGLXCreateGLXPixmapReq *) pc; __GLXconfig *config; __GLXscreen *pGlxScreen; int err; REQUEST_SIZE_MATCH(xGLXCreateGLXPixmapReq); if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) return err; if (!validGlxVisual(cl->client, pGlxScreen, req->visual, &config, &err)) return err; return DoCreateGLXPixmap(cl->client, pGlxScreen, config, req->pixmap, req->glxpixmap); } int __glXDisp_CreatePixmap(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXCreatePixmapReq *req = (xGLXCreatePixmapReq *) pc; __GLXconfig *config; __GLXscreen *pGlxScreen; int err; REQUEST_AT_LEAST_SIZE(xGLXCreatePixmapReq); if (req->numAttribs > (UINT32_MAX >> 3)) { client->errorValue = req->numAttribs; return BadValue; } REQUEST_FIXED_SIZE(xGLXCreatePixmapReq, req->numAttribs << 3); if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) return err; if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err)) return err; err = DoCreateGLXPixmap(cl->client, pGlxScreen, config, req->pixmap, req->glxpixmap); if (err != Success) return err; determineTextureTarget(cl->client, req->glxpixmap, (CARD32 *) (req + 1), req->numAttribs); return Success; } int __glXDisp_CreateGLXPixmapWithConfigSGIX(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXCreateGLXPixmapWithConfigSGIXReq *req = (xGLXCreateGLXPixmapWithConfigSGIXReq *) pc; __GLXconfig *config; __GLXscreen *pGlxScreen; int err; REQUEST_SIZE_MATCH(xGLXCreateGLXPixmapWithConfigSGIXReq); if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) return err; if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err)) return err; return DoCreateGLXPixmap(cl->client, pGlxScreen, config, req->pixmap, req->glxpixmap); } static int DoDestroyDrawable(__GLXclientState * cl, XID glxdrawable, int type) { __GLXdrawable *pGlxDraw; int err; if (!validGlxDrawable(cl->client, glxdrawable, type, DixDestroyAccess, &pGlxDraw, &err)) return err; FreeResource(glxdrawable, FALSE); return Success; } int __glXDisp_DestroyGLXPixmap(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc; REQUEST_SIZE_MATCH(xGLXDestroyGLXPixmapReq); return DoDestroyDrawable(cl, req->glxpixmap, GLX_DRAWABLE_PIXMAP); } int __glXDisp_DestroyPixmap(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXDestroyPixmapReq *req = (xGLXDestroyPixmapReq *) pc; /* should be REQUEST_SIZE_MATCH, but mesa's glXDestroyPixmap used to set * length to 3 instead of 2 */ REQUEST_AT_LEAST_SIZE(xGLXDestroyPixmapReq); return DoDestroyDrawable(cl, req->glxpixmap, GLX_DRAWABLE_PIXMAP); } static int DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId, int width, int height, XID glxDrawableId) { __GLXconfig *config; __GLXscreen *pGlxScreen; PixmapPtr pPixmap; int err; LEGAL_NEW_RESOURCE(glxDrawableId, client); if (!validGlxScreen(client, screenNum, &pGlxScreen, &err)) return err; if (!validGlxFBConfig(client, pGlxScreen, fbconfigId, &config, &err)) return err; __glXenterServer(GL_FALSE); pPixmap = (*pGlxScreen->pScreen->CreatePixmap) (pGlxScreen->pScreen, width, height, config->rgbBits, 0); __glXleaveServer(GL_FALSE); /* Assign the pixmap the same id as the pbuffer and add it as a * resource so it and the DRI2 drawable will be reclaimed when the * pbuffer is destroyed. */ pPixmap->drawable.id = glxDrawableId; if (!AddResource(pPixmap->drawable.id, RT_PIXMAP, pPixmap)) return BadAlloc; return DoCreateGLXDrawable(client, pGlxScreen, config, &pPixmap->drawable, glxDrawableId, glxDrawableId, GLX_DRAWABLE_PBUFFER); } int __glXDisp_CreatePbuffer(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXCreatePbufferReq *req = (xGLXCreatePbufferReq *) pc; CARD32 *attrs; int width, height, i; REQUEST_AT_LEAST_SIZE(xGLXCreatePbufferReq); if (req->numAttribs > (UINT32_MAX >> 3)) { client->errorValue = req->numAttribs; return BadValue; } REQUEST_FIXED_SIZE(xGLXCreatePbufferReq, req->numAttribs << 3); attrs = (CARD32 *) (req + 1); width = 0; height = 0; for (i = 0; i < req->numAttribs; i++) { switch (attrs[i * 2]) { case GLX_PBUFFER_WIDTH: width = attrs[i * 2 + 1]; break; case GLX_PBUFFER_HEIGHT: height = attrs[i * 2 + 1]; break; case GLX_LARGEST_PBUFFER: case GLX_PRESERVED_CONTENTS: /* FIXME: huh... */ break; } } return DoCreatePbuffer(cl->client, req->screen, req->fbconfig, width, height, req->pbuffer); } int __glXDisp_CreateGLXPbufferSGIX(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXCreateGLXPbufferSGIXReq *req = (xGLXCreateGLXPbufferSGIXReq *) pc; REQUEST_AT_LEAST_SIZE(xGLXCreateGLXPbufferSGIXReq); return DoCreatePbuffer(cl->client, req->screen, req->fbconfig, req->width, req->height, req->pbuffer); } int __glXDisp_DestroyPbuffer(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXDestroyPbufferReq *req = (xGLXDestroyPbufferReq *) pc; REQUEST_SIZE_MATCH(xGLXDestroyPbufferReq); return DoDestroyDrawable(cl, req->pbuffer, GLX_DRAWABLE_PBUFFER); } int __glXDisp_DestroyGLXPbufferSGIX(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXDestroyGLXPbufferSGIXReq *req = (xGLXDestroyGLXPbufferSGIXReq *) pc; REQUEST_SIZE_MATCH(xGLXDestroyGLXPbufferSGIXReq); return DoDestroyDrawable(cl, req->pbuffer, GLX_DRAWABLE_PBUFFER); } static int DoChangeDrawableAttributes(ClientPtr client, XID glxdrawable, int numAttribs, CARD32 *attribs) { __GLXdrawable *pGlxDraw; int i, err; if (!validGlxDrawable(client, glxdrawable, GLX_DRAWABLE_ANY, DixSetAttrAccess, &pGlxDraw, &err)) return err; for (i = 0; i < numAttribs; i++) { switch (attribs[i * 2]) { case GLX_EVENT_MASK: /* All we do is to record the event mask so we can send it * back when queried. We never actually clobber the * pbuffers, so we never need to send out the event. */ pGlxDraw->eventMask = attribs[i * 2 + 1]; break; } } return Success; } int __glXDisp_ChangeDrawableAttributes(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXChangeDrawableAttributesReq *req = (xGLXChangeDrawableAttributesReq *) pc; REQUEST_AT_LEAST_SIZE(xGLXChangeDrawableAttributesReq); if (req->numAttribs > (UINT32_MAX >> 3)) { client->errorValue = req->numAttribs; return BadValue; } #if 0 /* mesa sends an additional 8 bytes */ REQUEST_FIXED_SIZE(xGLXChangeDrawableAttributesReq, req->numAttribs << 3); #else if (((sizeof(xGLXChangeDrawableAttributesReq) + (req->numAttribs << 3)) >> 2) < client->req_len) return BadLength; #endif return DoChangeDrawableAttributes(cl->client, req->drawable, req->numAttribs, (CARD32 *) (req + 1)); } int __glXDisp_ChangeDrawableAttributesSGIX(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXChangeDrawableAttributesSGIXReq *req = (xGLXChangeDrawableAttributesSGIXReq *) pc; REQUEST_AT_LEAST_SIZE(xGLXChangeDrawableAttributesSGIXReq); if (req->numAttribs > (UINT32_MAX >> 3)) { client->errorValue = req->numAttribs; return BadValue; } REQUEST_FIXED_SIZE(xGLXChangeDrawableAttributesSGIXReq, req->numAttribs << 3); return DoChangeDrawableAttributes(cl->client, req->drawable, req->numAttribs, (CARD32 *) (req + 1)); } int __glXDisp_CreateWindow(__GLXclientState * cl, GLbyte * pc) { xGLXCreateWindowReq *req = (xGLXCreateWindowReq *) pc; __GLXconfig *config; __GLXscreen *pGlxScreen; ClientPtr client = cl->client; DrawablePtr pDraw; int err; REQUEST_AT_LEAST_SIZE(xGLXCreateWindowReq); if (req->numAttribs > (UINT32_MAX >> 3)) { client->errorValue = req->numAttribs; return BadValue; } REQUEST_FIXED_SIZE(xGLXCreateWindowReq, req->numAttribs << 3); LEGAL_NEW_RESOURCE(req->glxwindow, client); if (!validGlxScreen(client, req->screen, &pGlxScreen, &err)) return err; if (!validGlxFBConfig(client, pGlxScreen, req->fbconfig, &config, &err)) return err; err = dixLookupDrawable(&pDraw, req->window, client, 0, DixAddAccess); if (err != Success || pDraw->type != DRAWABLE_WINDOW) { client->errorValue = req->window; return BadWindow; } if (!validGlxFBConfigForWindow(client, config, pDraw, &err)) return err; return DoCreateGLXDrawable(client, pGlxScreen, config, pDraw, req->window, req->glxwindow, GLX_DRAWABLE_WINDOW); } int __glXDisp_DestroyWindow(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXDestroyWindowReq *req = (xGLXDestroyWindowReq *) pc; /* mesa's glXDestroyWindow used to set length to 3 instead of 2 */ REQUEST_AT_LEAST_SIZE(xGLXDestroyWindowReq); return DoDestroyDrawable(cl, req->glxwindow, GLX_DRAWABLE_WINDOW); } /*****************************************************************************/ /* ** NOTE: There is no portable implementation for swap buffers as of ** this time that is of value. Consequently, this code must be ** implemented by somebody other than SGI. */ int __glXDisp_SwapBuffers(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXSwapBuffersReq *req = (xGLXSwapBuffersReq *) pc; GLXContextTag tag; XID drawId; __GLXcontext *glxc = NULL; __GLXdrawable *pGlxDraw; int error; REQUEST_SIZE_MATCH(xGLXSwapBuffersReq); tag = req->contextTag; drawId = req->drawable; if (tag) { glxc = __glXLookupContextByTag(cl, tag); if (!glxc) { return __glXError(GLXBadContextTag); } /* ** The calling thread is swapping its current drawable. In this case, ** glxSwapBuffers is in both GL and X streams, in terms of ** sequentiality. */ if (__glXForceCurrent(cl, tag, &error)) { /* ** Do whatever is needed to make sure that all preceding requests ** in both streams are completed before the swap is executed. */ CALL_Finish(GET_DISPATCH(), ()); glxc->hasUnflushedCommands = GL_FALSE; } else { return error; } } pGlxDraw = __glXGetDrawable(glxc, drawId, client, &error); if (pGlxDraw == NULL) return error; if (pGlxDraw->type == DRAWABLE_WINDOW && (*pGlxDraw->swapBuffers) (cl->client, pGlxDraw) == GL_FALSE) return __glXError(GLXBadDrawable); return Success; } static int DoQueryContext(__GLXclientState * cl, GLXContextID gcId) { ClientPtr client = cl->client; __GLXcontext *ctx; xGLXQueryContextInfoEXTReply reply; int nProps; int *sendBuf, *pSendBuf; int nReplyBytes; int err; if (!validGlxContext(cl->client, gcId, DixReadAccess, &ctx, &err)) return err; nProps = 3; reply = (xGLXQueryContextInfoEXTReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = nProps << 1, .n = nProps }; nReplyBytes = reply.length << 2; sendBuf = (int *) malloc((size_t) nReplyBytes); if (sendBuf == NULL) { return __glXError(GLXBadContext); /* XXX: Is this correct? */ } pSendBuf = sendBuf; *pSendBuf++ = GLX_SHARE_CONTEXT_EXT; *pSendBuf++ = (int) (ctx->share_id); *pSendBuf++ = GLX_VISUAL_ID_EXT; *pSendBuf++ = (int) (ctx->config->visualID); *pSendBuf++ = GLX_SCREEN_EXT; *pSendBuf++ = (int) (ctx->pGlxScreen->pScreen->myNum); if (client->swapped) { __glXSwapQueryContextInfoEXTReply(client, &reply, sendBuf); } else { WriteToClient(client, sz_xGLXQueryContextInfoEXTReply, &reply); WriteToClient(client, nReplyBytes, sendBuf); } free((char *) sendBuf); return Success; } int __glXDisp_QueryContextInfoEXT(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXQueryContextInfoEXTReq *req = (xGLXQueryContextInfoEXTReq *) pc; REQUEST_SIZE_MATCH(xGLXQueryContextInfoEXTReq); return DoQueryContext(cl, req->context); } int __glXDisp_QueryContext(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXQueryContextReq *req = (xGLXQueryContextReq *) pc; REQUEST_SIZE_MATCH(xGLXQueryContextReq); return DoQueryContext(cl, req->context); } int __glXDisp_BindTexImageEXT(__GLXclientState * cl, GLbyte * pc) { xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc; ClientPtr client = cl->client; __GLXcontext *context; __GLXdrawable *pGlxDraw; GLXDrawable drawId; int buffer; int error; CARD32 num_attribs; if ((sizeof(xGLXVendorPrivateReq) + 12) >> 2 > client->req_len) return BadLength; pc += __GLX_VENDPRIV_HDR_SIZE; drawId = *((CARD32 *) (pc)); buffer = *((INT32 *) (pc + 4)); num_attribs = *((CARD32 *) (pc + 8)); if (num_attribs > (UINT32_MAX >> 3)) { client->errorValue = num_attribs; return BadValue; } REQUEST_FIXED_SIZE(xGLXVendorPrivateReq, 12 + (num_attribs << 3)); if (buffer != GLX_FRONT_LEFT_EXT) return __glXError(GLXBadPixmap); context = __glXForceCurrent(cl, req->contextTag, &error); if (!context) return error; if (!validGlxDrawable(client, drawId, GLX_DRAWABLE_PIXMAP, DixReadAccess, &pGlxDraw, &error)) return error; if (!context->textureFromPixmap) return __glXError(GLXUnsupportedPrivateRequest); return context->textureFromPixmap->bindTexImage(context, buffer, pGlxDraw); } int __glXDisp_ReleaseTexImageEXT(__GLXclientState * cl, GLbyte * pc) { xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc; ClientPtr client = cl->client; __GLXdrawable *pGlxDraw; __GLXcontext *context; GLXDrawable drawId; int buffer; int error; REQUEST_FIXED_SIZE(xGLXVendorPrivateReq, 8); pc += __GLX_VENDPRIV_HDR_SIZE; drawId = *((CARD32 *) (pc)); buffer = *((INT32 *) (pc + 4)); context = __glXForceCurrent(cl, req->contextTag, &error); if (!context) return error; if (!validGlxDrawable(client, drawId, GLX_DRAWABLE_PIXMAP, DixReadAccess, &pGlxDraw, &error)) return error; if (!context->textureFromPixmap) return __glXError(GLXUnsupportedPrivateRequest); return context->textureFromPixmap->releaseTexImage(context, buffer, pGlxDraw); } int __glXDisp_CopySubBufferMESA(__GLXclientState * cl, GLbyte * pc) { xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc; GLXContextTag tag = req->contextTag; __GLXcontext *glxc = NULL; __GLXdrawable *pGlxDraw; ClientPtr client = cl->client; GLXDrawable drawId; int error; int x, y, width, height; (void) client; (void) req; REQUEST_FIXED_SIZE(xGLXVendorPrivateReq, 20); pc += __GLX_VENDPRIV_HDR_SIZE; drawId = *((CARD32 *) (pc)); x = *((INT32 *) (pc + 4)); y = *((INT32 *) (pc + 8)); width = *((INT32 *) (pc + 12)); height = *((INT32 *) (pc + 16)); if (tag) { glxc = __glXLookupContextByTag(cl, tag); if (!glxc) { return __glXError(GLXBadContextTag); } /* ** The calling thread is swapping its current drawable. In this case, ** glxSwapBuffers is in both GL and X streams, in terms of ** sequentiality. */ if (__glXForceCurrent(cl, tag, &error)) { /* ** Do whatever is needed to make sure that all preceding requests ** in both streams are completed before the swap is executed. */ CALL_Finish(GET_DISPATCH(), ()); glxc->hasUnflushedCommands = GL_FALSE; } else { return error; } } pGlxDraw = __glXGetDrawable(glxc, drawId, client, &error); if (!pGlxDraw) return error; if (pGlxDraw == NULL || pGlxDraw->type != GLX_DRAWABLE_WINDOW || pGlxDraw->copySubBuffer == NULL) return __glXError(GLXBadDrawable); (*pGlxDraw->copySubBuffer) (pGlxDraw, x, y, width, height); return Success; } /* ** Get drawable attributes */ static int DoGetDrawableAttributes(__GLXclientState * cl, XID drawId) { ClientPtr client = cl->client; xGLXGetDrawableAttributesReply reply; __GLXdrawable *pGlxDraw; CARD32 attributes[6]; int numAttribs, error; if (!validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY, DixGetAttrAccess, &pGlxDraw, &error)) return error; numAttribs = 3; reply = (xGLXGetDrawableAttributesReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = numAttribs << 1, .numAttribs = numAttribs }; attributes[0] = GLX_TEXTURE_TARGET_EXT; attributes[1] = pGlxDraw->target == GL_TEXTURE_2D ? GLX_TEXTURE_2D_EXT : GLX_TEXTURE_RECTANGLE_EXT; attributes[2] = GLX_Y_INVERTED_EXT; attributes[3] = GL_FALSE; attributes[4] = GLX_EVENT_MASK; attributes[5] = pGlxDraw->eventMask; if (client->swapped) { __glXSwapGetDrawableAttributesReply(client, &reply, attributes); } else { WriteToClient(client, sz_xGLXGetDrawableAttributesReply, &reply); WriteToClient(client, reply.length * sizeof(CARD32), attributes); } return Success; } int __glXDisp_GetDrawableAttributes(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXGetDrawableAttributesReq *req = (xGLXGetDrawableAttributesReq *) pc; /* this should be REQUEST_SIZE_MATCH, but mesa sends an additional 4 bytes */ REQUEST_AT_LEAST_SIZE(xGLXGetDrawableAttributesReq); return DoGetDrawableAttributes(cl, req->drawable); } int __glXDisp_GetDrawableAttributesSGIX(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXGetDrawableAttributesSGIXReq *req = (xGLXGetDrawableAttributesSGIXReq *) pc; REQUEST_SIZE_MATCH(xGLXGetDrawableAttributesSGIXReq); return DoGetDrawableAttributes(cl, req->drawable); } /************************************************************************/ /* ** Render and Renderlarge are not in the GLX API. They are used by the GLX ** client library to send batches of GL rendering commands. */ /* ** Execute all the drawing commands in a request. */ int __glXDisp_Render(__GLXclientState * cl, GLbyte * pc) { xGLXRenderReq *req; ClientPtr client = cl->client; int left, cmdlen, error; int commandsDone; CARD16 opcode; __GLXrenderHeader *hdr; __GLXcontext *glxc; __GLX_DECLARE_SWAP_VARIABLES; REQUEST_AT_LEAST_SIZE(xGLXRenderReq); req = (xGLXRenderReq *) pc; if (client->swapped) { __GLX_SWAP_SHORT(&req->length); __GLX_SWAP_INT(&req->contextTag); } glxc = __glXForceCurrent(cl, req->contextTag, &error); if (!glxc) { return error; } commandsDone = 0; pc += sz_xGLXRenderReq; left = (req->length << 2) - sz_xGLXRenderReq; while (left > 0) { __GLXrenderSizeData entry; int extra; __GLXdispatchRenderProcPtr proc; int err; if (left < sizeof(__GLXrenderHeader)) return BadLength; /* ** Verify that the header length and the overall length agree. ** Also, each command must be word aligned. */ hdr = (__GLXrenderHeader *) pc; if (client->swapped) { __GLX_SWAP_SHORT(&hdr->length); __GLX_SWAP_SHORT(&hdr->opcode); } cmdlen = hdr->length; opcode = hdr->opcode; /* ** Check for core opcodes and grab entry data. */ err = __glXGetProtocolSizeData(&Render_dispatch_info, opcode, &entry); proc = (__GLXdispatchRenderProcPtr) __glXGetProtocolDecodeFunction(&Render_dispatch_info, opcode, client->swapped); if ((err < 0) || (proc == NULL)) { client->errorValue = commandsDone; return __glXError(GLXBadRenderRequest); } if (entry.varsize) { /* variable size command */ extra = (*entry.varsize) (pc + __GLX_RENDER_HDR_SIZE, client->swapped); if (extra < 0) { extra = 0; } if (cmdlen != __GLX_PAD(entry.bytes + extra)) { return BadLength; } } else { /* constant size command */ if (cmdlen != __GLX_PAD(entry.bytes)) { return BadLength; } } if (left < cmdlen) { return BadLength; } /* ** Skip over the header and execute the command. We allow the ** caller to trash the command memory. This is useful especially ** for things that require double alignment - they can just shift ** the data towards lower memory (trashing the header) by 4 bytes ** and achieve the required alignment. */ (*proc) (pc + __GLX_RENDER_HDR_SIZE); pc += cmdlen; left -= cmdlen; commandsDone++; } glxc->hasUnflushedCommands = GL_TRUE; return Success; } /* ** Execute a large rendering request (one that spans multiple X requests). */ int __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc) { xGLXRenderLargeReq *req; ClientPtr client = cl->client; size_t dataBytes; __GLXrenderLargeHeader *hdr; __GLXcontext *glxc; int error; CARD16 opcode; __GLX_DECLARE_SWAP_VARIABLES; req = (xGLXRenderLargeReq *) pc; if (client->swapped) { __GLX_SWAP_SHORT(&req->length); __GLX_SWAP_INT(&req->contextTag); __GLX_SWAP_INT(&req->dataBytes); __GLX_SWAP_SHORT(&req->requestNumber); __GLX_SWAP_SHORT(&req->requestTotal); } glxc = __glXForceCurrent(cl, req->contextTag, &error); if (!glxc) { /* Reset in case this isn't 1st request. */ __glXResetLargeCommandStatus(cl); return error; } dataBytes = req->dataBytes; /* ** Check the request length. */ if ((req->length << 2) != __GLX_PAD(dataBytes) + sz_xGLXRenderLargeReq) { client->errorValue = req->length; /* Reset in case this isn't 1st request. */ __glXResetLargeCommandStatus(cl); return BadLength; } pc += sz_xGLXRenderLargeReq; if (cl->largeCmdRequestsSoFar == 0) { __GLXrenderSizeData entry; int extra; size_t cmdlen; int err; /* ** This is the first request of a multi request command. ** Make enough space in the buffer, then copy the entire request. */ if (req->requestNumber != 1) { client->errorValue = req->requestNumber; return __glXError(GLXBadLargeRequest); } hdr = (__GLXrenderLargeHeader *) pc; if (client->swapped) { __GLX_SWAP_INT(&hdr->length); __GLX_SWAP_INT(&hdr->opcode); } cmdlen = hdr->length; opcode = hdr->opcode; /* ** Check for core opcodes and grab entry data. */ err = __glXGetProtocolSizeData(&Render_dispatch_info, opcode, &entry); if (err < 0) { client->errorValue = opcode; return __glXError(GLXBadLargeRequest); } if (entry.varsize) { /* ** If it's a variable-size command (a command whose length must ** be computed from its parameters), all the parameters needed ** will be in the 1st request, so it's okay to do this. */ extra = (*entry.varsize) (pc + __GLX_RENDER_LARGE_HDR_SIZE, client->swapped); if (extra < 0) { extra = 0; } /* large command's header is 4 bytes longer, so add 4 */ if (cmdlen != __GLX_PAD(entry.bytes + 4 + extra)) { return BadLength; } } else { /* constant size command */ if (cmdlen != __GLX_PAD(entry.bytes + 4)) { return BadLength; } } /* ** Make enough space in the buffer, then copy the entire request. */ if (cl->largeCmdBufSize < cmdlen) { if (!cl->largeCmdBuf) { cl->largeCmdBuf = (GLbyte *) malloc(cmdlen); } else { cl->largeCmdBuf = (GLbyte *) realloc(cl->largeCmdBuf, cmdlen); } if (!cl->largeCmdBuf) { return BadAlloc; } cl->largeCmdBufSize = cmdlen; } memcpy(cl->largeCmdBuf, pc, dataBytes); cl->largeCmdBytesSoFar = dataBytes; cl->largeCmdBytesTotal = cmdlen; cl->largeCmdRequestsSoFar = 1; cl->largeCmdRequestsTotal = req->requestTotal; return Success; } else { /* ** We are receiving subsequent (i.e. not the first) requests of a ** multi request command. */ /* ** Check the request number and the total request count. */ if (req->requestNumber != cl->largeCmdRequestsSoFar + 1) { client->errorValue = req->requestNumber; __glXResetLargeCommandStatus(cl); return __glXError(GLXBadLargeRequest); } if (req->requestTotal != cl->largeCmdRequestsTotal) { client->errorValue = req->requestTotal; __glXResetLargeCommandStatus(cl); return __glXError(GLXBadLargeRequest); } /* ** Check that we didn't get too much data. */ if ((cl->largeCmdBytesSoFar + dataBytes) > cl->largeCmdBytesTotal) { client->errorValue = dataBytes; __glXResetLargeCommandStatus(cl); return __glXError(GLXBadLargeRequest); } memcpy(cl->largeCmdBuf + cl->largeCmdBytesSoFar, pc, dataBytes); cl->largeCmdBytesSoFar += dataBytes; cl->largeCmdRequestsSoFar++; if (req->requestNumber == cl->largeCmdRequestsTotal) { __GLXdispatchRenderProcPtr proc; /* ** This is the last request; it must have enough bytes to complete ** the command. */ /* NOTE: the two pad macros have been added below; they are needed ** because the client library pads the total byte count, but not ** the per-request byte counts. The Protocol Encoding says the ** total byte count should not be padded, so a proposal will be ** made to the ARB to relax the padding constraint on the total ** byte count, thus preserving backward compatibility. Meanwhile, ** the padding done below fixes a bug that did not allow ** large commands of odd sizes to be accepted by the server. */ if (__GLX_PAD(cl->largeCmdBytesSoFar) != __GLX_PAD(cl->largeCmdBytesTotal)) { client->errorValue = dataBytes; __glXResetLargeCommandStatus(cl); return __glXError(GLXBadLargeRequest); } hdr = (__GLXrenderLargeHeader *) cl->largeCmdBuf; /* ** The opcode and length field in the header had already been ** swapped when the first request was received. ** ** Use the opcode to index into the procedure table. */ opcode = hdr->opcode; proc = (__GLXdispatchRenderProcPtr) __glXGetProtocolDecodeFunction(&Render_dispatch_info, opcode, client->swapped); if (proc == NULL) { client->errorValue = opcode; return __glXError(GLXBadLargeRequest); } /* ** Skip over the header and execute the command. */ (*proc) (cl->largeCmdBuf + __GLX_RENDER_LARGE_HDR_SIZE); glxc->hasUnflushedCommands = GL_TRUE; /* ** Reset for the next RenderLarge series. */ __glXResetLargeCommandStatus(cl); } else { /* ** This is neither the first nor the last request. */ } return Success; } } /************************************************************************/ /* ** No support is provided for the vendor-private requests other than ** allocating the entry points in the dispatch table. */ int __glXDisp_VendorPrivate(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc; GLint vendorcode = req->vendorCode; __GLXdispatchVendorPrivProcPtr proc; REQUEST_AT_LEAST_SIZE(xGLXVendorPrivateReq); proc = (__GLXdispatchVendorPrivProcPtr) __glXGetProtocolDecodeFunction(&VendorPriv_dispatch_info, vendorcode, 0); if (proc != NULL) { (*proc) (cl, (GLbyte *) req); return Success; } cl->client->errorValue = req->vendorCode; return __glXError(GLXUnsupportedPrivateRequest); } int __glXDisp_VendorPrivateWithReply(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc; GLint vendorcode = req->vendorCode; __GLXdispatchVendorPrivProcPtr proc; REQUEST_AT_LEAST_SIZE(xGLXVendorPrivateReq); proc = (__GLXdispatchVendorPrivProcPtr) __glXGetProtocolDecodeFunction(&VendorPriv_dispatch_info, vendorcode, 0); if (proc != NULL) { return (*proc) (cl, (GLbyte *) req); } cl->client->errorValue = vendorcode; return __glXError(GLXUnsupportedPrivateRequest); } int __glXDisp_QueryExtensionsString(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXQueryExtensionsStringReq *req = (xGLXQueryExtensionsStringReq *) pc; xGLXQueryExtensionsStringReply reply; __GLXscreen *pGlxScreen; size_t n, length; char *buf; int err; REQUEST_SIZE_MATCH(xGLXQueryExtensionsStringReq); if (!validGlxScreen(client, req->screen, &pGlxScreen, &err)) return err; n = strlen(pGlxScreen->GLXextensions) + 1; length = __GLX_PAD(n) >> 2; reply = (xGLXQueryExtensionsStringReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = length, .n = n }; /* Allocate buffer to make sure it's a multiple of 4 bytes big. */ buf = calloc(length, 4); if (buf == NULL) return BadAlloc; memcpy(buf, pGlxScreen->GLXextensions, n); if (client->swapped) { glxSwapQueryExtensionsStringReply(client, &reply, buf); } else { WriteToClient(client, sz_xGLXQueryExtensionsStringReply, &reply); WriteToClient(client, (int) (length << 2), buf); } free(buf); return Success; } int __glXDisp_QueryServerString(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) pc; xGLXQueryServerStringReply reply; size_t n, length; const char *ptr; char *buf; __GLXscreen *pGlxScreen; int err; char ver_str[16]; REQUEST_SIZE_MATCH(xGLXQueryServerStringReq); if (!validGlxScreen(client, req->screen, &pGlxScreen, &err)) return err; switch (req->name) { case GLX_VENDOR: ptr = pGlxScreen->GLXvendor; break; case GLX_VERSION: /* Return to the server version rather than the screen version * to prevent confusion when they do not match. */ snprintf(ver_str, 16, "%d.%d", glxMajorVersion, glxMinorVersion); ptr = ver_str; break; case GLX_EXTENSIONS: ptr = pGlxScreen->GLXextensions; break; default: return BadValue; } n = strlen(ptr) + 1; length = __GLX_PAD(n) >> 2; reply = (xGLXQueryServerStringReply) { .type = X_Reply, .sequenceNumber = client->sequence, .length = length, .n = n }; buf = calloc(length, 4); if (buf == NULL) { return BadAlloc; } memcpy(buf, ptr, n); if (client->swapped) { glxSwapQueryServerStringReply(client, &reply, buf); } else { WriteToClient(client, sz_xGLXQueryServerStringReply, &reply); WriteToClient(client, (int) (length << 2), buf); } free(buf); return Success; } int __glXDisp_ClientInfo(__GLXclientState * cl, GLbyte * pc) { ClientPtr client = cl->client; xGLXClientInfoReq *req = (xGLXClientInfoReq *) pc; const char *buf; REQUEST_AT_LEAST_SIZE(xGLXClientInfoReq); buf = (const char *) (req + 1); if (!memchr(buf, 0, (client->req_len << 2) - sizeof(xGLXClientInfoReq))) return BadLength; free(cl->GLClientextensions); cl->GLClientextensions = strdup(buf); return Success; }