Imported Upstream version 1.15.1
[deb_xorg-server.git] / glx / glxext.c
CommitLineData
a09e091a
JB
1/*
2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4 *
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:
11 *
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.
16 *
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
23 * SOFTWARE.
24 *
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.
29 */
30
31#ifdef HAVE_DIX_CONFIG_H
32#include <dix-config.h>
33#endif
34
35#include <string.h>
36#include "glxserver.h"
37#include <windowstr.h>
38#include <propertyst.h>
39#include <registry.h>
40#include "privates.h"
41#include <os.h>
42#include "extinit.h"
43#include "glx_extinit.h"
44#include "unpack.h"
45#include "glxutil.h"
46#include "glxext.h"
47#include "indirect_table.h"
48#include "indirect_util.h"
49
50/*
51** The last context used by the server. It is the context that is current
52** from the server's perspective.
53*/
54__GLXcontext *__glXLastContext;
55
56/*
57** X resources.
58*/
59RESTYPE __glXContextRes;
60RESTYPE __glXDrawableRes;
61
62/*
63** Reply for most singles.
64*/
65xGLXSingleReply __glXReply;
66
67static DevPrivateKeyRec glxClientPrivateKeyRec;
68
69#define glxClientPrivateKey (&glxClientPrivateKeyRec)
70
71/*
72** Forward declarations.
73*/
74static int __glXDispatch(ClientPtr);
75
76/*
77** Called when the extension is reset.
78*/
79static void
80ResetExtension(ExtensionEntry * extEntry)
81{
82 __glXFlushContextCache();
83}
84
85/*
86** Reset state used to keep track of large (multi-request) commands.
87*/
88void
89__glXResetLargeCommandStatus(__GLXclientState * cl)
90{
91 cl->largeCmdBytesSoFar = 0;
92 cl->largeCmdBytesTotal = 0;
93 cl->largeCmdRequestsSoFar = 0;
94 cl->largeCmdRequestsTotal = 0;
95}
96
97/*
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.
101 */
102static int
103ContextGone(__GLXcontext * cx, XID id)
104{
105 cx->idExists = GL_FALSE;
106 if (!cx->currentClient) {
107 __glXFreeContext(cx);
108 }
109
110 return True;
111}
112
113static __GLXcontext *glxPendingDestroyContexts;
114static __GLXcontext *glxAllContexts;
115static int glxServerLeaveCount;
116static int glxBlockClients;
117
118/*
119** Destroy routine that gets called when a drawable is freed. A drawable
120** contains the ancillary buffers needed for rendering.
121*/
122static Bool
123DrawableGone(__GLXdrawable * glxPriv, XID xid)
124{
125 __GLXcontext *c, *next;
126
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);
132 else
133 FreeResourceByType(glxPriv->drawId, __glXDrawableRes, TRUE);
134 }
135 /* otherwise this window was implicitly created by MakeCurrent */
136 }
137
138 for (c = glxAllContexts; c; c = next) {
139 next = 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();
146 }
147 if (c->drawPriv == glxPriv)
148 c->drawPriv = NULL;
149 if (c->readPriv == glxPriv)
150 c->readPriv = NULL;
151 }
152
153 /* drop our reference to any backing pixmap */
154 if (glxPriv->type == GLX_DRAWABLE_PIXMAP)
155 glxPriv->pDraw->pScreen->DestroyPixmap((PixmapPtr) glxPriv->pDraw);
156
157 glxPriv->destroy(glxPriv);
158
159 return True;
160}
161
162Bool
163__glXAddContext(__GLXcontext * cx)
164{
165 /* Register this context as a resource.
166 */
167 if (!AddResource(cx->id, __glXContextRes, (pointer)cx)) {
168 return False;
169 }
170
171 cx->next = glxAllContexts;
172 glxAllContexts = cx;
173 return True;
174}
175
176static void
177__glXRemoveFromContextList(__GLXcontext * cx)
178{
179 __GLXcontext *c, *prev;
180
181 if (cx == glxAllContexts)
182 glxAllContexts = cx->next;
183 else {
184 prev = glxAllContexts;
185 for (c = glxAllContexts; c; c = c->next) {
186 if (c == cx)
187 prev->next = c->next;
188 prev = c;
189 }
190 }
191}
192
193/*
194** Free a context.
195*/
196GLboolean
197__glXFreeContext(__GLXcontext * cx)
198{
199 if (cx->idExists || cx->currentClient)
200 return GL_FALSE;
201
202 __glXRemoveFromContextList(cx);
203
204 free(cx->feedbackBuf);
205 free(cx->selectBuf);
206 if (cx == __glXLastContext) {
207 __glXFlushContextCache();
208 }
209
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. */
213
214 if (!glxBlockClients) {
215 __glXleaveServer(GL_FALSE);
216 cx->destroy(cx);
217 __glXenterServer(GL_FALSE);
218 }
219 else {
220 cx->next = glxPendingDestroyContexts;
221 glxPendingDestroyContexts = cx;
222 }
223
224 return GL_TRUE;
225}
226
227/************************************************************************/
228
229/*
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.
234*/
235
236static GLboolean errorOccured = GL_FALSE;
237
238/*
239** The GL was will call this routine if an error occurs.
240*/
241void
242__glXErrorCallBack(GLenum code)
243{
244 errorOccured = GL_TRUE;
245}
246
247/*
248** Clear the error flag before calling the GL command.
249*/
250void
251__glXClearErrorOccured(void)
252{
253 errorOccured = GL_FALSE;
254}
255
256/*
257** Check if the GL command caused an error.
258*/
259GLboolean
260__glXErrorOccured(void)
261{
262 return errorOccured;
263}
264
265static int __glXErrorBase;
266int __glXEventBase;
267
268int
269__glXError(int error)
270{
271 return __glXErrorBase + error;
272}
273
274__GLXclientState *
275glxGetClient(ClientPtr pClient)
276{
277 return dixLookupPrivate(&pClient->devPrivates, glxClientPrivateKey);
278}
279
280static void
281glxClientCallback(CallbackListPtr *list, pointer closure, pointer data)
282{
283 NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
284 ClientPtr pClient = clientinfo->client;
285 __GLXclientState *cl = glxGetClient(pClient);
286 __GLXcontext *c, *next;
287
288 switch (pClient->clientState) {
289 case ClientStateRunning:
290 cl->client = pClient;
291 break;
292
293 case ClientStateGone:
294 /* detach from all current contexts */
295 for (c = glxAllContexts; c; c = next) {
296 next = c->next;
297 if (c->currentClient == pClient) {
298 c->loseCurrent(c);
299 c->currentClient = NULL;
300 __glXFreeContext(c);
301 }
302 }
303
304 free(cl->returnBuf);
305 free(cl->largeCmdBuf);
306 free(cl->GLClientextensions);
307 break;
308
309 default:
310 break;
311 }
312}
313
314/************************************************************************/
315
316static __GLXprovider *__glXProviderStack;
317
318void
319GlxPushProvider(__GLXprovider * provider)
320{
321 provider->next = __glXProviderStack;
322 __glXProviderStack = provider;
323}
324
325/*
326** Initialize the GLX extension.
327*/
328void
329GlxExtensionInit(void)
330{
331 ExtensionEntry *extEntry;
332 ScreenPtr pScreen;
333 int i;
334 __GLXprovider *p, **stack;
335 Bool glx_provided = False;
336
337 if (serverGeneration == 1) {
338 for (stack = &__glXProviderStack; *stack; stack = &(*stack)->next)
339 ;
340 *stack = &__glXDRISWRastProvider;
341 }
342
343 __glXContextRes = CreateNewResourceType((DeleteType) ContextGone,
344 "GLXContext");
345 __glXDrawableRes = CreateNewResourceType((DeleteType) DrawableGone,
346 "GLXDrawable");
347 if (!__glXContextRes || !__glXDrawableRes)
348 return;
349
350 if (!dixRegisterPrivateKey
351 (&glxClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(__GLXclientState)))
352 return;
353 if (!AddCallback(&ClientStateCallback, glxClientCallback, 0))
354 return;
355
356 for (i = 0; i < screenInfo.numScreens; i++) {
357 pScreen = screenInfo.screens[i];
358
359 for (p = __glXProviderStack; p != NULL; p = p->next) {
360 __GLXscreen *glxScreen;
361
362 glxScreen = p->screenProbe(pScreen);
363 if (glxScreen != NULL) {
364 if (glxScreen->GLXminor < glxMinorVersion)
365 glxMinorVersion = glxScreen->GLXminor;
366 LogMessage(X_INFO,
367 "GLX: Initialized %s GL provider for screen %d\n",
368 p->name, i);
369 break;
370 }
371
372 }
373
374 if (!p)
375 LogMessage(X_INFO,
376 "GLX: no usable GL providers found for screen %d\n", i);
377 else
378 glx_provided = True;
379 }
380
381 /* don't register extension if GL is not provided on any screen */
382 if (!glx_provided)
383 return;
384
385 /*
386 ** Add extension to server extensions.
387 */
388 extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS,
389 __GLX_NUMBER_ERRORS, __glXDispatch,
390 __glXDispatch, ResetExtension, StandardMinorOpcode);
391 if (!extEntry) {
392 FatalError("__glXExtensionInit: AddExtensions failed\n");
393 return;
394 }
395 if (!AddExtensionAlias(GLX_EXTENSION_ALIAS, extEntry)) {
396 ErrorF("__glXExtensionInit: AddExtensionAlias failed\n");
397 return;
398 }
399
400 __glXErrorBase = extEntry->errorBase;
401 __glXEventBase = extEntry->eventBase;
402#if PRESENT
403 __glXregisterPresentCompleteNotify();
404#endif
405}
406
407/************************************************************************/
408
409void
410__glXFlushContextCache(void)
411{
412 __glXLastContext = 0;
413}
414
415/*
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 *).
420*/
421__GLXcontext *
422__glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error)
423{
424 __GLXcontext *cx;
425
426 /*
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.
429 */
430 cx = __glXLookupContextByTag(cl, tag);
431 if (!cx) {
432 cl->client->errorValue = tag;
433 *error = __glXError(GLXBadContextTag);
434 return 0;
435 }
436
437 if (!cx->isDirect) {
438 if (cx->drawPriv == NULL) {
439 /*
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.
443 */
444 *error = __glXError(GLXBadCurrentWindow);
445 return 0;
446 }
447 }
448
449 if (cx->wait && (*cx->wait) (cx, cl, error))
450 return NULL;
451
452 if (cx == __glXLastContext) {
453 /* No need to re-bind */
454 return cx;
455 }
456
457 /* Make this context the current one for the GL. */
458 if (!cx->isDirect) {
459 if (!(*cx->makeCurrent) (cx)) {
460 /* Bind failed, and set the error code. Bummer */
461 cl->client->errorValue = cx->id;
462 *error = __glXError(GLXBadContextState);
463 return 0;
464 }
465 }
466 __glXLastContext = cx;
467 return cx;
468}
469
470/************************************************************************/
471
472void
473glxSuspendClients(void)
474{
475 int i;
476
477 for (i = 1; i < currentMaxClients; i++) {
478 if (clients[i] && glxGetClient(clients[i])->inUse)
479 IgnoreClient(clients[i]);
480 }
481
482 glxBlockClients = TRUE;
483}
484
485void
486glxResumeClients(void)
487{
488 __GLXcontext *cx, *next;
489 int i;
490
491 glxBlockClients = FALSE;
492
493 for (i = 1; i < currentMaxClients; i++) {
494 if (clients[i] && glxGetClient(clients[i])->inUse)
495 AttendClient(clients[i]);
496 }
497
498 __glXleaveServer(GL_FALSE);
499 for (cx = glxPendingDestroyContexts; cx != NULL; cx = next) {
500 next = cx->next;
501
502 cx->destroy(cx);
503 }
504 glxPendingDestroyContexts = NULL;
505 __glXenterServer(GL_FALSE);
506}
507
508static void
509__glXnopEnterServer(GLboolean rendering)
510{
511}
512
513static void
514__glXnopLeaveServer(GLboolean rendering)
515{
516}
517
518static void (*__glXenterServerFunc) (GLboolean) = __glXnopEnterServer;
519static void (*__glXleaveServerFunc) (GLboolean) = __glXnopLeaveServer;
520
521void
522__glXsetEnterLeaveServerFuncs(void (*enter) (GLboolean),
523 void (*leave) (GLboolean))
524{
525 __glXenterServerFunc = enter;
526 __glXleaveServerFunc = leave;
527}
528
529void
530__glXenterServer(GLboolean rendering)
531{
532 glxServerLeaveCount--;
533
534 if (glxServerLeaveCount == 0)
535 (*__glXenterServerFunc) (rendering);
536}
537
538void
539__glXleaveServer(GLboolean rendering)
540{
541 if (glxServerLeaveCount == 0)
542 (*__glXleaveServerFunc) (rendering);
543
544 glxServerLeaveCount++;
545}
546
547static glx_gpa_proc _get_proc_address;
548
549void
550__glXsetGetProcAddress(glx_gpa_proc get_proc_address)
551{
552 _get_proc_address = get_proc_address;
553}
554
555void *__glGetProcAddress(const char *proc)
556{
557 void *ret = _get_proc_address(proc);
558
559 return ret ? ret : NoopDDA;
560}
561
562/*
563** Top level dispatcher; all commands are executed from here down.
564*/
565static int
566__glXDispatch(ClientPtr client)
567{
568 REQUEST(xGLXSingleReq);
569 CARD8 opcode;
570 __GLXdispatchSingleProcPtr proc;
571 __GLXclientState *cl;
572 int retval;
573
574 opcode = stuff->glxCode;
575 cl = glxGetClient(client);
576 /* Mark it in use so we suspend it on VT switch. */
577 cl->inUse = TRUE;
578
579 /*
580 ** If we're expecting a glXRenderLarge request, this better be one.
581 */
582 if ((cl->largeCmdRequestsSoFar != 0) && (opcode != X_GLXRenderLarge)) {
583 client->errorValue = stuff->glxCode;
584 return __glXError(GLXBadLargeRequest);
585 }
586
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);
591 client->sequence--;
592 IgnoreClient(client);
593 return Success;
594 }
595
596 /*
597 ** Use the opcode to index into the procedure table.
598 */
599 proc = __glXGetProtocolDecodeFunction(&Single_dispatch_info, opcode,
600 client->swapped);
601 if (proc != NULL) {
602 GLboolean rendering = opcode <= X_GLXRenderLarge;
603
604 __glXleaveServer(rendering);
605
606 retval = (*proc) (cl, (GLbyte *) stuff);
607
608 __glXenterServer(rendering);
609 }
610 else {
611 retval = BadRequest;
612 }
613
614 return retval;
615}