First import
[xorg_rtime.git] / xorg-server-1.4 / GL / glx / glxext.c
blobb35175ed2653e9abbd31b35413ca82cda5a9c0d2
1 /*
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.
7 **
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.
21 #define NEED_REPLIES
22 #ifdef HAVE_DIX_CONFIG_H
23 #include <dix-config.h>
24 #endif
26 #include <string.h>
27 #include "glxserver.h"
28 #include <windowstr.h>
29 #include <propertyst.h>
30 #include <os.h>
31 #include "g_disptab.h"
32 #include "unpack.h"
33 #include "glxutil.h"
34 #include "glxext.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;
45 ** X resources.
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();
80 __glXResetScreens();
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.
120 ** use.
122 static int ContextGone(__GLXcontext* cx, XID id)
124 cx->idExists = GL_FALSE;
125 if (!cx->isCurrent) {
126 __glXFreeContext(cx);
129 return True;
133 ** Free a client's state.
135 static int ClientGone(int clientIndex, XID id)
137 __GLXcontext *cx;
138 __GLXclientState *cl = __glXClients[clientIndex];
139 int i;
141 if (cl) {
143 ** Free all the contexts that are current for this client.
145 for (i=0; i < cl->numCurrentContexts; i++) {
146 cx = cl->currentContexts[i];
147 if (cx) {
148 __glXDeassociateContext(cx);
149 cx->isCurrent = GL_FALSE;
150 if (!cx->idExists) {
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);
163 return True;
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) {
175 #ifdef XF86DRI
176 if (pGlxPixmap->pDamage) {
177 DamageUnregister (pGlxPixmap->pDraw, pGlxPixmap->pDamage);
178 DamageDestroy(pGlxPixmap->pDamage);
180 #endif
182 ** The DestroyPixmap routine should decrement the refcount and free
183 ** only if it's zero.
185 (*pGlxPixmap->pScreen->DestroyPixmap)(pPixmap);
186 xfree(pGlxPixmap);
189 return True;
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);
223 return True;
226 static __GLXcontext *glxPendingDestroyContexts;
227 static int glxServerLeaveCount;
228 static int glxBlockClients;
231 ** Free a context.
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);
249 cx->destroy(cx);
250 __glXenterServer(GL_FALSE);
251 } else {
252 cx->next = glxPendingDestroyContexts;
253 glxPendingDestroyContexts = cx;
256 return GL_TRUE;
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);
268 return True;
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)
303 return errorOccured;
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;
321 int i;
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);
336 if (!extEntry) {
337 FatalError("__glXExtensionInit: AddExtensions failed\n");
338 return;
340 if (!AddExtensionAlias(GLX_EXTENSION_ALIAS, extEntry)) {
341 ErrorF("__glXExtensionInit: AddExtensionAlias failed\n");
342 return;
345 __glXErrorBase = extEntry->errorBase;
348 ** Initialize table of client state. There is never a client 0.
350 for (i = 1; i <= MAXCLIENTS; i++) {
351 __glXClients[i] = 0;
355 ** Initialize screen specific data.
357 __glXInitScreens();
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,
374 int *error)
376 __GLXcontext *cx;
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);
383 if (!cx) {
384 cl->client->errorValue = tag;
385 *error = __glXError(GLXBadContextTag);
386 return 0;
389 if (!cx->isDirect) {
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);
397 return 0;
401 if (cx == __glXLastContext) {
402 /* No need to re-bind */
403 return cx;
406 /* Make this context the current one for the GL. */
407 if (!cx->isDirect) {
408 if (!(*cx->forceCurrent)(cx)) {
409 /* Bind failed, and set the error code. Bummer */
410 cl->client->errorValue = cx->id;
411 *error = __glXError(GLXBadContextState);
412 return 0;
415 __glXLastContext = cx;
416 return cx;
419 /************************************************************************/
421 void glxSuspendClients(void)
423 int i;
425 for (i = 1; i <= MAXCLIENTS; i++) {
426 if (__glXClients[i] == NULL || !__glXClients[i]->inUse)
427 continue;
429 IgnoreClient(__glXClients[i]->client);
432 glxBlockClients = TRUE;
435 void glxResumeClients(void)
437 __GLXcontext *cx, *next;
438 int i;
440 glxBlockClients = FALSE;
442 for (i = 1; i <= MAXCLIENTS; i++) {
443 if (__glXClients[i] == NULL || !__glXClients[i]->inUse)
444 continue;
446 AttendClient(__glXClients[i]->client);
449 __glXleaveServer(GL_FALSE);
450 for (cx = glxPendingDestroyContexts; cx != NULL; cx = next) {
451 next = cx->next;
453 cx->destroy(cx);
455 glxPendingDestroyContexts = NULL;
456 __glXenterServer(GL_FALSE);
459 static void
460 __glXnopEnterServer(GLboolean rendering)
464 static void
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);
502 CARD8 opcode;
503 __GLXdispatchSingleProcPtr proc;
504 __GLXclientState *cl;
505 int retval;
507 opcode = stuff->glxCode;
508 cl = __glXClients[client->index];
509 if (!cl) {
510 cl = (__GLXclientState *) xalloc(sizeof(__GLXclientState));
511 __glXClients[client->index] = cl;
512 if (!cl) {
513 return BadAlloc;
515 memset(cl, 0, sizeof(__GLXclientState));
518 if (!cl->inUse) {
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)) {
525 return BadAlloc;
527 ResetClientState(client->index);
528 cl->inUse = GL_TRUE;
529 cl->client = client;
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);
544 client->sequence--;
545 IgnoreClient(client);
546 return(client->noClientException);
550 ** Use the opcode to index into the procedure table.
552 proc = (__GLXdispatchSingleProcPtr) __glXGetProtocolDecodeFunction(& Single_dispatch_info,
553 opcode,
554 client->swapped);
555 if (proc != NULL) {
556 GLboolean rendering = opcode <= X_GLXRenderLarge;
557 __glXleaveServer(rendering);
559 __pGlxClient = client;
561 retval = (*proc)(cl, (GLbyte *) stuff);
563 __glXenterServer(rendering);
565 else {
566 retval = BadRequest;
569 return retval;