Commit | Line | Data |
---|---|---|
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_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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
169 | PixmapGone(__GLXpixmap * pGlxPixmap, XID id) | |
170 | { | |
171 | ||
172 | pGlxPixmap->idExists = False; | |
173 | __glXFreeGLXPixmap(pGlxPixmap); | |
174 | ||
175 | return True; | |
176 | } | |
177 | ||
178 | void | |
179 | __glXFreeGLXWindow(__glXWindow * pGlxWindow) | |
180 | { | |
181 | if (!pGlxWindow->idExists && !pGlxWindow->refcnt) { | |
182 | WindowPtr pWindow = (WindowPtr) pGlxWindow->pDraw; | |
183 | WindowPtr ret; | |
184 | ||
185 | dixLookupResourceByType((pointer) &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 | |
197 | WindowGone(__glXWindow * pGlxWindow, XID id) | |
198 | { | |
199 | pGlxWindow->idExists = False; | |
200 | __glXFreeGLXWindow(pGlxWindow); | |
201 | } | |
202 | ||
203 | void | |
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 | |
213 | PbufferGone(__glXPbuffer * pGlxPbuffer, XID id) | |
214 | { | |
215 | pGlxPbuffer->idExists = False; | |
216 | __glXFreeGLXPbuffer(pGlxPbuffer); | |
217 | } | |
218 | ||
219 | /* | |
220 | ** Free a context. | |
221 | */ | |
222 | GLboolean | |
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 | |
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 | 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 | ||
367 | Bool | |
368 | __glXCoreType(void) | |
369 | { | |
370 | return 0; | |
371 | } | |
372 | ||
373 | /************************************************************************/ | |
374 | ||
375 | void | |
376 | __glXFlushContextCache(void) | |
377 | { | |
378 | __glXLastContext = 0; | |
379 | } | |
380 | ||
381 | /************************************************************************/ | |
382 | ||
383 | /* | |
384 | ** Top level dispatcher; all commands are executed from here down. | |
385 | */ | |
386 | static int | |
387 | __glXDispatch(ClientPtr client) | |
388 | { | |
389 | REQUEST(xGLXSingleReq); | |
390 | CARD8 opcode; | |
391 | int (*proc) (__GLXclientState * cl, GLbyte * pc); | |
392 | __GLXclientState *cl; | |
393 | ||
394 | opcode = stuff->glxCode; | |
395 | cl = __glXClients[client->index]; | |
396 | if (!cl) { | |
397 | cl = calloc(1, sizeof(__GLXclientState)); | |
398 | __glXClients[client->index] = cl; | |
399 | if (!cl) { | |
400 | return BadAlloc; | |
401 | } | |
402 | ||
403 | cl->be_displays = calloc(screenInfo.numScreens, sizeof(Display *)); | |
404 | if (!cl->be_displays) { | |
405 | free(cl); | |
406 | return BadAlloc; | |
407 | } | |
408 | } | |
409 | ||
410 | if (!cl->inUse) { | |
411 | /* | |
412 | ** This is first request from this client. Associate a resource | |
413 | ** with the client so we will be notified when the client dies. | |
414 | */ | |
415 | XID xid = FakeClientID(client->index); | |
416 | ||
417 | if (!AddResource(xid, __glXClientRes, (pointer) (long) client->index)) { | |
418 | return BadAlloc; | |
419 | } | |
420 | ResetClientState(client->index); | |
421 | cl->largeCmdRequestsTotal = 0; | |
422 | cl->inUse = GL_TRUE; | |
423 | cl->client = client; | |
424 | } | |
425 | ||
426 | /* | |
427 | ** Check for valid opcode. | |
428 | */ | |
429 | if (opcode >= __GLX_SINGLE_TABLE_SIZE) { | |
430 | return BadRequest; | |
431 | } | |
432 | ||
433 | /* | |
434 | ** Use the opcode to index into the procedure table. | |
435 | */ | |
436 | proc = __glXSingleTable[opcode]; | |
437 | return (*proc) (cl, (GLbyte *) stuff); | |
438 | } | |
439 | ||
440 | static int | |
441 | __glXSwapDispatch(ClientPtr client) | |
442 | { | |
443 | REQUEST(xGLXSingleReq); | |
444 | CARD8 opcode; | |
445 | int (*proc) (__GLXclientState * cl, GLbyte * pc); | |
446 | __GLXclientState *cl; | |
447 | ||
448 | opcode = stuff->glxCode; | |
449 | cl = __glXClients[client->index]; | |
450 | if (!cl) { | |
451 | cl = calloc(1, sizeof(__GLXclientState)); | |
452 | __glXClients[client->index] = cl; | |
453 | if (!cl) { | |
454 | return BadAlloc; | |
455 | } | |
456 | ||
457 | cl->be_displays = calloc(screenInfo.numScreens, sizeof(Display *)); | |
458 | if (!cl->be_displays) { | |
459 | free(cl); | |
460 | return BadAlloc; | |
461 | } | |
462 | } | |
463 | ||
464 | if (!cl->inUse) { | |
465 | /* | |
466 | ** This is first request from this client. Associate a resource | |
467 | ** with the client so we will be notified when the client dies. | |
468 | */ | |
469 | XID xid = FakeClientID(client->index); | |
470 | ||
471 | if (!AddResource(xid, __glXClientRes, (pointer) (long) client->index)) { | |
472 | return BadAlloc; | |
473 | } | |
474 | ResetClientState(client->index); | |
475 | cl->inUse = GL_TRUE; | |
476 | cl->client = client; | |
477 | } | |
478 | ||
479 | /* | |
480 | ** Check for valid opcode. | |
481 | */ | |
482 | if (opcode >= __GLX_SINGLE_TABLE_SIZE) { | |
483 | return BadRequest; | |
484 | } | |
485 | ||
486 | /* | |
487 | ** Use the opcode to index into the procedure table. | |
488 | */ | |
489 | proc = __glXSwapSingleTable[opcode]; | |
490 | return (*proc) (cl, (GLbyte *) stuff); | |
491 | } | |
492 | ||
493 | int | |
494 | __glXNoSuchSingleOpcode(__GLXclientState * cl, GLbyte * pc) | |
495 | { | |
496 | return BadRequest; | |
497 | } | |
498 | ||
499 | void | |
500 | __glXNoSuchRenderOpcode(GLbyte * pc) | |
501 | { | |
502 | return; | |
503 | } |