aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/glx/glxext.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/glx/glxext.c')
-rw-r--r--xorg-server/glx/glxext.c521
1 files changed, 521 insertions, 0 deletions
diff --git a/xorg-server/glx/glxext.c b/xorg-server/glx/glxext.c
new file mode 100644
index 000000000..6ba404fb1
--- /dev/null
+++ b/xorg-server/glx/glxext.c
@@ -0,0 +1,521 @@
+/*
+** The contents of this file are subject to the GLX Public License Version 1.0
+** (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, 2011 N. Shoreline Blvd., Mountain View, CA 94043
+** or at http://www.sgi.com/software/opensource/glx/license.html.
+**
+** Software distributed under the License is distributed on an "AS IS"
+** basis. ALL WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY
+** IMPLIED WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR
+** PURPOSE OR OF NON- INFRINGEMENT. See the License for the specific
+** language governing rights and limitations under the License.
+**
+** The Original Software is GLX version 1.2 source code, released February,
+** 1999. The developer of the Original Software is Silicon Graphics, Inc.
+** Those portions of the Subject Software created by Silicon Graphics, Inc.
+** are Copyright (c) 1991-9 Silicon Graphics, Inc. All Rights Reserved.
+**
+*/
+
+#define NEED_REPLIES
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#endif
+
+#include <string.h>
+#include "glxserver.h"
+#include <windowstr.h>
+#include <propertyst.h>
+#include "privates.h"
+#include <os.h>
+#include "g_disptab.h"
+#include "unpack.h"
+#include "glxutil.h"
+#include "glxext.h"
+#include "indirect_table.h"
+#include "indirect_util.h"
+
+/*
+** The last context used by the server. It is the context that is current
+** from the server's perspective.
+*/
+__GLXcontext *__glXLastContext;
+
+/*
+** X resources.
+*/
+RESTYPE __glXContextRes;
+RESTYPE __glXDrawableRes;
+RESTYPE __glXSwapBarrierRes;
+
+/*
+** Reply for most singles.
+*/
+xGLXSingleReply __glXReply;
+
+static DevPrivateKey glxClientPrivateKey = &glxClientPrivateKey;
+
+/*
+** Client that called into GLX dispatch.
+*/
+ClientPtr __pGlxClient;
+
+/*
+** Forward declarations.
+*/
+static int __glXDispatch(ClientPtr);
+
+/*
+** Called when the extension is reset.
+*/
+static void ResetExtension(ExtensionEntry* extEntry)
+{
+ __glXFlushContextCache();
+}
+
+/*
+** Reset state used to keep track of large (multi-request) commands.
+*/
+void __glXResetLargeCommandStatus(__GLXclientState *cl)
+{
+ cl->largeCmdBytesSoFar = 0;
+ cl->largeCmdBytesTotal = 0;
+ cl->largeCmdRequestsSoFar = 0;
+ cl->largeCmdRequestsTotal = 0;
+}
+
+/*
+** This procedure is called when the client who created the context goes
+** away OR when glXDestroyContext is called. In either case, all we do is
+** flag that the ID is no longer valid, and (maybe) free the context.
+** use.
+*/
+static int ContextGone(__GLXcontext* cx, XID id)
+{
+ cx->idExists = GL_FALSE;
+ if (!cx->isCurrent) {
+ __glXFreeContext(cx);
+ }
+
+ return True;
+}
+
+/*
+** Destroy routine that gets called when a drawable is freed. A drawable
+** contains the ancillary buffers needed for rendering.
+*/
+static Bool DrawableGone(__GLXdrawable *glxPriv, XID xid)
+{
+ ScreenPtr pScreen = glxPriv->pDraw->pScreen;
+
+ switch (glxPriv->type) {
+ case GLX_DRAWABLE_PIXMAP:
+ case GLX_DRAWABLE_PBUFFER:
+ (*pScreen->DestroyPixmap)((PixmapPtr) glxPriv->pDraw);
+ break;
+ }
+
+ glxPriv->pDraw = NULL;
+ glxPriv->drawId = 0;
+ __glXUnrefDrawable(glxPriv);
+
+ return True;
+}
+
+static __GLXcontext *glxPendingDestroyContexts;
+static int glxServerLeaveCount;
+static int glxBlockClients;
+
+/*
+** Free a context.
+*/
+GLboolean __glXFreeContext(__GLXcontext *cx)
+{
+ if (cx->idExists || cx->isCurrent) return GL_FALSE;
+
+ if (cx->feedbackBuf) xfree(cx->feedbackBuf);
+ if (cx->selectBuf) xfree(cx->selectBuf);
+ if (cx == __glXLastContext) {
+ __glXFlushContextCache();
+ }
+
+ /* We can get here through both regular dispatching from
+ * __glXDispatch() or as a callback from the resource manager. In
+ * the latter case we need to lift the DRI lock manually. */
+
+ if (!glxBlockClients) {
+ __glXleaveServer(GL_FALSE);
+ cx->destroy(cx);
+ __glXenterServer(GL_FALSE);
+ } else {
+ cx->next = glxPendingDestroyContexts;
+ glxPendingDestroyContexts = cx;
+ }
+
+ return GL_TRUE;
+}
+
+extern RESTYPE __glXSwapBarrierRes;
+
+static int SwapBarrierGone(int screen, XID drawable)
+{
+ __GLXscreen *pGlxScreen = glxGetScreen(screenInfo.screens[screen]);
+
+ if (pGlxScreen->swapBarrierFuncs) {
+ pGlxScreen->swapBarrierFuncs->bindSwapBarrierFunc(screen, drawable, 0);
+ }
+ FreeResourceByType(drawable, __glXSwapBarrierRes, FALSE);
+ return True;
+}
+
+/************************************************************************/
+
+/*
+** These routines can be used to check whether a particular GL command
+** has caused an error. Specifically, we use them to check whether a
+** given query has caused an error, in which case a zero-length data
+** reply is sent to the client.
+*/
+
+static GLboolean errorOccured = GL_FALSE;
+
+/*
+** The GL was will call this routine if an error occurs.
+*/
+void __glXErrorCallBack(GLenum code)
+{
+ errorOccured = GL_TRUE;
+}
+
+/*
+** Clear the error flag before calling the GL command.
+*/
+void __glXClearErrorOccured(void)
+{
+ errorOccured = GL_FALSE;
+}
+
+/*
+** Check if the GL command caused an error.
+*/
+GLboolean __glXErrorOccured(void)
+{
+ return errorOccured;
+}
+
+static int __glXErrorBase;
+
+int __glXError(int error)
+{
+ return __glXErrorBase + error;
+}
+
+__GLXclientState *
+glxGetClient(ClientPtr pClient)
+{
+ return dixLookupPrivate(&pClient->devPrivates, glxClientPrivateKey);
+}
+
+static void
+glxClientCallback (CallbackListPtr *list,
+ pointer closure,
+ pointer data)
+{
+ NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
+ ClientPtr pClient = clientinfo->client;
+ __GLXclientState *cl = glxGetClient(pClient);
+ __GLXcontext *cx;
+ int i;
+
+ switch (pClient->clientState) {
+ case ClientStateRunning:
+ /*
+ ** By default, assume that the client supports
+ ** GLX major version 1 minor version 0 protocol.
+ */
+ cl->GLClientmajorVersion = 1;
+ cl->GLClientminorVersion = 0;
+ cl->client = pClient;
+ break;
+
+ case ClientStateGone:
+ for (i = 0; i < cl->numCurrentContexts; i++) {
+ cx = cl->currentContexts[i];
+ if (cx) {
+ cx->isCurrent = GL_FALSE;
+ if (!cx->idExists)
+ __glXFreeContext(cx);
+ }
+ }
+
+ if (cl->returnBuf) xfree(cl->returnBuf);
+ if (cl->largeCmdBuf) xfree(cl->largeCmdBuf);
+ if (cl->currentContexts) xfree(cl->currentContexts);
+ if (cl->GLClientextensions) xfree(cl->GLClientextensions);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/************************************************************************/
+
+static __GLXprovider *__glXProviderStack;
+
+void GlxPushProvider(__GLXprovider *provider)
+{
+ provider->next = __glXProviderStack;
+ __glXProviderStack = provider;
+}
+
+/*
+** Initialize the GLX extension.
+*/
+void GlxExtensionInit(void)
+{
+ ExtensionEntry *extEntry;
+ ScreenPtr pScreen;
+ int i;
+ __GLXprovider *p;
+ Bool glx_provided = False;
+
+ __glXContextRes = CreateNewResourceType((DeleteType)ContextGone);
+ __glXDrawableRes = CreateNewResourceType((DeleteType)DrawableGone);
+ __glXSwapBarrierRes = CreateNewResourceType((DeleteType)SwapBarrierGone);
+
+ if (!dixRequestPrivate(glxClientPrivateKey, sizeof (__GLXclientState)))
+ return;
+ if (!AddCallback (&ClientStateCallback, glxClientCallback, 0))
+ return;
+
+ for (i = 0; i < screenInfo.numScreens; i++) {
+ pScreen = screenInfo.screens[i];
+
+ for (p = __glXProviderStack; p != NULL; p = p->next) {
+ if (p->screenProbe(pScreen) != NULL) {
+ LogMessage(X_INFO,
+ "GLX: Initialized %s GL provider for screen %d\n",
+ p->name, i);
+ break;
+ }
+ }
+
+ if (!p)
+ LogMessage(X_INFO,
+ "GLX: no usable GL providers found for screen %d\n", i);
+ else
+ glx_provided = True;
+ }
+
+ /* don't register extension if GL is not provided on any screen */
+ if (!glx_provided)
+ return;
+
+ /*
+ ** Add extension to server extensions.
+ */
+ extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS,
+ __GLX_NUMBER_ERRORS, __glXDispatch,
+ __glXDispatch, ResetExtension,
+ StandardMinorOpcode);
+ if (!extEntry) {
+ FatalError("__glXExtensionInit: AddExtensions failed\n");
+ return;
+ }
+ if (!AddExtensionAlias(GLX_EXTENSION_ALIAS, extEntry)) {
+ ErrorF("__glXExtensionInit: AddExtensionAlias failed\n");
+ return;
+ }
+
+ __glXErrorBase = extEntry->errorBase;
+}
+
+/************************************************************************/
+
+void __glXFlushContextCache(void)
+{
+ __glXLastContext = 0;
+}
+
+/*
+** Make a context the current one for the GL (in this implementation, there
+** is only one instance of the GL, and we use it to serve all GL clients by
+** switching it between different contexts). While we are at it, look up
+** a context by its tag and return its (__GLXcontext *).
+*/
+__GLXcontext *__glXForceCurrent(__GLXclientState *cl, GLXContextTag tag,
+ int *error)
+{
+ __GLXcontext *cx;
+
+ /*
+ ** See if the context tag is legal; it is managed by the extension,
+ ** so if it's invalid, we have an implementation error.
+ */
+ cx = (__GLXcontext *) __glXLookupContextByTag(cl, tag);
+ if (!cx) {
+ cl->client->errorValue = tag;
+ *error = __glXError(GLXBadContextTag);
+ return 0;
+ }
+
+ if (!cx->isDirect) {
+ if (cx->drawPriv == NULL) {
+ /*
+ ** The drawable has vanished. It must be a window, because only
+ ** windows can be destroyed from under us; GLX pixmaps are
+ ** refcounted and don't go away until no one is using them.
+ */
+ *error = __glXError(GLXBadCurrentWindow);
+ return 0;
+ }
+ }
+
+ if (cx == __glXLastContext) {
+ /* No need to re-bind */
+ return cx;
+ }
+
+ /* Make this context the current one for the GL. */
+ if (!cx->isDirect) {
+ if (!(*cx->forceCurrent)(cx)) {
+ /* Bind failed, and set the error code. Bummer */
+ cl->client->errorValue = cx->id;
+ *error = __glXError(GLXBadContextState);
+ return 0;
+ }
+ }
+ __glXLastContext = cx;
+ return cx;
+}
+
+/************************************************************************/
+
+void glxSuspendClients(void)
+{
+ int i;
+
+ for (i = 1; i < currentMaxClients; i++) {
+ if (clients[i] && glxGetClient(clients[i])->inUse)
+ IgnoreClient(clients[i]);
+ }
+
+ glxBlockClients = TRUE;
+}
+
+void glxResumeClients(void)
+{
+ __GLXcontext *cx, *next;
+ int i;
+
+ glxBlockClients = FALSE;
+
+ for (i = 1; i < currentMaxClients; i++) {
+ if (clients[i] && glxGetClient(clients[i])->inUse)
+ AttendClient(clients[i]);
+ }
+
+ __glXleaveServer(GL_FALSE);
+ for (cx = glxPendingDestroyContexts; cx != NULL; cx = next) {
+ next = cx->next;
+
+ cx->destroy(cx);
+ }
+ glxPendingDestroyContexts = NULL;
+ __glXenterServer(GL_FALSE);
+}
+
+static void
+__glXnopEnterServer(GLboolean rendering)
+{
+}
+
+static void
+__glXnopLeaveServer(GLboolean rendering)
+{
+}
+
+static void (*__glXenterServerFunc)(GLboolean) = __glXnopEnterServer;
+static void (*__glXleaveServerFunc)(GLboolean) = __glXnopLeaveServer;
+
+void __glXsetEnterLeaveServerFuncs(void (*enter)(GLboolean),
+ void (*leave)(GLboolean))
+{
+ __glXenterServerFunc = enter;
+ __glXleaveServerFunc = leave;
+}
+
+
+void __glXenterServer(GLboolean rendering)
+{
+ glxServerLeaveCount--;
+
+ if (glxServerLeaveCount == 0)
+ (*__glXenterServerFunc)(rendering);
+}
+
+void __glXleaveServer(GLboolean rendering)
+{
+ if (glxServerLeaveCount == 0)
+ (*__glXleaveServerFunc)(rendering);
+
+ glxServerLeaveCount++;
+}
+
+/*
+** Top level dispatcher; all commands are executed from here down.
+*/
+static int __glXDispatch(ClientPtr client)
+{
+ REQUEST(xGLXSingleReq);
+ CARD8 opcode;
+ __GLXdispatchSingleProcPtr proc;
+ __GLXclientState *cl;
+ int retval;
+
+ opcode = stuff->glxCode;
+ cl = glxGetClient(client);
+ /* Mark it in use so we suspend it on VT switch. */
+ cl->inUse = TRUE;
+
+ /*
+ ** If we're expecting a glXRenderLarge request, this better be one.
+ */
+ if ((cl->largeCmdRequestsSoFar != 0) && (opcode != X_GLXRenderLarge)) {
+ client->errorValue = stuff->glxCode;
+ return __glXError(GLXBadLargeRequest);
+ }
+
+ /* If we're currently blocking GLX clients, just put this guy to
+ * sleep, reset the request and return. */
+ if (glxBlockClients) {
+ ResetCurrentRequest(client);
+ client->sequence--;
+ IgnoreClient(client);
+ return(client->noClientException);
+ }
+
+ /*
+ ** Use the opcode to index into the procedure table.
+ */
+ proc = (__GLXdispatchSingleProcPtr) __glXGetProtocolDecodeFunction(& Single_dispatch_info,
+ opcode,
+ client->swapped);
+ if (proc != NULL) {
+ GLboolean rendering = opcode <= X_GLXRenderLarge;
+ __glXleaveServer(rendering);
+
+ __pGlxClient = client;
+
+ retval = (*proc)(cl, (GLbyte *) stuff);
+
+ __glXenterServer(rendering);
+ }
+ else {
+ retval = BadRequest;
+ }
+
+ return retval;
+}