diff options
Diffstat (limited to 'GL/glx/glxcmds.c')
-rw-r--r-- | GL/glx/glxcmds.c | 1578 |
1 files changed, 1578 insertions, 0 deletions
diff --git a/GL/glx/glxcmds.c b/GL/glx/glxcmds.c new file mode 100644 index 000000000..61989cfa4 --- /dev/null +++ b/GL/glx/glxcmds.c @@ -0,0 +1,1578 @@ +/* $XFree86: xc/programs/Xserver/GL/glx/glxcmds.c,v 1.9 2002/12/14 01:36:09 dawes Exp $ */ +/* +** License Applicability. Except to the extent portions of this file are +** made subject to an alternative license as permitted in the SGI Free +** Software License B, Version 1.1 (the "License"), the contents of this +** file are subject only to the provisions of the License. You may not use +** this file except in compliance with the License. You may obtain a copy +** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 +** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: +** +** http://oss.sgi.com/projects/FreeB +** +** Note that, as provided in the License, the Software is distributed on an +** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS +** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND +** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A +** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. +** +** Original Code. The Original Code is: OpenGL Sample Implementation, +** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, +** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. +** Copyright in any portions created by third parties is as indicated +** elsewhere herein. All Rights Reserved. +** +** Additional Notice Provisions: The application programming interfaces +** established by SGI in conjunction with the Original Code are The +** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released +** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version +** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X +** Window System(R) (Version 1.3), released October 19, 1998. This software +** was created using the OpenGL(R) version 1.2.1 Sample Implementation +** published by SGI, but has not been independently verified as being +** compliant with the OpenGL(R) version 1.2.1 Specification. +** +*/ + +#define NEED_REPLIES +#define FONT_PCF +#include "glxserver.h" +#include <GL/glxtokens.h> +#include <unpack.h> +#include "g_disptab.h" +#include <pixmapstr.h> +#include <windowstr.h> +#include "g_disptab_EXT.h" +#include "glximports.h" +#include "glxutil.h" +#include "glxext.h" +#include "GL/glx_ansic.h" + +/************************************************************************/ + +static __GLimports imports = { + __glXImpMalloc, + __glXImpCalloc, + __glXImpRealloc, + __glXImpFree, + __glXImpWarning, + __glXImpFatal, + __glXImpGetenv, + __glXImpAtoi, + __glXImpSprintf, + __glXImpFopen, + __glXImpFclose, + __glXImpFprintf, + __glXImpGetDrawablePrivate, + NULL +}; + +/************************************************************************/ + +/* +** Create a GL context with the given properties. +*/ +int __glXCreateContext(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; + VisualPtr pVisual; + ScreenPtr pScreen; + __GLXcontext *glxc, *shareglxc; + __GLXvisualConfig *pGlxVisual; + __GLXscreenInfo *pGlxScreen; + __GLinterface *shareGC; + GLXContextID gcId = req->context; + GLXContextID shareList = req->shareList; + VisualID visual = req->visual; + GLuint screen = req->screen; + GLboolean isDirect = req->isDirect; + GLint i; + + /* + ** Check if screen exists. + */ + if (screen >= screenInfo.numScreens) { + client->errorValue = screen; + return BadValue; + } + pScreen = screenInfo.screens[screen]; + pGlxScreen = &__glXActiveScreens[screen]; + + /* + ** Check if the visual ID is valid for this screen. + */ + pVisual = pScreen->visuals; + for (i = 0; i < pScreen->numVisuals; i++, pVisual++) { + if (pVisual->vid == visual) { + break; + } + } + if (i == pScreen->numVisuals) { + client->errorValue = visual; + return BadValue; + } + + /* + ** Get configuration of the visual. This assumes that the + ** glXActiveScreens structure contains visual configurations only for the + ** subset of Visuals that are supported by this implementation of the + ** OpenGL. + */ + pGlxVisual = pGlxScreen->pGlxVisual; + for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { + if (pGlxVisual->vid == visual) { + break; + } + } + if (i == pGlxScreen->numVisuals) { + /* + ** Visual not support on this screen by this OpenGL implementation. + */ + client->errorValue = visual; + return BadValue; + } + + /* + ** 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) { + shareGC = 0; + } else { + shareglxc = (__GLXcontext *) LookupIDByType(shareList, __glXContextRes); + if (!shareglxc) { + client->errorValue = shareList; + return __glXBadContext; + } + if (shareglxc->isDirect) { + /* + ** NOTE: no support for sharing display lists between direct + ** contexts, even if they are in the same address space. + */ +#if 0 + /* Disabling this code seems to allow shared display lists + * and texture objects to work. We'll leave it disabled for now. + */ + client->errorValue = shareList; + return BadMatch; +#endif + } else { + /* + ** Create an indirect context regardless of what the client asked + ** for; this way we can share display list space with shareList. + */ + isDirect = GL_FALSE; + } + shareGC = shareglxc->gc; + } + + /* + ** Allocate memory for the new context + */ + glxc = (__GLXcontext *) __glXMalloc(sizeof(__GLXcontext)); + if (!glxc) { + return BadAlloc; + } + __glXMemset(glxc, 0, sizeof(__GLXcontext)); + + /* + ** Initially, setup the part of the context that could be used by + ** a GL core that needs windowing information (e.g., Mesa). + */ + glxc->pScreen = pScreen; + glxc->pGlxScreen = pGlxScreen; + glxc->pVisual = pVisual; + glxc->pGlxVisual = pGlxVisual; + + if (!isDirect) { + __GLcontextModes *modes; + /* + ** first build __GLcontextModes from __GLXvisualConfig + */ + modes = (__GLcontextModes *) __glXMalloc(sizeof(__GLcontextModes)); + glxc->modes = modes; + __glXFormatGLModes(modes, pGlxVisual); + + /* + ** Allocate a GL context + */ + imports.other = (void *)glxc; + glxc->gc = (*pGlxScreen->createContext)(&imports, modes, shareGC); + if (!glxc->gc) { + __glXFree(glxc); + client->errorValue = gcId; + return BadAlloc; + } + } else { + /* + ** Don't need local GL context for a direct context. + */ + glxc->gc = 0; + } + /* + ** Register this context as a resource. + */ + if (!AddResource(gcId, __glXContextRes, (pointer)glxc)) { + if (!isDirect) { + (*glxc->gc->exports.destroyContext)((__GLcontext *)glxc->gc); + } + __glXFree(glxc); + client->errorValue = gcId; + return BadAlloc; + } + + /* + ** Finally, now that everything is working, setup the rest of the + ** context. + */ + glxc->id = gcId; + glxc->share_id = shareList; + glxc->idExists = GL_TRUE; + glxc->isCurrent = GL_FALSE; + glxc->isDirect = isDirect; + glxc->renderMode = GL_RENDER; + + return Success; +} + +/* +** Destroy a GL context as an X resource. +*/ +int __glXDestroyContext(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc; + GLXContextID gcId = req->context; + __GLXcontext *glxc; + + glxc = (__GLXcontext *) LookupIDByType(gcId, __glXContextRes); + if (glxc) { + /* + ** Just free the resource; don't actually destroy the context, + ** because it might be in use. The + ** destroy method will be called by the resource destruction routine + ** if necessary. + */ + FreeResourceByType(gcId, __glXContextRes, FALSE); + return Success; + } else { + client->errorValue = gcId; + return __glXBadContext; + } +} + +/*****************************************************************************/ + +/* +** For each client, the server keeps a table of all the contexts that are +** current for that client (each thread of a client may have its own current +** context). These routines add, change, and lookup contexts in the table. +*/ + +/* +** Add a current context, and return the tag that will be used to refer to it. +*/ +static int AddCurrentContext(__GLXclientState *cl, __GLXcontext *glxc) +{ + int i; + int num = cl->numCurrentContexts; + __GLXcontext **table = cl->currentContexts; + + if (!glxc) return -1; + + /* + ** Try to find an empty slot and use it. + */ + for (i=0; i < num; i++) { + if (!table[i]) { + table[i] = glxc; + return i+1; + } + } + /* + ** Didn't find a free slot, so we'll have to grow the table. + */ + if (!num) { + table = (__GLXcontext **) __glXMalloc(sizeof(__GLXcontext *)); + } else { + table = (__GLXcontext **) __glXRealloc(table, + (num+1)*sizeof(__GLXcontext *)); + } + table[num] = glxc; + cl->currentContexts = table; + cl->numCurrentContexts++; + return num+1; +} + +/* +** Given a tag, change the current context for the corresponding entry. +*/ +static void ChangeCurrentContext(__GLXclientState *cl, __GLXcontext *glxc, + GLXContextTag tag) +{ + __GLXcontext **table = cl->currentContexts; + table[tag-1] = glxc; +} + +/* +** For this implementation we have chosen to simply use the index of the +** context's entry in the table as the context tag. A tag must be greater +** than 0. +*/ +__GLXcontext *__glXLookupContextByTag(__GLXclientState *cl, GLXContextTag tag) +{ + int num = cl->numCurrentContexts; + + if (tag < 1 || tag > num) { + return 0; + } else { + return cl->currentContexts[tag-1]; + } +} + +/*****************************************************************************/ + +static void StopUsingContext(__GLXcontext *glxc) +{ + if (glxc) { + if (glxc == __glXLastContext) { + /* Tell server GL library */ + __glXLastContext = 0; + } + glxc->isCurrent = GL_FALSE; + if (!glxc->idExists) { + __glXFreeContext(glxc); + } + } +} + +static void StartUsingContext(__GLXclientState *cl, __GLXcontext *glxc) +{ + glxc->isCurrent = GL_TRUE; +} + +/*****************************************************************************/ +/* +** Make an OpenGL context and drawable current. +*/ +int __glXMakeCurrent(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + DrawablePtr pDraw; + xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc; + xGLXMakeCurrentReply reply; + GLXDrawable drawId = req->drawable; + GLXContextID contextId = req->context; + __GLXpixmap *pGlxPixmap = 0; + __GLXcontext *glxc, *prevglxc; + __GLinterface *gc, *prevgc; + __GLXdrawablePrivate *glxPriv = NULL; + GLXContextTag tag = req->oldContextTag; + GLint error; + + /* + ** If one is None and the other isn't, it's a bad match. + */ + if ((drawId == None && contextId != None) || + (drawId != None && contextId == None)) { + 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 __glXBadContextTag; + } + if (prevglxc->renderMode != GL_RENDER) { + /* Oops. Not in render mode render. */ + client->errorValue = prevglxc->id; + return __glXBadContextState; + } + prevgc = prevglxc->gc; + } else { + prevglxc = 0; + prevgc = 0; + } + + /* + ** Lookup new context. It must not be current for someone else. + */ + if (contextId != None) { + glxc = (__GLXcontext *) LookupIDByType(contextId, __glXContextRes); + if (!glxc) { + client->errorValue = contextId; + return __glXBadContext; + } + if ((glxc != prevglxc) && glxc->isCurrent) { + /* Context is current to somebody else */ + return BadAccess; + } + gc = glxc->gc; + } else { + /* Switching to no context. Ignore new drawable. */ + glxc = 0; + gc = 0; + } + + if (drawId != None) { + pDraw = (DrawablePtr) LookupDrawable(drawId, client); + if (pDraw) { + if (pDraw->type == DRAWABLE_WINDOW) { + /* + ** Drawable is an X Window. + */ + WindowPtr pWin = (WindowPtr)pDraw; + VisualID vid = wVisual(pWin); + + /* + ** Check if window and context are similar. + */ + if ((vid != glxc->pVisual->vid) || + (pWin->drawable.pScreen != glxc->pScreen)) { + client->errorValue = drawId; + return BadMatch; + } + + } else { + /* + ** An X Pixmap is not allowed as a parameter (a GLX Pixmap + ** is, but it must first be created with glxCreateGLXPixmap). + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } else { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + /* + ** Check if pixmap and context are similar. + */ + if (pGlxPixmap->pScreen != glxc->pScreen || + pGlxPixmap->pGlxVisual != glxc->pGlxVisual) { + client->errorValue = drawId; + return BadMatch; + } + pDraw = pGlxPixmap->pDraw; + + } else { + /* + ** Drawable is neither a Window nor a GLXPixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + } else { + pDraw = 0; + } + + /* get the drawable private */ + if (pDraw) { + glxPriv = __glXGetDrawablePrivate(pDraw, drawId, glxc->modes); + if (glxPriv == NULL) { + return __glXBadDrawable; + } + } + + if (prevglxc) { + /* + ** Flush the previous context if needed. + */ + if (__GLX_HAS_UNFLUSHED_CMDS(prevglxc)) { + if (__glXForceCurrent(cl, tag, (int *)&error)) { + glFlush(); + __GLX_NOTE_FLUSHED_CMDS(prevglxc); + } else { + return error; + } + } + + /* + ** Make the previous context not current. + */ + if (!(*prevgc->exports.loseCurrent)((__GLcontext *)prevgc)) { + return __glXBadContext; + } + __glXDeassociateContext(prevglxc, prevglxc->glxPriv); + } + + if ((glxc != 0) && !glxc->isDirect) { + + glxc->glxPriv = glxPriv; + __glXCacheDrawableSize(glxPriv); + + /* make the context current */ + if (!(*gc->exports.makeCurrent)((__GLcontext *)gc, &glxPriv->glPriv)) { + glxc->glxPriv = NULL; + return __glXBadContext; + } + + /* resize the buffers */ + if (!__glXResizeDrawableBuffers(glxPriv)) { + /* could not do initial resize. make current failed */ + (*gc->exports.loseCurrent)((__GLcontext *)gc); + glxc->glxPriv = NULL; + return __glXBadContext; + } + + glxc->isCurrent = GL_TRUE; + __glXAssociateContext(glxc, glxPriv); + assert(glxPriv->glxc == glxc); + } + + if (prevglxc) { + if (prevglxc->pGlxPixmap) { + /* + ** The previous drawable was a glx pixmap, release it. + */ + prevglxc->pGlxPixmap->refcnt--; + if (!prevglxc->pGlxPixmap->idExists && + !prevglxc->pGlxPixmap->refcnt) { + PixmapPtr pPixmap = (PixmapPtr) prevglxc->pGlxPixmap->pDraw; + /* + ** The DestroyPixmap routine should decrement the + ** refcount of the X pixmap and free only if it's zero. + */ + (*prevglxc->pGlxPixmap->pScreen->DestroyPixmap)(pPixmap); + __glXFree(prevglxc->pGlxPixmap); + } + prevglxc->pGlxPixmap = 0; + } + ChangeCurrentContext(cl, glxc, tag); + StopUsingContext(prevglxc); + } else { + tag = AddCurrentContext(cl, glxc); + } + if (glxc) { + if (pGlxPixmap) { + pGlxPixmap->refcnt++; + glxc->pGlxPixmap = pGlxPixmap; + } + StartUsingContext(cl, glxc); + reply.contextTag = tag; + } else { + reply.contextTag = 0; + } + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + __glXSwapMakeCurrentReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXMakeCurrentReply, (char *)&reply); + } + return Success; +} + +int __glXIsDirect(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc; + xGLXIsDirectReply reply; + __GLXcontext *glxc; + + /* + ** Find the GL context. + */ + glxc = (__GLXcontext *) LookupIDByType(req->context, __glXContextRes); + if (!glxc) { + client->errorValue = req->context; + return __glXBadContext; + } + + reply.isDirect = glxc->isDirect; + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + __glXSwapIsDirectReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXIsDirectReply, (char *)&reply); + } + + return Success; +} + +int __glXQueryVersion(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc; + xGLXQueryVersionReply reply; + GLuint major, minor; + + major = req->majorVersion; + minor = req->minorVersion; + + /* + ** 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.majorVersion = GLX_SERVER_MAJOR_VERSION; + reply.minorVersion = GLX_SERVER_MINOR_VERSION; + reply.length = 0; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + if (client->swapped) { + __glXSwapQueryVersionReply(client, &reply); + } else { + WriteToClient(client, sz_xGLXQueryVersionReply, (char *)&reply); + } + return Success; +} + +int __glXWaitGL(__GLXclientState *cl, GLbyte *pc) +{ + xGLXWaitGLReq *req = (xGLXWaitGLReq *)pc; + int error; + + if (!__glXForceCurrent(cl, req->contextTag, &error)) { + return error; + } + glFinish(); + return Success; +} + +int __glXWaitX(__GLXclientState *cl, GLbyte *pc) +{ + xGLXWaitXReq *req = (xGLXWaitXReq *)pc; + int error; + + if (!__glXForceCurrent(cl, req->contextTag, &error)) { + return error; + } + /* + ** In a multithreaded server that had separate X and GL threads, we would + ** have to wait for the X thread to finish before returning. As it stands, + ** this sample implementation only supports singlethreaded servers, and + ** nothing needs to be done here. + */ + return Success; +} + +int __glXCopyContext(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc; + GLXContextID source = req->source; + GLXContextID dest = req->dest; + GLXContextTag tag = req->contextTag; + unsigned long mask = req->mask; + __GLXcontext *src, *dst; + int error; + + /* + ** Check that each context exists. + */ + src = (__GLXcontext *) LookupIDByType(source, __glXContextRes); + if (!src) { + client->errorValue = source; + return __glXBadContext; + } + dst = (__GLXcontext *) LookupIDByType(dest, __glXContextRes); + if (!dst) { + client->errorValue = dest; + return __glXBadContext; + } + + /* + ** 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 __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. + */ + glFinish(); + __GLX_NOTE_FLUSHED_CMDS(tagcx); + } else { + return error; + } + } + /* + ** Issue copy. The only reason for failure is a bad mask. + */ + if (!(*dst->gc->exports.copyContext)((__GLcontext *)dst->gc, + (__GLcontext *)src->gc, + mask)) { + client->errorValue = mask; + return BadValue; + } + return Success; +} + +int __glXGetVisualConfigs(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) pc; + xGLXGetVisualConfigsReply reply; + __GLXscreenInfo *pGlxScreen; + __GLXvisualConfig *pGlxVisual; + CARD32 buf[__GLX_TOTAL_CONFIG]; + unsigned int screen; + int i, p; + + screen = req->screen; + if (screen >= screenInfo.numScreens) { + /* The client library must send a valid screen number. */ + client->errorValue = screen; + return BadValue; + } + pGlxScreen = &__glXActiveScreens[screen]; + + reply.numVisuals = pGlxScreen->numUsableVisuals; + reply.numProps = __GLX_TOTAL_CONFIG; + reply.length = (pGlxScreen->numUsableVisuals * __GLX_SIZE_CARD32 * + __GLX_TOTAL_CONFIG) >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + + WriteToClient(client, sz_xGLXGetVisualConfigsReply, (char *)&reply); + + for (i=0; i < pGlxScreen->numVisuals; i++) { + pGlxVisual = &pGlxScreen->pGlxVisual[i]; + if (pGlxVisual->vid == 0) { + /* not a usable visual */ + continue; + } + p = 0; + buf[p++] = pGlxVisual->vid; + buf[p++] = pGlxVisual->class; + buf[p++] = pGlxVisual->rgba; + + buf[p++] = pGlxVisual->redSize; + buf[p++] = pGlxVisual->greenSize; + buf[p++] = pGlxVisual->blueSize; + buf[p++] = pGlxVisual->alphaSize; + buf[p++] = pGlxVisual->accumRedSize; + buf[p++] = pGlxVisual->accumGreenSize; + buf[p++] = pGlxVisual->accumBlueSize; + buf[p++] = pGlxVisual->accumAlphaSize; + + buf[p++] = pGlxVisual->doubleBuffer; + buf[p++] = pGlxVisual->stereo; + + buf[p++] = pGlxVisual->bufferSize; + buf[p++] = pGlxVisual->depthSize; + buf[p++] = pGlxVisual->stencilSize; + buf[p++] = pGlxVisual->auxBuffers; + buf[p++] = pGlxVisual->level; + /* + ** Add token/value pairs for extensions. + */ + buf[p++] = GLX_VISUAL_CAVEAT_EXT; + buf[p++] = pGlxVisual->visualRating; + buf[p++] = GLX_TRANSPARENT_TYPE_EXT; + buf[p++] = pGlxVisual->transparentPixel; + buf[p++] = GLX_TRANSPARENT_RED_VALUE_EXT; + buf[p++] = pGlxVisual->transparentRed; + buf[p++] = GLX_TRANSPARENT_GREEN_VALUE_EXT; + buf[p++] = pGlxVisual->transparentGreen; + buf[p++] = GLX_TRANSPARENT_BLUE_VALUE_EXT; + buf[p++] = pGlxVisual->transparentBlue; + buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE_EXT; + buf[p++] = pGlxVisual->transparentAlpha; + buf[p++] = GLX_TRANSPARENT_INDEX_VALUE_EXT; + buf[p++] = pGlxVisual->transparentIndex; + + WriteToClient(client, __GLX_SIZE_CARD32 * __GLX_TOTAL_CONFIG, + (char *)buf); + } + return Success; +} + +/* +** Create a GLX Pixmap from an X Pixmap. +*/ +int __glXCreateGLXPixmap(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXCreateGLXPixmapReq *req = (xGLXCreateGLXPixmapReq *) pc; + VisualID visual = req->visual; + GLuint screenNum = req->screen; + XID pixmapId = req->pixmap; + XID glxpixmapId = req->glxpixmap; + DrawablePtr pDraw; + ScreenPtr pScreen; + VisualPtr pVisual; + __GLXpixmap *pGlxPixmap; + __GLXscreenInfo *pGlxScreen; + __GLXvisualConfig *pGlxVisual; + int i; + + pDraw = (DrawablePtr) LookupDrawable(pixmapId, client); + if (!pDraw || pDraw->type != DRAWABLE_PIXMAP) { + client->errorValue = pixmapId; + return BadPixmap; + } + + /* + ** Check if screen of visual matches screen of pixmap. + */ + pScreen = pDraw->pScreen; + if (screenNum != pScreen->myNum) { + return BadMatch; + } + + /* + ** Find the VisualRec for this visual. + */ + pVisual = pScreen->visuals; + for (i=0; i < pScreen->numVisuals; i++, pVisual++) { + if (pVisual->vid == visual) { + break; + } + } + if (i == pScreen->numVisuals) { + client->errorValue = visual; + return BadValue; + } + /* + ** Check if depth of visual matches depth of pixmap. + */ + if (pVisual->nplanes != pDraw->depth) { + return BadMatch; + } + + /* + ** Get configuration of the visual. + */ + pGlxScreen = &__glXActiveScreens[screenNum]; + pGlxVisual = pGlxScreen->pGlxVisual; + for (i = 0; i < pGlxScreen->numVisuals; i++, pGlxVisual++) { + if (pGlxVisual->vid == visual) { + break; + } + } + if (i == pGlxScreen->numVisuals) { + /* + ** Visual not support on this screen by this OpenGL implementation. + */ + client->errorValue = visual; + return BadValue; + } + + pGlxPixmap = (__GLXpixmap *) __glXMalloc(sizeof(__GLXpixmap)); + if (!pGlxPixmap) { + return BadAlloc; + } + if (!(AddResource(glxpixmapId, __glXPixmapRes, pGlxPixmap))) { + return BadAlloc; + } + pGlxPixmap->pDraw = pDraw; + pGlxPixmap->pGlxScreen = pGlxScreen; + pGlxPixmap->pGlxVisual = pGlxVisual; + pGlxPixmap->pScreen = pScreen; + pGlxPixmap->idExists = True; + pGlxPixmap->refcnt = 0; + + /* + ** Bump the ref count on the X pixmap so it won't disappear. + */ + ((PixmapPtr) pDraw)->refcnt++; + + return Success; +} + +int __glXDestroyGLXPixmap(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc; + XID glxpixmap = req->glxpixmap; + + /* + ** Check if it's a valid GLX pixmap. + */ + if (!LookupIDByType(glxpixmap, __glXPixmapRes)) { + client->errorValue = glxpixmap; + return __glXBadPixmap; + } + FreeResource(glxpixmap, FALSE); + return Success; +} + +/*****************************************************************************/ + +/* +** 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 __glXSwapBuffers(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + DrawablePtr pDraw; + xGLXSwapBuffersReq *req = (xGLXSwapBuffersReq *) pc; + GLXContextTag tag = req->contextTag; + XID drawId = req->drawable; + __GLXpixmap *pGlxPixmap; + __GLXcontext *glxc = NULL; + int error; + + /* + ** Check that the GLX drawable is valid. + */ + pDraw = (DrawablePtr) LookupDrawable(drawId, client); + if (pDraw) { + if (pDraw->type == DRAWABLE_WINDOW) { + /* + ** Drawable is an X window. + */ + } else { + /* + ** Drawable is an X pixmap, which is not allowed. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } else { + pGlxPixmap = (__GLXpixmap *) LookupIDByType(drawId, + __glXPixmapRes); + if (pGlxPixmap) { + /* + ** Drawable is a GLX pixmap. + */ + } else { + /* + ** Drawable is neither a X window nor a GLX pixmap. + */ + client->errorValue = drawId; + return __glXBadDrawable; + } + } + + if (tag) { + glxc = __glXLookupContextByTag(cl, tag); + if (!glxc) { + return __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. + */ + glFinish(); + __GLX_NOTE_FLUSHED_CMDS(glxc); + } else { + return error; + } + } + + if (pDraw) { + __GLXdrawablePrivate *glxPriv; + + if (glxc) { + glxPriv = __glXGetDrawablePrivate(pDraw, drawId, glxc->modes); + if (glxPriv == NULL) { + return __glXBadDrawable; + } + } + else { + glxPriv = __glXFindDrawablePrivate(drawId); + if (glxPriv == NULL) { + /* This is a window we've never seen before, do nothing */ + return Success; + } + } + + if ((*glxPriv->swapBuffers)(glxPriv) == GL_FALSE) { + return __glXBadDrawable; + } + } + + return Success; +} + + +int __glXQueryContextInfoEXT(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + __GLXcontext *ctx; + xGLXQueryContextInfoEXTReq *req; + xGLXQueryContextInfoEXTReply reply; + int nProps; + int *sendBuf, *pSendBuf; + int nReplyBytes; + + req = (xGLXQueryContextInfoEXTReq *)pc; + ctx = (__GLXcontext *) LookupIDByType(req->context, __glXContextRes); + if (!ctx) { + client->errorValue = req->context; + return __glXBadContext; + } + + nProps = 3; + reply.length = nProps << 1; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.n = nProps; + + nReplyBytes = reply.length << 2; + sendBuf = (int *)__glXMalloc((size_t)nReplyBytes); + if (sendBuf == NULL) { + return __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->pVisual->vid); + *pSendBuf++ = GLX_SCREEN_EXT; + *pSendBuf++ = (int)(ctx->pScreen->myNum); + + if (client->swapped) { + __glXSwapQueryContextInfoEXTReply(client, &reply, sendBuf); + } else { + WriteToClient(client, sz_xGLXQueryContextInfoEXTReply, (char *)&reply); + WriteToClient(client, nReplyBytes, (char *)sendBuf); + } + __glXFree((char *)sendBuf); + + return Success; +} + + +/************************************************************************/ + +/* +** 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 __glXRender(__GLXclientState *cl, GLbyte *pc) +{ + xGLXRenderReq *req; + ClientPtr client= cl->client; + int left, cmdlen, error; + int commandsDone; + CARD16 opcode; + __GLXrenderHeader *hdr; + __GLXcontext *glxc; + + /* + ** NOTE: much of this code also appears in the byteswapping version of this + ** routine, __glXSwapRender(). Any changes made here should also be + ** duplicated there. + */ + + req = (xGLXRenderReq *) pc; + 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; + void (* proc)(GLbyte *); + + /* + ** Verify that the header length and the overall length agree. + ** Also, each command must be word aligned. + */ + hdr = (__GLXrenderHeader *) pc; + cmdlen = hdr->length; + opcode = hdr->opcode; + + /* + ** Check for core opcodes and grab entry data. + */ + if ( (opcode >= __GLX_MIN_RENDER_OPCODE) && + (opcode <= __GLX_MAX_RENDER_OPCODE) ) { + entry = &__glXRenderSizeTable[opcode]; + proc = __glXRenderTable[opcode]; +#if __GLX_MAX_RENDER_OPCODE_EXT > __GLX_MIN_RENDER_OPCODE_EXT + } else if ( (opcode >= __GLX_MIN_RENDER_OPCODE_EXT) && + (opcode <= __GLX_MAX_RENDER_OPCODE_EXT) ) { + entry = + &__glXRenderSizeTable_EXT[opcode - + __GLX_MIN_RENDER_OPCODE_EXT]; + proc = __glXRenderTable_EXT[opcode - + __GLX_MIN_RENDER_OPCODE_EXT]; +#endif /* __GLX_MAX_RENDER_OPCODE_EXT > __GLX_MIN_RENDER_OPCODE_EXT */ + } else { + client->errorValue = commandsDone; + return __glXBadRenderRequest; + } + + if (!entry->bytes) { + /* unused opcode */ + client->errorValue = commandsDone; + return __glXBadRenderRequest; + } + if (entry->varsize) { + /* variable size command */ + extra = (*entry->varsize)(pc + __GLX_RENDER_HDR_SIZE, False); + 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++; + } + __GLX_NOTE_UNFLUSHED_CMDS(glxc); + return Success; +} + +/* +** Execute a large rendering request (one that spans multiple X requests). +*/ +int __glXRenderLarge(__GLXclientState *cl, GLbyte *pc) +{ + xGLXRenderLargeReq *req; + ClientPtr client= cl->client; + GLuint dataBytes; + void (*proc)(GLbyte *); + __GLXrenderLargeHeader *hdr; + __GLXcontext *glxc; + int error; + CARD16 opcode; + + /* + ** NOTE: much of this code also appears in the byteswapping version of this + ** routine, __glXSwapRenderLarge(). Any changes made here should also be + ** duplicated there. + */ + + req = (xGLXRenderLargeReq *) pc; + 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, cmdlen; + /* + ** 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 __glXBadLargeRequest; + } + + hdr = (__GLXrenderLargeHeader *) pc; + cmdlen = hdr->length; + opcode = hdr->opcode; + + /* + ** Check for core opcodes and grab entry data. + */ + if ( (opcode >= __GLX_MIN_RENDER_OPCODE) && + (opcode <= __GLX_MAX_RENDER_OPCODE) ) { + entry = &__glXRenderSizeTable[opcode]; +#if __GLX_MAX_RENDER_OPCODE_EXT > __GLX_MIN_RENDER_OPCODE_EXT + } else if ( (opcode >= __GLX_MIN_RENDER_OPCODE_EXT) && + (opcode <= __GLX_MAX_RENDER_OPCODE_EXT) ) { + opcode -= __GLX_MIN_RENDER_OPCODE_EXT; + entry = &__glXRenderSizeTable_EXT[opcode]; +#endif /* __GLX_MAX_RENDER_OPCODE_EXT > __GLX_MIN_RENDER_OPCODE_EXT */ + } else { + client->errorValue = opcode; + return __glXBadLargeRequest; + } + + if (!entry->bytes) { + /* unused opcode */ + client->errorValue = opcode; + return __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, False); + 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 *) __glXMalloc((size_t)cmdlen); + } else { + cl->largeCmdBuf = (GLbyte *) __glXRealloc(cl->largeCmdBuf, + (size_t)cmdlen); + } + if (!cl->largeCmdBuf) { + return BadAlloc; + } + cl->largeCmdBufSize = cmdlen; + } + __glXMemcpy(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 __glXBadLargeRequest; + } + if (req->requestTotal != cl->largeCmdRequestsTotal) { + client->errorValue = req->requestTotal; + __glXResetLargeCommandStatus(cl); + return __glXBadLargeRequest; + } + + /* + ** Check that we didn't get too much data. + */ + if ((cl->largeCmdBytesSoFar + dataBytes) > cl->largeCmdBytesTotal) { + client->errorValue = dataBytes; + __glXResetLargeCommandStatus(cl); + return __glXBadLargeRequest; + } + __glXMemcpy(cl->largeCmdBuf + cl->largeCmdBytesSoFar, pc, dataBytes); + cl->largeCmdBytesSoFar += dataBytes; + cl->largeCmdRequestsSoFar++; + + if (req->requestNumber == cl->largeCmdRequestsTotal) { + /* + ** 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 __glXBadLargeRequest; + } + hdr = (__GLXrenderLargeHeader *) cl->largeCmdBuf; + opcode = hdr->opcode; + + /* + ** Use the opcode to index into the procedure table. + */ + if ( (opcode >= __GLX_MIN_RENDER_OPCODE) && + (opcode <= __GLX_MAX_RENDER_OPCODE) ) { + proc = __glXRenderTable[opcode]; +#if __GLX_MAX_RENDER_OPCODE_EXT > __GLX_MIN_RENDER_OPCODE_EXT + } else if ( (opcode >= __GLX_MIN_RENDER_OPCODE_EXT) && + (opcode <= __GLX_MAX_RENDER_OPCODE_EXT) ) { + opcode -= __GLX_MIN_RENDER_OPCODE_EXT; + proc = __glXRenderTable_EXT[opcode]; +#endif /* __GLX_MAX_RENDER_OPCODE_EXT > __GLX_MIN_RENDER_OPCODE_EXT */ + } else { + client->errorValue = opcode; + return __glXBadLargeRequest; + } + + /* + ** Skip over the header and execute the command. + */ + (*proc)(cl->largeCmdBuf + __GLX_RENDER_LARGE_HDR_SIZE); + __GLX_NOTE_UNFLUSHED_CMDS(glxc); + + /* + ** 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 __glXVendorPrivate(__GLXclientState *cl, GLbyte *pc) +{ + xGLXVendorPrivateReq *req; + GLint vendorcode; + + req = (xGLXVendorPrivateReq *) pc; + vendorcode = req->vendorCode; + + if ((vendorcode >= __GLX_MIN_VENDPRIV_OPCODE_EXT) && + (vendorcode <= __GLX_MAX_VENDPRIV_OPCODE_EXT)) { + (*__glXVendorPrivTable_EXT[vendorcode-__GLX_MIN_VENDPRIV_OPCODE_EXT]) + (cl, (GLbyte*)req); + return Success; + } + /* + ** This sample implemention does not support any private requests. + */ + cl->client->errorValue = req->vendorCode; + return __glXUnsupportedPrivateRequest; +} + +int __glXVendorPrivateWithReply(__GLXclientState *cl, GLbyte *pc) +{ + xGLXVendorPrivateWithReplyReq *req; + GLint vendorcode; + + req = (xGLXVendorPrivateWithReplyReq *) pc; + vendorcode = req->vendorCode; + + switch (vendorcode) { + case X_GLXvop_QueryContextInfoEXT: + return __glXQueryContextInfoEXT(cl, pc); + default: + break; + } + + if ((vendorcode >= __GLX_MIN_VENDPRIV_OPCODE_EXT) && + (vendorcode <= __GLX_MAX_VENDPRIV_OPCODE_EXT)) { + return + (*__glXVendorPrivTable_EXT[vendorcode-__GLX_MIN_VENDPRIV_OPCODE_EXT]) + (cl, (GLbyte*)req); + } + + cl->client->errorValue = vendorcode; + return __glXUnsupportedPrivateRequest; +} + +int __glXQueryExtensionsString(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXQueryExtensionsStringReq *req = (xGLXQueryExtensionsStringReq *) pc; + xGLXQueryExtensionsStringReply reply; + GLuint screen; + size_t n, length; + const char *ptr; + char *buf; + + screen = req->screen; + /* + ** Check if screen exists. + */ + if (screen >= screenInfo.numScreens) { + client->errorValue = screen; + return BadValue; + } + + ptr = __glXActiveScreens[screen].GLXextensions; + + n = __glXStrlen(ptr) + 1; + length = __GLX_PAD(n) >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = length; + reply.n = n; + + if ((buf = (char *) __glXMalloc(length << 2)) == NULL) { + return BadAlloc; + } + __glXStrncpy(buf, ptr, n); + + if (client->swapped) { + glxSwapQueryExtensionsStringReply(client, &reply, buf); + } else { + WriteToClient(client, sz_xGLXQueryExtensionsStringReply,(char *)&reply); + WriteToClient(client, (int)(length << 2), (char *)buf); + } + + __glXFree(buf); + return Success; +} + +int __glXQueryServerString(__GLXclientState *cl, GLbyte *pc) +{ + ClientPtr client = cl->client; + xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) pc; + xGLXQueryServerStringReply reply; + int name; + GLuint screen; + size_t n, length; + const char *ptr; + char *buf; + + name = req->name; + screen = req->screen; + /* + ** Check if screen exists. + */ + if (screen >= screenInfo.numScreens) { + client->errorValue = screen; + return BadValue; + } + switch(name) { + case GLX_VENDOR: + ptr = __glXActiveScreens[screen].GLXvendor; + break; + case GLX_VERSION: + ptr = __glXActiveScreens[screen].GLXversion; + break; + case GLX_EXTENSIONS: + ptr = __glXActiveScreens[screen].GLXextensions; + break; + default: + return BadValue; + } + + n = __glXStrlen(ptr) + 1; + length = __GLX_PAD(n) >> 2; + reply.type = X_Reply; + reply.sequenceNumber = client->sequence; + reply.length = length; + reply.n = n; + + if ((buf = (char *) Xalloc(length << 2)) == NULL) { + return BadAlloc; + } + __glXStrncpy(buf, ptr, n); + + if (client->swapped) { + glxSwapQueryServerStringReply(client, &reply, buf); + } else { + WriteToClient(client, sz_xGLXQueryServerStringReply, (char *)&reply); + WriteToClient(client, (int)(length << 2), buf); + } + + __glXFree(buf); + return Success; +} + +int __glXClientInfo(__GLXclientState *cl, GLbyte *pc) +{ + xGLXClientInfoReq *req = (xGLXClientInfoReq *) pc; + const char *buf; + + cl->GLClientmajorVersion = req->major; + cl->GLClientminorVersion = req->minor; + if (cl->GLClientextensions) __glXFree(cl->GLClientextensions); + buf = (const char *)(req+1); + cl->GLClientextensions = __glXStrdup(buf); + + return Success; +} + |