497 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			497 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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_DMX_CONFIG_H
 | |
| #include <dmx-config.h>
 | |
| #endif
 | |
| 
 | |
| #include "dmx.h"
 | |
| 
 | |
| #include "glxserver.h"
 | |
| #include <windowstr.h>
 | |
| #include <propertyst.h>
 | |
| #include <os.h>
 | |
| #include "g_disptab.h"
 | |
| #include "glxutil.h"
 | |
| #include "glxext.h"
 | |
| #include "glxvisuals.h"
 | |
| #include "micmap.h"
 | |
| #include "glxswap.h"
 | |
| 
 | |
| /*
 | |
| ** Stubs to satisfy miinitext.c references.
 | |
| */
 | |
| typedef int __GLXprovider;
 | |
| __GLXprovider __glXDRISWRastProvider;
 | |
| void GlxPushProvider(__GLXprovider *provider) { }
 | |
| 
 | |
| /*
 | |
| ** Forward declarations.
 | |
| */
 | |
| static int __glXSwapDispatch(ClientPtr);
 | |
| static int __glXDispatch(ClientPtr);
 | |
| 
 | |
| /*
 | |
| ** Called when the extension is reset.
 | |
| */
 | |
| static void ResetExtension(ExtensionEntry* extEntry)
 | |
