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_DMX_CONFIG_H
32 #include <dmx-config.h>
33 #endif
34 
35 #include "dmx.h"
36 
37 #include "glxserver.h"
38 #include <windowstr.h>
39 #include <propertyst.h>
40 #include <os.h>
41 #include "g_disptab.h"
42 #include "glxutil.h"
43 #include "glxext.h"
44 #include "glxvisuals.h"
45 #include "micmap.h"
46 #include "glxswap.h"
47 #include "extinit.h"
48 #include "glx_extinit.h"
49 
50 /*
51 ** Forward declarations.
52 */
53 static int __glXSwapDispatch(ClientPtr);
54 static int __glXDispatch(ClientPtr);
55 
56 /*
57 ** Called when the extension is reset.
58 */
59 static void
ResetExtension(ExtensionEntry * extEntry)60 ResetExtension(ExtensionEntry * extEntry)
61 {
62     __glXFlushContextCache();
63     __glXScreenReset();
64     SwapBarrierReset();
65 }
66 
67 /*
68 ** Initialize the per-client context storage.
69 */
70 static void
ResetClientState(int clientIndex)71 ResetClientState(int clientIndex)
72 {
73     __GLXclientState *cl = __glXClients[clientIndex];
74     Display **keep_be_displays;
75     int i;
76 
77     free(cl->returnBuf);
78     free(cl->currentContexts);
79     free(cl->currentDrawables);
80     free(cl->largeCmdBuf);
81 
82     for (i = 0; i < screenInfo.numScreens; i++) {
83         if (cl->be_displays[i])
84             XCloseDisplay(cl->be_displays[i]);
85     }
86 
87     keep_be_displays = cl->be_displays;
88     memset(cl, 0, sizeof(__GLXclientState));
89     cl->be_displays = keep_be_displays;
90 
91     free(cl->GLClientextensions);
92 
93     memset(cl->be_displays, 0, screenInfo.numScreens * sizeof(Display *));
94 }
95 
96 /*
97 ** This procedure is called when the client who created the context goes
98 ** away OR when glXDestroyContext is called.  In either case, all we do is
99 ** flag that the ID is no longer valid, and (maybe) free the context.
100 ** use.
101 */
102 static int
ContextGone(__GLXcontext * cx,XID id)103 ContextGone(__GLXcontext * cx, XID id)
104 {
105     cx->idExists = GL_FALSE;
106     if (!cx->isCurrent) {
107         __glXFreeContext(cx);
108     }
109 
110     return True;
111 }
112 
113 /*
114 ** Free a client's state.
115 */
116 static int
ClientGone(int clientIndex,XID id)117 ClientGone(int clientIndex, XID id)
118 {
119     __GLXcontext *cx;
120     __GLXclientState *cl = __glXClients[clientIndex];
121     int i;
122 
123     if (cl) {
124         /*
125          ** Free all the contexts that are current for this client.
126          */
127         for (i = 0; i < cl->numCurrentContexts; i++) {
128             cx = cl->currentContexts[i];
129             if (cx) {
130                 cx->isCurrent = GL_FALSE;
131                 if (!cx->idExists) {
132                     __glXFreeContext(cx);
133                 }
134             }
135         }
136         /*
137          ** Re-initialize the client state structure.  Don't free it because
138          ** we'll probably get another client with this index and use the struct
139          ** again.  There is a maximum of MAXCLIENTS of these structures.
140          */
141         ResetClientState(clientIndex);
142     }
143 
144     return True;
145 }
146 
147 /*
148 ** Free a GLX Pixmap.
149 */
150 void
__glXFreeGLXPixmap(__GLXpixmap * pGlxPixmap)151 __glXFreeGLXPixmap(__GLXpixmap * pGlxPixmap)
152 {
153     if (!pGlxPixmap->idExists && !pGlxPixmap->refcnt) {
154 
155         PixmapPtr pPixmap = (PixmapPtr) pGlxPixmap->pDraw;
156 
157         /*
158          ** The DestroyPixmap routine should decrement the refcount and free
159          ** only if it's zero.
160          */
161         (*pGlxPixmap->pScreen->DestroyPixmap) (pPixmap);
162         free(pGlxPixmap->be_xids);
163         free(pGlxPixmap);
164     }
165 
166 }
167 
168 static int
PixmapGone(__GLXpixmap * pGlxPixmap,XID id)169 PixmapGone(__GLXpixmap * pGlxPixmap, XID id)
170 {
171 
172     pGlxPixmap->idExists = False;
173     __glXFreeGLXPixmap(pGlxPixmap);
174 
175     return True;
176 }
177 
178 void
__glXFreeGLXWindow(__glXWindow * pGlxWindow)179 __glXFreeGLXWindow(__glXWindow * pGlxWindow)
180 {
181     if (!pGlxWindow->idExists && !pGlxWindow->refcnt) {
182         WindowPtr pWindow = (WindowPtr) pGlxWindow->pDraw;
183         WindowPtr ret;
184 
185         dixLookupResourceByType((void *) &ret,
186                                 pWindow->drawable.id, RT_WINDOW,
187                                 NullClient, DixUnknownAccess);
188         if (ret == pWindow) {
189             (*pGlxWindow->pScreen->DestroyWindow) (pWindow);
190         }
191 
192         free(pGlxWindow);
193     }
194 }
195 
196 static void
WindowGone(__glXWindow * pGlxWindow,XID id)197 WindowGone(__glXWindow * pGlxWindow, XID id)
198 {
199     pGlxWindow->idExists = False;
200     __glXFreeGLXWindow(pGlxWindow);
201 }
202 
203 void
__glXFreeGLXPbuffer(__glXPbuffer * pGlxPbuffer)204 __glXFreeGLXPbuffer(__glXPbuffer * pGlxPbuffer)
205 {
206     if (!pGlxPbuffer->idExists && !pGlxPbuffer->refcnt) {
207         free(pGlxPbuffer->be_xids);
208         free(pGlxPbuffer);
209     }
210 }
211 
212 static void
PbufferGone(__glXPbuffer * pGlxPbuffer,XID id)213 PbufferGone(__glXPbuffer * pGlxPbuffer, XID id)
214 {
215     pGlxPbuffer->idExists = False;
216     __glXFreeGLXPbuffer(pGlxPbuffer);
217 }
218 
219 /*
220 ** Free a context.
221 */
222 GLboolean
__glXFreeContext(__GLXcontext * cx)223 __glXFreeContext(__GLXcontext * cx)
224 {
225     if (cx->idExists || cx->isCurrent)
226         return GL_FALSE;
227 
228     free(cx->feedbackBuf);
229     free(cx->selectBuf);
230     free(cx->real_ids);
231     free(cx->real_vids);
232 
233     if (cx->pGlxPixmap) {
234         /*
235          ** The previous drawable was a glx pixmap, release it.
236          */
237         cx->pGlxPixmap->refcnt--;
238         __glXFreeGLXPixmap(cx->pGlxPixmap);
239         cx->pGlxPixmap = 0;
240     }
241 
242     if (cx->pGlxReadPixmap) {
243         /*
244          ** The previous drawable was a glx pixmap, release it.
245          */
246         cx->pGlxReadPixmap->refcnt--;
247         __glXFreeGLXPixmap(cx->pGlxReadPixmap);
248         cx->pGlxReadPixmap = 0;
249     }
250 
251     if (cx->pGlxWindow) {
252         /*
253          ** The previous drawable was a glx window, release it.
254          */
255         cx->pGlxWindow->refcnt--;
256         __glXFreeGLXWindow(cx->pGlxWindow);
257         cx->pGlxWindow = 0;
258     }
259 
260     if (cx->pGlxReadWindow) {
261         /*
262          ** The previous drawable was a glx window, release it.
263          */
264         cx->pGlxReadWindow->refcnt--;
265         __glXFreeGLXWindow(cx->pGlxReadWindow);
266         cx->pGlxReadWindow = 0;
267     }
268 
269     free(cx);
270 
271     if (cx == __glXLastContext) {
272         __glXFlushContextCache();
273     }
274 
275     return GL_TRUE;
276 }
277 
278 /*
279 ** Initialize the GLX extension.
280 */
281 void
GlxExtensionInit(void)282 GlxExtensionInit(void)
283 {
284     ExtensionEntry *extEntry;
285     int i;
286     int glxSupported = 1;
287 
288     /*
289        // do not initialize GLX extension if GLX is not supported
290        // by ALL back-end servers.
291      */
292     for (i = 0; i < screenInfo.numScreens; i++) {
293         glxSupported &= (dmxScreens[i].glxMajorOpcode > 0);
294     }
295 
296     if (!glxSupported || !dmxGLXProxy) {
297         return;
298     }
299 
300     __glXContextRes = CreateNewResourceType((DeleteType) ContextGone,
301                                             "GLXContext");
302     __glXClientRes = CreateNewResourceType((DeleteType) ClientGone,
303                                            "GLXClient");
304     __glXPixmapRes = CreateNewResourceType((DeleteType) PixmapGone,
305                                            "GLXPixmap");
306     __glXWindowRes = CreateNewResourceType((DeleteType) WindowGone,
307                                            "GLXWindow");
308     __glXPbufferRes = CreateNewResourceType((DeleteType) PbufferGone,
309                                             "GLXPbuffer");
310 
311     if (!__glXContextRes || !__glXClientRes || !__glXPixmapRes ||
312         !__glXWindowRes || !__glXPbufferRes)
313         return;
314 
315     /*
316      ** Add extension to server extensions.
317      */
318     extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS,
319                             __GLX_NUMBER_ERRORS, __glXDispatch,
320                             __glXSwapDispatch, ResetExtension,
321                             StandardMinorOpcode);
322     if (!extEntry) {
323         FatalError("__glXExtensionInit: AddExtensions failed\n");
324         return;
325     }
326 
327     __glXerrorBase = extEntry->errorBase;
328     __glXBadContext = extEntry->errorBase + GLXBadContext;
329     __glXBadContextState = extEntry->errorBase + GLXBadContextState;
330     __glXBadDrawable = extEntry->errorBase + GLXBadDrawable;
331     __glXBadPixmap = extEntry->errorBase + GLXBadPixmap;
332     __glXBadContextTag = extEntry->errorBase + GLXBadContextTag;
333     __glXBadCurrentWindow = extEntry->errorBase + GLXBadCurrentWindow;
334     __glXBadRenderRequest = extEntry->errorBase + GLXBadRenderRequest;
335     __glXBadLargeRequest = extEntry->errorBase + GLXBadLargeRequest;
336     __glXUnsupportedPrivateRequest = extEntry->errorBase +
337         GLXUnsupportedPrivateRequest;
338     __glXBadFBConfig = extEntry->errorBase + GLXBadFBConfig;
339     __glXBadPbuffer = extEntry->errorBase + GLXBadPbuffer;
340 
341     /*
342      ** Initialize table of client state.  There is never a client 0.
343      */
344     for (i = 1; i <= LimitClients; i++) {
345         __glXClients[i] = 0;
346     }
347 
348     /*
349      ** Initialize screen specific data.
350      */
351     __glXScreenInit(screenInfo.numScreens);
352 
353     /*
354      ** Initialize swap barrier support.
355      */
356     SwapBarrierInit();
357 }
358 
359 /************************************************************************/
360 
361 Bool
__glXCoreType(void)362 __glXCoreType(void)
363 {
364     return 0;
365 }
366 
367 /************************************************************************/
368 
369 void
__glXFlushContextCache(void)370 __glXFlushContextCache(void)
371 {
372     __glXLastContext = 0;
373 }
374 
375 /************************************************************************/
376 
377 /*
378 ** Top level dispatcher; all commands are executed from here down.
379 */
380 static int
__glXDispatch(ClientPtr client)381 __glXDispatch(ClientPtr client)
382 {
383     REQUEST(xGLXSingleReq);
384     CARD8 opcode;
385     int (*proc) (__GLXclientState * cl, GLbyte * pc);
386     __GLXclientState *cl;
387 
388     opcode = stuff->glxCode;
389     cl = __glXClients[client->index];
390     if (!cl) {
391         cl = calloc(1, sizeof(__GLXclientState));
392         __glXClients[client->index] = cl;
393         if (!cl) {
394             return BadAlloc;
395         }
396 
397         cl->be_displays = calloc(screenInfo.numScreens, sizeof(Display *));
398         if (!cl->be_displays) {
399             free(cl);
400             return BadAlloc;
401         }
402     }
403 
404     if (!cl->inUse) {
405         /*
406          ** This is first request from this client.  Associate a resource
407          ** with the client so we will be notified when the client dies.
408          */
409         XID xid = FakeClientID(client->index);
410 
411         if (!AddResource(xid, __glXClientRes, (void *) (long) client->index)) {
412             return BadAlloc;
413         }
414         ResetClientState(client->index);
415         cl->largeCmdRequestsTotal = 0;
416         cl->inUse = GL_TRUE;
417         cl->client = client;
418     }
419 
420     /*
421      ** Check for valid opcode.
422      */
423     if (opcode >= __GLX_SINGLE_TABLE_SIZE) {
424         return BadRequest;
425     }
426 
427     /*
428      ** Use the opcode to index into the procedure table.
429      */
430     proc = __glXSingleTable[opcode];
431     return (*proc) (cl, (GLbyte *) stuff);
432 }
433 
434 static int
__glXSwapDispatch(ClientPtr client)435 __glXSwapDispatch(ClientPtr client)
436 {
437     REQUEST(xGLXSingleReq);
438     CARD8 opcode;
439     int (*proc) (__GLXclientState * cl, GLbyte * pc);
440     __GLXclientState *cl;
441 
442     opcode = stuff->glxCode;
443     cl = __glXClients[client->index];
444     if (!cl) {
445         cl = calloc(1, sizeof(__GLXclientState));
446         __glXClients[client->index] = cl;
447         if (!cl) {
448             return BadAlloc;
449         }
450 
451         cl->be_displays = calloc(screenInfo.numScreens, sizeof(Display *));
452         if (!cl->be_displays) {
453             free(cl);
454             return BadAlloc;
455         }
456     }
457 
458     if (!cl->inUse) {
459         /*
460          ** This is first request from this client.  Associate a resource
461          ** with the client so we will be notified when the client dies.
462          */
463         XID xid = FakeClientID(client->index);
464 
465         if (!AddResource(xid, __glXClientRes, (void *) (long) client->index)) {
466             return BadAlloc;
467         }
468         ResetClientState(client->index);
469         cl->inUse = GL_TRUE;
470         cl->client = client;
471     }
472 
473     /*
474      ** Check for valid opcode.
475      */
476     if (opcode >= __GLX_SINGLE_TABLE_SIZE) {
477         return BadRequest;
478     }
479 
480     /*
481      ** Use the opcode to index into the procedure table.
482      */
483     proc = __glXSwapSingleTable[opcode];
484     return (*proc) (cl, (GLbyte *) stuff);
485 }
486 
487 int
__glXNoSuchSingleOpcode(__GLXclientState * cl,GLbyte * pc)488 __glXNoSuchSingleOpcode(__GLXclientState * cl, GLbyte * pc)
489 {
490     return BadRequest;
491 }
492 
493 void
__glXNoSuchRenderOpcode(GLbyte * pc)494 __glXNoSuchRenderOpcode(GLbyte * pc)
495 {
496     return;
497 }
498