Imported Upstream version 1.15.1
[deb_xorg-server.git] / glx / glxext.c
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 */
59 RESTYPE __glXContextRes;
60 RESTYPE __glXDrawableRes;
61
62 /*
63 ** Reply for most singles.
64 */
65 xGLXSingleReply __glXReply;
66
67 static DevPrivateKeyRec glxClientPrivateKeyRec;
68
69 #define glxClientPrivateKey (&glxClientPrivateKeyRec)
70
71 /*
72 ** Forward declarations.
73 */
74 static int __glXDispatch(ClientPtr);
75
76 /*
77 ** Called when the extension is reset.
78 */
79 static void
80 ResetExtension(ExtensionEntry * extEntry)
81 {
82 __glXFlushContextCache();
83 }
84
85 /*
86 ** Reset state used to keep track of large (multi-request) commands.
87 */
88 void
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 */
102 static int
103 ContextGone(__GLXcontext * cx, XID id)
104 {
105 cx->idExists = GL_FALSE;
106 if (!cx->currentClient) {
107 __glXFreeContext(cx);
108 }
109
110 return True;
111 }
112
113 static __GLXcontext *glxPendingDestroyContexts;
114 static __GLXcontext *glxAllContexts;
115 static int glxServerLeaveCount;
116 static 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 */
122 static Bool
123 DrawableGone(__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
162 Bool
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
176 static 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 */
196 GLboolean
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
236 static GLboolean errorOccured = GL_FALSE;
237
238 /*
239 ** The GL was will call this routine if an error occurs.
240 */
241 void
242 __glXErrorCallBack(GLenum code)
243 {
244 errorOccured = GL_TRUE;
245 }
246
247 /*
248 ** Clear the error flag before calling the GL command.
249 */
250 void
251 __glXClearErrorOccured(void)
252 {
253 errorOccured = GL_FALSE;
254 }
255
256 /*
257 ** Check if the GL command caused an error.
258 */
259 GLboolean
260 __glXErrorOccured(void)
261 {
262 return errorOccured;
263 }
264
265 static int __glXErrorBase;
266 int __glXEventBase;
267
268 int
269 __glXError(int error)
270 {
271 return __glXErrorBase + error;
272 }
273
274 __GLXclientState *
275 glxGetClient(ClientPtr pClient)
276 {
277 return dixLookupPrivate(&pClient->devPrivates, glxClientPrivateKey);
278 }
279
280 static void
281 glxClientCallback(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
316 static __GLXprovider *__glXProviderStack;
317
318 void
319 GlxPushProvider(__GLXprovider * provider)
320 {
321 provider->next = __glXProviderStack;
322 __glXProviderStack = provider;
323 }
324
325 /*
326 ** Initialize the GLX extension.
327 */
328 void
329 GlxExtensionInit(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
409 void
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
472 void
473 glxSuspendClients(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
485 void
486 glxResumeClients(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
508 static void
509 __glXnopEnterServer(GLboolean rendering)
510 {
511 }
512
513 static void
514 __glXnopLeaveServer(GLboolean rendering)
515 {
516 }
517
518 static void (*__glXenterServerFunc) (GLboolean) = __glXnopEnterServer;
519 static void (*__glXleaveServerFunc) (GLboolean) = __glXnopLeaveServer;
520
521 void
522 __glXsetEnterLeaveServerFuncs(void (*enter) (GLboolean),
523 void (*leave) (GLboolean))
524 {
525 __glXenterServerFunc = enter;
526 __glXleaveServerFunc = leave;
527 }
528
529 void
530 __glXenterServer(GLboolean rendering)
531 {
532 glxServerLeaveCount--;
533
534 if (glxServerLeaveCount == 0)
535 (*__glXenterServerFunc) (rendering);
536 }
537
538 void
539 __glXleaveServer(GLboolean rendering)
540 {
541 if (glxServerLeaveCount == 0)
542 (*__glXleaveServerFunc) (rendering);
543
544 glxServerLeaveCount++;
545 }
546
547 static glx_gpa_proc _get_proc_address;
548
549 void
550 __glXsetGetProcAddress(glx_gpa_proc get_proc_address)
551 {
552 _get_proc_address = get_proc_address;
553 }
554
555 void *__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 */
565 static 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 }