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_DIX_CONFIG_H | |
32 | #include <dix-config.h> | |
33 | #endif | |
34 | ||
35 | #include <string.h> | |
36 | #include <assert.h> | |
37 | ||
38 | #include "glxserver.h" | |
39 | #include <GL/glxtokens.h> | |
40 | #include <unpack.h> | |
41 | #include <pixmapstr.h> | |
42 | #include <windowstr.h> | |
43 | #include "glxutil.h" | |
44 | #include "glxext.h" | |
45 | #include "indirect_dispatch.h" | |
46 | #include "indirect_table.h" | |
47 | #include "indirect_util.h" | |
48 | ||
49 | static char GLXServerVendorName[] = "SGI"; | |
50 | ||
51 | _X_HIDDEN int | |
52 | validGlxScreen(ClientPtr client, int screen, __GLXscreen ** pGlxScreen, | |
53 | int *err) | |
54 | { | |
55 | /* | |
56 | ** Check if screen exists. | |
57 | */ | |
58 | if (screen < 0 || screen >= screenInfo.numScreens) { | |
59 | client->errorValue = screen; | |
60 | *err = BadValue; | |
61 | return FALSE; | |
62 | } | |
63 | *pGlxScreen = glxGetScreen(screenInfo.screens[screen]); | |
64 | ||
65 | return TRUE; | |
66 | } | |
67 | ||
68 | _X_HIDDEN int | |
69 | validGlxFBConfig(ClientPtr client, __GLXscreen * pGlxScreen, XID id, | |
70 | __GLXconfig ** config, int *err) | |
71 | { | |
72 | __GLXconfig *m; | |
73 | ||
74 | for (m = pGlxScreen->fbconfigs; m != NULL; m = m->next) | |
75 | if (m->fbconfigID == id) { | |
76 | *config = m; | |
77 | return TRUE; | |
78 | } | |
79 | ||
80 | client->errorValue = id; | |
81 | *err = __glXError(GLXBadFBConfig); | |
82 | ||
83 | return FALSE; | |
84 | } | |
85 | ||
86 | static int | |
87 | validGlxVisual(ClientPtr client, __GLXscreen * pGlxScreen, XID id, | |
88 | __GLXconfig ** config, int *err) | |
89 | { | |
90 | int i; | |
91 | ||
92 | for (i = 0; i < pGlxScreen->numVisuals; i++) | |
93 | if (pGlxScreen->visuals[i]->visualID == id) { | |
94 | *config = pGlxScreen->visuals[i]; | |
95 | return TRUE; | |
96 | } | |
97 | ||
98 | client->errorValue = id; | |
99 | *err = BadValue; | |
100 | ||
101 | return FALSE; | |
102 | } | |
103 | ||
104 | static int | |
105 | validGlxFBConfigForWindow(ClientPtr client, __GLXconfig * config, | |
106 | DrawablePtr pDraw, int *err) | |
107 | { | |
108 | ScreenPtr pScreen = pDraw->pScreen; | |
109 | VisualPtr pVisual = NULL; | |
110 | XID vid; | |
111 | int i; | |
112 | ||
113 | vid = wVisual((WindowPtr) pDraw); | |
114 | for (i = 0; i < pScreen->numVisuals; i++) { | |
115 | if (pScreen->visuals[i].vid == vid) { | |
116 | pVisual = &pScreen->visuals[i]; | |
117 | break; | |
118 | } | |
119 | } | |
120 | ||
121 | /* FIXME: What exactly should we check here... */ | |
122 | if (pVisual->class != glxConvertToXVisualType(config->visualType) || | |
123 | !(config->drawableType & GLX_WINDOW_BIT)) { | |
124 | client->errorValue = pDraw->id; | |
125 | *err = BadMatch; | |
126 | return FALSE; | |
127 | } | |
128 | ||
129 | return TRUE; | |
130 | } | |
131 | ||
132 | _X_HIDDEN int | |
133 | validGlxContext(ClientPtr client, XID id, int access_mode, | |
134 | __GLXcontext ** context, int *err) | |
135 | { | |
136 | *err = dixLookupResourceByType((pointer *) context, id, | |
137 | __glXContextRes, client, access_mode); | |
138 | if (*err != Success || (*context)->idExists == GL_FALSE) { | |
139 | client->errorValue = id; | |
140 | if (*err == BadValue || *err == Success) | |
141 | *err = __glXError(GLXBadContext); | |
142 | return FALSE; | |
143 | } | |
144 | ||
145 | return TRUE; | |
146 | } | |
147 | ||
148 | static int | |
149 | validGlxDrawable(ClientPtr client, XID id, int type, int access_mode, | |
150 | __GLXdrawable ** drawable, int *err) | |
151 | { | |
152 | int rc; | |
153 | ||
154 | rc = dixLookupResourceByType((pointer *) drawable, id, | |
155 | __glXDrawableRes, client, access_mode); | |
156 | if (rc != Success && rc != BadValue) { | |
157 | *err = rc; | |
158 | client->errorValue = id; | |
159 | return FALSE; | |
160 | } | |
161 | ||
162 | /* If the ID of the glx drawable we looked up doesn't match the id | |
163 | * we looked for, it's because we looked it up under the X | |
164 | * drawable ID (see DoCreateGLXDrawable). */ | |
165 | if (rc == BadValue || | |
166 | (*drawable)->drawId != id || | |
167 | (type != GLX_DRAWABLE_ANY && type != (*drawable)->type)) { | |
168 | client->errorValue = id; | |
169 | switch (type) { | |
170 | case GLX_DRAWABLE_WINDOW: | |
171 | *err = __glXError(GLXBadWindow); | |
172 | return FALSE; | |
173 | case GLX_DRAWABLE_PIXMAP: | |
174 | *err = __glXError(GLXBadPixmap); | |
175 | return FALSE; | |
176 | case GLX_DRAWABLE_PBUFFER: | |
177 | *err = __glXError(GLXBadPbuffer); | |
178 | return FALSE; | |
179 | case GLX_DRAWABLE_ANY: | |
180 | *err = __glXError(GLXBadDrawable); | |
181 | return FALSE; | |
182 | } | |
183 | } | |
184 | ||
185 | return TRUE; | |
186 | } | |
187 | ||
188 | void | |
189 | __glXContextDestroy(__GLXcontext * context) | |
190 | { | |
191 | __glXFlushContextCache(); | |
192 | } | |
193 | ||
194 | static void | |
195 | __glXdirectContextDestroy(__GLXcontext * context) | |
196 | { | |
197 | __glXContextDestroy(context); | |
198 | free(context); | |
199 | } | |
200 | ||
201 | _X_HIDDEN __GLXcontext * | |
202 | __glXdirectContextCreate(__GLXscreen * screen, | |
203 | __GLXconfig * modes, __GLXcontext * shareContext) | |
204 | { | |
205 | __GLXcontext *context; | |
206 | ||
207 | context = calloc(1, sizeof(__GLXcontext)); | |
208 | if (context == NULL) | |
209 | return NULL; | |
210 | ||
211 | context->destroy = __glXdirectContextDestroy; | |
212 | ||
213 | return context; | |
214 | } | |
215 | ||
216 | /** | |
217 | * Create a GL context with the given properties. This routine is used | |
218 | * to implement \c glXCreateContext, \c glXCreateNewContext, and | |
219 | * \c glXCreateContextWithConfigSGIX. This works becuase of the hack way | |
220 | * that GLXFBConfigs are implemented. Basically, the FBConfigID is the | |
221 | * same as the VisualID. | |
222 | */ | |
223 | ||
224 | static int | |
225 | DoCreateContext(__GLXclientState * cl, GLXContextID gcId, | |
226 | GLXContextID shareList, __GLXconfig * config, | |
227 | __GLXscreen * pGlxScreen, GLboolean isDirect) | |
228 | { | |
229 | ClientPtr client = cl->client; | |
230 | __GLXcontext *glxc, *shareglxc; | |
231 | int err; | |
232 | ||
233 | LEGAL_NEW_RESOURCE(gcId, client); | |
234 | ||
235 | /* | |
236 | ** Find the display list space that we want to share. | |
237 | ** | |
238 | ** NOTE: In a multithreaded X server, we would need to keep a reference | |
239 | ** count for each display list so that if one client detroyed a list that | |
240 | ** another client was using, the list would not really be freed until it | |
241 | ** was no longer in use. Since this sample implementation has no support | |
242 | ** for multithreaded servers, we don't do this. | |
243 | */ | |
244 | if (shareList == None) { | |
245 | shareglxc = 0; | |
246 | } | |
247 | else { | |
248 | if (!validGlxContext(client, shareList, DixReadAccess, | |
249 | &shareglxc, &err)) | |
250 | return err; | |
251 | ||
252 | /* Page 26 (page 32 of the PDF) of the GLX 1.4 spec says: | |
253 | * | |
254 | * "The server context state for all sharing contexts must exist | |
255 | * in a single address space or a BadMatch error is generated." | |
256 | * | |
257 | * If the share context is indirect, force the new context to also be | |
258 | * indirect. If the shard context is direct but the new context | |
259 | * cannot be direct, generate BadMatch. | |
260 | */ | |
261 | if (shareglxc->isDirect && !isDirect) { | |
262 | client->errorValue = shareList; | |
263 | return BadMatch; | |
264 | } | |
265 | else if (!shareglxc->isDirect) { | |
266 | /* | |
267 | ** Create an indirect context regardless of what the client asked | |
268 | ** for; this way we can share display list space with shareList. | |
269 | */ | |
270 | isDirect = GL_FALSE; | |
271 | } | |
272 | } | |
273 | ||
274 | /* | |
275 | ** Allocate memory for the new context | |
276 | */ | |
277 | if (!isDirect) { | |
278 | /* Without any attributes, the only error that the driver should be | |
279 | * able to generate is BadAlloc. As result, just drop the error | |
280 | * returned from the driver on the floor. | |
281 | */ | |
282 | glxc = pGlxScreen->createContext(pGlxScreen, config, shareglxc, | |
283 | 0, NULL, &err); | |
284 | } | |
285 | else | |
286 | glxc = __glXdirectContextCreate(pGlxScreen, config, shareglxc); | |
287 | if (!glxc) { | |
288 | return BadAlloc; | |
289 | } | |
290 | ||
291 | /* Initialize the GLXcontext structure. | |
292 | */ | |
293 | glxc->pGlxScreen = pGlxScreen; | |
294 | glxc->config = config; | |
295 | glxc->id = gcId; | |
296 | glxc->share_id = shareList; | |
297 | glxc->idExists = GL_TRUE; | |
298 | glxc->currentClient = NULL; | |
299 | glxc->isDirect = isDirect; | |
300 | glxc->hasUnflushedCommands = GL_FALSE; | |
301 | glxc->renderMode = GL_RENDER; | |
302 | glxc->feedbackBuf = NULL; | |
303 | glxc->feedbackBufSize = 0; | |
304 | glxc->selectBuf = NULL; | |
305 | glxc->selectBufSize = 0; | |
306 | glxc->drawPriv = NULL; | |
307 | glxc->readPriv = NULL; | |
308 | ||
309 | /* The GLX_ARB_create_context_robustness spec says: | |
310 | * | |
311 | * "The default value for GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB | |
312 | * is GLX_NO_RESET_NOTIFICATION_ARB." | |
313 | * | |
314 | * Without using glXCreateContextAttribsARB, there is no way to specify a | |
315 | * non-default reset notification strategy. | |
316 | */ | |
317 | glxc->resetNotificationStrategy = GLX_NO_RESET_NOTIFICATION_ARB; | |
318 | ||
319 | /* Add the new context to the various global tables of GLX contexts. | |
320 | */ | |
321 | if (!__glXAddContext(glxc)) { | |
322 | (*glxc->destroy) (glxc); | |
323 | client->errorValue = gcId; | |
324 | return BadAlloc; | |
325 | } | |
326 | ||
327 | return Success; | |
328 | } | |
329 | ||
330 | int | |
331 | __glXDisp_CreateContext(__GLXclientState * cl, GLbyte * pc) | |
332 | { | |
333 | ClientPtr client = cl->client; | |
334 | xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc; | |
335 | __GLXconfig *config; | |
336 | __GLXscreen *pGlxScreen; | |
337 | int err; | |
338 | ||
339 | REQUEST_SIZE_MATCH(xGLXCreateContextReq); | |
340 | ||
341 | if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) | |
342 | return err; | |
343 | if (!validGlxVisual(cl->client, pGlxScreen, req->visual, &config, &err)) | |
344 | return err; | |
345 | ||
346 | return DoCreateContext(cl, req->context, req->shareList, | |
347 | config, pGlxScreen, req->isDirect); | |
348 | } | |
349 | ||
350 | int | |
351 | __glXDisp_CreateNewContext(__GLXclientState * cl, GLbyte * pc) | |
352 | { | |
353 | ClientPtr client = cl->client; | |
354 | xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc; | |
355 | __GLXconfig *config; | |
356 | __GLXscreen *pGlxScreen; | |
357 | int err; | |
358 | ||
359 | REQUEST_SIZE_MATCH(xGLXCreateNewContextReq); | |
360 | ||
361 | if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) | |
362 | return err; | |
363 | if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err)) | |
364 | return err; | |
365 | ||
366 | return DoCreateContext(cl, req->context, req->shareList, | |
367 | config, pGlxScreen, req->isDirect); | |
368 | } | |
369 | ||
370 | int | |
371 | __glXDisp_CreateContextWithConfigSGIX(__GLXclientState * cl, GLbyte * pc) | |
372 | { | |
373 | ClientPtr client = cl->client; | |
374 | xGLXCreateContextWithConfigSGIXReq *req = | |
375 | (xGLXCreateContextWithConfigSGIXReq *) pc; | |
376 | __GLXconfig *config; | |
377 | __GLXscreen *pGlxScreen; | |
378 | int err; | |
379 | ||
380 | REQUEST_SIZE_MATCH(xGLXCreateContextWithConfigSGIXReq); | |
381 | ||
382 | if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) | |
383 | return err; | |
384 | if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err)) | |
385 | return err; | |
386 | ||
387 | return DoCreateContext(cl, req->context, req->shareList, | |
388 | config, pGlxScreen, req->isDirect); | |
389 | } | |
390 | ||
391 | int | |
392 | __glXDisp_DestroyContext(__GLXclientState * cl, GLbyte * pc) | |
393 | { | |
394 | ClientPtr client = cl->client; | |
395 | xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc; | |
396 | __GLXcontext *glxc; | |
397 | int err; | |
398 | ||
399 | REQUEST_SIZE_MATCH(xGLXDestroyContextReq); | |
400 | ||
401 | if (!validGlxContext(cl->client, req->context, DixDestroyAccess, | |
402 | &glxc, &err)) | |
403 | return err; | |
404 | ||
405 | FreeResourceByType(req->context, __glXContextRes, FALSE); | |
406 | ||
407 | return Success; | |
408 | } | |
409 | ||
410 | /* | |
411 | * This will return "deleted" contexts, ie, where idExists is GL_FALSE. | |
412 | * Contrast validGlxContext, which will not. We're cheating here and | |
413 | * using the XID as the context tag, which is fine as long as we defer | |
414 | * actually destroying the context until it's no longer referenced, and | |
415 | * block clients from trying to MakeCurrent on contexts that are on the | |
416 | * way to destruction. Notice that DoMakeCurrent calls validGlxContext | |
417 | * for new contexts but __glXLookupContextByTag for previous contexts. | |
418 | */ | |
419 | __GLXcontext * | |
420 | __glXLookupContextByTag(__GLXclientState * cl, GLXContextTag tag) | |
421 | { | |
422 | __GLXcontext *ret; | |
423 | ||
424 | if (dixLookupResourceByType((void **) &ret, tag, __glXContextRes, | |
425 | cl->client, DixUseAccess) == Success) | |
426 | return ret; | |
427 | ||
428 | return NULL; | |
429 | } | |
430 | ||
431 | /*****************************************************************************/ | |
432 | ||
433 | static void | |
434 | StopUsingContext(__GLXcontext * glxc) | |
435 | { | |
436 | if (glxc) { | |
437 | if (glxc == __glXLastContext) { | |
438 | /* Tell server GL library */ | |
439 | __glXLastContext = 0; | |
440 | } | |
441 | glxc->currentClient = NULL; | |
442 | if (!glxc->idExists) { | |
443 | FreeResourceByType(glxc->id, __glXContextRes, FALSE); | |
444 | } | |
445 | } | |
446 | } | |
447 | ||
448 | static void | |
449 | StartUsingContext(__GLXclientState * cl, __GLXcontext * glxc) | |
450 | { | |
451 | __glXLastContext = glxc; | |
452 | glxc->currentClient = cl->client; | |
453 | } | |
454 | ||
455 | /** | |
456 | * This is a helper function to handle the legacy (pre GLX 1.3) cases | |
457 | * where passing an X window to glXMakeCurrent is valid. Given a | |
458 | * resource ID, look up the GLX drawable if available, otherwise, make | |
459 | * sure it's an X window and create a GLX drawable one the fly. | |
460 | */ | |
461 | static __GLXdrawable * | |
462 | __glXGetDrawable(__GLXcontext * glxc, GLXDrawable drawId, ClientPtr client, | |
463 | int *error) | |
464 | { | |
465 | DrawablePtr pDraw; | |
466 | __GLXdrawable *pGlxDraw; | |
467 | int rc; | |
468 | ||
469 | if (validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY, | |
470 | DixWriteAccess, &pGlxDraw, &rc)) { | |
471 | if (glxc != NULL && pGlxDraw->config != glxc->config) { | |
472 | client->errorValue = drawId; | |
473 | *error = BadMatch; | |
474 | return NULL; | |
475 | } | |
476 | ||
477 | return pGlxDraw; | |
478 | } | |
479 | ||
480 | /* No active context and an unknown drawable, bail. */ | |
481 | if (glxc == NULL) { | |
482 | client->errorValue = drawId; | |
483 | *error = BadMatch; | |
484 | return NULL; | |
485 | } | |
486 | ||
487 | /* The drawId wasn't a GLX drawable. Make sure it's a window and | |
488 | * create a GLXWindow for it. Check that the drawable screen | |
489 | * matches the context screen and that the context fbconfig is | |
490 | * compatible with the window visual. */ | |
491 | ||
492 | rc = dixLookupDrawable(&pDraw, drawId, client, 0, DixGetAttrAccess); | |
493 | if (rc != Success || pDraw->type != DRAWABLE_WINDOW) { | |
494 | client->errorValue = drawId; | |
495 | *error = __glXError(GLXBadDrawable); | |
496 | return NULL; | |
497 | } | |
498 | ||
499 | if (pDraw->pScreen != glxc->pGlxScreen->pScreen) { | |
500 | client->errorValue = pDraw->pScreen->myNum; | |
501 | *error = BadMatch; | |
502 | return NULL; | |
503 | } | |
504 | ||
505 | if (!validGlxFBConfigForWindow(client, glxc->config, pDraw, error)) | |
506 | return NULL; | |
507 | ||
508 | pGlxDraw = glxc->pGlxScreen->createDrawable(client, glxc->pGlxScreen, | |
509 | pDraw, drawId, | |
510 | GLX_DRAWABLE_WINDOW, | |
511 | drawId, glxc->config); | |
512 | if (!pGlxDraw) { | |
513 | *error = BadAlloc; | |
514 | return NULL; | |
515 | } | |
516 | ||
517 | /* since we are creating the drawablePrivate, drawId should be new */ | |
518 | if (!AddResource(drawId, __glXDrawableRes, pGlxDraw)) { | |
519 | pGlxDraw->destroy(pGlxDraw); | |
520 | *error = BadAlloc; | |
521 | return NULL; | |
522 | } | |
523 | ||
524 | return pGlxDraw; | |
525 | } | |
526 | ||
527 | /*****************************************************************************/ | |
528 | /* | |
529 | ** Make an OpenGL context and drawable current. | |
530 | */ | |
531 | ||
532 | static int | |
533 | DoMakeCurrent(__GLXclientState * cl, | |
534 | GLXDrawable drawId, GLXDrawable readId, | |
535 | GLXContextID contextId, GLXContextTag tag) | |
536 | { | |
537 | ClientPtr client = cl->client; | |
538 | xGLXMakeCurrentReply reply; | |
539 | __GLXcontext *glxc, *prevglxc; | |
540 | __GLXdrawable *drawPriv = NULL; | |
541 | __GLXdrawable *readPriv = NULL; | |
542 | int error; | |
543 | GLuint mask; | |
544 | ||
545 | /* | |
546 | ** If one is None and the other isn't, it's a bad match. | |
547 | */ | |
548 | ||
549 | mask = (drawId == None) ? (1 << 0) : 0; | |
550 | mask |= (readId == None) ? (1 << 1) : 0; | |
551 | mask |= (contextId == None) ? (1 << 2) : 0; | |
552 | ||
553 | if ((mask != 0x00) && (mask != 0x07)) { | |
554 | return BadMatch; | |
555 | } | |
556 | ||
557 | /* | |
558 | ** Lookup old context. If we have one, it must be in a usable state. | |
559 | */ | |
560 | if (tag != 0) { | |
561 | prevglxc = __glXLookupContextByTag(cl, tag); | |
562 | if (!prevglxc) { | |
563 | /* | |
564 | ** Tag for previous context is invalid. | |
565 | */ | |
566 | return __glXError(GLXBadContextTag); | |
567 | } | |
568 | if (prevglxc->renderMode != GL_RENDER) { | |
569 | /* Oops. Not in render mode render. */ | |
570 | client->errorValue = prevglxc->id; | |
571 | return __glXError(GLXBadContextState); | |
572 | } | |
573 | } | |
574 | else { | |
575 | prevglxc = 0; | |
576 | } | |
577 | ||
578 | /* | |
579 | ** Lookup new context. It must not be current for someone else. | |
580 | */ | |
581 | if (contextId != None) { | |
582 | int status; | |
583 | ||
584 | if (!validGlxContext(client, contextId, DixUseAccess, &glxc, &error)) | |
585 | return error; | |
586 | if ((glxc != prevglxc) && glxc->currentClient) { | |
587 | /* Context is current to somebody else */ | |
588 | return BadAccess; | |
589 | } | |
590 | ||
591 | assert(drawId != None); | |
592 | assert(readId != None); | |
593 | ||
594 | drawPriv = __glXGetDrawable(glxc, drawId, client, &status); | |
595 | if (drawPriv == NULL) | |
596 | return status; | |
597 | ||
598 | readPriv = __glXGetDrawable(glxc, readId, client, &status); | |
599 | if (readPriv == NULL) | |
600 | return status; | |
601 | ||
602 | } | |
603 | else { | |
604 | /* Switching to no context. Ignore new drawable. */ | |
605 | glxc = 0; | |
606 | drawPriv = 0; | |
607 | readPriv = 0; | |
608 | } | |
609 | ||
610 | if (prevglxc) { | |
611 | /* | |
612 | ** Flush the previous context if needed. | |
613 | */ | |
614 | if (prevglxc->hasUnflushedCommands) { | |
615 | if (__glXForceCurrent(cl, tag, (int *) &error)) { | |
616 | glFlush(); | |
617 | prevglxc->hasUnflushedCommands = GL_FALSE; | |
618 | } | |
619 | else { | |
620 | return error; | |
621 | } | |
622 | } | |
623 | ||
624 | /* | |
625 | ** Make the previous context not current. | |
626 | */ | |
627 | if (!(*prevglxc->loseCurrent) (prevglxc)) { | |
628 | return __glXError(GLXBadContext); | |
629 | } | |
630 | __glXFlushContextCache(); | |
631 | if (!prevglxc->isDirect) { | |
632 | prevglxc->drawPriv = NULL; | |
633 | prevglxc->readPriv = NULL; | |
634 | } | |
635 | } | |
636 | ||
637 | if ((glxc != 0) && !glxc->isDirect) { | |
638 | ||
639 | glxc->drawPriv = drawPriv; | |
640 | glxc->readPriv = readPriv; | |
641 | ||
642 | /* make the context current */ | |
643 | if (!(*glxc->makeCurrent) (glxc)) { | |
644 | glxc->drawPriv = NULL; | |
645 | glxc->readPriv = NULL; | |
646 | return __glXError(GLXBadContext); | |
647 | } | |
648 | ||
649 | glxc->currentClient = client; | |
650 | } | |
651 | ||
652 | StopUsingContext(prevglxc); | |
653 | ||
654 | reply = (xGLXMakeCurrentReply) { | |
655 | .type = X_Reply, | |
656 | .sequenceNumber = client->sequence, | |
657 | .length = 0, | |
658 | .contextTag = 0 | |
659 | }; | |
660 | ||
661 | if (glxc) { | |
662 | StartUsingContext(cl, glxc); | |
663 | reply.contextTag = glxc->id; | |
664 | } | |
665 | ||
666 | if (client->swapped) { | |
667 | __glXSwapMakeCurrentReply(client, &reply); | |
668 | } | |
669 | else { | |
670 | WriteToClient(client, sz_xGLXMakeCurrentReply, &reply); | |
671 | } | |
672 | return Success; | |
673 | } | |
674 | ||
675 | int | |
676 | __glXDisp_MakeCurrent(__GLXclientState * cl, GLbyte * pc) | |
677 | { | |
678 | ClientPtr client = cl->client; | |
679 | xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc; | |
680 | ||
681 | REQUEST_SIZE_MATCH(xGLXMakeCurrentReq); | |
682 | ||
683 | return DoMakeCurrent(cl, req->drawable, req->drawable, | |
684 | req->context, req->oldContextTag); | |
685 | } | |
686 | ||
687 | int | |
688 | __glXDisp_MakeContextCurrent(__GLXclientState * cl, GLbyte * pc) | |
689 | { | |
690 | ClientPtr client = cl->client; | |
691 | xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) pc; | |
692 | ||
693 | REQUEST_SIZE_MATCH(xGLXMakeContextCurrentReq); | |
694 | ||
695 | return DoMakeCurrent(cl, req->drawable, req->readdrawable, | |
696 | req->context, req->oldContextTag); | |
697 | } | |
698 | ||
699 | int | |
700 | __glXDisp_MakeCurrentReadSGI(__GLXclientState * cl, GLbyte * pc) | |
701 | { | |
702 | ClientPtr client = cl->client; | |
703 | xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) pc; | |
704 | ||
705 | REQUEST_SIZE_MATCH(xGLXMakeCurrentReadSGIReq); | |
706 | ||
707 | return DoMakeCurrent(cl, req->drawable, req->readable, | |
708 | req->context, req->oldContextTag); | |
709 | } | |
710 | ||
711 | int | |
712 | __glXDisp_IsDirect(__GLXclientState * cl, GLbyte * pc) | |
713 | { | |
714 | ClientPtr client = cl->client; | |
715 | xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc; | |
716 | xGLXIsDirectReply reply; | |
717 | __GLXcontext *glxc; | |
718 | int err; | |
719 | ||
720 | REQUEST_SIZE_MATCH(xGLXIsDirectReq); | |
721 | ||
722 | if (!validGlxContext(cl->client, req->context, DixReadAccess, &glxc, &err)) | |
723 | return err; | |
724 | ||
725 | reply = (xGLXIsDirectReply) { | |
726 | .type = X_Reply, | |
727 | .sequenceNumber = client->sequence, | |
728 | .length = 0, | |
729 | .isDirect = glxc->isDirect | |
730 | }; | |
731 | ||
732 | if (client->swapped) { | |
733 | __glXSwapIsDirectReply(client, &reply); | |
734 | } | |
735 | else { | |
736 | WriteToClient(client, sz_xGLXIsDirectReply, &reply); | |
737 | } | |
738 | ||
739 | return Success; | |
740 | } | |
741 | ||
742 | int | |
743 | __glXDisp_QueryVersion(__GLXclientState * cl, GLbyte * pc) | |
744 | { | |
745 | ClientPtr client = cl->client; | |
746 | xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc; | |
747 | xGLXQueryVersionReply reply; | |
748 | GLuint major, minor; | |
749 | ||
750 | REQUEST_SIZE_MATCH(xGLXQueryVersionReq); | |
751 | ||
752 | major = req->majorVersion; | |
753 | minor = req->minorVersion; | |
754 | (void) major; | |
755 | (void) minor; | |
756 | ||
757 | /* | |
758 | ** Server should take into consideration the version numbers sent by the | |
759 | ** client if it wants to work with older clients; however, in this | |
760 | ** implementation the server just returns its version number. | |
761 | */ | |
762 | reply = (xGLXQueryVersionReply) { | |
763 | .type = X_Reply, | |
764 | .sequenceNumber = client->sequence, | |
765 | .length = 0, | |
766 | .majorVersion = glxMajorVersion, | |
767 | .minorVersion = glxMinorVersion | |
768 | }; | |
769 | ||
770 | if (client->swapped) { | |
771 | __glXSwapQueryVersionReply(client, &reply); | |
772 | } | |
773 | else { | |
774 | WriteToClient(client, sz_xGLXQueryVersionReply, &reply); | |
775 | } | |
776 | return Success; | |
777 | } | |
778 | ||
779 | int | |
780 | __glXDisp_WaitGL(__GLXclientState * cl, GLbyte * pc) | |
781 | { | |
782 | ClientPtr client = cl->client; | |
783 | xGLXWaitGLReq *req = (xGLXWaitGLReq *) pc; | |
784 | GLXContextTag tag; | |
785 | __GLXcontext *glxc = NULL; | |
786 | int error; | |
787 | ||
788 | REQUEST_SIZE_MATCH(xGLXWaitGLReq); | |
789 | ||
790 | tag = req->contextTag; | |
791 | if (tag) { | |
792 | glxc = __glXLookupContextByTag(cl, tag); | |
793 | if (!glxc) | |
794 | return __glXError(GLXBadContextTag); | |
795 | ||
796 | if (!__glXForceCurrent(cl, req->contextTag, &error)) | |
797 | return error; | |
798 | ||
799 | glFinish(); | |
800 | } | |
801 | ||
802 | if (glxc && glxc->drawPriv->waitGL) | |
803 | (*glxc->drawPriv->waitGL) (glxc->drawPriv); | |
804 | ||
805 | return Success; | |
806 | } | |
807 | ||
808 | int | |
809 | __glXDisp_WaitX(__GLXclientState * cl, GLbyte * pc) | |
810 | { | |
811 | ClientPtr client = cl->client; | |
812 | xGLXWaitXReq *req = (xGLXWaitXReq *) pc; | |
813 | GLXContextTag tag; | |
814 | __GLXcontext *glxc = NULL; | |
815 | int error; | |
816 | ||
817 | REQUEST_SIZE_MATCH(xGLXWaitXReq); | |
818 | ||
819 | tag = req->contextTag; | |
820 | if (tag) { | |
821 | glxc = __glXLookupContextByTag(cl, tag); | |
822 | if (!glxc) | |
823 | return __glXError(GLXBadContextTag); | |
824 | ||
825 | if (!__glXForceCurrent(cl, req->contextTag, &error)) | |
826 | return error; | |
827 | } | |
828 | ||
829 | if (glxc && glxc->drawPriv->waitX) | |
830 | (*glxc->drawPriv->waitX) (glxc->drawPriv); | |
831 | ||
832 | return Success; | |
833 | } | |
834 | ||
835 | int | |
836 | __glXDisp_CopyContext(__GLXclientState * cl, GLbyte * pc) | |
837 | { | |
838 | ClientPtr client = cl->client; | |
839 | xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc; | |
840 | GLXContextID source; | |
841 | GLXContextID dest; | |
842 | GLXContextTag tag; | |
843 | unsigned long mask; | |
844 | __GLXcontext *src, *dst; | |
845 | int error; | |
846 | ||
847 | REQUEST_SIZE_MATCH(xGLXCopyContextReq); | |
848 | ||
849 | source = req->source; | |
850 | dest = req->dest; | |
851 | tag = req->contextTag; | |
852 | mask = req->mask; | |
853 | if (!validGlxContext(cl->client, source, DixReadAccess, &src, &error)) | |
854 | return error; | |
855 | if (!validGlxContext(cl->client, dest, DixWriteAccess, &dst, &error)) | |
856 | return error; | |
857 | ||
858 | /* | |
859 | ** They must be in the same address space, and same screen. | |
860 | ** NOTE: no support for direct rendering contexts here. | |
861 | */ | |
862 | if (src->isDirect || dst->isDirect || (src->pGlxScreen != dst->pGlxScreen)) { | |
863 | client->errorValue = source; | |
864 | return BadMatch; | |
865 | } | |
866 | ||
867 | /* | |
868 | ** The destination context must not be current for any client. | |
869 | */ | |
870 | if (dst->currentClient) { | |
871 | client->errorValue = dest; | |
872 | return BadAccess; | |
873 | } | |
874 | ||
875 | if (tag) { | |
876 | __GLXcontext *tagcx = __glXLookupContextByTag(cl, tag); | |
877 | ||
878 | if (!tagcx) { | |
879 | return __glXError(GLXBadContextTag); | |
880 | } | |
881 | if (tagcx != src) { | |
882 | /* | |
883 | ** This would be caused by a faulty implementation of the client | |
884 | ** library. | |
885 | */ | |
886 | return BadMatch; | |
887 | } | |
888 | /* | |
889 | ** In this case, glXCopyContext is in both GL and X streams, in terms | |
890 | ** of sequentiality. | |
891 | */ | |
892 | if (__glXForceCurrent(cl, tag, &error)) { | |
893 | /* | |
894 | ** Do whatever is needed to make sure that all preceding requests | |
895 | ** in both streams are completed before the copy is executed. | |
896 | */ | |
897 | glFinish(); | |
898 | tagcx->hasUnflushedCommands = GL_FALSE; | |
899 | } | |
900 | else { | |
901 | return error; | |
902 | } | |
903 | } | |
904 | /* | |
905 | ** Issue copy. The only reason for failure is a bad mask. | |
906 | */ | |
907 | if (!(*dst->copy) (dst, src, mask)) { | |
908 | client->errorValue = mask; | |
909 | return BadValue; | |
910 | } | |
911 | return Success; | |
912 | } | |
913 | ||
914 | enum { | |
915 | GLX_VIS_CONFIG_UNPAIRED = 18, | |
916 | GLX_VIS_CONFIG_PAIRED = 22 | |
917 | }; | |
918 | ||
919 | enum { | |
920 | GLX_VIS_CONFIG_TOTAL = GLX_VIS_CONFIG_UNPAIRED + GLX_VIS_CONFIG_PAIRED | |
921 | }; | |
922 | ||
923 | int | |
924 | __glXDisp_GetVisualConfigs(__GLXclientState * cl, GLbyte * pc) | |
925 | { | |
926 | xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) pc; | |
927 | ClientPtr client = cl->client; | |
928 | xGLXGetVisualConfigsReply reply; | |
929 | __GLXscreen *pGlxScreen; | |
930 | __GLXconfig *modes; | |
931 | CARD32 buf[GLX_VIS_CONFIG_TOTAL]; | |
932 | int p, i, err; | |
933 | ||
934 | __GLX_DECLARE_SWAP_VARIABLES; | |
935 | __GLX_DECLARE_SWAP_ARRAY_VARIABLES; | |
936 | ||
937 | REQUEST_SIZE_MATCH(xGLXGetVisualConfigsReq); | |
938 | ||
939 | if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) | |
940 | return err; | |
941 | ||
942 | reply = (xGLXGetVisualConfigsReply) { | |
943 | .type = X_Reply, | |
944 | .sequenceNumber = client->sequence, | |
945 | .length = (pGlxScreen->numVisuals * | |
946 | __GLX_SIZE_CARD32 * GLX_VIS_CONFIG_TOTAL) >> 2, | |
947 | .numVisuals = pGlxScreen->numVisuals, | |
948 | .numProps = GLX_VIS_CONFIG_TOTAL | |
949 | }; | |
950 | ||
951 | if (client->swapped) { | |
952 | __GLX_SWAP_SHORT(&reply.sequenceNumber); | |
953 | __GLX_SWAP_INT(&reply.length); | |
954 | __GLX_SWAP_INT(&reply.numVisuals); | |
955 | __GLX_SWAP_INT(&reply.numProps); | |
956 | } | |
957 | ||
958 | WriteToClient(client, sz_xGLXGetVisualConfigsReply, &reply); | |
959 | ||
960 | for (i = 0; i < pGlxScreen->numVisuals; i++) { | |
961 | modes = pGlxScreen->visuals[i]; | |
962 | ||
963 | p = 0; | |
964 | buf[p++] = modes->visualID; | |
965 | buf[p++] = glxConvertToXVisualType(modes->visualType); | |
966 | buf[p++] = (modes->renderType & GLX_RGBA_BIT) ? GL_TRUE : GL_FALSE; | |
967 | ||
968 | buf[p++] = modes->redBits; | |
969 | buf[p++] = modes->greenBits; | |
970 | buf[p++] = modes->blueBits; | |
971 | buf[p++] = modes->alphaBits; | |
972 | buf[p++] = modes->accumRedBits; | |
973 | buf[p++] = modes->accumGreenBits; | |
974 | buf[p++] = modes->accumBlueBits; | |
975 | buf[p++] = modes->accumAlphaBits; | |
976 | ||
977 | buf[p++] = modes->doubleBufferMode; | |
978 | buf[p++] = modes->stereoMode; | |
979 | ||
980 | buf[p++] = modes->rgbBits; | |
981 | buf[p++] = modes->depthBits; | |
982 | buf[p++] = modes->stencilBits; | |
983 | buf[p++] = modes->numAuxBuffers; | |
984 | buf[p++] = modes->level; | |
985 | ||
986 | assert(p == GLX_VIS_CONFIG_UNPAIRED); | |
987 | /* | |
988 | ** Add token/value pairs for extensions. | |
989 | */ | |
990 | buf[p++] = GLX_VISUAL_CAVEAT_EXT; | |
991 | buf[p++] = modes->visualRating; | |
992 | buf[p++] = GLX_TRANSPARENT_TYPE; | |
993 | buf[p++] = modes->transparentPixel; | |
994 | buf[p++] = GLX_TRANSPARENT_RED_VALUE; | |
995 | buf[p++] = modes->transparentRed; | |
996 | buf[p++] = GLX_TRANSPARENT_GREEN_VALUE; | |
997 | buf[p++] = modes->transparentGreen; | |
998 | buf[p++] = GLX_TRANSPARENT_BLUE_VALUE; | |
999 | buf[p++] = modes->transparentBlue; | |
1000 | buf[p++] = GLX_TRANSPARENT_ALPHA_VALUE; | |
1001 | buf[p++] = modes->transparentAlpha; | |
1002 | buf[p++] = GLX_TRANSPARENT_INDEX_VALUE; | |
1003 | buf[p++] = modes->transparentIndex; | |
1004 | buf[p++] = GLX_SAMPLES_SGIS; | |
1005 | buf[p++] = modes->samples; | |
1006 | buf[p++] = GLX_SAMPLE_BUFFERS_SGIS; | |
1007 | buf[p++] = modes->sampleBuffers; | |
1008 | /* Add attribute only if its value is not default. */ | |
1009 | if (modes->sRGBCapable != GL_FALSE) { | |
1010 | buf[p++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT; | |
1011 | buf[p++] = modes->sRGBCapable; | |
1012 | } | |
1013 | /* Don't add visualSelectGroup (GLX_VISUAL_SELECT_GROUP_SGIX)? | |
1014 | * Pad the remaining place with zeroes, so that attributes count is constant. */ | |
1015 | while (p < GLX_VIS_CONFIG_TOTAL) { | |
1016 | buf[p++] = 0; | |
1017 | buf[p++] = 0; | |
1018 | } | |
1019 | ||
1020 | assert(p == GLX_VIS_CONFIG_TOTAL); | |
1021 | if (client->swapped) { | |
1022 | __GLX_SWAP_INT_ARRAY(buf, p); | |
1023 | } | |
1024 | WriteToClient(client, __GLX_SIZE_CARD32 * p, buf); | |
1025 | } | |
1026 | return Success; | |
1027 | } | |
1028 | ||
1029 | #define __GLX_TOTAL_FBCONFIG_ATTRIBS (44) | |
1030 | #define __GLX_FBCONFIG_ATTRIBS_LENGTH (__GLX_TOTAL_FBCONFIG_ATTRIBS * 2) | |
1031 | /** | |
1032 | * Send the set of GLXFBConfigs to the client. There is not currently | |
1033 | * and interface into the driver on the server-side to get GLXFBConfigs, | |
1034 | * so we "invent" some based on the \c __GLXvisualConfig structures that | |
1035 | * the driver does supply. | |
1036 | * | |
1037 | * The reply format for both \c glXGetFBConfigs and \c glXGetFBConfigsSGIX | |
1038 | * is the same, so this routine pulls double duty. | |
1039 | */ | |
1040 | ||
1041 | static int | |
1042 | DoGetFBConfigs(__GLXclientState * cl, unsigned screen) | |
1043 | { | |
1044 | ClientPtr client = cl->client; | |
1045 | xGLXGetFBConfigsReply reply; | |
1046 | __GLXscreen *pGlxScreen; | |
1047 | CARD32 buf[__GLX_FBCONFIG_ATTRIBS_LENGTH]; | |
1048 | int p, err; | |
1049 | __GLXconfig *modes; | |
1050 | ||
1051 | __GLX_DECLARE_SWAP_VARIABLES; | |
1052 | __GLX_DECLARE_SWAP_ARRAY_VARIABLES; | |
1053 | ||
1054 | if (!validGlxScreen(cl->client, screen, &pGlxScreen, &err)) | |
1055 | return err; | |
1056 | ||
1057 | reply = (xGLXGetFBConfigsReply) { | |
1058 | .type = X_Reply, | |
1059 | .sequenceNumber = client->sequence, | |
1060 | .length = __GLX_FBCONFIG_ATTRIBS_LENGTH * pGlxScreen->numFBConfigs, | |
1061 | .numFBConfigs = pGlxScreen->numFBConfigs, | |
1062 | .numAttribs = __GLX_TOTAL_FBCONFIG_ATTRIBS | |
1063 | }; | |
1064 | ||
1065 | if (client->swapped) { | |
1066 | __GLX_SWAP_SHORT(&reply.sequenceNumber); | |
1067 | __GLX_SWAP_INT(&reply.length); | |
1068 | __GLX_SWAP_INT(&reply.numFBConfigs); | |
1069 | __GLX_SWAP_INT(&reply.numAttribs); | |
1070 | } | |
1071 | ||
1072 | WriteToClient(client, sz_xGLXGetFBConfigsReply, &reply); | |
1073 | ||
1074 | for (modes = pGlxScreen->fbconfigs; modes != NULL; modes = modes->next) { | |
1075 | p = 0; | |
1076 | ||
1077 | #define WRITE_PAIR(tag,value) \ | |
1078 | do { buf[p++] = tag ; buf[p++] = value ; } while( 0 ) | |
1079 | ||
1080 | WRITE_PAIR(GLX_VISUAL_ID, modes->visualID); | |
1081 | WRITE_PAIR(GLX_FBCONFIG_ID, modes->fbconfigID); | |
1082 | WRITE_PAIR(GLX_X_RENDERABLE, GL_TRUE); | |
1083 | ||
1084 | WRITE_PAIR(GLX_RGBA, | |
1085 | (modes->renderType & GLX_RGBA_BIT) ? GL_TRUE : GL_FALSE); | |
1086 | WRITE_PAIR(GLX_RENDER_TYPE, modes->renderType); | |
1087 | WRITE_PAIR(GLX_DOUBLEBUFFER, modes->doubleBufferMode); | |
1088 | WRITE_PAIR(GLX_STEREO, modes->stereoMode); | |
1089 | ||
1090 | WRITE_PAIR(GLX_BUFFER_SIZE, modes->rgbBits); | |
1091 | WRITE_PAIR(GLX_LEVEL, modes->level); | |
1092 | WRITE_PAIR(GLX_AUX_BUFFERS, modes->numAuxBuffers); | |
1093 | WRITE_PAIR(GLX_RED_SIZE, modes->redBits); | |
1094 | WRITE_PAIR(GLX_GREEN_SIZE, modes->greenBits); | |
1095 | WRITE_PAIR(GLX_BLUE_SIZE, modes->blueBits); | |
1096 | WRITE_PAIR(GLX_ALPHA_SIZE, modes->alphaBits); | |
1097 | WRITE_PAIR(GLX_ACCUM_RED_SIZE, modes->accumRedBits); | |
1098 | WRITE_PAIR(GLX_ACCUM_GREEN_SIZE, modes->accumGreenBits); | |
1099 | WRITE_PAIR(GLX_ACCUM_BLUE_SIZE, modes->accumBlueBits); | |
1100 | WRITE_PAIR(GLX_ACCUM_ALPHA_SIZE, modes->accumAlphaBits); | |
1101 | WRITE_PAIR(GLX_DEPTH_SIZE, modes->depthBits); | |
1102 | WRITE_PAIR(GLX_STENCIL_SIZE, modes->stencilBits); | |
1103 | WRITE_PAIR(GLX_X_VISUAL_TYPE, modes->visualType); | |
1104 | WRITE_PAIR(GLX_CONFIG_CAVEAT, modes->visualRating); | |
1105 | WRITE_PAIR(GLX_TRANSPARENT_TYPE, modes->transparentPixel); | |
1106 | WRITE_PAIR(GLX_TRANSPARENT_RED_VALUE, modes->transparentRed); | |
1107 | WRITE_PAIR(GLX_TRANSPARENT_GREEN_VALUE, modes->transparentGreen); | |
1108 | WRITE_PAIR(GLX_TRANSPARENT_BLUE_VALUE, modes->transparentBlue); | |
1109 | WRITE_PAIR(GLX_TRANSPARENT_ALPHA_VALUE, modes->transparentAlpha); | |
1110 | WRITE_PAIR(GLX_TRANSPARENT_INDEX_VALUE, modes->transparentIndex); | |
1111 | WRITE_PAIR(GLX_SWAP_METHOD_OML, modes->swapMethod); | |
1112 | WRITE_PAIR(GLX_SAMPLES_SGIS, modes->samples); | |
1113 | WRITE_PAIR(GLX_SAMPLE_BUFFERS_SGIS, modes->sampleBuffers); | |
1114 | WRITE_PAIR(GLX_VISUAL_SELECT_GROUP_SGIX, modes->visualSelectGroup); | |
1115 | WRITE_PAIR(GLX_DRAWABLE_TYPE, modes->drawableType); | |
1116 | WRITE_PAIR(GLX_BIND_TO_TEXTURE_RGB_EXT, modes->bindToTextureRgb); | |
1117 | WRITE_PAIR(GLX_BIND_TO_TEXTURE_RGBA_EXT, modes->bindToTextureRgba); | |
1118 | WRITE_PAIR(GLX_BIND_TO_MIPMAP_TEXTURE_EXT, modes->bindToMipmapTexture); | |
1119 | WRITE_PAIR(GLX_BIND_TO_TEXTURE_TARGETS_EXT, | |
1120 | modes->bindToTextureTargets); | |
1121 | /* can't report honestly until mesa is fixed */ | |
1122 | WRITE_PAIR(GLX_Y_INVERTED_EXT, GLX_DONT_CARE); | |
1123 | if (modes->drawableType & GLX_PBUFFER_BIT) { | |
1124 | WRITE_PAIR(GLX_MAX_PBUFFER_WIDTH, modes->maxPbufferWidth); | |
1125 | WRITE_PAIR(GLX_MAX_PBUFFER_HEIGHT, modes->maxPbufferHeight); | |
1126 | WRITE_PAIR(GLX_MAX_PBUFFER_PIXELS, modes->maxPbufferPixels); | |
1127 | WRITE_PAIR(GLX_OPTIMAL_PBUFFER_WIDTH_SGIX, | |
1128 | modes->optimalPbufferWidth); | |
1129 | WRITE_PAIR(GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX, | |
1130 | modes->optimalPbufferHeight); | |
1131 | } | |
1132 | /* Add attribute only if its value is not default. */ | |
1133 | if (modes->sRGBCapable != GL_FALSE) { | |
1134 | WRITE_PAIR(GLX_FRAMEBUFFER_SRGB_CAPABLE_EXT, modes->sRGBCapable); | |
1135 | } | |
1136 | /* Pad the remaining place with zeroes, so that attributes count is constant. */ | |
1137 | while (p < __GLX_FBCONFIG_ATTRIBS_LENGTH) { | |
1138 | WRITE_PAIR(0, 0); | |
1139 | } | |
1140 | assert(p == __GLX_FBCONFIG_ATTRIBS_LENGTH); | |
1141 | ||
1142 | if (client->swapped) { | |
1143 | __GLX_SWAP_INT_ARRAY(buf, __GLX_FBCONFIG_ATTRIBS_LENGTH); | |
1144 | } | |
1145 | WriteToClient(client, __GLX_SIZE_CARD32 * __GLX_FBCONFIG_ATTRIBS_LENGTH, | |
1146 | (char *) buf); | |
1147 | } | |
1148 | return Success; | |
1149 | } | |
1150 | ||
1151 | int | |
1152 | __glXDisp_GetFBConfigs(__GLXclientState * cl, GLbyte * pc) | |
1153 | { | |
1154 | ClientPtr client = cl->client; | |
1155 | xGLXGetFBConfigsReq *req = (xGLXGetFBConfigsReq *) pc; | |
1156 | ||
1157 | REQUEST_SIZE_MATCH(xGLXGetFBConfigsReq); | |
1158 | return DoGetFBConfigs(cl, req->screen); | |
1159 | } | |
1160 | ||
1161 | int | |
1162 | __glXDisp_GetFBConfigsSGIX(__GLXclientState * cl, GLbyte * pc) | |
1163 | { | |
1164 | ClientPtr client = cl->client; | |
1165 | xGLXGetFBConfigsSGIXReq *req = (xGLXGetFBConfigsSGIXReq *) pc; | |
1166 | ||
1167 | /* work around mesa bug, don't use REQUEST_SIZE_MATCH */ | |
1168 | REQUEST_AT_LEAST_SIZE(xGLXGetFBConfigsSGIXReq); | |
1169 | return DoGetFBConfigs(cl, req->screen); | |
1170 | } | |
1171 | ||
1172 | GLboolean | |
1173 | __glXDrawableInit(__GLXdrawable * drawable, | |
1174 | __GLXscreen * screen, DrawablePtr pDraw, int type, | |
1175 | XID drawId, __GLXconfig * config) | |
1176 | { | |
1177 | drawable->pDraw = pDraw; | |
1178 | drawable->type = type; | |
1179 | drawable->drawId = drawId; | |
1180 | drawable->config = config; | |
1181 | drawable->eventMask = 0; | |
1182 | ||
1183 | return GL_TRUE; | |
1184 | } | |
1185 | ||
1186 | void | |
1187 | __glXDrawableRelease(__GLXdrawable * drawable) | |
1188 | { | |
1189 | } | |
1190 | ||
1191 | static int | |
1192 | DoCreateGLXDrawable(ClientPtr client, __GLXscreen * pGlxScreen, | |
1193 | __GLXconfig * config, DrawablePtr pDraw, XID drawableId, | |
1194 | XID glxDrawableId, int type) | |
1195 | { | |
1196 | __GLXdrawable *pGlxDraw; | |
1197 | ||
1198 | if (pGlxScreen->pScreen != pDraw->pScreen) | |
1199 | return BadMatch; | |
1200 | ||
1201 | pGlxDraw = pGlxScreen->createDrawable(client, pGlxScreen, pDraw, | |
1202 | drawableId, type, | |
1203 | glxDrawableId, config); | |
1204 | if (pGlxDraw == NULL) | |
1205 | return BadAlloc; | |
1206 | ||
1207 | if (!AddResource(glxDrawableId, __glXDrawableRes, pGlxDraw)) { | |
1208 | pGlxDraw->destroy(pGlxDraw); | |
1209 | return BadAlloc; | |
1210 | } | |
1211 | ||
1212 | /* | |
1213 | * Windows aren't refcounted, so track both the X and the GLX window | |
1214 | * so we get called regardless of destruction order. | |
1215 | */ | |
1216 | if (drawableId != glxDrawableId && type == GLX_DRAWABLE_WINDOW && | |
1217 | !AddResource(pDraw->id, __glXDrawableRes, pGlxDraw)) { | |
1218 | pGlxDraw->destroy(pGlxDraw); | |
1219 | return BadAlloc; | |
1220 | } | |
1221 | ||
1222 | return Success; | |
1223 | } | |
1224 | ||
1225 | static int | |
1226 | DoCreateGLXPixmap(ClientPtr client, __GLXscreen * pGlxScreen, | |
1227 | __GLXconfig * config, XID drawableId, XID glxDrawableId) | |
1228 | { | |
1229 | DrawablePtr pDraw; | |
1230 | int err; | |
1231 | ||
1232 | LEGAL_NEW_RESOURCE(glxDrawableId, client); | |
1233 | ||
1234 | err = dixLookupDrawable(&pDraw, drawableId, client, 0, DixAddAccess); | |
1235 | if (err != Success) { | |
1236 | client->errorValue = drawableId; | |
1237 | return err; | |
1238 | } | |
1239 | if (pDraw->type != DRAWABLE_PIXMAP) { | |
1240 | client->errorValue = drawableId; | |
1241 | return BadPixmap; | |
1242 | } | |
1243 | ||
1244 | err = DoCreateGLXDrawable(client, pGlxScreen, config, pDraw, drawableId, | |
1245 | glxDrawableId, GLX_DRAWABLE_PIXMAP); | |
1246 | ||
1247 | if (err == Success) | |
1248 | ((PixmapPtr) pDraw)->refcnt++; | |
1249 | ||
1250 | return err; | |
1251 | } | |
1252 | ||
1253 | static void | |
1254 | determineTextureTarget(ClientPtr client, XID glxDrawableID, | |
1255 | CARD32 *attribs, CARD32 numAttribs) | |
1256 | { | |
1257 | GLenum target = 0; | |
1258 | GLenum format = 0; | |
1259 | int i, err; | |
1260 | __GLXdrawable *pGlxDraw; | |
1261 | ||
1262 | if (!validGlxDrawable(client, glxDrawableID, GLX_DRAWABLE_PIXMAP, | |
1263 | DixWriteAccess, &pGlxDraw, &err)) | |
1264 | /* We just added it in CreatePixmap, so we should never get here. */ | |
1265 | return; | |
1266 | ||
1267 | for (i = 0; i < numAttribs; i++) { | |
1268 | if (attribs[2 * i] == GLX_TEXTURE_TARGET_EXT) { | |
1269 | switch (attribs[2 * i + 1]) { | |
1270 | case GLX_TEXTURE_2D_EXT: | |
1271 | target = GL_TEXTURE_2D; | |
1272 | break; | |
1273 | case GLX_TEXTURE_RECTANGLE_EXT: | |
1274 | target = GL_TEXTURE_RECTANGLE_ARB; | |
1275 | break; | |
1276 | } | |
1277 | } | |
1278 | ||
1279 | if (attribs[2 * i] == GLX_TEXTURE_FORMAT_EXT) | |
1280 | format = attribs[2 * i + 1]; | |
1281 | } | |
1282 | ||
1283 | if (!target) { | |
1284 | int w = pGlxDraw->pDraw->width, h = pGlxDraw->pDraw->height; | |
1285 | ||
1286 | if (h & (h - 1) || w & (w - 1)) | |
1287 | target = GL_TEXTURE_RECTANGLE_ARB; | |
1288 | else | |
1289 | target = GL_TEXTURE_2D; | |
1290 | } | |
1291 | ||
1292 | pGlxDraw->target = target; | |
1293 | pGlxDraw->format = format; | |
1294 | } | |
1295 | ||
1296 | int | |
1297 | __glXDisp_CreateGLXPixmap(__GLXclientState * cl, GLbyte * pc) | |
1298 | { | |
1299 | ClientPtr client = cl->client; | |
1300 | xGLXCreateGLXPixmapReq *req = (xGLXCreateGLXPixmapReq *) pc; | |
1301 | __GLXconfig *config; | |
1302 | __GLXscreen *pGlxScreen; | |
1303 | int err; | |
1304 | ||
1305 | REQUEST_SIZE_MATCH(xGLXCreateGLXPixmapReq); | |
1306 | ||
1307 | if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) | |
1308 | return err; | |
1309 | if (!validGlxVisual(cl->client, pGlxScreen, req->visual, &config, &err)) | |
1310 | return err; | |
1311 | ||
1312 | return DoCreateGLXPixmap(cl->client, pGlxScreen, config, | |
1313 | req->pixmap, req->glxpixmap); | |
1314 | } | |
1315 | ||
1316 | int | |
1317 | __glXDisp_CreatePixmap(__GLXclientState * cl, GLbyte * pc) | |
1318 | { | |
1319 | ClientPtr client = cl->client; | |
1320 | xGLXCreatePixmapReq *req = (xGLXCreatePixmapReq *) pc; | |
1321 | __GLXconfig *config; | |
1322 | __GLXscreen *pGlxScreen; | |
1323 | int err; | |
1324 | ||
1325 | REQUEST_AT_LEAST_SIZE(xGLXCreatePixmapReq); | |
1326 | if (req->numAttribs > (UINT32_MAX >> 3)) { | |
1327 | client->errorValue = req->numAttribs; | |
1328 | return BadValue; | |
1329 | } | |
1330 | REQUEST_FIXED_SIZE(xGLXCreatePixmapReq, req->numAttribs << 3); | |
1331 | ||
1332 | if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) | |
1333 | return err; | |
1334 | if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err)) | |
1335 | return err; | |
1336 | ||
1337 | err = DoCreateGLXPixmap(cl->client, pGlxScreen, config, | |
1338 | req->pixmap, req->glxpixmap); | |
1339 | if (err != Success) | |
1340 | return err; | |
1341 | ||
1342 | determineTextureTarget(cl->client, req->glxpixmap, | |
1343 | (CARD32 *) (req + 1), req->numAttribs); | |
1344 | ||
1345 | return Success; | |
1346 | } | |
1347 | ||
1348 | int | |
1349 | __glXDisp_CreateGLXPixmapWithConfigSGIX(__GLXclientState * cl, GLbyte * pc) | |
1350 | { | |
1351 | ClientPtr client = cl->client; | |
1352 | xGLXCreateGLXPixmapWithConfigSGIXReq *req = | |
1353 | (xGLXCreateGLXPixmapWithConfigSGIXReq *) pc; | |
1354 | __GLXconfig *config; | |
1355 | __GLXscreen *pGlxScreen; | |
1356 | int err; | |
1357 | ||
1358 | REQUEST_SIZE_MATCH(xGLXCreateGLXPixmapWithConfigSGIXReq); | |
1359 | ||
1360 | if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err)) | |
1361 | return err; | |
1362 | if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err)) | |
1363 | return err; | |
1364 | ||
1365 | return DoCreateGLXPixmap(cl->client, pGlxScreen, | |
1366 | config, req->pixmap, req->glxpixmap); | |
1367 | } | |
1368 | ||
1369 | static int | |
1370 | DoDestroyDrawable(__GLXclientState * cl, XID glxdrawable, int type) | |
1371 | { | |
1372 | __GLXdrawable *pGlxDraw; | |
1373 | int err; | |
1374 | ||
1375 | if (!validGlxDrawable(cl->client, glxdrawable, type, | |
1376 | DixDestroyAccess, &pGlxDraw, &err)) | |
1377 | return err; | |
1378 | ||
1379 | FreeResource(glxdrawable, FALSE); | |
1380 | ||
1381 | return Success; | |
1382 | } | |
1383 | ||
1384 | int | |
1385 | __glXDisp_DestroyGLXPixmap(__GLXclientState * cl, GLbyte * pc) | |
1386 | { | |
1387 | ClientPtr client = cl->client; | |
1388 | xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc; | |
1389 | ||
1390 | REQUEST_SIZE_MATCH(xGLXDestroyGLXPixmapReq); | |
1391 | ||
1392 | return DoDestroyDrawable(cl, req->glxpixmap, GLX_DRAWABLE_PIXMAP); | |
1393 | } | |
1394 | ||
1395 | int | |
1396 | __glXDisp_DestroyPixmap(__GLXclientState * cl, GLbyte * pc) | |
1397 | { | |
1398 | ClientPtr client = cl->client; | |
1399 | xGLXDestroyPixmapReq *req = (xGLXDestroyPixmapReq *) pc; | |
1400 | ||
1401 | /* should be REQUEST_SIZE_MATCH, but mesa's glXDestroyPixmap used to set | |
1402 | * length to 3 instead of 2 */ | |
1403 | REQUEST_AT_LEAST_SIZE(xGLXDestroyPixmapReq); | |
1404 | ||
1405 | return DoDestroyDrawable(cl, req->glxpixmap, GLX_DRAWABLE_PIXMAP); | |
1406 | } | |
1407 | ||
1408 | static int | |
1409 | DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId, | |
1410 | int width, int height, XID glxDrawableId) | |
1411 | { | |
1412 | __GLXconfig *config; | |
1413 | __GLXscreen *pGlxScreen; | |
1414 | PixmapPtr pPixmap; | |
1415 | int err; | |
1416 | ||
1417 | LEGAL_NEW_RESOURCE(glxDrawableId, client); | |
1418 | ||
1419 | if (!validGlxScreen(client, screenNum, &pGlxScreen, &err)) | |
1420 | return err; | |
1421 | if (!validGlxFBConfig(client, pGlxScreen, fbconfigId, &config, &err)) | |
1422 | return err; | |
1423 | ||
1424 | __glXenterServer(GL_FALSE); | |
1425 | pPixmap = (*pGlxScreen->pScreen->CreatePixmap) (pGlxScreen->pScreen, | |
1426 | width, height, | |
1427 | config->rgbBits, 0); | |
1428 | __glXleaveServer(GL_FALSE); | |
1429 | if (!pPixmap) | |
1430 | return BadAlloc; | |
1431 | ||
1432 | /* Assign the pixmap the same id as the pbuffer and add it as a | |
1433 | * resource so it and the DRI2 drawable will be reclaimed when the | |
1434 | * pbuffer is destroyed. */ | |
1435 | pPixmap->drawable.id = glxDrawableId; | |
1436 | if (!AddResource(pPixmap->drawable.id, RT_PIXMAP, pPixmap)) | |
1437 | return BadAlloc; | |
1438 | ||
1439 | return DoCreateGLXDrawable(client, pGlxScreen, config, &pPixmap->drawable, | |
1440 | glxDrawableId, glxDrawableId, | |
1441 | GLX_DRAWABLE_PBUFFER); | |
1442 | } | |
1443 | ||
1444 | int | |
1445 | __glXDisp_CreatePbuffer(__GLXclientState * cl, GLbyte * pc) | |
1446 | { | |
1447 | ClientPtr client = cl->client; | |
1448 | xGLXCreatePbufferReq *req = (xGLXCreatePbufferReq *) pc; | |
1449 | CARD32 *attrs; | |
1450 | int width, height, i; | |
1451 | ||
1452 | REQUEST_AT_LEAST_SIZE(xGLXCreatePbufferReq); | |
1453 | if (req->numAttribs > (UINT32_MAX >> 3)) { | |
1454 | client->errorValue = req->numAttribs; | |
1455 | return BadValue; | |
1456 | } | |
1457 | REQUEST_FIXED_SIZE(xGLXCreatePbufferReq, req->numAttribs << 3); | |
1458 | ||
1459 | attrs = (CARD32 *) (req + 1); | |
1460 | width = 0; | |
1461 | height = 0; | |
1462 | ||
1463 | for (i = 0; i < req->numAttribs; i++) { | |
1464 | switch (attrs[i * 2]) { | |
1465 | case GLX_PBUFFER_WIDTH: | |
1466 | width = attrs[i * 2 + 1]; | |
1467 | break; | |
1468 | case GLX_PBUFFER_HEIGHT: | |
1469 | height = attrs[i * 2 + 1]; | |
1470 | break; | |
1471 | case GLX_LARGEST_PBUFFER: | |
1472 | /* FIXME: huh... */ | |
1473 | break; | |
1474 | } | |
1475 | } | |
1476 | ||
1477 | return DoCreatePbuffer(cl->client, req->screen, req->fbconfig, | |
1478 | width, height, req->pbuffer); | |
1479 | } | |
1480 | ||
1481 | int | |
1482 | __glXDisp_CreateGLXPbufferSGIX(__GLXclientState * cl, GLbyte * pc) | |
1483 | { | |
1484 | ClientPtr client = cl->client; | |
1485 | xGLXCreateGLXPbufferSGIXReq *req = (xGLXCreateGLXPbufferSGIXReq *) pc; | |
1486 | ||
1487 | REQUEST_AT_LEAST_SIZE(xGLXCreateGLXPbufferSGIXReq); | |
1488 | ||
1489 | /* | |
1490 | * We should really handle attributes correctly, but this extension | |
1491 | * is so rare I have difficulty caring. | |
1492 | */ | |
1493 | return DoCreatePbuffer(cl->client, req->screen, req->fbconfig, | |
1494 | req->width, req->height, req->pbuffer); | |
1495 | } | |
1496 | ||
1497 | int | |
1498 | __glXDisp_DestroyPbuffer(__GLXclientState * cl, GLbyte * pc) | |
1499 | { | |
1500 | ClientPtr client = cl->client; | |
1501 | xGLXDestroyPbufferReq *req = (xGLXDestroyPbufferReq *) pc; | |
1502 | ||
1503 | REQUEST_SIZE_MATCH(xGLXDestroyPbufferReq); | |
1504 | ||
1505 | return DoDestroyDrawable(cl, req->pbuffer, GLX_DRAWABLE_PBUFFER); | |
1506 | } | |
1507 | ||
1508 | int | |
1509 | __glXDisp_DestroyGLXPbufferSGIX(__GLXclientState * cl, GLbyte * pc) | |
1510 | { | |
1511 | ClientPtr client = cl->client; | |
1512 | xGLXDestroyGLXPbufferSGIXReq *req = (xGLXDestroyGLXPbufferSGIXReq *) pc; | |
1513 | ||
1514 | REQUEST_SIZE_MATCH(xGLXDestroyGLXPbufferSGIXReq); | |
1515 | ||
1516 | return DoDestroyDrawable(cl, req->pbuffer, GLX_DRAWABLE_PBUFFER); | |
1517 | } | |
1518 | ||
1519 | static int | |
1520 | DoChangeDrawableAttributes(ClientPtr client, XID glxdrawable, | |
1521 | int numAttribs, CARD32 *attribs) | |
1522 | { | |
1523 | __GLXdrawable *pGlxDraw; | |
1524 | int i, err; | |
1525 | ||
1526 | if (!validGlxDrawable(client, glxdrawable, GLX_DRAWABLE_ANY, | |
1527 | DixSetAttrAccess, &pGlxDraw, &err)) | |
1528 | return err; | |
1529 | ||
1530 | for (i = 0; i < numAttribs; i++) { | |
1531 | switch (attribs[i * 2]) { | |
1532 | case GLX_EVENT_MASK: | |
1533 | /* All we do is to record the event mask so we can send it | |
1534 | * back when queried. We never actually clobber the | |
1535 | * pbuffers, so we never need to send out the event. */ | |
1536 | pGlxDraw->eventMask = attribs[i * 2 + 1]; | |
1537 | break; | |
1538 | } | |
1539 | } | |
1540 | ||
1541 | return Success; | |
1542 | } | |
1543 | ||
1544 | int | |
1545 | __glXDisp_ChangeDrawableAttributes(__GLXclientState * cl, GLbyte * pc) | |
1546 | { | |
1547 | ClientPtr client = cl->client; | |
1548 | xGLXChangeDrawableAttributesReq *req = | |
1549 | (xGLXChangeDrawableAttributesReq *) pc; | |
1550 | ||
1551 | REQUEST_AT_LEAST_SIZE(xGLXChangeDrawableAttributesReq); | |
1552 | if (req->numAttribs > (UINT32_MAX >> 3)) { | |
1553 | client->errorValue = req->numAttribs; | |
1554 | return BadValue; | |
1555 | } | |
1556 | #if 0 | |
1557 | /* mesa sends an additional 8 bytes */ | |
1558 | REQUEST_FIXED_SIZE(xGLXChangeDrawableAttributesReq, req->numAttribs << 3); | |
1559 | #else | |
1560 | if (((sizeof(xGLXChangeDrawableAttributesReq) + | |
1561 | (req->numAttribs << 3)) >> 2) < client->req_len) | |
1562 | return BadLength; | |
1563 | #endif | |
1564 | ||
1565 | return DoChangeDrawableAttributes(cl->client, req->drawable, | |
1566 | req->numAttribs, (CARD32 *) (req + 1)); | |
1567 | } | |
1568 | ||
1569 | int | |
1570 | __glXDisp_ChangeDrawableAttributesSGIX(__GLXclientState * cl, GLbyte * pc) | |
1571 | { | |
1572 | ClientPtr client = cl->client; | |
1573 | xGLXChangeDrawableAttributesSGIXReq *req = | |
1574 | (xGLXChangeDrawableAttributesSGIXReq *) pc; | |
1575 | ||
1576 | REQUEST_AT_LEAST_SIZE(xGLXChangeDrawableAttributesSGIXReq); | |
1577 | if (req->numAttribs > (UINT32_MAX >> 3)) { | |
1578 | client->errorValue = req->numAttribs; | |
1579 | return BadValue; | |
1580 | } | |
1581 | REQUEST_FIXED_SIZE(xGLXChangeDrawableAttributesSGIXReq, | |
1582 | req->numAttribs << 3); | |
1583 | ||
1584 | return DoChangeDrawableAttributes(cl->client, req->drawable, | |
1585 | req->numAttribs, (CARD32 *) (req + 1)); | |
1586 | } | |
1587 | ||
1588 | int | |
1589 | __glXDisp_CreateWindow(__GLXclientState * cl, GLbyte * pc) | |
1590 | { | |
1591 | xGLXCreateWindowReq *req = (xGLXCreateWindowReq *) pc; | |
1592 | __GLXconfig *config; | |
1593 | __GLXscreen *pGlxScreen; | |
1594 | ClientPtr client = cl->client; | |
1595 | DrawablePtr pDraw; | |
1596 | int err; | |
1597 | ||
1598 | REQUEST_AT_LEAST_SIZE(xGLXCreateWindowReq); | |
1599 | if (req->numAttribs > (UINT32_MAX >> 3)) { | |
1600 | client->errorValue = req->numAttribs; | |
1601 | return BadValue; | |
1602 | } | |
1603 | REQUEST_FIXED_SIZE(xGLXCreateWindowReq, req->numAttribs << 3); | |
1604 | ||
1605 | LEGAL_NEW_RESOURCE(req->glxwindow, client); | |
1606 | ||
1607 | if (!validGlxScreen(client, req->screen, &pGlxScreen, &err)) | |
1608 | return err; | |
1609 | if (!validGlxFBConfig(client, pGlxScreen, req->fbconfig, &config, &err)) | |
1610 | return err; | |
1611 | ||
1612 | err = dixLookupDrawable(&pDraw, req->window, client, 0, DixAddAccess); | |
1613 | if (err != Success || pDraw->type != DRAWABLE_WINDOW) { | |
1614 | client->errorValue = req->window; | |
1615 | return BadWindow; | |
1616 | } | |
1617 | ||
1618 | if (!validGlxFBConfigForWindow(client, config, pDraw, &err)) | |
1619 | return err; | |
1620 | ||
1621 | return DoCreateGLXDrawable(client, pGlxScreen, config, | |
1622 | pDraw, req->window, | |
1623 | req->glxwindow, GLX_DRAWABLE_WINDOW); | |
1624 | } | |
1625 | ||
1626 | int | |
1627 | __glXDisp_DestroyWindow(__GLXclientState * cl, GLbyte * pc) | |
1628 | { | |
1629 | ClientPtr client = cl->client; | |
1630 | xGLXDestroyWindowReq *req = (xGLXDestroyWindowReq *) pc; | |
1631 | ||
1632 | /* mesa's glXDestroyWindow used to set length to 3 instead of 2 */ | |
1633 | REQUEST_AT_LEAST_SIZE(xGLXDestroyWindowReq); | |
1634 | ||
1635 | return DoDestroyDrawable(cl, req->glxwindow, GLX_DRAWABLE_WINDOW); | |
1636 | } | |
1637 | ||
1638 | /*****************************************************************************/ | |
1639 | ||
1640 | /* | |
1641 | ** NOTE: There is no portable implementation for swap buffers as of | |
1642 | ** this time that is of value. Consequently, this code must be | |
1643 | ** implemented by somebody other than SGI. | |
1644 | */ | |
1645 | int | |
1646 | __glXDisp_SwapBuffers(__GLXclientState * cl, GLbyte * pc) | |
1647 | { | |
1648 | ClientPtr client = cl->client; | |
1649 | xGLXSwapBuffersReq *req = (xGLXSwapBuffersReq *) pc; | |
1650 | GLXContextTag tag; | |
1651 | XID drawId; | |
1652 | __GLXcontext *glxc = NULL; | |
1653 | __GLXdrawable *pGlxDraw; | |
1654 | int error; | |
1655 | ||
1656 | REQUEST_SIZE_MATCH(xGLXSwapBuffersReq); | |
1657 | ||
1658 | tag = req->contextTag; | |
1659 | drawId = req->drawable; | |
1660 | if (tag) { | |
1661 | glxc = __glXLookupContextByTag(cl, tag); | |
1662 | if (!glxc) { | |
1663 | return __glXError(GLXBadContextTag); | |
1664 | } | |
1665 | /* | |
1666 | ** The calling thread is swapping its current drawable. In this case, | |
1667 | ** glxSwapBuffers is in both GL and X streams, in terms of | |
1668 | ** sequentiality. | |
1669 | */ | |
1670 | if (__glXForceCurrent(cl, tag, &error)) { | |
1671 | /* | |
1672 | ** Do whatever is needed to make sure that all preceding requests | |
1673 | ** in both streams are completed before the swap is executed. | |
1674 | */ | |
1675 | glFinish(); | |
1676 | glxc->hasUnflushedCommands = GL_FALSE; | |
1677 | } | |
1678 | else { | |
1679 | return error; | |
1680 | } | |
1681 | } | |
1682 | ||
1683 | pGlxDraw = __glXGetDrawable(glxc, drawId, client, &error); | |
1684 | if (pGlxDraw == NULL) | |
1685 | return error; | |
1686 | ||
1687 | if (pGlxDraw->type == DRAWABLE_WINDOW && | |
1688 | (*pGlxDraw->swapBuffers) (cl->client, pGlxDraw) == GL_FALSE) | |
1689 | return __glXError(GLXBadDrawable); | |
1690 | ||
1691 | return Success; | |
1692 | } | |
1693 | ||
1694 | static int | |
1695 | DoQueryContext(__GLXclientState * cl, GLXContextID gcId) | |
1696 | { | |
1697 | ClientPtr client = cl->client; | |
1698 | __GLXcontext *ctx; | |
1699 | xGLXQueryContextInfoEXTReply reply; | |
1700 | int nProps = 3; | |
1701 | int sendBuf[nProps * 2]; | |
1702 | int nReplyBytes; | |
1703 | int err; | |
1704 | ||
1705 | if (!validGlxContext(cl->client, gcId, DixReadAccess, &ctx, &err)) | |
1706 | return err; | |
1707 | ||
1708 | reply = (xGLXQueryContextInfoEXTReply) { | |
1709 | .type = X_Reply, | |
1710 | .sequenceNumber = client->sequence, | |
1711 | .length = nProps << 1, | |
1712 | .n = nProps | |
1713 | }; | |
1714 | ||
1715 | nReplyBytes = reply.length << 2; | |
1716 | sendBuf[0] = GLX_SHARE_CONTEXT_EXT; | |
1717 | sendBuf[1] = (int) (ctx->share_id); | |
1718 | sendBuf[2] = GLX_VISUAL_ID_EXT; | |
1719 | sendBuf[3] = (int) (ctx->config->visualID); | |
1720 | sendBuf[4] = GLX_SCREEN_EXT; | |
1721 | sendBuf[5] = (int) (ctx->pGlxScreen->pScreen->myNum); | |
1722 | ||
1723 | if (client->swapped) { | |
1724 | __glXSwapQueryContextInfoEXTReply(client, &reply, sendBuf); | |
1725 | } | |
1726 | else { | |
1727 | WriteToClient(client, sz_xGLXQueryContextInfoEXTReply, &reply); | |
1728 | WriteToClient(client, nReplyBytes, sendBuf); | |
1729 | } | |
1730 | ||
1731 | return Success; | |
1732 | } | |
1733 | ||
1734 | int | |
1735 | __glXDisp_QueryContextInfoEXT(__GLXclientState * cl, GLbyte * pc) | |
1736 | { | |
1737 | ClientPtr client = cl->client; | |
1738 | xGLXQueryContextInfoEXTReq *req = (xGLXQueryContextInfoEXTReq *) pc; | |
1739 | ||
1740 | REQUEST_SIZE_MATCH(xGLXQueryContextInfoEXTReq); | |
1741 | ||
1742 | return DoQueryContext(cl, req->context); | |
1743 | } | |
1744 | ||
1745 | int | |
1746 | __glXDisp_QueryContext(__GLXclientState * cl, GLbyte * pc) | |
1747 | { | |
1748 | ClientPtr client = cl->client; | |
1749 | xGLXQueryContextReq *req = (xGLXQueryContextReq *) pc; | |
1750 | ||
1751 | REQUEST_SIZE_MATCH(xGLXQueryContextReq); | |
1752 | ||
1753 | return DoQueryContext(cl, req->context); | |
1754 | } | |
1755 | ||
1756 | int | |
1757 | __glXDisp_BindTexImageEXT(__GLXclientState * cl, GLbyte * pc) | |
1758 | { | |
1759 | xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc; | |
1760 | ClientPtr client = cl->client; | |
1761 | __GLXcontext *context; | |
1762 | __GLXdrawable *pGlxDraw; | |
1763 | GLXDrawable drawId; | |
1764 | int buffer; | |
1765 | int error; | |
1766 | CARD32 num_attribs; | |
1767 | ||
1768 | if ((sizeof(xGLXVendorPrivateReq) + 12) >> 2 > client->req_len) | |
1769 | return BadLength; | |
1770 | ||
1771 | pc += __GLX_VENDPRIV_HDR_SIZE; | |
1772 | ||
1773 | drawId = *((CARD32 *) (pc)); | |
1774 | buffer = *((INT32 *) (pc + 4)); | |
1775 | num_attribs = *((CARD32 *) (pc + 8)); | |
1776 | if (num_attribs > (UINT32_MAX >> 3)) { | |
1777 | client->errorValue = num_attribs; | |
1778 | return BadValue; | |
1779 | } | |
1780 | REQUEST_FIXED_SIZE(xGLXVendorPrivateReq, 12 + (num_attribs << 3)); | |
1781 | ||
1782 | if (buffer != GLX_FRONT_LEFT_EXT) | |
1783 | return __glXError(GLXBadPixmap); | |
1784 | ||
1785 | context = __glXForceCurrent(cl, req->contextTag, &error); | |
1786 | if (!context) | |
1787 | return error; | |
1788 | ||
1789 | if (!validGlxDrawable(client, drawId, GLX_DRAWABLE_PIXMAP, | |
1790 | DixReadAccess, &pGlxDraw, &error)) | |
1791 | return error; | |
1792 | ||
1793 | if (!context->textureFromPixmap) | |
1794 | return __glXError(GLXUnsupportedPrivateRequest); | |
1795 | ||
1796 | return context->textureFromPixmap->bindTexImage(context, buffer, pGlxDraw); | |
1797 | } | |
1798 | ||
1799 | int | |
1800 | __glXDisp_ReleaseTexImageEXT(__GLXclientState * cl, GLbyte * pc) | |
1801 | { | |
1802 | xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc; | |
1803 | ClientPtr client = cl->client; | |
1804 | __GLXdrawable *pGlxDraw; | |
1805 | __GLXcontext *context; | |
1806 | GLXDrawable drawId; | |
1807 | int buffer; | |
1808 | int error; | |
1809 | ||
1810 | REQUEST_FIXED_SIZE(xGLXVendorPrivateReq, 8); | |
1811 | ||
1812 | pc += __GLX_VENDPRIV_HDR_SIZE; | |
1813 | ||
1814 | drawId = *((CARD32 *) (pc)); | |
1815 | buffer = *((INT32 *) (pc + 4)); | |
1816 | ||
1817 | context = __glXForceCurrent(cl, req->contextTag, &error); | |
1818 | if (!context) | |
1819 | return error; | |
1820 | ||
1821 | if (!validGlxDrawable(client, drawId, GLX_DRAWABLE_PIXMAP, | |
1822 | DixReadAccess, &pGlxDraw, &error)) | |
1823 | return error; | |
1824 | ||
1825 | if (!context->textureFromPixmap) | |
1826 | return __glXError(GLXUnsupportedPrivateRequest); | |
1827 | ||
1828 | return context->textureFromPixmap->releaseTexImage(context, | |
1829 | buffer, pGlxDraw); | |
1830 | } | |
1831 | ||
1832 | int | |
1833 | __glXDisp_CopySubBufferMESA(__GLXclientState * cl, GLbyte * pc) | |
1834 | { | |
1835 | xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc; | |
1836 | GLXContextTag tag = req->contextTag; | |
1837 | __GLXcontext *glxc = NULL; | |
1838 | __GLXdrawable *pGlxDraw; | |
1839 | ClientPtr client = cl->client; | |
1840 | GLXDrawable drawId; | |
1841 | int error; | |
1842 | int x, y, width, height; | |
1843 | ||
1844 | (void) client; | |
1845 | (void) req; | |
1846 | ||
1847 | REQUEST_FIXED_SIZE(xGLXVendorPrivateReq, 20); | |
1848 | ||
1849 | pc += __GLX_VENDPRIV_HDR_SIZE; | |
1850 | ||
1851 | drawId = *((CARD32 *) (pc)); | |
1852 | x = *((INT32 *) (pc + 4)); | |
1853 | y = *((INT32 *) (pc + 8)); | |
1854 | width = *((INT32 *) (pc + 12)); | |
1855 | height = *((INT32 *) (pc + 16)); | |
1856 | ||
1857 | if (tag) { | |
1858 | glxc = __glXLookupContextByTag(cl, tag); | |
1859 | if (!glxc) { | |
1860 | return __glXError(GLXBadContextTag); | |
1861 | } | |
1862 | /* | |
1863 | ** The calling thread is swapping its current drawable. In this case, | |
1864 | ** glxSwapBuffers is in both GL and X streams, in terms of | |
1865 | ** sequentiality. | |
1866 | */ | |
1867 | if (__glXForceCurrent(cl, tag, &error)) { | |
1868 | /* | |
1869 | ** Do whatever is needed to make sure that all preceding requests | |
1870 | ** in both streams are completed before the swap is executed. | |
1871 | */ | |
1872 | glFinish(); | |
1873 | glxc->hasUnflushedCommands = GL_FALSE; | |
1874 | } | |
1875 | else { | |
1876 | return error; | |
1877 | } | |
1878 | } | |
1879 | ||
1880 | pGlxDraw = __glXGetDrawable(glxc, drawId, client, &error); | |
1881 | if (!pGlxDraw) | |
1882 | return error; | |
1883 | ||
1884 | if (pGlxDraw == NULL || | |
1885 | pGlxDraw->type != GLX_DRAWABLE_WINDOW || | |
1886 | pGlxDraw->copySubBuffer == NULL) | |
1887 | return __glXError(GLXBadDrawable); | |
1888 | ||
1889 | (*pGlxDraw->copySubBuffer) (pGlxDraw, x, y, width, height); | |
1890 | ||
1891 | return Success; | |
1892 | } | |
1893 | ||
1894 | /* | |
1895 | ** Get drawable attributes | |
1896 | */ | |
1897 | static int | |
1898 | DoGetDrawableAttributes(__GLXclientState * cl, XID drawId) | |
1899 | { | |
1900 | ClientPtr client = cl->client; | |
1901 | xGLXGetDrawableAttributesReply reply; | |
1902 | __GLXdrawable *pGlxDraw; | |
1903 | CARD32 attributes[14]; | |
1904 | int numAttribs = 0, error; | |
1905 | ||
1906 | if (!validGlxDrawable(client, drawId, GLX_DRAWABLE_ANY, | |
1907 | DixGetAttrAccess, &pGlxDraw, &error)) | |
1908 | return error; | |
1909 | ||
1910 | attributes[0] = GLX_TEXTURE_TARGET_EXT; | |
1911 | attributes[1] = pGlxDraw->target == GL_TEXTURE_2D ? GLX_TEXTURE_2D_EXT : | |
1912 | GLX_TEXTURE_RECTANGLE_EXT; | |
1913 | numAttribs++; | |
1914 | attributes[2] = GLX_Y_INVERTED_EXT; | |
1915 | attributes[3] = GL_FALSE; | |
1916 | numAttribs++; | |
1917 | attributes[4] = GLX_EVENT_MASK; | |
1918 | attributes[5] = pGlxDraw->eventMask; | |
1919 | numAttribs++; | |
1920 | attributes[6] = GLX_WIDTH; | |
1921 | attributes[7] = pGlxDraw->pDraw->width; | |
1922 | numAttribs++; | |
1923 | attributes[8] = GLX_HEIGHT; | |
1924 | attributes[9] = pGlxDraw->pDraw->height; | |
1925 | numAttribs++; | |
1926 | attributes[10] = GLX_FBCONFIG_ID; | |
1927 | attributes[11] = pGlxDraw->config->fbconfigID; | |
1928 | numAttribs++; | |
1929 | if (pGlxDraw->type == GLX_DRAWABLE_PBUFFER) { | |
1930 | attributes[12] = GLX_PRESERVED_CONTENTS; | |
1931 | attributes[13] = GL_TRUE; | |
1932 | numAttribs++; | |
1933 | } | |
1934 | ||
1935 | reply = (xGLXGetDrawableAttributesReply) { | |
1936 | .type = X_Reply, | |
1937 | .sequenceNumber = client->sequence, | |
1938 | .length = numAttribs << 1, | |
1939 | .numAttribs = numAttribs | |
1940 | }; | |
1941 | ||
1942 | if (client->swapped) { | |
1943 | __glXSwapGetDrawableAttributesReply(client, &reply, attributes); | |
1944 | } | |
1945 | else { | |
1946 | WriteToClient(client, sz_xGLXGetDrawableAttributesReply, &reply); | |
1947 | WriteToClient(client, reply.length * sizeof(CARD32), attributes); | |
1948 | } | |
1949 | ||
1950 | return Success; | |
1951 | } | |
1952 | ||
1953 | int | |
1954 | __glXDisp_GetDrawableAttributes(__GLXclientState * cl, GLbyte * pc) | |
1955 | { | |
1956 | ClientPtr client = cl->client; | |
1957 | xGLXGetDrawableAttributesReq *req = (xGLXGetDrawableAttributesReq *) pc; | |
1958 | ||
1959 | /* this should be REQUEST_SIZE_MATCH, but mesa sends an additional 4 bytes */ | |
1960 | REQUEST_AT_LEAST_SIZE(xGLXGetDrawableAttributesReq); | |
1961 | ||
1962 | return DoGetDrawableAttributes(cl, req->drawable); | |
1963 | } | |
1964 | ||
1965 | int | |
1966 | __glXDisp_GetDrawableAttributesSGIX(__GLXclientState * cl, GLbyte * pc) | |
1967 | { | |
1968 | ClientPtr client = cl->client; | |
1969 | xGLXGetDrawableAttributesSGIXReq *req = | |
1970 | (xGLXGetDrawableAttributesSGIXReq *) pc; | |
1971 | ||
1972 | REQUEST_SIZE_MATCH(xGLXGetDrawableAttributesSGIXReq); | |
1973 | ||
1974 | return DoGetDrawableAttributes(cl, req->drawable); | |
1975 | } | |
1976 | ||
1977 | /************************************************************************/ | |
1978 | ||
1979 | /* | |
1980 | ** Render and Renderlarge are not in the GLX API. They are used by the GLX | |
1981 | ** client library to send batches of GL rendering commands. | |
1982 | */ | |
1983 | ||
1984 | /* | |
1985 | ** Execute all the drawing commands in a request. | |
1986 | */ | |
1987 | int | |
1988 | __glXDisp_Render(__GLXclientState * cl, GLbyte * pc) | |
1989 | { | |
1990 | xGLXRenderReq *req; | |
1991 | ClientPtr client = cl->client; | |
1992 | int left, cmdlen, error; | |
1993 | int commandsDone; | |
1994 | CARD16 opcode; | |
1995 | __GLXrenderHeader *hdr; | |
1996 | __GLXcontext *glxc; | |
1997 | ||
1998 | __GLX_DECLARE_SWAP_VARIABLES; | |
1999 | ||
2000 | REQUEST_AT_LEAST_SIZE(xGLXRenderReq); | |
2001 | ||
2002 | req = (xGLXRenderReq *) pc; | |
2003 | if (client->swapped) { | |
2004 | __GLX_SWAP_SHORT(&req->length); | |
2005 | __GLX_SWAP_INT(&req->contextTag); | |
2006 | } | |
2007 | ||
2008 | glxc = __glXForceCurrent(cl, req->contextTag, &error); | |
2009 | if (!glxc) { | |
2010 | return error; | |
2011 | } | |
2012 | ||
2013 | commandsDone = 0; | |
2014 | pc += sz_xGLXRenderReq; | |
2015 | left = (req->length << 2) - sz_xGLXRenderReq; | |
2016 | while (left > 0) { | |
2017 | __GLXrenderSizeData entry; | |
2018 | int extra; | |
2019 | __GLXdispatchRenderProcPtr proc; | |
2020 | int err; | |
2021 | ||
2022 | if (left < sizeof(__GLXrenderHeader)) | |
2023 | return BadLength; | |
2024 | ||
2025 | /* | |
2026 | ** Verify that the header length and the overall length agree. | |
2027 | ** Also, each command must be word aligned. | |
2028 | */ | |
2029 | hdr = (__GLXrenderHeader *) pc; | |
2030 | if (client->swapped) { | |
2031 | __GLX_SWAP_SHORT(&hdr->length); | |
2032 | __GLX_SWAP_SHORT(&hdr->opcode); | |
2033 | } | |
2034 | cmdlen = hdr->length; | |
2035 | opcode = hdr->opcode; | |
2036 | ||
2037 | /* | |
2038 | ** Check for core opcodes and grab entry data. | |
2039 | */ | |
2040 | err = __glXGetProtocolSizeData(&Render_dispatch_info, opcode, &entry); | |
2041 | proc = (__GLXdispatchRenderProcPtr) | |
2042 | __glXGetProtocolDecodeFunction(&Render_dispatch_info, | |
2043 | opcode, client->swapped); | |
2044 | ||
2045 | if ((err < 0) || (proc == NULL)) { | |
2046 | client->errorValue = commandsDone; | |
2047 | return __glXError(GLXBadRenderRequest); | |
2048 | } | |
2049 | ||
2050 | if (entry.varsize) { | |
2051 | /* variable size command */ | |
2052 | extra = (*entry.varsize) (pc + __GLX_RENDER_HDR_SIZE, | |
2053 | client->swapped); | |
2054 | if (extra < 0) { | |
2055 | extra = 0; | |
2056 | } | |
2057 | if (cmdlen != __GLX_PAD(entry.bytes + extra)) { | |
2058 | return BadLength; | |
2059 | } | |
2060 | } | |
2061 | else { | |
2062 | /* constant size command */ | |
2063 | if (cmdlen != __GLX_PAD(entry.bytes)) { | |
2064 | return BadLength; | |
2065 | } | |
2066 | } | |
2067 | if (left < cmdlen) { | |
2068 | return BadLength; | |
2069 | } | |
2070 | ||
2071 | /* | |
2072 | ** Skip over the header and execute the command. We allow the | |
2073 | ** caller to trash the command memory. This is useful especially | |
2074 | ** for things that require double alignment - they can just shift | |
2075 | ** the data towards lower memory (trashing the header) by 4 bytes | |
2076 | ** and achieve the required alignment. | |
2077 | */ | |
2078 | (*proc) (pc + __GLX_RENDER_HDR_SIZE); | |
2079 | pc += cmdlen; | |
2080 | left -= cmdlen; | |
2081 | commandsDone++; | |
2082 | } | |
2083 | glxc->hasUnflushedCommands = GL_TRUE; | |
2084 | return Success; | |
2085 | } | |
2086 | ||
2087 | /* | |
2088 | ** Execute a large rendering request (one that spans multiple X requests). | |
2089 | */ | |
2090 | int | |
2091 | __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc) | |
2092 | { | |
2093 | xGLXRenderLargeReq *req; | |
2094 | ClientPtr client = cl->client; | |
2095 | size_t dataBytes; | |
2096 | __GLXrenderLargeHeader *hdr; | |
2097 | __GLXcontext *glxc; | |
2098 | int error; | |
2099 | CARD16 opcode; | |
2100 | ||
2101 | __GLX_DECLARE_SWAP_VARIABLES; | |
2102 | ||
2103 | req = (xGLXRenderLargeReq *) pc; | |
2104 | if (client->swapped) { | |
2105 | __GLX_SWAP_SHORT(&req->length); | |
2106 | __GLX_SWAP_INT(&req->contextTag); | |
2107 | __GLX_SWAP_INT(&req->dataBytes); | |
2108 | __GLX_SWAP_SHORT(&req->requestNumber); | |
2109 | __GLX_SWAP_SHORT(&req->requestTotal); | |
2110 | } | |
2111 | ||
2112 | glxc = __glXForceCurrent(cl, req->contextTag, &error); | |
2113 | if (!glxc) { | |
2114 | /* Reset in case this isn't 1st request. */ | |
2115 | __glXResetLargeCommandStatus(cl); | |
2116 | return error; | |
2117 | } | |
2118 | dataBytes = req->dataBytes; | |
2119 | ||
2120 | /* | |
2121 | ** Check the request length. | |
2122 | */ | |
2123 | if ((req->length << 2) != __GLX_PAD(dataBytes) + sz_xGLXRenderLargeReq) { | |
2124 | client->errorValue = req->length; | |
2125 | /* Reset in case this isn't 1st request. */ | |
2126 | __glXResetLargeCommandStatus(cl); | |
2127 | return BadLength; | |
2128 | } | |
2129 | pc += sz_xGLXRenderLargeReq; | |
2130 | ||
2131 | if (cl->largeCmdRequestsSoFar == 0) { | |
2132 | __GLXrenderSizeData entry; | |
2133 | int extra; | |
2134 | size_t cmdlen; | |
2135 | int err; | |
2136 | ||
2137 | /* | |
2138 | ** This is the first request of a multi request command. | |
2139 | ** Make enough space in the buffer, then copy the entire request. | |
2140 | */ | |
2141 | if (req->requestNumber != 1) { | |
2142 | client->errorValue = req->requestNumber; | |
2143 | return __glXError(GLXBadLargeRequest); | |
2144 | } | |
2145 | ||
2146 | hdr = (__GLXrenderLargeHeader *) pc; | |
2147 | if (client->swapped) { | |
2148 | __GLX_SWAP_INT(&hdr->length); | |
2149 | __GLX_SWAP_INT(&hdr->opcode); | |
2150 | } | |
2151 | cmdlen = hdr->length; | |
2152 | opcode = hdr->opcode; | |
2153 | ||
2154 | /* | |
2155 | ** Check for core opcodes and grab entry data. | |
2156 | */ | |
2157 | err = __glXGetProtocolSizeData(&Render_dispatch_info, opcode, &entry); | |
2158 | if (err < 0) { | |
2159 | client->errorValue = opcode; | |
2160 | return __glXError(GLXBadLargeRequest); | |
2161 | } | |
2162 | ||
2163 | if (entry.varsize) { | |
2164 | /* | |
2165 | ** If it's a variable-size command (a command whose length must | |
2166 | ** be computed from its parameters), all the parameters needed | |
2167 | ** will be in the 1st request, so it's okay to do this. | |
2168 | */ | |
2169 | extra = (*entry.varsize) (pc + __GLX_RENDER_LARGE_HDR_SIZE, | |
2170 | client->swapped); | |
2171 | if (extra < 0) { | |
2172 | extra = 0; | |
2173 | } | |
2174 | /* large command's header is 4 bytes longer, so add 4 */ | |
2175 | if (cmdlen != __GLX_PAD(entry.bytes + 4 + extra)) { | |
2176 | return BadLength; | |
2177 | } | |
2178 | } | |
2179 | else { | |
2180 | /* constant size command */ | |
2181 | if (cmdlen != __GLX_PAD(entry.bytes + 4)) { | |
2182 | return BadLength; | |
2183 | } | |
2184 | } | |
2185 | /* | |
2186 | ** Make enough space in the buffer, then copy the entire request. | |
2187 | */ | |
2188 | if (cl->largeCmdBufSize < cmdlen) { | |
2189 | GLbyte *newbuf = cl->largeCmdBuf; | |
2190 | ||
2191 | if (!(newbuf = realloc(newbuf, cmdlen))) | |
2192 | return BadAlloc; | |
2193 | ||
2194 | cl->largeCmdBuf = newbuf; | |
2195 | cl->largeCmdBufSize = cmdlen; | |
2196 | } | |
2197 | memcpy(cl->largeCmdBuf, pc, dataBytes); | |
2198 | ||
2199 | cl->largeCmdBytesSoFar = dataBytes; | |
2200 | cl->largeCmdBytesTotal = cmdlen; | |
2201 | cl->largeCmdRequestsSoFar = 1; | |
2202 | cl->largeCmdRequestsTotal = req->requestTotal; | |
2203 | return Success; | |
2204 | ||
2205 | } | |
2206 | else { | |
2207 | /* | |
2208 | ** We are receiving subsequent (i.e. not the first) requests of a | |
2209 | ** multi request command. | |
2210 | */ | |
2211 | ||
2212 | /* | |
2213 | ** Check the request number and the total request count. | |
2214 | */ | |
2215 | if (req->requestNumber != cl->largeCmdRequestsSoFar + 1) { | |
2216 | client->errorValue = req->requestNumber; | |
2217 | __glXResetLargeCommandStatus(cl); | |
2218 | return __glXError(GLXBadLargeRequest); | |
2219 | } | |
2220 | if (req->requestTotal != cl->largeCmdRequestsTotal) { | |
2221 | client->errorValue = req->requestTotal; | |
2222 | __glXResetLargeCommandStatus(cl); | |
2223 | return __glXError(GLXBadLargeRequest); | |
2224 | } | |
2225 | ||
2226 | /* | |
2227 | ** Check that we didn't get too much data. | |
2228 | */ | |
2229 | if ((cl->largeCmdBytesSoFar + dataBytes) > cl->largeCmdBytesTotal) { | |
2230 | client->errorValue = dataBytes; | |
2231 | __glXResetLargeCommandStatus(cl); | |
2232 | return __glXError(GLXBadLargeRequest); | |
2233 | } | |
2234 | memcpy(cl->largeCmdBuf + cl->largeCmdBytesSoFar, pc, dataBytes); | |
2235 | cl->largeCmdBytesSoFar += dataBytes; | |
2236 | cl->largeCmdRequestsSoFar++; | |
2237 | ||
2238 | if (req->requestNumber == cl->largeCmdRequestsTotal) { | |
2239 | __GLXdispatchRenderProcPtr proc; | |
2240 | ||
2241 | /* | |
2242 | ** This is the last request; it must have enough bytes to complete | |
2243 | ** the command. | |
2244 | */ | |
2245 | /* NOTE: the two pad macros have been added below; they are needed | |
2246 | ** because the client library pads the total byte count, but not | |
2247 | ** the per-request byte counts. The Protocol Encoding says the | |
2248 | ** total byte count should not be padded, so a proposal will be | |
2249 | ** made to the ARB to relax the padding constraint on the total | |
2250 | ** byte count, thus preserving backward compatibility. Meanwhile, | |
2251 | ** the padding done below fixes a bug that did not allow | |
2252 | ** large commands of odd sizes to be accepted by the server. | |
2253 | */ | |
2254 | if (__GLX_PAD(cl->largeCmdBytesSoFar) != | |
2255 | __GLX_PAD(cl->largeCmdBytesTotal)) { | |
2256 | client->errorValue = dataBytes; | |
2257 | __glXResetLargeCommandStatus(cl); | |
2258 | return __glXError(GLXBadLargeRequest); | |
2259 | } | |
2260 | hdr = (__GLXrenderLargeHeader *) cl->largeCmdBuf; | |
2261 | /* | |
2262 | ** The opcode and length field in the header had already been | |
2263 | ** swapped when the first request was received. | |
2264 | ** | |
2265 | ** Use the opcode to index into the procedure table. | |
2266 | */ | |
2267 | opcode = hdr->opcode; | |
2268 | ||
2269 | proc = (__GLXdispatchRenderProcPtr) | |
2270 | __glXGetProtocolDecodeFunction(&Render_dispatch_info, opcode, | |
2271 | client->swapped); | |
2272 | if (proc == NULL) { | |
2273 | client->errorValue = opcode; | |
2274 | return __glXError(GLXBadLargeRequest); | |
2275 | } | |
2276 | ||
2277 | /* | |
2278 | ** Skip over the header and execute the command. | |
2279 | */ | |
2280 | (*proc) (cl->largeCmdBuf + __GLX_RENDER_LARGE_HDR_SIZE); | |
2281 | glxc->hasUnflushedCommands = GL_TRUE; | |
2282 | ||
2283 | /* | |
2284 | ** Reset for the next RenderLarge series. | |
2285 | */ | |
2286 | __glXResetLargeCommandStatus(cl); | |
2287 | } | |
2288 | else { | |
2289 | /* | |
2290 | ** This is neither the first nor the last request. | |
2291 | */ | |
2292 | } | |
2293 | return Success; | |
2294 | } | |
2295 | } | |
2296 | ||
2297 | /************************************************************************/ | |
2298 | ||
2299 | /* | |
2300 | ** No support is provided for the vendor-private requests other than | |
2301 | ** allocating the entry points in the dispatch table. | |
2302 | */ | |
2303 | ||
2304 | int | |
2305 | __glXDisp_VendorPrivate(__GLXclientState * cl, GLbyte * pc) | |
2306 | { | |
2307 | ClientPtr client = cl->client; | |
2308 | xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc; | |
2309 | GLint vendorcode = req->vendorCode; | |
2310 | __GLXdispatchVendorPrivProcPtr proc; | |
2311 | ||
2312 | REQUEST_AT_LEAST_SIZE(xGLXVendorPrivateReq); | |
2313 | ||
2314 | proc = (__GLXdispatchVendorPrivProcPtr) | |
2315 | __glXGetProtocolDecodeFunction(&VendorPriv_dispatch_info, | |
2316 | vendorcode, 0); | |
2317 | if (proc != NULL) { | |
2318 | (*proc) (cl, (GLbyte *) req); | |
2319 | return Success; | |
2320 | } | |
2321 | ||
2322 | cl->client->errorValue = req->vendorCode; | |
2323 | return __glXError(GLXUnsupportedPrivateRequest); | |
2324 | } | |
2325 | ||
2326 | int | |
2327 | __glXDisp_VendorPrivateWithReply(__GLXclientState * cl, GLbyte * pc) | |
2328 | { | |
2329 | ClientPtr client = cl->client; | |
2330 | xGLXVendorPrivateReq *req = (xGLXVendorPrivateReq *) pc; | |
2331 | GLint vendorcode = req->vendorCode; | |
2332 | __GLXdispatchVendorPrivProcPtr proc; | |
2333 | ||
2334 | REQUEST_AT_LEAST_SIZE(xGLXVendorPrivateReq); | |
2335 | ||
2336 | proc = (__GLXdispatchVendorPrivProcPtr) | |
2337 | __glXGetProtocolDecodeFunction(&VendorPriv_dispatch_info, | |
2338 | vendorcode, 0); | |
2339 | if (proc != NULL) { | |
2340 | return (*proc) (cl, (GLbyte *) req); | |
2341 | } | |
2342 | ||
2343 | cl->client->errorValue = vendorcode; | |
2344 | return __glXError(GLXUnsupportedPrivateRequest); | |
2345 | } | |
2346 | ||
2347 | int | |
2348 | __glXDisp_QueryExtensionsString(__GLXclientState * cl, GLbyte * pc) | |
2349 | { | |
2350 | ClientPtr client = cl->client; | |
2351 | xGLXQueryExtensionsStringReq *req = (xGLXQueryExtensionsStringReq *) pc; | |
2352 | xGLXQueryExtensionsStringReply reply; | |
2353 | __GLXscreen *pGlxScreen; | |
2354 | size_t n, length; | |
2355 | char *buf; | |
2356 | int err; | |
2357 | ||
2358 | REQUEST_SIZE_MATCH(xGLXQueryExtensionsStringReq); | |
2359 | ||
2360 | if (!validGlxScreen(client, req->screen, &pGlxScreen, &err)) | |
2361 | return err; | |
2362 | ||
2363 | n = strlen(pGlxScreen->GLXextensions) + 1; | |
2364 | length = __GLX_PAD(n) >> 2; | |
2365 | reply = (xGLXQueryExtensionsStringReply) { | |
2366 | .type = X_Reply, | |
2367 | .sequenceNumber = client->sequence, | |
2368 | .length = length, | |
2369 | .n = n | |
2370 | }; | |
2371 | ||
2372 | /* Allocate buffer to make sure it's a multiple of 4 bytes big. */ | |
2373 | buf = calloc(length, 4); | |
2374 | if (buf == NULL) | |
2375 | return BadAlloc; | |
2376 | memcpy(buf, pGlxScreen->GLXextensions, n); | |
2377 | ||
2378 | if (client->swapped) { | |
2379 | glxSwapQueryExtensionsStringReply(client, &reply, buf); | |
2380 | } | |
2381 | else { | |
2382 | WriteToClient(client, sz_xGLXQueryExtensionsStringReply, &reply); | |
2383 | WriteToClient(client, (int) (length << 2), buf); | |
2384 | } | |
2385 | ||
2386 | free(buf); | |
2387 | return Success; | |
2388 | } | |
2389 | ||
2390 | int | |
2391 | __glXDisp_QueryServerString(__GLXclientState * cl, GLbyte * pc) | |
2392 | { | |
2393 | ClientPtr client = cl->client; | |
2394 | xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) pc; | |
2395 | xGLXQueryServerStringReply reply; | |
2396 | size_t n, length; | |
2397 | const char *ptr; | |
2398 | char *buf; | |
2399 | __GLXscreen *pGlxScreen; | |
2400 | int err; | |
2401 | char ver_str[16]; | |
2402 | ||
2403 | REQUEST_SIZE_MATCH(xGLXQueryServerStringReq); | |
2404 | ||
2405 | if (!validGlxScreen(client, req->screen, &pGlxScreen, &err)) | |
2406 | return err; | |
2407 | ||
2408 | switch (req->name) { | |
2409 | case GLX_VENDOR: | |
2410 | ptr = GLXServerVendorName; | |
2411 | break; | |
2412 | case GLX_VERSION: | |
2413 | /* Return to the server version rather than the screen version | |
2414 | * to prevent confusion when they do not match. | |
2415 | */ | |
2416 | snprintf(ver_str, 16, "%d.%d", glxMajorVersion, glxMinorVersion); | |
2417 | ptr = ver_str; | |
2418 | break; | |
2419 | case GLX_EXTENSIONS: | |
2420 | ptr = pGlxScreen->GLXextensions; | |
2421 | break; | |
2422 | default: | |
2423 | return BadValue; | |
2424 | } | |
2425 | ||
2426 | n = strlen(ptr) + 1; | |
2427 | length = __GLX_PAD(n) >> 2; | |
2428 | reply = (xGLXQueryServerStringReply) { | |
2429 | .type = X_Reply, | |
2430 | .sequenceNumber = client->sequence, | |
2431 | .length = length, | |
2432 | .n = n | |
2433 | }; | |
2434 | ||
2435 | buf = calloc(length, 4); | |
2436 | if (buf == NULL) { | |
2437 | return BadAlloc; | |
2438 | } | |
2439 | memcpy(buf, ptr, n); | |
2440 | ||
2441 | if (client->swapped) { | |
2442 | glxSwapQueryServerStringReply(client, &reply, buf); | |
2443 | } | |
2444 | else { | |
2445 | WriteToClient(client, sz_xGLXQueryServerStringReply, &reply); | |
2446 | WriteToClient(client, (int) (length << 2), buf); | |
2447 | } | |
2448 | ||
2449 | free(buf); | |
2450 | return Success; | |
2451 | } | |
2452 | ||
2453 | int | |
2454 | __glXDisp_ClientInfo(__GLXclientState * cl, GLbyte * pc) | |
2455 | { | |
2456 | ClientPtr client = cl->client; | |
2457 | xGLXClientInfoReq *req = (xGLXClientInfoReq *) pc; | |
2458 | const char *buf; | |
2459 | ||
2460 | REQUEST_AT_LEAST_SIZE(xGLXClientInfoReq); | |
2461 | ||
2462 | buf = (const char *) (req + 1); | |
2463 | if (!memchr(buf, 0, (client->req_len << 2) - sizeof(xGLXClientInfoReq))) | |
2464 | return BadLength; | |
2465 | ||
2466 | free(cl->GLClientextensions); | |
2467 | cl->GLClientextensions = strdup(buf); | |
2468 | ||
2469 | return Success; | |
2470 | } | |
2471 | ||
2472 | #include <GL/glxtokens.h> | |
2473 | ||
2474 | void | |
2475 | __glXsendSwapEvent(__GLXdrawable *drawable, int type, CARD64 ust, | |
2476 | CARD64 msc, CARD32 sbc) | |
2477 | { | |
2478 | ClientPtr client = clients[CLIENT_ID(drawable->drawId)]; | |
2479 | ||
2480 | xGLXBufferSwapComplete2 wire = { | |
2481 | .type = __glXEventBase + GLX_BufferSwapComplete | |
2482 | }; | |
2483 | ||
2484 | if (!client) | |
2485 | return; | |
2486 | ||
2487 | if (!(drawable->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)) | |
2488 | return; | |
2489 | ||
2490 | wire.event_type = type; | |
2491 | wire.drawable = drawable->drawId; | |
2492 | wire.ust_hi = ust >> 32; | |
2493 | wire.ust_lo = ust & 0xffffffff; | |
2494 | wire.msc_hi = msc >> 32; | |
2495 | wire.msc_lo = msc & 0xffffffff; | |
2496 | wire.sbc = sbc; | |
2497 | ||
2498 | WriteEventsToClient(client, 1, (xEvent *) &wire); | |
2499 | } | |
2500 | ||
2501 | #if PRESENT | |
2502 | static void | |
2503 | __glXpresentCompleteNotify(WindowPtr window, CARD8 present_mode, CARD32 serial, | |
2504 | uint64_t ust, uint64_t msc) | |
2505 | { | |
2506 | __GLXdrawable *drawable; | |
2507 | int glx_type; | |
2508 | int rc; | |
2509 | ||
2510 | rc = dixLookupResourceByType((pointer *) &drawable, window->drawable.id, | |
2511 | __glXDrawableRes, serverClient, DixGetAttrAccess); | |
2512 | ||
2513 | if (rc != Success) | |
2514 | return; | |
2515 | ||
2516 | if (present_mode == PresentCompleteModeFlip) | |
2517 | glx_type = GLX_FLIP_COMPLETE_INTEL; | |
2518 | else | |
2519 | glx_type = GLX_BLIT_COMPLETE_INTEL; | |
2520 | ||
2521 | __glXsendSwapEvent(drawable, glx_type, ust, msc, serial); | |
2522 | } | |
2523 | ||
2524 | #include <present.h> | |
2525 | ||
2526 | void | |
2527 | __glXregisterPresentCompleteNotify(void) | |
2528 | { | |
2529 | present_register_complete_notify(__glXpresentCompleteNotify); | |
2530 | } | |
2531 | #endif |