2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice including the dates of first publication and
13 * either this permission notice or a reference to
14 * http://oss.sgi.com/projects/FreeB/
15 * shall be included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * Except as contained in this notice, the name of Silicon Graphics, Inc.
26 * shall not be used in advertising or otherwise to promote the sale, use or
27 * other dealings in this Software without prior written authorization from
28 * Silicon Graphics, Inc.
31 #ifdef HAVE_DIX_CONFIG_H
32 #include <dix-config.h>
36 #include "glxserver.h"
37 #include <windowstr.h>
38 #include <propertyst.h>
43 #include "glx_extinit.h"
47 #include "indirect_table.h"
48 #include "indirect_util.h"
51 ** The last context used by the server. It is the context that is current
52 ** from the server's perspective.
54 __GLXcontext
*__glXLastContext
;
59 RESTYPE __glXContextRes
;
60 RESTYPE __glXDrawableRes
;
63 ** Reply for most singles.
65 xGLXSingleReply __glXReply
;
67 static DevPrivateKeyRec glxClientPrivateKeyRec
;
69 #define glxClientPrivateKey (&glxClientPrivateKeyRec)
72 ** Forward declarations.
74 static int __glXDispatch(ClientPtr
);
77 ** Called when the extension is reset.
80 ResetExtension(ExtensionEntry
* extEntry
)
82 __glXFlushContextCache();
86 ** Reset state used to keep track of large (multi-request) commands.
89 __glXResetLargeCommandStatus(__GLXclientState
* cl
)
91 cl
->largeCmdBytesSoFar
= 0;
92 cl
->largeCmdBytesTotal
= 0;
93 cl
->largeCmdRequestsSoFar
= 0;
94 cl
->largeCmdRequestsTotal
= 0;
98 * This procedure is called when the client who created the context goes away
99 * OR when glXDestroyContext is called. In either case, all we do is flag that
100 * the ID is no longer valid, and (maybe) free the context.
103 ContextGone(__GLXcontext
* cx
, XID id
)
105 cx
->idExists
= GL_FALSE
;
106 if (!cx
->currentClient
) {
107 __glXFreeContext(cx
);
113 static __GLXcontext
*glxPendingDestroyContexts
;
114 static __GLXcontext
*glxAllContexts
;
115 static int glxServerLeaveCount
;
116 static int glxBlockClients
;
119 ** Destroy routine that gets called when a drawable is freed. A drawable
120 ** contains the ancillary buffers needed for rendering.
123 DrawableGone(__GLXdrawable
* glxPriv
, XID xid
)
125 __GLXcontext
*c
, *next
;
127 if (glxPriv
->type
== GLX_DRAWABLE_WINDOW
) {
128 /* If this was created by glXCreateWindow, free the matching resource */
129 if (glxPriv
->drawId
!= glxPriv
->pDraw
->id
) {
130 if (xid
== glxPriv
->drawId
)
131 FreeResourceByType(glxPriv
->pDraw
->id
, __glXDrawableRes
, TRUE
);
133 FreeResourceByType(glxPriv
->drawId
, __glXDrawableRes
, TRUE
);
135 /* otherwise this window was implicitly created by MakeCurrent */
138 for (c
= glxAllContexts
; c
; c
= next
) {
140 if (c
->currentClient
&&
141 (c
->drawPriv
== glxPriv
|| c
->readPriv
== glxPriv
)) {
142 /* just force a re-bind the next time through */
143 (*c
->loseCurrent
) (c
);
144 if (c
== __glXLastContext
)
145 __glXFlushContextCache();
147 if (c
->drawPriv
== glxPriv
)
149 if (c
->readPriv
== glxPriv
)
153 /* drop our reference to any backing pixmap */
154 if (glxPriv
->type
== GLX_DRAWABLE_PIXMAP
)
155 glxPriv
->pDraw
->pScreen
->DestroyPixmap((PixmapPtr
) glxPriv
->pDraw
);
157 glxPriv
->destroy(glxPriv
);
163 __glXAddContext(__GLXcontext
* cx
)
165 /* Register this context as a resource.
167 if (!AddResource(cx
->id
, __glXContextRes
, (pointer
)cx
)) {
171 cx
->next
= glxAllContexts
;
177 __glXRemoveFromContextList(__GLXcontext
* cx
)
179 __GLXcontext
*c
, *prev
;
181 if (cx
== glxAllContexts
)
182 glxAllContexts
= cx
->next
;
184 prev
= glxAllContexts
;
185 for (c
= glxAllContexts
; c
; c
= c
->next
) {
187 prev
->next
= c
->next
;
197 __glXFreeContext(__GLXcontext
* cx
)
199 if (cx
->idExists
|| cx
->currentClient
)
202 __glXRemoveFromContextList(cx
);
204 free(cx
->feedbackBuf
);
206 if (cx
== __glXLastContext
) {
207 __glXFlushContextCache();
210 /* We can get here through both regular dispatching from
211 * __glXDispatch() or as a callback from the resource manager. In
212 * the latter case we need to lift the DRI lock manually. */
214 if (!glxBlockClients
) {
215 __glXleaveServer(GL_FALSE
);
217 __glXenterServer(GL_FALSE
);
220 cx
->next
= glxPendingDestroyContexts
;
221 glxPendingDestroyContexts
= cx
;
227 /************************************************************************/
230 ** These routines can be used to check whether a particular GL command
231 ** has caused an error. Specifically, we use them to check whether a
232 ** given query has caused an error, in which case a zero-length data
233 ** reply is sent to the client.
236 static GLboolean errorOccured
= GL_FALSE
;
239 ** The GL was will call this routine if an error occurs.
242 __glXErrorCallBack(GLenum code
)
244 errorOccured
= GL_TRUE
;
248 ** Clear the error flag before calling the GL command.
251 __glXClearErrorOccured(void)
253 errorOccured
= GL_FALSE
;
257 ** Check if the GL command caused an error.
260 __glXErrorOccured(void)
265 static int __glXErrorBase
;
269 __glXError(int error
)
271 return __glXErrorBase
+ error
;
275 glxGetClient(ClientPtr pClient
)
277 return dixLookupPrivate(&pClient
->devPrivates
, glxClientPrivateKey
);
281 glxClientCallback(CallbackListPtr
*list
, pointer closure
, pointer data
)
283 NewClientInfoRec
*clientinfo
= (NewClientInfoRec
*) data
;
284 ClientPtr pClient
= clientinfo
->client
;
285 __GLXclientState
*cl
= glxGetClient(pClient
);
286 __GLXcontext
*c
, *next
;
288 switch (pClient
->clientState
) {
289 case ClientStateRunning
:
290 cl
->client
= pClient
;
293 case ClientStateGone
:
294 /* detach from all current contexts */
295 for (c
= glxAllContexts
; c
; c
= next
) {
297 if (c
->currentClient
== pClient
) {
299 c
->currentClient
= NULL
;
305 free(cl
->largeCmdBuf
);
306 free(cl
->GLClientextensions
);
314 /************************************************************************/
316 static __GLXprovider
*__glXProviderStack
;
319 GlxPushProvider(__GLXprovider
* provider
)
321 provider
->next
= __glXProviderStack
;
322 __glXProviderStack
= provider
;
326 ** Initialize the GLX extension.
329 GlxExtensionInit(void)
331 ExtensionEntry
*extEntry
;
334 __GLXprovider
*p
, **stack
;
335 Bool glx_provided
= False
;
337 if (serverGeneration
== 1) {
338 for (stack
= &__glXProviderStack
; *stack
; stack
= &(*stack
)->next
)
340 *stack
= &__glXDRISWRastProvider
;
343 __glXContextRes
= CreateNewResourceType((DeleteType
) ContextGone
,
345 __glXDrawableRes
= CreateNewResourceType((DeleteType
) DrawableGone
,
347 if (!__glXContextRes
|| !__glXDrawableRes
)
350 if (!dixRegisterPrivateKey
351 (&glxClientPrivateKeyRec
, PRIVATE_CLIENT
, sizeof(__GLXclientState
)))
353 if (!AddCallback(&ClientStateCallback
, glxClientCallback
, 0))
356 for (i
= 0; i
< screenInfo
.numScreens
; i
++) {
357 pScreen
= screenInfo
.screens
[i
];
359 for (p
= __glXProviderStack
; p
!= NULL
; p
= p
->next
) {
360 __GLXscreen
*glxScreen
;
362 glxScreen
= p
->screenProbe(pScreen
);
363 if (glxScreen
!= NULL
) {
364 if (glxScreen
->GLXminor
< glxMinorVersion
)
365 glxMinorVersion
= glxScreen
->GLXminor
;
367 "GLX: Initialized %s GL provider for screen %d\n",
376 "GLX: no usable GL providers found for screen %d\n", i
);
381 /* don't register extension if GL is not provided on any screen */
386 ** Add extension to server extensions.
388 extEntry
= AddExtension(GLX_EXTENSION_NAME
, __GLX_NUMBER_EVENTS
,
389 __GLX_NUMBER_ERRORS
, __glXDispatch
,
390 __glXDispatch
, ResetExtension
, StandardMinorOpcode
);
392 FatalError("__glXExtensionInit: AddExtensions failed\n");
395 if (!AddExtensionAlias(GLX_EXTENSION_ALIAS
, extEntry
)) {
396 ErrorF("__glXExtensionInit: AddExtensionAlias failed\n");
400 __glXErrorBase
= extEntry
->errorBase
;
401 __glXEventBase
= extEntry
->eventBase
;
403 __glXregisterPresentCompleteNotify();
407 /************************************************************************/
410 __glXFlushContextCache(void)
412 __glXLastContext
= 0;
416 ** Make a context the current one for the GL (in this implementation, there
417 ** is only one instance of the GL, and we use it to serve all GL clients by
418 ** switching it between different contexts). While we are at it, look up
419 ** a context by its tag and return its (__GLXcontext *).
422 __glXForceCurrent(__GLXclientState
* cl
, GLXContextTag tag
, int *error
)
427 ** See if the context tag is legal; it is managed by the extension,
428 ** so if it's invalid, we have an implementation error.
430 cx
= __glXLookupContextByTag(cl
, tag
);
432 cl
->client
->errorValue
= tag
;
433 *error
= __glXError(GLXBadContextTag
);
438 if (cx
->drawPriv
== NULL
) {
440 ** The drawable has vanished. It must be a window, because only
441 ** windows can be destroyed from under us; GLX pixmaps are
442 ** refcounted and don't go away until no one is using them.
444 *error
= __glXError(GLXBadCurrentWindow
);
449 if (cx
->wait
&& (*cx
->wait
) (cx
, cl
, error
))
452 if (cx
== __glXLastContext
) {
453 /* No need to re-bind */
457 /* Make this context the current one for the GL. */
459 if (!(*cx
->makeCurrent
) (cx
)) {
460 /* Bind failed, and set the error code. Bummer */
461 cl
->client
->errorValue
= cx
->id
;
462 *error
= __glXError(GLXBadContextState
);
466 __glXLastContext
= cx
;
470 /************************************************************************/
473 glxSuspendClients(void)
477 for (i
= 1; i
< currentMaxClients
; i
++) {
478 if (clients
[i
] && glxGetClient(clients
[i
])->inUse
)
479 IgnoreClient(clients
[i
]);
482 glxBlockClients
= TRUE
;
486 glxResumeClients(void)
488 __GLXcontext
*cx
, *next
;
491 glxBlockClients
= FALSE
;
493 for (i
= 1; i
< currentMaxClients
; i
++) {
494 if (clients
[i
] && glxGetClient(clients
[i
])->inUse
)
495 AttendClient(clients
[i
]);
498 __glXleaveServer(GL_FALSE
);
499 for (cx
= glxPendingDestroyContexts
; cx
!= NULL
; cx
= next
) {
504 glxPendingDestroyContexts
= NULL
;
505 __glXenterServer(GL_FALSE
);
509 __glXnopEnterServer(GLboolean rendering
)
514 __glXnopLeaveServer(GLboolean rendering
)
518 static void (*__glXenterServerFunc
) (GLboolean
) = __glXnopEnterServer
;
519 static void (*__glXleaveServerFunc
) (GLboolean
) = __glXnopLeaveServer
;
522 __glXsetEnterLeaveServerFuncs(void (*enter
) (GLboolean
),
523 void (*leave
) (GLboolean
))
525 __glXenterServerFunc
= enter
;
526 __glXleaveServerFunc
= leave
;
530 __glXenterServer(GLboolean rendering
)
532 glxServerLeaveCount
--;
534 if (glxServerLeaveCount
== 0)
535 (*__glXenterServerFunc
) (rendering
);
539 __glXleaveServer(GLboolean rendering
)
541 if (glxServerLeaveCount
== 0)
542 (*__glXleaveServerFunc
) (rendering
);
544 glxServerLeaveCount
++;
547 static glx_gpa_proc _get_proc_address
;
550 __glXsetGetProcAddress(glx_gpa_proc get_proc_address
)
552 _get_proc_address
= get_proc_address
;
555 void *__glGetProcAddress(const char *proc
)
557 void *ret
= _get_proc_address(proc
);
559 return ret
? ret
: NoopDDA
;
563 ** Top level dispatcher; all commands are executed from here down.
566 __glXDispatch(ClientPtr client
)
568 REQUEST(xGLXSingleReq
);
570 __GLXdispatchSingleProcPtr proc
;
571 __GLXclientState
*cl
;
574 opcode
= stuff
->glxCode
;
575 cl
= glxGetClient(client
);
576 /* Mark it in use so we suspend it on VT switch. */
580 ** If we're expecting a glXRenderLarge request, this better be one.
582 if ((cl
->largeCmdRequestsSoFar
!= 0) && (opcode
!= X_GLXRenderLarge
)) {
583 client
->errorValue
= stuff
->glxCode
;
584 return __glXError(GLXBadLargeRequest
);
587 /* If we're currently blocking GLX clients, just put this guy to
588 * sleep, reset the request and return. */
589 if (glxBlockClients
) {
590 ResetCurrentRequest(client
);
592 IgnoreClient(client
);
597 ** Use the opcode to index into the procedure table.
599 proc
= __glXGetProtocolDecodeFunction(&Single_dispatch_info
, opcode
,
602 GLboolean rendering
= opcode
<= X_GLXRenderLarge
;
604 __glXleaveServer(rendering
);
606 retval
= (*proc
) (cl
, (GLbyte
*) stuff
);
608 __glXenterServer(rendering
);