2 ** The contents of this file are subject to the GLX Public License Version 1.0
3 ** (the "License"). You may not use this file except in compliance with the
4 ** License. You may obtain a copy of the License at Silicon Graphics, Inc.,
5 ** attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043
6 ** or at http://www.sgi.com/software/opensource/glx/license.html.
8 ** Software distributed under the License is distributed on an "AS IS"
9 ** basis. ALL WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY
10 ** IMPLIED WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR
11 ** PURPOSE OR OF NON- INFRINGEMENT. See the License for the specific
12 ** language governing rights and limitations under the License.
14 ** The Original Software is GLX version 1.2 source code, released February,
15 ** 1999. The developer of the Original Software is Silicon Graphics, Inc.
16 ** Those portions of the Subject Software created by Silicon Graphics, Inc.
17 ** are Copyright (c) 1991-9 Silicon Graphics, Inc. All Rights Reserved.
22 #ifdef HAVE_DIX_CONFIG_H
23 #include <dix-config.h>
27 #include "glxserver.h"
28 #include <windowstr.h>
29 #include <propertyst.h>
31 #include "g_disptab.h"
35 #include "indirect_table.h"
36 #include "indirect_util.h"
39 ** The last context used by the server. It is the context that is current
40 ** from the server's perspective.
42 __GLXcontext
*__glXLastContext
;
47 RESTYPE __glXContextRes
;
48 RESTYPE __glXClientRes
;
49 RESTYPE __glXPixmapRes
;
50 RESTYPE __glXDrawableRes
;
51 RESTYPE __glXSwapBarrierRes
;
54 ** Reply for most singles.
56 xGLXSingleReply __glXReply
;
59 ** A set of state for each client. The 0th one is unused because client
60 ** indices start at 1, not 0.
62 static __GLXclientState
*__glXClients
[MAXCLIENTS
+ 1];
65 ** Client that called into GLX dispatch.
67 ClientPtr __pGlxClient
;
70 ** Forward declarations.
72 static int __glXDispatch(ClientPtr
);
75 ** Called when the extension is reset.
77 static void ResetExtension(ExtensionEntry
* extEntry
)
79 __glXFlushContextCache();
84 ** Initialize the per-client context storage.
86 static void ResetClientState(int clientIndex
)
88 __GLXclientState
*cl
= __glXClients
[clientIndex
];
90 if (cl
->returnBuf
) xfree(cl
->returnBuf
);
91 if (cl
->largeCmdBuf
) xfree(cl
->largeCmdBuf
);
92 if (cl
->currentContexts
) xfree(cl
->currentContexts
);
93 memset(cl
, 0, sizeof(__GLXclientState
));
95 ** By default, assume that the client supports
96 ** GLX major version 1 minor version 0 protocol.
98 cl
->GLClientmajorVersion
= 1;
99 cl
->GLClientminorVersion
= 0;
100 if (cl
->GLClientextensions
)
101 xfree(cl
->GLClientextensions
);
106 ** Reset state used to keep track of large (multi-request) commands.
108 void __glXResetLargeCommandStatus(__GLXclientState
*cl
)
110 cl
->largeCmdBytesSoFar
= 0;
111 cl
->largeCmdBytesTotal
= 0;
112 cl
->largeCmdRequestsSoFar
= 0;
113 cl
->largeCmdRequestsTotal
= 0;
117 ** This procedure is called when the client who created the context goes
118 ** away OR when glXDestroyContext is called. In either case, all we do is
119 ** flag that the ID is no longer valid, and (maybe) free the context.
122 static int ContextGone(__GLXcontext
* cx
, XID id
)
124 cx
->idExists
= GL_FALSE
;
125 if (!cx
->isCurrent
) {
126 __glXFreeContext(cx
);
133 ** Free a client's state.
135 static int ClientGone(int clientIndex
, XID id
)
138 __GLXclientState
*cl
= __glXClients
[clientIndex
];
143 ** Free all the contexts that are current for this client.
145 for (i
=0; i
< cl
->numCurrentContexts
; i
++) {
146 cx
= cl
->currentContexts
[i
];
148 __glXDeassociateContext(cx
);
149 cx
->isCurrent
= GL_FALSE
;
151 __glXFreeContext(cx
);
156 ** Re-initialize the client state structure. Don't free it because
157 ** we'll probably get another client with this index and use the struct
158 ** again. There is a maximum of MAXCLIENTS of these structures.
160 ResetClientState(clientIndex
);
167 ** Free a GLX Pixmap.
169 static int PixmapGone(__GLXpixmap
*pGlxPixmap
, XID id
)
171 PixmapPtr pPixmap
= (PixmapPtr
) pGlxPixmap
->pDraw
;
173 pGlxPixmap
->idExists
= False
;
174 if (!pGlxPixmap
->refcnt
) {
176 if (pGlxPixmap
->pDamage
) {
177 DamageUnregister (pGlxPixmap
->pDraw
, pGlxPixmap
->pDamage
);
178 DamageDestroy(pGlxPixmap
->pDamage
);
182 ** The DestroyPixmap routine should decrement the refcount and free
183 ** only if it's zero.
185 (*pGlxPixmap
->pScreen
->DestroyPixmap
)(pPixmap
);
193 ** Destroy routine that gets called when a drawable is freed. A drawable
194 ** contains the ancillary buffers needed for rendering.
196 static Bool
DrawableGone(__GLXdrawable
*glxPriv
, XID xid
)
198 __GLXcontext
*cx
, *cx1
;
201 ** Use glxPriv->type to figure out what kind of drawable this is. Don't
202 ** use glxPriv->pDraw->type because by the time this routine is called,
203 ** the pDraw might already have been freed.
205 if (glxPriv
->type
== DRAWABLE_WINDOW
) {
207 ** When a window is destroyed, notify all context bound to
208 ** it, that there are no longer bound to anything.
210 for (cx
= glxPriv
->drawGlxc
; cx
; cx
= cx1
) {
211 cx1
= cx
->nextDrawPriv
;
212 cx
->pendingState
|= __GLX_PENDING_DESTROY
;
215 for (cx
= glxPriv
->readGlxc
; cx
; cx
= cx1
) {
216 cx1
= cx
->nextReadPriv
;
217 cx
->pendingState
|= __GLX_PENDING_DESTROY
;
221 __glXUnrefDrawable(glxPriv
);
226 static __GLXcontext
*glxPendingDestroyContexts
;
227 static int glxServerLeaveCount
;
228 static int glxBlockClients
;
233 GLboolean
__glXFreeContext(__GLXcontext
*cx
)
235 if (cx
->idExists
|| cx
->isCurrent
) return GL_FALSE
;
237 if (cx
->feedbackBuf
) xfree(cx
->feedbackBuf
);
238 if (cx
->selectBuf
) xfree(cx
->selectBuf
);
239 if (cx
== __glXLastContext
) {
240 __glXFlushContextCache();
243 /* We can get here through both regular dispatching from
244 * __glXDispatch() or as a callback from the resource manager. In
245 * the latter case we need to lift the DRI lock manually. */
247 if (!glxBlockClients
) {
248 __glXleaveServer(GL_FALSE
);
250 __glXenterServer(GL_FALSE
);
252 cx
->next
= glxPendingDestroyContexts
;
253 glxPendingDestroyContexts
= cx
;
259 extern RESTYPE __glXSwapBarrierRes
;
261 static int SwapBarrierGone(int screen
, XID drawable
)
263 if (__glXSwapBarrierFuncs
&&
264 __glXSwapBarrierFuncs
[screen
].bindSwapBarrierFunc
!= NULL
) {
265 __glXSwapBarrierFuncs
[screen
].bindSwapBarrierFunc(screen
, drawable
, 0);
267 FreeResourceByType(drawable
, __glXSwapBarrierRes
, FALSE
);
271 /************************************************************************/
274 ** These routines can be used to check whether a particular GL command
275 ** has caused an error. Specifically, we use them to check whether a
276 ** given query has caused an error, in which case a zero-length data
277 ** reply is sent to the client.
280 static GLboolean errorOccured
= GL_FALSE
;
283 ** The GL was will call this routine if an error occurs.
285 void __glXErrorCallBack(GLenum code
)
287 errorOccured
= GL_TRUE
;
291 ** Clear the error flag before calling the GL command.
293 void __glXClearErrorOccured(void)
295 errorOccured
= GL_FALSE
;
299 ** Check if the GL command caused an error.
301 GLboolean
__glXErrorOccured(void)
306 static int __glXErrorBase
;
308 int __glXError(int error
)
310 return __glXErrorBase
+ error
;
313 /************************************************************************/
316 ** Initialize the GLX extension.
318 void GlxExtensionInit(void)
320 ExtensionEntry
*extEntry
;
323 __glXContextRes
= CreateNewResourceType((DeleteType
)ContextGone
);
324 __glXClientRes
= CreateNewResourceType((DeleteType
)ClientGone
);
325 __glXPixmapRes
= CreateNewResourceType((DeleteType
)PixmapGone
);
326 __glXDrawableRes
= CreateNewResourceType((DeleteType
)DrawableGone
);
327 __glXSwapBarrierRes
= CreateNewResourceType((DeleteType
)SwapBarrierGone
);
330 ** Add extension to server extensions.
332 extEntry
= AddExtension(GLX_EXTENSION_NAME
, __GLX_NUMBER_EVENTS
,
333 __GLX_NUMBER_ERRORS
, __glXDispatch
,
334 __glXDispatch
, ResetExtension
,
335 StandardMinorOpcode
);
337 FatalError("__glXExtensionInit: AddExtensions failed\n");
340 if (!AddExtensionAlias(GLX_EXTENSION_ALIAS
, extEntry
)) {
341 ErrorF("__glXExtensionInit: AddExtensionAlias failed\n");
345 __glXErrorBase
= extEntry
->errorBase
;
348 ** Initialize table of client state. There is never a client 0.
350 for (i
= 1; i
<= MAXCLIENTS
; i
++) {
355 ** Initialize screen specific data.
360 /************************************************************************/
362 void __glXFlushContextCache(void)
364 __glXLastContext
= 0;
368 ** Make a context the current one for the GL (in this implementation, there
369 ** is only one instance of the GL, and we use it to serve all GL clients by
370 ** switching it between different contexts). While we are at it, look up
371 ** a context by its tag and return its (__GLXcontext *).
373 __GLXcontext
*__glXForceCurrent(__GLXclientState
*cl
, GLXContextTag tag
,
379 ** See if the context tag is legal; it is managed by the extension,
380 ** so if it's invalid, we have an implementation error.
382 cx
= (__GLXcontext
*) __glXLookupContextByTag(cl
, tag
);
384 cl
->client
->errorValue
= tag
;
385 *error
= __glXError(GLXBadContextTag
);
390 if (cx
->drawPriv
== NULL
) {
392 ** The drawable has vanished. It must be a window, because only
393 ** windows can be destroyed from under us; GLX pixmaps are
394 ** refcounted and don't go away until no one is using them.
396 *error
= __glXError(GLXBadCurrentWindow
);
401 if (cx
== __glXLastContext
) {
402 /* No need to re-bind */
406 /* Make this context the current one for the GL. */
408 if (!(*cx
->forceCurrent
)(cx
)) {
409 /* Bind failed, and set the error code. Bummer */
410 cl
->client
->errorValue
= cx
->id
;
411 *error
= __glXError(GLXBadContextState
);
415 __glXLastContext
= cx
;
419 /************************************************************************/
421 void glxSuspendClients(void)
425 for (i
= 1; i
<= MAXCLIENTS
; i
++) {
426 if (__glXClients
[i
] == NULL
|| !__glXClients
[i
]->inUse
)
429 IgnoreClient(__glXClients
[i
]->client
);
432 glxBlockClients
= TRUE
;
435 void glxResumeClients(void)
437 __GLXcontext
*cx
, *next
;
440 glxBlockClients
= FALSE
;
442 for (i
= 1; i
<= MAXCLIENTS
; i
++) {
443 if (__glXClients
[i
] == NULL
|| !__glXClients
[i
]->inUse
)
446 AttendClient(__glXClients
[i
]->client
);
449 __glXleaveServer(GL_FALSE
);
450 for (cx
= glxPendingDestroyContexts
; cx
!= NULL
; cx
= next
) {
455 glxPendingDestroyContexts
= NULL
;
456 __glXenterServer(GL_FALSE
);
460 __glXnopEnterServer(GLboolean rendering
)
465 __glXnopLeaveServer(GLboolean rendering
)
469 static void (*__glXenterServerFunc
)(GLboolean
) = __glXnopEnterServer
;
470 static void (*__glXleaveServerFunc
)(GLboolean
) = __glXnopLeaveServer
;
472 void __glXsetEnterLeaveServerFuncs(void (*enter
)(GLboolean
),
473 void (*leave
)(GLboolean
))
475 __glXenterServerFunc
= enter
;
476 __glXleaveServerFunc
= leave
;
480 void __glXenterServer(GLboolean rendering
)
482 glxServerLeaveCount
--;
484 if (glxServerLeaveCount
== 0)
485 (*__glXenterServerFunc
)(rendering
);
488 void __glXleaveServer(GLboolean rendering
)
490 if (glxServerLeaveCount
== 0)
491 (*__glXleaveServerFunc
)(rendering
);
493 glxServerLeaveCount
++;
497 ** Top level dispatcher; all commands are executed from here down.
499 static int __glXDispatch(ClientPtr client
)
501 REQUEST(xGLXSingleReq
);
503 __GLXdispatchSingleProcPtr proc
;
504 __GLXclientState
*cl
;
507 opcode
= stuff
->glxCode
;
508 cl
= __glXClients
[client
->index
];
510 cl
= (__GLXclientState
*) xalloc(sizeof(__GLXclientState
));
511 __glXClients
[client
->index
] = cl
;
515 memset(cl
, 0, sizeof(__GLXclientState
));
520 ** This is first request from this client. Associate a resource
521 ** with the client so we will be notified when the client dies.
523 XID xid
= FakeClientID(client
->index
);
524 if (!AddResource( xid
, __glXClientRes
, (pointer
)(long)client
->index
)) {
527 ResetClientState(client
->index
);
533 ** If we're expecting a glXRenderLarge request, this better be one.
535 if ((cl
->largeCmdRequestsSoFar
!= 0) && (opcode
!= X_GLXRenderLarge
)) {
536 client
->errorValue
= stuff
->glxCode
;
537 return __glXError(GLXBadLargeRequest
);
540 /* If we're currently blocking GLX clients, just put this guy to
541 * sleep, reset the request and return. */
542 if (glxBlockClients
) {
543 ResetCurrentRequest(client
);
545 IgnoreClient(client
);
546 return(client
->noClientException
);
550 ** Use the opcode to index into the procedure table.
552 proc
= (__GLXdispatchSingleProcPtr
) __glXGetProtocolDecodeFunction(& Single_dispatch_info
,
556 GLboolean rendering
= opcode
<= X_GLXRenderLarge
;
557 __glXleaveServer(rendering
);
559 __pGlxClient
= client
;
561 retval
= (*proc
)(cl
, (GLbyte
*) stuff
);
563 __glXenterServer(rendering
);