xenocara/xserver/hw/dmx/glxProxy/glxext.c

510 lines
13 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"
#include "extinit.h"
#include "glx_extinit.h"
/*
** 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;
}