| {
 | |
|     __glXFlushContextCache();
 | |
|     __glXScreenReset();
 | |
|     SwapBarrierReset();
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Initialize the per-client context storage.
 | |
| */
 | |
| static void ResetClientState(int clientIndex)
 | |
| {
 | |
|     __GLXclientState *cl = __glXClients[clientIndex];
 | |
|     Display **keep_be_displays;
 | |
|     int i;
 | |
| 
 | |
|     free(cl->returnBuf);
 | |
|     free(cl->currentContexts);
 | |
|     free(cl->currentDrawables);
 | |
|     free(cl->largeCmdBuf);
 | |
| 
 | |
|     for (i=0; i< screenInfo.numScreens; i++) {
 | |
|        if (cl->be_displays[i])
 | |
| 	  XCloseDisplay( cl->be_displays[i] );
 | |
|     }
 | |
| 
 | |
|     keep_be_displays = cl->be_displays;
 | |
|     memset(cl, 0, sizeof(__GLXclientState));
 | |
|     cl->be_displays = keep_be_displays;
 | |
| 
 | |
|     /*
 | |
|     ** By default, assume that the client supports
 | |
|     ** GLX major version 1 minor version 0 protocol.
 | |
|     */
 | |
|     cl->GLClientmajorVersion = 1;
 | |
|     cl->GLClientminorVersion = 0;
 | |
|     free(cl->GLClientextensions);
 | |
| 
 | |
|     memset(cl->be_displays, 0, screenInfo.numScreens * sizeof(Display *));
 | |
| }
 | |
| 
 | |
| 
 | |
| /*
 | |
| ** 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;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Free a client's state.
 | |
| */
 | |
| static int ClientGone(int clientIndex, XID id)
 | |
| {
 | |
|     __GLXcontext *cx;
 | |
|     __GLXclientState *cl = __glXClients[clientIndex];
 | |
|     int i;
 | |
| 
 | |
|     if (cl) {
 | |
| 	/*
 | |
| 	** Free all the contexts that are current for this client.
 | |
| 	*/
 | |
| 	for (i=0; i < cl->numCurrentContexts; i++) {
 | |
| 	    cx = cl->currentContexts[i];
 | |
| 	    if (cx) {
 | |
| 		cx->isCurrent = GL_FALSE;
 | |
| 		if (!cx->idExists) {
 | |
| 		    __glXFreeContext(cx);
 | |
| 		}
 | |
| 	    }
 | |
| 	}
 | |
| 	/*
 | |
| 	** Re-initialize the client state structure.  Don't free it because
 | |
| 	** we'll probably get another client with this index and use the struct
 | |
| 	** again.  There is a maximum of MAXCLIENTS of these structures.
 | |
| 	*/
 | |
| 	ResetClientState(clientIndex);
 | |
|     }
 | |
| 
 | |
|     return True;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Free a GLX Pixmap.
 | |
| */
 | |
| void __glXFreeGLXPixmap( __GLXpixmap *pGlxPixmap )
 | |
| {
 | |
|    if (!pGlxPixmap->idExists &&
 | |
|        !pGlxPixmap->refcnt) {
 | |
| 
 | |
|        PixmapPtr pPixmap = (PixmapPtr) pGlxPixmap->pDraw;
 | |
| 
 | |
| 	/*
 | |
| 	** The DestroyPixmap routine should decrement the refcount and free
 | |
| 	** only if it's zero.
 | |
| 	*/
 | |
| 	(*pGlxPixmap->pScreen->DestroyPixmap)(pPixmap);
 | |
| 	free(pGlxPixmap->be_xids);
 | |
| 	free(pGlxPixmap);
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| static int PixmapGone(__GLXpixmap *pGlxPixmap, XID id)
 | |
| {
 | |
| 
 | |
|     pGlxPixmap->idExists = False;
 | |
|     __glXFreeGLXPixmap( pGlxPixmap );
 | |
| 
 | |
|     return True;
 | |
| }
 | |
| 
 | |
| void __glXFreeGLXWindow(__glXWindow *pGlxWindow)
 | |
| {
 | |
|     if (!pGlxWindow->idExists && !pGlxWindow->refcnt) {
 | |
| 	WindowPtr pWindow = (WindowPtr) pGlxWindow->pDraw;
 | |
| 	WindowPtr ret;
 | |
| 
 | |
| 	dixLookupResourceByType((pointer) &ret,
 | |
| 				pWindow->drawable.id, RT_WINDOW,
 | |
| 				NullClient, DixUnknownAccess);
 | |
|         if (ret == pWindow) {
 | |
|             (*pGlxWindow->pScreen->DestroyWindow)(pWindow);
 | |
|         }
 | |
| 
 | |
| 	free(pGlxWindow);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void WindowGone(__glXWindow *pGlxWindow, XID id)
 | |
| {
 | |
|     pGlxWindow->idExists = False;
 | |
|     __glXFreeGLXWindow(pGlxWindow);
 | |
| }
 | |
| 
 | |
| void __glXFreeGLXPbuffer(__glXPbuffer *pGlxPbuffer)
 | |
| {
 | |
|     if (!pGlxPbuffer->idExists && !pGlxPbuffer->refcnt) {
 | |
|         free(pGlxPbuffer->be_xids);
 | |
|         free(pGlxPbuffer);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void PbufferGone(__glXPbuffer *pGlxPbuffer, XID id)
 | |
| {
 | |
|     pGlxPbuffer->idExists = False;
 | |
|     __glXFreeGLXPbuffer(pGlxPbuffer);
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Free a context.
 | |
| */
 | |
| GLboolean __glXFreeContext(__GLXcontext *cx)
 | |
| {
 | |
|     if (cx->idExists || cx->isCurrent) return GL_FALSE;
 | |
|     
 | |
|     free(cx->feedbackBuf);
 | |
|     free(cx->selectBuf);
 | |
|     free(cx->real_ids);
 | |
|     free(cx->real_vids);
 | |
| 
 | |
|     if (cx->pGlxPixmap) {
 | |
|        /*
 | |
| 	** The previous drawable was a glx pixmap, release it.
 | |
| 	*/
 | |
|        cx->pGlxPixmap->refcnt--;
 | |
|        __glXFreeGLXPixmap( cx->pGlxPixmap );
 | |
|        cx->pGlxPixmap = 0;
 | |
|     }
 | |
| 
 | |
|     if (cx->pGlxReadPixmap) {
 | |
|        /*
 | |
| 	** The previous drawable was a glx pixmap, release it.
 | |
| 	*/
 | |
|        cx->pGlxReadPixmap->refcnt--;
 | |
|        __glXFreeGLXPixmap( cx->pGlxReadPixmap );
 | |
|        cx->pGlxReadPixmap = 0;
 | |
|     }
 | |
| 
 | |
|     if (cx->pGlxWindow) {
 | |
|        /*
 | |
| 	** The previous drawable was a glx window, release it.
 | |
| 	*/
 | |
|        cx->pGlxWindow->refcnt--;
 | |
|        __glXFreeGLXWindow( cx->pGlxWindow );
 | |
|        cx->pGlxWindow = 0;   
 | |
|     }
 | |
| 
 | |
|     if (cx->pGlxReadWindow) {
 | |
|        /*
 | |
| 	** The previous drawable was a glx window, release it.
 | |
| 	*/
 | |
|        cx->pGlxReadWindow->refcnt--;
 | |
|        __glXFreeGLXWindow( cx->pGlxReadWindow );
 | |
|        cx->pGlxReadWindow = 0;   
 | |
|     }
 | |
| 
 | |
|     free(cx);
 | |
| 
 | |
|     if (cx == __glXLastContext) {
 | |
| 	__glXFlushContextCache();
 | |
|     }
 | |
| 
 | |
|     return GL_TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
| ** Initialize the GLX extension.
 | |
| */
 | |
| void GlxExtensionInit(void)
 | |
| {
 | |
|     ExtensionEntry *extEntry;
 | |
|     int i;
 | |
|     int glxSupported = 1;
 | |
| 
 | |
|     /*
 | |
|     // do not initialize GLX extension if GLX is not supported
 | |
|     // by ALL back-end servers.
 | |
|     */
 | |
|     for (i=0; i<screenInfo.numScreens; i++) {
 | |
|        glxSupported &= (dmxScreens[i].glxMajorOpcode > 0);
 | |
|     }
 | |
| 
 | |
|     if (!glxSupported || !dmxGLXProxy) {
 | |
|        return;
 | |
|     }
 | |
|     
 | |
|     __glXContextRes = CreateNewResourceType((DeleteType)ContextGone,
 | |
| 					    "GLXContext");
 | |
|     __glXClientRes = CreateNewResourceType((DeleteType)ClientGone,
 | |
| 					   "GLXClient");
 | |
|     __glXPixmapRes = CreateNewResourceType((DeleteType)PixmapGone,
 | |
| 					   "GLXPixmap");
 | |
|     __glXWindowRes = CreateNewResourceType((DeleteType)WindowGone,
 | |
| 					   "GLXWindow");
 | |
|     __glXPbufferRes = CreateNewResourceType((DeleteType)PbufferGone,
 | |
| 					    "GLXPbuffer");
 | |
| 
 | |
|     if (!__glXContextRes || !__glXClientRes || !__glXPixmapRes ||
 | |
| 	!__glXWindowRes || !__glXPbufferRes)
 | |
| 	return;
 | |
| 
 | |
|     /*
 | |
|     ** Add extension to server extensions.
 | |
|     */
 | |
|     extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS,
 | |
| 			    __GLX_NUMBER_ERRORS, __glXDispatch,
 | |
| 			    __glXSwapDispatch, 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;
 | |
|     __glXBadContext = extEntry->errorBase + GLXBadContext;
 | |
|     __glXBadContextState = extEntry->errorBase + GLXBadContextState;
 | |
|     __glXBadDrawable = extEntry->errorBase + GLXBadDrawable;
 | |
|     __glXBadPixmap = extEntry->errorBase + GLXBadPixmap;
 | |
|     __glXBadContextTag = extEntry->errorBase + GLXBadContextTag;
 | |
|     __glXBadCurrentWindow = extEntry->errorBase + GLXBadCurrentWindow;
 | |
|     __glXBadRenderRequest = extEntry->errorBase + GLXBadRenderRequest;
 | |
|     __glXBadLargeRequest = extEntry->errorBase + GLXBadLargeRequest;
 | |
|     __glXUnsupportedPrivateRequest = extEntry->errorBase +
 | |
|       			GLXUnsupportedPrivateRequest;
 | |
|     __glXBadFBConfig = extEntry->errorBase + GLXBadFBConfig;
 | |
|     __glXBadPbuffer = extEntry->errorBase + GLXBadPbuffer;
 | |
| 
 | |
|     /*
 | |
|     ** Initialize table of client state.  There is never a client 0.
 | |
|     */
 | |
|     for (i=1; i <= MAXCLIENTS; i++) {
 | |
| 	__glXClients[i] = 0;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|     ** Initialize screen specific data.
 | |
|     */
 | |
|     __glXScreenInit(screenInfo.numScreens);
 | |
| 
 | |
|     /*
 | |
|     ** Initialize swap barrier support.
 | |
|     */
 | |
|     SwapBarrierInit();
 | |
| }
 | |
| 
 | |
| /************************************************************************/
 | |
| 
 | |
| Bool __glXCoreType(void)
 | |
| {
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /************************************************************************/
 | |
| 
 | |
| void __glXFlushContextCache(void)
 | |
| {
 | |
|     __glXLastContext = 0;
 | |
| }
 | |
| 
 | |
| /************************************************************************/
 | |
| 
 | |
| /*
 | |
| ** Top level dispatcher; all commands are executed from here down.
 | |
| */
 | |
| static int __glXDispatch(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xGLXSingleReq);
 | |
|     CARD8 opcode;
 | |
|     int (*proc)(__GLXclientState *cl, GLbyte *pc);
 | |
|     __GLXclientState *cl;
 | |
| 
 | |
|     opcode = stuff->glxCode;
 | |
|     cl = __glXClients[client->index];
 | |
|     if (!cl) {
 | |
| 	cl = calloc(1, sizeof(__GLXclientState));
 | |
| 	 __glXClients[client->index] = cl;
 | |
| 	if (!cl) {
 | |
| 	    return BadAlloc;
 | |
| 	}
 | |
| 
 | |
| 	cl->be_displays = calloc(screenInfo.numScreens, sizeof(Display *));
 | |
| 	if (!cl->be_displays) {
 | |
| 	    free( cl );
 | |
| 	    return BadAlloc;
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|     if (!cl->inUse) {
 | |
| 	/*
 | |
| 	** This is first request from this client.  Associate a resource
 | |
| 	** with the client so we will be notified when the client dies.
 | |
| 	*/
 | |
| 	XID xid = FakeClientID(client->index);
 | |
| 	if (!AddResource( xid, __glXClientRes, (pointer)(long)client->index)) {
 | |
| 	    return BadAlloc;
 | |
| 	}
 | |
| 	ResetClientState(client->index);
 | |
| 	cl->largeCmdRequestsTotal = 0;
 | |
| 	cl->inUse = GL_TRUE;
 | |
| 	cl->client = client;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|     ** Check for valid opcode.
 | |
|     */
 | |
|     if (opcode >= __GLX_SINGLE_TABLE_SIZE) {
 | |
| 	return BadRequest;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|     ** Use the opcode to index into the procedure table.
 | |
|     */
 | |
|     proc = __glXSingleTable[opcode];
 | |
|     return (*proc)(cl, (GLbyte *) stuff);
 | |
| }
 | |
| 
 | |
| static int __glXSwapDispatch(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xGLXSingleReq);
 | |
|     CARD8 opcode;
 | |
|     int (*proc)(__GLXclientState *cl, GLbyte *pc);
 | |
|     __GLXclientState *cl;
 | |
| 
 | |
|     opcode = stuff->glxCode;
 | |
|     cl = __glXClients[client->index];
 | |
|     if (!cl) {
 | |
| 	cl = calloc(1, sizeof(__GLXclientState));
 | |
| 	 __glXClients[client->index] = cl;
 | |
| 	if (!cl) {
 | |
| 	    return BadAlloc;
 | |
| 	}
 | |
| 
 | |
| 	cl->be_displays = calloc(screenInfo.numScreens, sizeof(Display *));
 | |
| 	if (!cl->be_displays) {
 | |
| 	    free( cl );
 | |
| 	    return BadAlloc;
 | |
| 	}
 | |
|     }
 | |
|     
 | |
|     if (!cl->inUse) {
 | |
| 	/*
 | |
| 	** This is first request from this client.  Associate a resource
 | |
| 	** with the client so we will be notified when the client dies.
 | |
| 	*/
 | |
| 	XID xid = FakeClientID(client->index);
 | |
| 	if (!AddResource( xid, __glXClientRes, (pointer)(long)client->index)) {
 | |
| 	    return BadAlloc;
 | |
| 	}
 | |
| 	ResetClientState(client->index);
 | |
| 	cl->inUse = GL_TRUE;
 | |
| 	cl->client = client;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|     ** Check for valid opcode.
 | |
|     */
 | |
|     if (opcode >= __GLX_SINGLE_TABLE_SIZE) {
 | |
| 	return BadRequest;
 | |
|     }
 | |
| 
 | |
|     /*
 | |
|     ** Use the opcode to index into the procedure table.
 | |
|     */
 | |
|     proc = __glXSwapSingleTable[opcode];
 | |
|     return (*proc)(cl, (GLbyte *) stuff);
 | |
| }
 | |
| 
 | |
| int __glXNoSuchSingleOpcode(__GLXclientState *cl, GLbyte *pc)
 | |
| {
 | |
|     return BadRequest;
 | |
| }
 | |
| 
 | |
| void __glXNoSuchRenderOpcode(GLbyte *pc)
 | |
| {
 | |
|     return;
 | |
| }
 | |
| 
 |