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