Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 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 | /** |
||
32 | * \file glxcmds.c |
||
33 | * Client-side GLX interface. |
||
34 | */ |
||
35 | |||
36 | #include "glxclient.h" |
||
37 | #include "glapi.h" |
||
38 | #include "glxextensions.h" |
||
39 | #include "indirect.h" |
||
40 | #include "glx_error.h" |
||
41 | |||
42 | #ifdef GLX_DIRECT_RENDERING |
||
43 | #ifdef GLX_USE_APPLEGL |
||
44 | #include "apple/apple_glx_context.h" |
||
45 | #include "apple/apple_glx.h" |
||
46 | #else |
||
47 | #include |
||
48 | #ifdef XF86VIDMODE |
||
49 | #include |
||
50 | #endif |
||
51 | #endif |
||
52 | #endif |
||
53 | |||
54 | #include |
||
55 | #include |
||
56 | #include |
||
57 | |||
58 | static const char __glXGLXClientVendorName[] = "Mesa Project and SGI"; |
||
59 | static const char __glXGLXClientVersion[] = "1.4"; |
||
60 | |||
61 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
62 | |||
63 | /** |
||
64 | * Get the __DRIdrawable for the drawable associated with a GLXContext |
||
65 | * |
||
66 | * \param dpy The display associated with \c drawable. |
||
67 | * \param drawable GLXDrawable whose __DRIdrawable part is to be retrieved. |
||
68 | * \param scrn_num If non-NULL, the drawables screen is stored there |
||
69 | * \returns A pointer to the context's __DRIdrawable on success, or NULL if |
||
70 | * the drawable is not associated with a direct-rendering context. |
||
71 | */ |
||
72 | _X_HIDDEN __GLXDRIdrawable * |
||
73 | GetGLXDRIDrawable(Display * dpy, GLXDrawable drawable) |
||
74 | { |
||
75 | struct glx_display *priv = __glXInitialize(dpy); |
||
76 | __GLXDRIdrawable *pdraw; |
||
77 | |||
78 | if (priv == NULL) |
||
79 | return NULL; |
||
80 | |||
81 | if (__glxHashLookup(priv->drawHash, drawable, (void *) &pdraw) == 0) |
||
82 | return pdraw; |
||
83 | |||
84 | return NULL; |
||
85 | } |
||
86 | |||
87 | #endif |
||
88 | |||
89 | _X_HIDDEN struct glx_drawable * |
||
90 | GetGLXDrawable(Display *dpy, GLXDrawable drawable) |
||
91 | { |
||
92 | struct glx_display *priv = __glXInitialize(dpy); |
||
93 | struct glx_drawable *glxDraw; |
||
94 | |||
95 | if (priv == NULL) |
||
96 | return NULL; |
||
97 | |||
98 | if (__glxHashLookup(priv->glXDrawHash, drawable, (void *) &glxDraw) == 0) |
||
99 | return glxDraw; |
||
100 | |||
101 | return NULL; |
||
102 | } |
||
103 | |||
104 | _X_HIDDEN int |
||
105 | InitGLXDrawable(Display *dpy, struct glx_drawable *glxDraw, XID xDrawable, |
||
106 | GLXDrawable drawable) |
||
107 | { |
||
108 | struct glx_display *priv = __glXInitialize(dpy); |
||
109 | |||
110 | if (!priv) |
||
111 | return -1; |
||
112 | |||
113 | glxDraw->xDrawable = xDrawable; |
||
114 | glxDraw->drawable = drawable; |
||
115 | glxDraw->lastEventSbc = 0; |
||
116 | glxDraw->eventSbcWrap = 0; |
||
117 | |||
118 | return __glxHashInsert(priv->glXDrawHash, drawable, glxDraw); |
||
119 | } |
||
120 | |||
121 | _X_HIDDEN void |
||
122 | DestroyGLXDrawable(Display *dpy, GLXDrawable drawable) |
||
123 | { |
||
124 | struct glx_display *priv = __glXInitialize(dpy); |
||
125 | struct glx_drawable *glxDraw; |
||
126 | |||
127 | if (!priv) |
||
128 | return; |
||
129 | |||
130 | glxDraw = GetGLXDrawable(dpy, drawable); |
||
131 | __glxHashDelete(priv->glXDrawHash, drawable); |
||
132 | free(glxDraw); |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Get the GLX per-screen data structure associated with a GLX context. |
||
137 | * |
||
138 | * \param dpy Display for which the GLX per-screen information is to be |
||
139 | * retrieved. |
||
140 | * \param scrn Screen on \c dpy for which the GLX per-screen information is |
||
141 | * to be retrieved. |
||
142 | * \returns A pointer to the GLX per-screen data if \c dpy and \c scrn |
||
143 | * specify a valid GLX screen, or NULL otherwise. |
||
144 | * |
||
145 | * \todo Should this function validate that \c scrn is within the screen |
||
146 | * number range for \c dpy? |
||
147 | */ |
||
148 | |||
149 | _X_HIDDEN struct glx_screen * |
||
150 | GetGLXScreenConfigs(Display * dpy, int scrn) |
||
151 | { |
||
152 | struct glx_display *const priv = __glXInitialize(dpy); |
||
153 | |||
154 | return (priv |
||
155 | && priv->screens != |
||
156 | NULL) ? priv->screens[scrn] : NULL; |
||
157 | } |
||
158 | |||
159 | |||
160 | static int |
||
161 | GetGLXPrivScreenConfig(Display * dpy, int scrn, struct glx_display ** ppriv, |
||
162 | struct glx_screen ** ppsc) |
||
163 | { |
||
164 | /* Initialize the extension, if needed . This has the added value |
||
165 | * of initializing/allocating the display private |
||
166 | */ |
||
167 | |||
168 | if (dpy == NULL) { |
||
169 | return GLX_NO_EXTENSION; |
||
170 | } |
||
171 | |||
172 | *ppriv = __glXInitialize(dpy); |
||
173 | if (*ppriv == NULL) { |
||
174 | return GLX_NO_EXTENSION; |
||
175 | } |
||
176 | |||
177 | /* Check screen number to see if its valid */ |
||
178 | if ((scrn < 0) || (scrn >= ScreenCount(dpy))) { |
||
179 | return GLX_BAD_SCREEN; |
||
180 | } |
||
181 | |||
182 | /* Check to see if the GL is supported on this screen */ |
||
183 | *ppsc = (*ppriv)->screens[scrn]; |
||
184 | if ((*ppsc)->configs == NULL && (*ppsc)->visuals == NULL) { |
||
185 | /* No support for GL on this screen regardless of visual */ |
||
186 | return GLX_BAD_VISUAL; |
||
187 | } |
||
188 | |||
189 | return Success; |
||
190 | } |
||
191 | |||
192 | |||
193 | /** |
||
194 | * Determine if a \c GLXFBConfig supplied by the application is valid. |
||
195 | * |
||
196 | * \param dpy Application supplied \c Display pointer. |
||
197 | * \param config Application supplied \c GLXFBConfig. |
||
198 | * |
||
199 | * \returns If the \c GLXFBConfig is valid, the a pointer to the matching |
||
200 | * \c struct glx_config structure is returned. Otherwise, \c NULL |
||
201 | * is returned. |
||
202 | */ |
||
203 | static struct glx_config * |
||
204 | ValidateGLXFBConfig(Display * dpy, GLXFBConfig fbconfig) |
||
205 | { |
||
206 | struct glx_display *const priv = __glXInitialize(dpy); |
||
207 | int num_screens = ScreenCount(dpy); |
||
208 | unsigned i; |
||
209 | struct glx_config *config; |
||
210 | |||
211 | if (priv != NULL) { |
||
212 | for (i = 0; i < num_screens; i++) { |
||
213 | for (config = priv->screens[i]->configs; config != NULL; |
||
214 | config = config->next) { |
||
215 | if (config == (struct glx_config *) fbconfig) { |
||
216 | return config; |
||
217 | } |
||
218 | } |
||
219 | } |
||
220 | } |
||
221 | |||
222 | return NULL; |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Verifies context's GLX_RENDER_TYPE value with config. |
||
227 | * |
||
228 | * \param config GLX FBConfig which will support the returned renderType. |
||
229 | * \param renderType The context render type to be verified. |
||
230 | * \return True if the value of context renderType was approved, or 0 if no |
||
231 | * valid value was found. |
||
232 | */ |
||
233 | Bool |
||
234 | validate_renderType_against_config(const struct glx_config *config, |
||
235 | int renderType) |
||
236 | { |
||
237 | switch (renderType) { |
||
238 | case GLX_RGBA_TYPE: |
||
239 | return (config->renderType & GLX_RGBA_BIT) != 0; |
||
240 | case GLX_COLOR_INDEX_TYPE: |
||
241 | return (config->renderType & GLX_COLOR_INDEX_BIT) != 0; |
||
242 | case GLX_RGBA_FLOAT_TYPE_ARB: |
||
243 | return (config->renderType & GLX_RGBA_FLOAT_BIT_ARB) != 0; |
||
244 | case GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT: |
||
245 | return (config->renderType & GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT) != 0; |
||
246 | default: |
||
247 | break; |
||
248 | } |
||
249 | return 0; |
||
250 | } |
||
251 | |||
252 | _X_HIDDEN Bool |
||
253 | glx_context_init(struct glx_context *gc, |
||
254 | struct glx_screen *psc, struct glx_config *config) |
||
255 | { |
||
256 | gc->majorOpcode = __glXSetupForCommand(psc->display->dpy); |
||
257 | if (!gc->majorOpcode) |
||
258 | return False; |
||
259 | |||
260 | gc->screen = psc->scr; |
||
261 | gc->psc = psc; |
||
262 | gc->config = config; |
||
263 | gc->isDirect = GL_TRUE; |
||
264 | gc->currentContextTag = -1; |
||
265 | |||
266 | return True; |
||
267 | } |
||
268 | |||
269 | |||
270 | /** |
||
271 | * Create a new context. |
||
272 | * |
||
273 | * \param renderType For FBConfigs, what is the rendering type? |
||
274 | */ |
||
275 | |||
276 | static GLXContext |
||
277 | CreateContext(Display *dpy, int generic_id, struct glx_config *config, |
||
278 | GLXContext shareList_user, Bool allowDirect, |
||
279 | unsigned code, int renderType, int screen) |
||
280 | { |
||
281 | struct glx_context *gc; |
||
282 | struct glx_screen *psc; |
||
283 | struct glx_context *shareList = (struct glx_context *) shareList_user; |
||
284 | if (dpy == NULL) |
||
285 | return NULL; |
||
286 | |||
287 | psc = GetGLXScreenConfigs(dpy, screen); |
||
288 | if (psc == NULL) |
||
289 | return NULL; |
||
290 | |||
291 | if (generic_id == None) |
||
292 | return NULL; |
||
293 | |||
294 | gc = NULL; |
||
295 | #ifdef GLX_USE_APPLEGL |
||
296 | gc = applegl_create_context(psc, config, shareList, renderType); |
||
297 | #else |
||
298 | if (allowDirect && psc->vtable->create_context) |
||
299 | gc = psc->vtable->create_context(psc, config, shareList, renderType); |
||
300 | if (!gc) |
||
301 | gc = indirect_create_context(psc, config, shareList, renderType); |
||
302 | #endif |
||
303 | if (!gc) |
||
304 | return NULL; |
||
305 | |||
306 | LockDisplay(dpy); |
||
307 | switch (code) { |
||
308 | case X_GLXCreateContext: { |
||
309 | xGLXCreateContextReq *req; |
||
310 | |||
311 | /* Send the glXCreateContext request */ |
||
312 | GetReq(GLXCreateContext, req); |
||
313 | req->reqType = gc->majorOpcode; |
||
314 | req->glxCode = X_GLXCreateContext; |
||
315 | req->context = gc->xid = XAllocID(dpy); |
||
316 | req->visual = generic_id; |
||
317 | req->screen = screen; |
||
318 | req->shareList = shareList ? shareList->xid : None; |
||
319 | req->isDirect = gc->isDirect; |
||
320 | break; |
||
321 | } |
||
322 | |||
323 | case X_GLXCreateNewContext: { |
||
324 | xGLXCreateNewContextReq *req; |
||
325 | |||
326 | /* Send the glXCreateNewContext request */ |
||
327 | GetReq(GLXCreateNewContext, req); |
||
328 | req->reqType = gc->majorOpcode; |
||
329 | req->glxCode = X_GLXCreateNewContext; |
||
330 | req->context = gc->xid = XAllocID(dpy); |
||
331 | req->fbconfig = generic_id; |
||
332 | req->screen = screen; |
||
333 | req->renderType = renderType; |
||
334 | req->shareList = shareList ? shareList->xid : None; |
||
335 | req->isDirect = gc->isDirect; |
||
336 | break; |
||
337 | } |
||
338 | |||
339 | case X_GLXvop_CreateContextWithConfigSGIX: { |
||
340 | xGLXVendorPrivateWithReplyReq *vpreq; |
||
341 | xGLXCreateContextWithConfigSGIXReq *req; |
||
342 | |||
343 | /* Send the glXCreateNewContext request */ |
||
344 | GetReqExtra(GLXVendorPrivateWithReply, |
||
345 | sz_xGLXCreateContextWithConfigSGIXReq - |
||
346 | sz_xGLXVendorPrivateWithReplyReq, vpreq); |
||
347 | req = (xGLXCreateContextWithConfigSGIXReq *) vpreq; |
||
348 | req->reqType = gc->majorOpcode; |
||
349 | req->glxCode = X_GLXVendorPrivateWithReply; |
||
350 | req->vendorCode = X_GLXvop_CreateContextWithConfigSGIX; |
||
351 | req->context = gc->xid = XAllocID(dpy); |
||
352 | req->fbconfig = generic_id; |
||
353 | req->screen = screen; |
||
354 | req->renderType = renderType; |
||
355 | req->shareList = shareList ? shareList->xid : None; |
||
356 | req->isDirect = gc->isDirect; |
||
357 | break; |
||
358 | } |
||
359 | |||
360 | default: |
||
361 | /* What to do here? This case is the sign of an internal error. It |
||
362 | * should never be reachable. |
||
363 | */ |
||
364 | break; |
||
365 | } |
||
366 | |||
367 | UnlockDisplay(dpy); |
||
368 | SyncHandle(); |
||
369 | |||
370 | gc->share_xid = shareList ? shareList->xid : None; |
||
371 | gc->imported = GL_FALSE; |
||
372 | |||
373 | return (GLXContext) gc; |
||
374 | } |
||
375 | |||
376 | _X_EXPORT GLXContext |
||
377 | glXCreateContext(Display * dpy, XVisualInfo * vis, |
||
378 | GLXContext shareList, Bool allowDirect) |
||
379 | { |
||
380 | struct glx_config *config = NULL; |
||
381 | int renderType = GLX_RGBA_TYPE; |
||
382 | |||
383 | #if defined(GLX_DIRECT_RENDERING) || defined(GLX_USE_APPLEGL) |
||
384 | struct glx_screen *const psc = GetGLXScreenConfigs(dpy, vis->screen); |
||
385 | |||
386 | if (psc) |
||
387 | config = glx_config_find_visual(psc->visuals, vis->visualid); |
||
388 | |||
389 | if (config == NULL) { |
||
390 | xError error; |
||
391 | |||
392 | error.errorCode = BadValue; |
||
393 | error.resourceID = vis->visualid; |
||
394 | error.sequenceNumber = dpy->request; |
||
395 | error.type = X_Error; |
||
396 | error.majorCode = __glXSetupForCommand(dpy); |
||
397 | error.minorCode = X_GLXCreateContext; |
||
398 | _XError(dpy, &error); |
||
399 | return None; |
||
400 | } |
||
401 | |||
402 | /* Choose the context render type based on DRI config values. It is |
||
403 | * unusual to set this type from config, but we have no other choice, as |
||
404 | * this old API does not provide renderType parameter. |
||
405 | */ |
||
406 | if (config->renderType & GLX_RGBA_FLOAT_BIT_ARB) { |
||
407 | renderType = GLX_RGBA_FLOAT_TYPE_ARB; |
||
408 | } else if (config->renderType & GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT) { |
||
409 | renderType = GLX_RGBA_UNSIGNED_FLOAT_TYPE_EXT; |
||
410 | } else if (config->renderType & GLX_RGBA_BIT) { |
||
411 | renderType = GLX_RGBA_TYPE; |
||
412 | } else if (config->renderType & GLX_COLOR_INDEX_BIT) { |
||
413 | renderType = GLX_COLOR_INDEX_TYPE; |
||
414 | } else if (config->rgbMode) { |
||
415 | /* If we're here, then renderType is not set correctly. Let's use a |
||
416 | * safeguard - any TrueColor or DirectColor mode is RGB mode. Such |
||
417 | * default value is needed by old DRI drivers, which didn't set |
||
418 | * renderType correctly as the value was just ignored. |
||
419 | */ |
||
420 | renderType = GLX_RGBA_TYPE; |
||
421 | } else { |
||
422 | /* Safeguard - only one option left, all non-RGB modes are indexed |
||
423 | * modes. Again, this allows drivers with invalid renderType to work |
||
424 | * properly. |
||
425 | */ |
||
426 | renderType = GLX_COLOR_INDEX_TYPE; |
||
427 | } |
||
428 | #endif |
||
429 | |||
430 | return CreateContext(dpy, vis->visualid, config, shareList, allowDirect, |
||
431 | X_GLXCreateContext, renderType, vis->screen); |
||
432 | } |
||
433 | |||
434 | static void |
||
435 | glx_send_destroy_context(Display *dpy, XID xid) |
||
436 | { |
||
437 | CARD8 opcode = __glXSetupForCommand(dpy); |
||
438 | xGLXDestroyContextReq *req; |
||
439 | |||
440 | LockDisplay(dpy); |
||
441 | GetReq(GLXDestroyContext, req); |
||
442 | req->reqType = opcode; |
||
443 | req->glxCode = X_GLXDestroyContext; |
||
444 | req->context = xid; |
||
445 | UnlockDisplay(dpy); |
||
446 | SyncHandle(); |
||
447 | } |
||
448 | |||
449 | /* |
||
450 | ** Destroy the named context |
||
451 | */ |
||
452 | |||
453 | _X_EXPORT void |
||
454 | glXDestroyContext(Display * dpy, GLXContext ctx) |
||
455 | { |
||
456 | struct glx_context *gc = (struct glx_context *) ctx; |
||
457 | |||
458 | if (gc == NULL || gc->xid == None) |
||
459 | return; |
||
460 | |||
461 | __glXLock(); |
||
462 | if (!gc->imported) |
||
463 | glx_send_destroy_context(dpy, gc->xid); |
||
464 | |||
465 | if (gc->currentDpy) { |
||
466 | /* This context is bound to some thread. According to the man page, |
||
467 | * we should not actually delete the context until it's unbound. |
||
468 | * Note that we set gc->xid = None above. In MakeContextCurrent() |
||
469 | * we check for that and delete the context there. |
||
470 | */ |
||
471 | gc->xid = None; |
||
472 | } else { |
||
473 | gc->vtable->destroy(gc); |
||
474 | } |
||
475 | __glXUnlock(); |
||
476 | } |
||
477 | |||
478 | /* |
||
479 | ** Return the major and minor version #s for the GLX extension |
||
480 | */ |
||
481 | _X_EXPORT Bool |
||
482 | glXQueryVersion(Display * dpy, int *major, int *minor) |
||
483 | { |
||
484 | struct glx_display *priv; |
||
485 | |||
486 | /* Init the extension. This fetches the major and minor version. */ |
||
487 | priv = __glXInitialize(dpy); |
||
488 | if (!priv) |
||
489 | return False; |
||
490 | |||
491 | if (major) |
||
492 | *major = priv->majorVersion; |
||
493 | if (minor) |
||
494 | *minor = priv->minorVersion; |
||
495 | return True; |
||
496 | } |
||
497 | |||
498 | /* |
||
499 | ** Query the existence of the GLX extension |
||
500 | */ |
||
501 | _X_EXPORT Bool |
||
502 | glXQueryExtension(Display * dpy, int *errorBase, int *eventBase) |
||
503 | { |
||
504 | int major_op, erb, evb; |
||
505 | Bool rv; |
||
506 | |||
507 | rv = XQueryExtension(dpy, GLX_EXTENSION_NAME, &major_op, &evb, &erb); |
||
508 | if (rv) { |
||
509 | if (errorBase) |
||
510 | *errorBase = erb; |
||
511 | if (eventBase) |
||
512 | *eventBase = evb; |
||
513 | } |
||
514 | return rv; |
||
515 | } |
||
516 | |||
517 | /* |
||
518 | ** Put a barrier in the token stream that forces the GL to finish its |
||
519 | ** work before X can proceed. |
||
520 | */ |
||
521 | _X_EXPORT void |
||
522 | glXWaitGL(void) |
||
523 | { |
||
524 | struct glx_context *gc = __glXGetCurrentContext(); |
||
525 | |||
526 | if (gc && gc->vtable->wait_gl) |
||
527 | gc->vtable->wait_gl(gc); |
||
528 | } |
||
529 | |||
530 | /* |
||
531 | ** Put a barrier in the token stream that forces X to finish its |
||
532 | ** work before GL can proceed. |
||
533 | */ |
||
534 | _X_EXPORT void |
||
535 | glXWaitX(void) |
||
536 | { |
||
537 | struct glx_context *gc = __glXGetCurrentContext(); |
||
538 | |||
539 | if (gc && gc->vtable->wait_x) |
||
540 | gc->vtable->wait_x(gc); |
||
541 | } |
||
542 | |||
543 | _X_EXPORT void |
||
544 | glXUseXFont(Font font, int first, int count, int listBase) |
||
545 | { |
||
546 | struct glx_context *gc = __glXGetCurrentContext(); |
||
547 | |||
548 | if (gc && gc->vtable->use_x_font) |
||
549 | gc->vtable->use_x_font(gc, font, first, count, listBase); |
||
550 | } |
||
551 | |||
552 | /************************************************************************/ |
||
553 | |||
554 | /* |
||
555 | ** Copy the source context to the destination context using the |
||
556 | ** attribute "mask". |
||
557 | */ |
||
558 | _X_EXPORT void |
||
559 | glXCopyContext(Display * dpy, GLXContext source_user, |
||
560 | GLXContext dest_user, unsigned long mask) |
||
561 | { |
||
562 | struct glx_context *source = (struct glx_context *) source_user; |
||
563 | struct glx_context *dest = (struct glx_context *) dest_user; |
||
564 | #ifdef GLX_USE_APPLEGL |
||
565 | struct glx_context *gc = __glXGetCurrentContext(); |
||
566 | int errorcode; |
||
567 | bool x11error; |
||
568 | |||
569 | if(apple_glx_copy_context(gc->driContext, source->driContext, dest->driContext, |
||
570 | mask, &errorcode, &x11error)) { |
||
571 | __glXSendError(dpy, errorcode, 0, X_GLXCopyContext, x11error); |
||
572 | } |
||
573 | |||
574 | #else |
||
575 | xGLXCopyContextReq *req; |
||
576 | struct glx_context *gc = __glXGetCurrentContext(); |
||
577 | GLXContextTag tag; |
||
578 | CARD8 opcode; |
||
579 | |||
580 | opcode = __glXSetupForCommand(dpy); |
||
581 | if (!opcode) { |
||
582 | return; |
||
583 | } |
||
584 | |||
585 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
586 | if (gc->isDirect) { |
||
587 | /* NOT_DONE: This does not work yet */ |
||
588 | } |
||
589 | #endif |
||
590 | |||
591 | /* |
||
592 | ** If the source is the current context, send its tag so that the context |
||
593 | ** can be flushed before the copy. |
||
594 | */ |
||
595 | if (source == gc && dpy == gc->currentDpy) { |
||
596 | tag = gc->currentContextTag; |
||
597 | } |
||
598 | else { |
||
599 | tag = 0; |
||
600 | } |
||
601 | |||
602 | /* Send the glXCopyContext request */ |
||
603 | LockDisplay(dpy); |
||
604 | GetReq(GLXCopyContext, req); |
||
605 | req->reqType = opcode; |
||
606 | req->glxCode = X_GLXCopyContext; |
||
607 | req->source = source ? source->xid : None; |
||
608 | req->dest = dest ? dest->xid : None; |
||
609 | req->mask = mask; |
||
610 | req->contextTag = tag; |
||
611 | UnlockDisplay(dpy); |
||
612 | SyncHandle(); |
||
613 | #endif /* GLX_USE_APPLEGL */ |
||
614 | } |
||
615 | |||
616 | |||
617 | /** |
||
618 | * Determine if a context uses direct rendering. |
||
619 | * |
||
620 | * \param dpy Display where the context was created. |
||
621 | * \param contextID ID of the context to be tested. |
||
622 | * |
||
623 | * \returns \c True if the context is direct rendering or not. |
||
624 | */ |
||
625 | static Bool |
||
626 | __glXIsDirect(Display * dpy, GLXContextID contextID) |
||
627 | { |
||
628 | CARD8 opcode; |
||
629 | xcb_connection_t *c; |
||
630 | xcb_generic_error_t *err; |
||
631 | xcb_glx_is_direct_reply_t *reply; |
||
632 | Bool is_direct; |
||
633 | |||
634 | opcode = __glXSetupForCommand(dpy); |
||
635 | if (!opcode) { |
||
636 | return False; |
||
637 | } |
||
638 | |||
639 | c = XGetXCBConnection(dpy); |
||
640 | reply = xcb_glx_is_direct_reply(c, xcb_glx_is_direct(c, contextID), &err); |
||
641 | is_direct = (reply != NULL && reply->is_direct) ? True : False; |
||
642 | |||
643 | if (err != NULL) { |
||
644 | __glXSendErrorForXcb(dpy, err); |
||
645 | free(err); |
||
646 | } |
||
647 | |||
648 | free(reply); |
||
649 | |||
650 | return is_direct; |
||
651 | } |
||
652 | |||
653 | /** |
||
654 | * \todo |
||
655 | * Shouldn't this function \b always return \c False when |
||
656 | * \c GLX_DIRECT_RENDERING is not defined? Do we really need to bother with |
||
657 | * the GLX protocol here at all? |
||
658 | */ |
||
659 | _X_EXPORT Bool |
||
660 | glXIsDirect(Display * dpy, GLXContext gc_user) |
||
661 | { |
||
662 | struct glx_context *gc = (struct glx_context *) gc_user; |
||
663 | |||
664 | if (!gc) { |
||
665 | return False; |
||
666 | } |
||
667 | else if (gc->isDirect) { |
||
668 | return True; |
||
669 | } |
||
670 | #ifdef GLX_USE_APPLEGL /* TODO: indirect on darwin */ |
||
671 | return False; |
||
672 | #else |
||
673 | return __glXIsDirect(dpy, gc->xid); |
||
674 | #endif |
||
675 | } |
||
676 | |||
677 | _X_EXPORT GLXPixmap |
||
678 | glXCreateGLXPixmap(Display * dpy, XVisualInfo * vis, Pixmap pixmap) |
||
679 | { |
||
680 | #ifdef GLX_USE_APPLEGL |
||
681 | int screen = vis->screen; |
||
682 | struct glx_screen *const psc = GetGLXScreenConfigs(dpy, screen); |
||
683 | const struct glx_config *config; |
||
684 | |||
685 | config = glx_config_find_visual(psc->visuals, vis->visualid); |
||
686 | |||
687 | if(apple_glx_pixmap_create(dpy, vis->screen, pixmap, config)) |
||
688 | return None; |
||
689 | |||
690 | return pixmap; |
||
691 | #else |
||
692 | xGLXCreateGLXPixmapReq *req; |
||
693 | struct glx_drawable *glxDraw; |
||
694 | GLXPixmap xid; |
||
695 | CARD8 opcode; |
||
696 | |||
697 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
698 | struct glx_display *const priv = __glXInitialize(dpy); |
||
699 | |||
700 | if (priv == NULL) |
||
701 | return None; |
||
702 | #endif |
||
703 | |||
704 | opcode = __glXSetupForCommand(dpy); |
||
705 | if (!opcode) { |
||
706 | return None; |
||
707 | } |
||
708 | |||
709 | glxDraw = malloc(sizeof(*glxDraw)); |
||
710 | if (!glxDraw) |
||
711 | return None; |
||
712 | |||
713 | /* Send the glXCreateGLXPixmap request */ |
||
714 | LockDisplay(dpy); |
||
715 | GetReq(GLXCreateGLXPixmap, req); |
||
716 | req->reqType = opcode; |
||
717 | req->glxCode = X_GLXCreateGLXPixmap; |
||
718 | req->screen = vis->screen; |
||
719 | req->visual = vis->visualid; |
||
720 | req->pixmap = pixmap; |
||
721 | req->glxpixmap = xid = XAllocID(dpy); |
||
722 | UnlockDisplay(dpy); |
||
723 | SyncHandle(); |
||
724 | |||
725 | if (InitGLXDrawable(dpy, glxDraw, pixmap, req->glxpixmap)) { |
||
726 | free(glxDraw); |
||
727 | return None; |
||
728 | } |
||
729 | |||
730 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
731 | do { |
||
732 | /* FIXME: Maybe delay __DRIdrawable creation until the drawable |
||
733 | * is actually bound to a context... */ |
||
734 | |||
735 | __GLXDRIdrawable *pdraw; |
||
736 | struct glx_screen *psc; |
||
737 | struct glx_config *config; |
||
738 | |||
739 | psc = priv->screens[vis->screen]; |
||
740 | if (psc->driScreen == NULL) |
||
741 | return xid; |
||
742 | |||
743 | config = glx_config_find_visual(psc->visuals, vis->visualid); |
||
744 | pdraw = psc->driScreen->createDrawable(psc, pixmap, xid, config); |
||
745 | if (pdraw == NULL) { |
||
746 | fprintf(stderr, "failed to create pixmap\n"); |
||
747 | xid = None; |
||
748 | break; |
||
749 | } |
||
750 | |||
751 | if (__glxHashInsert(priv->drawHash, xid, pdraw)) { |
||
752 | (*pdraw->destroyDrawable) (pdraw); |
||
753 | xid = None; |
||
754 | break; |
||
755 | } |
||
756 | } while (0); |
||
757 | |||
758 | if (xid == None) { |
||
759 | xGLXDestroyGLXPixmapReq *dreq; |
||
760 | LockDisplay(dpy); |
||
761 | GetReq(GLXDestroyGLXPixmap, dreq); |
||
762 | dreq->reqType = opcode; |
||
763 | dreq->glxCode = X_GLXDestroyGLXPixmap; |
||
764 | dreq->glxpixmap = xid; |
||
765 | UnlockDisplay(dpy); |
||
766 | SyncHandle(); |
||
767 | } |
||
768 | #endif |
||
769 | |||
770 | return xid; |
||
771 | #endif |
||
772 | } |
||
773 | |||
774 | /* |
||
775 | ** Destroy the named pixmap |
||
776 | */ |
||
777 | _X_EXPORT void |
||
778 | glXDestroyGLXPixmap(Display * dpy, GLXPixmap glxpixmap) |
||
779 | { |
||
780 | #ifdef GLX_USE_APPLEGL |
||
781 | if(apple_glx_pixmap_destroy(dpy, glxpixmap)) |
||
782 | __glXSendError(dpy, GLXBadPixmap, glxpixmap, X_GLXDestroyPixmap, false); |
||
783 | #else |
||
784 | xGLXDestroyGLXPixmapReq *req; |
||
785 | CARD8 opcode; |
||
786 | |||
787 | opcode = __glXSetupForCommand(dpy); |
||
788 | if (!opcode) { |
||
789 | return; |
||
790 | } |
||
791 | |||
792 | /* Send the glXDestroyGLXPixmap request */ |
||
793 | LockDisplay(dpy); |
||
794 | GetReq(GLXDestroyGLXPixmap, req); |
||
795 | req->reqType = opcode; |
||
796 | req->glxCode = X_GLXDestroyGLXPixmap; |
||
797 | req->glxpixmap = glxpixmap; |
||
798 | UnlockDisplay(dpy); |
||
799 | SyncHandle(); |
||
800 | |||
801 | DestroyGLXDrawable(dpy, glxpixmap); |
||
802 | |||
803 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
804 | { |
||
805 | struct glx_display *const priv = __glXInitialize(dpy); |
||
806 | __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, glxpixmap); |
||
807 | |||
808 | if (priv != NULL && pdraw != NULL) { |
||
809 | (*pdraw->destroyDrawable) (pdraw); |
||
810 | __glxHashDelete(priv->drawHash, glxpixmap); |
||
811 | } |
||
812 | } |
||
813 | #endif |
||
814 | #endif /* GLX_USE_APPLEGL */ |
||
815 | } |
||
816 | |||
817 | _X_EXPORT void |
||
818 | glXSwapBuffers(Display * dpy, GLXDrawable drawable) |
||
819 | { |
||
820 | #ifdef GLX_USE_APPLEGL |
||
821 | struct glx_context * gc = __glXGetCurrentContext(); |
||
822 | if(gc && apple_glx_is_current_drawable(dpy, gc->driContext, drawable)) { |
||
823 | apple_glx_swap_buffers(gc->driContext); |
||
824 | } else { |
||
825 | __glXSendError(dpy, GLXBadCurrentWindow, 0, X_GLXSwapBuffers, false); |
||
826 | } |
||
827 | #else |
||
828 | struct glx_context *gc; |
||
829 | GLXContextTag tag; |
||
830 | CARD8 opcode; |
||
831 | xcb_connection_t *c; |
||
832 | |||
833 | gc = __glXGetCurrentContext(); |
||
834 | |||
835 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
836 | { |
||
837 | __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable); |
||
838 | |||
839 | if (pdraw != NULL) { |
||
840 | Bool flush = gc && drawable == gc->currentDrawable; |
||
841 | |||
842 | (*pdraw->psc->driScreen->swapBuffers)(pdraw, 0, 0, 0, flush); |
||
843 | return; |
||
844 | } |
||
845 | } |
||
846 | #endif |
||
847 | |||
848 | opcode = __glXSetupForCommand(dpy); |
||
849 | if (!opcode) { |
||
850 | return; |
||
851 | } |
||
852 | |||
853 | /* |
||
854 | ** The calling thread may or may not have a current context. If it |
||
855 | ** does, send the context tag so the server can do a flush. |
||
856 | */ |
||
857 | if ((gc != NULL) && (dpy == gc->currentDpy) && |
||
858 | ((drawable == gc->currentDrawable) |
||
859 | || (drawable == gc->currentReadable))) { |
||
860 | tag = gc->currentContextTag; |
||
861 | } |
||
862 | else { |
||
863 | tag = 0; |
||
864 | } |
||
865 | |||
866 | c = XGetXCBConnection(dpy); |
||
867 | xcb_glx_swap_buffers(c, tag, drawable); |
||
868 | xcb_flush(c); |
||
869 | #endif /* GLX_USE_APPLEGL */ |
||
870 | } |
||
871 | |||
872 | |||
873 | /* |
||
874 | ** Return configuration information for the given display, screen and |
||
875 | ** visual combination. |
||
876 | */ |
||
877 | _X_EXPORT int |
||
878 | glXGetConfig(Display * dpy, XVisualInfo * vis, int attribute, |
||
879 | int *value_return) |
||
880 | { |
||
881 | struct glx_display *priv; |
||
882 | struct glx_screen *psc; |
||
883 | struct glx_config *config; |
||
884 | int status; |
||
885 | |||
886 | status = GetGLXPrivScreenConfig(dpy, vis->screen, &priv, &psc); |
||
887 | if (status == Success) { |
||
888 | config = glx_config_find_visual(psc->visuals, vis->visualid); |
||
889 | |||
890 | /* Lookup attribute after first finding a match on the visual */ |
||
891 | if (config != NULL) { |
||
892 | return glx_config_get(config, attribute, value_return); |
||
893 | } |
||
894 | |||
895 | status = GLX_BAD_VISUAL; |
||
896 | } |
||
897 | |||
898 | /* |
||
899 | ** If we can't find the config for this visual, this visual is not |
||
900 | ** supported by the OpenGL implementation on the server. |
||
901 | */ |
||
902 | if ((status == GLX_BAD_VISUAL) && (attribute == GLX_USE_GL)) { |
||
903 | *value_return = False; |
||
904 | status = Success; |
||
905 | } |
||
906 | |||
907 | return status; |
||
908 | } |
||
909 | |||
910 | /************************************************************************/ |
||
911 | |||
912 | static void |
||
913 | init_fbconfig_for_chooser(struct glx_config * config, |
||
914 | GLboolean fbconfig_style_tags) |
||
915 | { |
||
916 | memset(config, 0, sizeof(struct glx_config)); |
||
917 | config->visualID = (XID) GLX_DONT_CARE; |
||
918 | config->visualType = GLX_DONT_CARE; |
||
919 | |||
920 | /* glXChooseFBConfig specifies different defaults for these properties than |
||
921 | * glXChooseVisual. |
||
922 | */ |
||
923 | if (fbconfig_style_tags) { |
||
924 | config->rgbMode = GL_TRUE; |
||
925 | config->doubleBufferMode = GLX_DONT_CARE; |
||
926 | config->renderType = GLX_RGBA_BIT; |
||
927 | } |
||
928 | |||
929 | config->drawableType = GLX_WINDOW_BIT; |
||
930 | config->visualRating = GLX_DONT_CARE; |
||
931 | config->transparentPixel = GLX_NONE; |
||
932 | config->transparentRed = GLX_DONT_CARE; |
||
933 | config->transparentGreen = GLX_DONT_CARE; |
||
934 | config->transparentBlue = GLX_DONT_CARE; |
||
935 | config->transparentAlpha = GLX_DONT_CARE; |
||
936 | config->transparentIndex = GLX_DONT_CARE; |
||
937 | |||
938 | config->xRenderable = GLX_DONT_CARE; |
||
939 | config->fbconfigID = (GLXFBConfigID) (GLX_DONT_CARE); |
||
940 | |||
941 | config->swapMethod = GLX_DONT_CARE; |
||
942 | } |
||
943 | |||
944 | #define MATCH_DONT_CARE( param ) \ |
||
945 | do { \ |
||
946 | if ( ((int) a-> param != (int) GLX_DONT_CARE) \ |
||
947 | && (a-> param != b-> param) ) { \ |
||
948 | return False; \ |
||
949 | } \ |
||
950 | } while ( 0 ) |
||
951 | |||
952 | #define MATCH_MINIMUM( param ) \ |
||
953 | do { \ |
||
954 | if ( ((int) a-> param != (int) GLX_DONT_CARE) \ |
||
955 | && (a-> param > b-> param) ) { \ |
||
956 | return False; \ |
||
957 | } \ |
||
958 | } while ( 0 ) |
||
959 | |||
960 | #define MATCH_EXACT( param ) \ |
||
961 | do { \ |
||
962 | if ( a-> param != b-> param) { \ |
||
963 | return False; \ |
||
964 | } \ |
||
965 | } while ( 0 ) |
||
966 | |||
967 | /* Test that all bits from a are contained in b */ |
||
968 | #define MATCH_MASK(param) \ |
||
969 | do { \ |
||
970 | if ( ((int) a-> param != (int) GLX_DONT_CARE) \ |
||
971 | && ((a->param & ~b->param) != 0) ) { \ |
||
972 | return False; \ |
||
973 | } \ |
||
974 | } while (0); |
||
975 | |||
976 | /** |
||
977 | * Determine if two GLXFBConfigs are compatible. |
||
978 | * |
||
979 | * \param a Application specified config to test. |
||
980 | * \param b Server specified config to test against \c a. |
||
981 | */ |
||
982 | static Bool |
||
983 | fbconfigs_compatible(const struct glx_config * const a, |
||
984 | const struct glx_config * const b) |
||
985 | { |
||
986 | MATCH_DONT_CARE(doubleBufferMode); |
||
987 | MATCH_DONT_CARE(visualType); |
||
988 | MATCH_DONT_CARE(visualRating); |
||
989 | MATCH_DONT_CARE(xRenderable); |
||
990 | MATCH_DONT_CARE(fbconfigID); |
||
991 | MATCH_DONT_CARE(swapMethod); |
||
992 | |||
993 | MATCH_MINIMUM(rgbBits); |
||
994 | MATCH_MINIMUM(numAuxBuffers); |
||
995 | MATCH_MINIMUM(redBits); |
||
996 | MATCH_MINIMUM(greenBits); |
||
997 | MATCH_MINIMUM(blueBits); |
||
998 | MATCH_MINIMUM(alphaBits); |
||
999 | MATCH_MINIMUM(depthBits); |
||
1000 | MATCH_MINIMUM(stencilBits); |
||
1001 | MATCH_MINIMUM(accumRedBits); |
||
1002 | MATCH_MINIMUM(accumGreenBits); |
||
1003 | MATCH_MINIMUM(accumBlueBits); |
||
1004 | MATCH_MINIMUM(accumAlphaBits); |
||
1005 | MATCH_MINIMUM(sampleBuffers); |
||
1006 | MATCH_MINIMUM(maxPbufferWidth); |
||
1007 | MATCH_MINIMUM(maxPbufferHeight); |
||
1008 | MATCH_MINIMUM(maxPbufferPixels); |
||
1009 | MATCH_MINIMUM(samples); |
||
1010 | |||
1011 | MATCH_DONT_CARE(stereoMode); |
||
1012 | MATCH_EXACT(level); |
||
1013 | |||
1014 | MATCH_MASK(drawableType); |
||
1015 | MATCH_MASK(renderType); |
||
1016 | |||
1017 | /* There is a bug in a few of the XFree86 DDX drivers. They contain |
||
1018 | * visuals with a "transparent type" of 0 when they really mean GLX_NONE. |
||
1019 | * Technically speaking, it is a bug in the DDX driver, but there is |
||
1020 | * enough of an installed base to work around the problem here. In any |
||
1021 | * case, 0 is not a valid value of the transparent type, so we'll treat 0 |
||
1022 | * from the app as GLX_DONT_CARE. We'll consider GLX_NONE from the app and |
||
1023 | * 0 from the server to be a match to maintain backward compatibility with |
||
1024 | * the (broken) drivers. |
||
1025 | */ |
||
1026 | |||
1027 | if (a->transparentPixel != (int) GLX_DONT_CARE && a->transparentPixel != 0) { |
||
1028 | if (a->transparentPixel == GLX_NONE) { |
||
1029 | if (b->transparentPixel != GLX_NONE && b->transparentPixel != 0) |
||
1030 | return False; |
||
1031 | } |
||
1032 | else { |
||
1033 | MATCH_EXACT(transparentPixel); |
||
1034 | } |
||
1035 | |||
1036 | switch (a->transparentPixel) { |
||
1037 | case GLX_TRANSPARENT_RGB: |
||
1038 | MATCH_DONT_CARE(transparentRed); |
||
1039 | MATCH_DONT_CARE(transparentGreen); |
||
1040 | MATCH_DONT_CARE(transparentBlue); |
||
1041 | MATCH_DONT_CARE(transparentAlpha); |
||
1042 | break; |
||
1043 | |||
1044 | case GLX_TRANSPARENT_INDEX: |
||
1045 | MATCH_DONT_CARE(transparentIndex); |
||
1046 | break; |
||
1047 | |||
1048 | default: |
||
1049 | break; |
||
1050 | } |
||
1051 | } |
||
1052 | |||
1053 | return True; |
||
1054 | } |
||
1055 | |||
1056 | |||
1057 | /* There's some trickly language in the GLX spec about how this is supposed |
||
1058 | * to work. Basically, if a given component size is either not specified |
||
1059 | * or the requested size is zero, it is supposed to act like PERFER_SMALLER. |
||
1060 | * Well, that's really hard to do with the code as-is. This behavior is |
||
1061 | * closer to correct, but still not technically right. |
||
1062 | */ |
||
1063 | #define PREFER_LARGER_OR_ZERO(comp) \ |
||
1064 | do { \ |
||
1065 | if ( ((*a)-> comp) != ((*b)-> comp) ) { \ |
||
1066 | if ( ((*a)-> comp) == 0 ) { \ |
||
1067 | return -1; \ |
||
1068 | } \ |
||
1069 | else if ( ((*b)-> comp) == 0 ) { \ |
||
1070 | return 1; \ |
||
1071 | } \ |
||
1072 | else { \ |
||
1073 | return ((*b)-> comp) - ((*a)-> comp) ; \ |
||
1074 | } \ |
||
1075 | } \ |
||
1076 | } while( 0 ) |
||
1077 | |||
1078 | #define PREFER_LARGER(comp) \ |
||
1079 | do { \ |
||
1080 | if ( ((*a)-> comp) != ((*b)-> comp) ) { \ |
||
1081 | return ((*b)-> comp) - ((*a)-> comp) ; \ |
||
1082 | } \ |
||
1083 | } while( 0 ) |
||
1084 | |||
1085 | #define PREFER_SMALLER(comp) \ |
||
1086 | do { \ |
||
1087 | if ( ((*a)-> comp) != ((*b)-> comp) ) { \ |
||
1088 | return ((*a)-> comp) - ((*b)-> comp) ; \ |
||
1089 | } \ |
||
1090 | } while( 0 ) |
||
1091 | |||
1092 | /** |
||
1093 | * Compare two GLXFBConfigs. This function is intended to be used as the |
||
1094 | * compare function passed in to qsort. |
||
1095 | * |
||
1096 | * \returns If \c a is a "better" config, according to the specification of |
||
1097 | * SGIX_fbconfig, a number less than zero is returned. If \c b is |
||
1098 | * better, then a number greater than zero is return. If both are |
||
1099 | * equal, zero is returned. |
||
1100 | * \sa qsort, glXChooseVisual, glXChooseFBConfig, glXChooseFBConfigSGIX |
||
1101 | */ |
||
1102 | static int |
||
1103 | fbconfig_compare(struct glx_config **a, struct glx_config **b) |
||
1104 | { |
||
1105 | /* The order of these comparisons must NOT change. It is defined by |
||
1106 | * the GLX 1.4 specification. |
||
1107 | */ |
||
1108 | |||
1109 | PREFER_SMALLER(visualSelectGroup); |
||
1110 | |||
1111 | /* The sort order for the visualRating is GLX_NONE, GLX_SLOW, and |
||
1112 | * GLX_NON_CONFORMANT_CONFIG. It just so happens that this is the |
||
1113 | * numerical sort order of the enums (0x8000, 0x8001, and 0x800D). |
||
1114 | */ |
||
1115 | PREFER_SMALLER(visualRating); |
||
1116 | |||
1117 | /* This isn't quite right. It is supposed to compare the sum of the |
||
1118 | * components the user specifically set minimums for. |
||
1119 | */ |
||
1120 | PREFER_LARGER_OR_ZERO(redBits); |
||
1121 | PREFER_LARGER_OR_ZERO(greenBits); |
||
1122 | PREFER_LARGER_OR_ZERO(blueBits); |
||
1123 | PREFER_LARGER_OR_ZERO(alphaBits); |
||
1124 | |||
1125 | PREFER_SMALLER(rgbBits); |
||
1126 | |||
1127 | if (((*a)->doubleBufferMode != (*b)->doubleBufferMode)) { |
||
1128 | /* Prefer single-buffer. |
||
1129 | */ |
||
1130 | return (!(*a)->doubleBufferMode) ? -1 : 1; |
||
1131 | } |
||
1132 | |||
1133 | PREFER_SMALLER(numAuxBuffers); |
||
1134 | |||
1135 | PREFER_SMALLER(sampleBuffers); |
||
1136 | PREFER_SMALLER(samples); |
||
1137 | |||
1138 | PREFER_LARGER_OR_ZERO(depthBits); |
||
1139 | PREFER_SMALLER(stencilBits); |
||
1140 | |||
1141 | /* This isn't quite right. It is supposed to compare the sum of the |
||
1142 | * components the user specifically set minimums for. |
||
1143 | */ |
||
1144 | PREFER_LARGER_OR_ZERO(accumRedBits); |
||
1145 | PREFER_LARGER_OR_ZERO(accumGreenBits); |
||
1146 | PREFER_LARGER_OR_ZERO(accumBlueBits); |
||
1147 | PREFER_LARGER_OR_ZERO(accumAlphaBits); |
||
1148 | |||
1149 | PREFER_SMALLER(visualType); |
||
1150 | |||
1151 | /* None of the pbuffer or fbconfig specs say that this comparison needs |
||
1152 | * to happen at all, but it seems like it should. |
||
1153 | */ |
||
1154 | PREFER_LARGER(maxPbufferWidth); |
||
1155 | PREFER_LARGER(maxPbufferHeight); |
||
1156 | PREFER_LARGER(maxPbufferPixels); |
||
1157 | |||
1158 | return 0; |
||
1159 | } |
||
1160 | |||
1161 | |||
1162 | /** |
||
1163 | * Selects and sorts a subset of the supplied configs based on the attributes. |
||
1164 | * This function forms to basis of \c glXChooseVisual, \c glXChooseFBConfig, |
||
1165 | * and \c glXChooseFBConfigSGIX. |
||
1166 | * |
||
1167 | * \param configs Array of pointers to possible configs. The elements of |
||
1168 | * this array that do not meet the criteria will be set to |
||
1169 | * NULL. The remaining elements will be sorted according to |
||
1170 | * the various visual / FBConfig selection rules. |
||
1171 | * \param num_configs Number of elements in the \c configs array. |
||
1172 | * \param attribList Attributes used select from \c configs. This array is |
||
1173 | * terminated by a \c None tag. The array can either take |
||
1174 | * the form expected by \c glXChooseVisual (where boolean |
||
1175 | * tags do not have a value) or by \c glXChooseFBConfig |
||
1176 | * (where every tag has a value). |
||
1177 | * \param fbconfig_style_tags Selects whether \c attribList is in |
||
1178 | * \c glXChooseVisual style or |
||
1179 | * \c glXChooseFBConfig style. |
||
1180 | * \returns The number of valid elements left in \c configs. |
||
1181 | * |
||
1182 | * \sa glXChooseVisual, glXChooseFBConfig, glXChooseFBConfigSGIX |
||
1183 | */ |
||
1184 | static int |
||
1185 | choose_visual(struct glx_config ** configs, int num_configs, |
||
1186 | const int *attribList, GLboolean fbconfig_style_tags) |
||
1187 | { |
||
1188 | struct glx_config test_config; |
||
1189 | int base; |
||
1190 | int i; |
||
1191 | |||
1192 | /* This is a fairly direct implementation of the selection method |
||
1193 | * described by GLX_SGIX_fbconfig. Start by culling out all the |
||
1194 | * configs that are not compatible with the selected parameter |
||
1195 | * list. |
||
1196 | */ |
||
1197 | |||
1198 | init_fbconfig_for_chooser(&test_config, fbconfig_style_tags); |
||
1199 | __glXInitializeVisualConfigFromTags(&test_config, 512, |
||
1200 | (const INT32 *) attribList, |
||
1201 | GL_TRUE, fbconfig_style_tags); |
||
1202 | |||
1203 | base = 0; |
||
1204 | for (i = 0; i < num_configs; i++) { |
||
1205 | if (fbconfigs_compatible(&test_config, configs[i])) { |
||
1206 | configs[base] = configs[i]; |
||
1207 | base++; |
||
1208 | } |
||
1209 | } |
||
1210 | |||
1211 | if (base == 0) { |
||
1212 | return 0; |
||
1213 | } |
||
1214 | |||
1215 | if (base < num_configs) { |
||
1216 | (void) memset(&configs[base], 0, sizeof(void *) * (num_configs - base)); |
||
1217 | } |
||
1218 | |||
1219 | /* After the incompatible configs are removed, the resulting |
||
1220 | * list is sorted according to the rules set out in the various |
||
1221 | * specifications. |
||
1222 | */ |
||
1223 | |||
1224 | qsort(configs, base, sizeof(struct glx_config *), |
||
1225 | (int (*)(const void *, const void *)) fbconfig_compare); |
||
1226 | return base; |
||
1227 | } |
||
1228 | |||
1229 | |||
1230 | |||
1231 | |||
1232 | /* |
||
1233 | ** Return the visual that best matches the template. Return None if no |
||
1234 | ** visual matches the template. |
||
1235 | */ |
||
1236 | _X_EXPORT XVisualInfo * |
||
1237 | glXChooseVisual(Display * dpy, int screen, int *attribList) |
||
1238 | { |
||
1239 | XVisualInfo *visualList = NULL; |
||
1240 | struct glx_display *priv; |
||
1241 | struct glx_screen *psc; |
||
1242 | struct glx_config test_config; |
||
1243 | struct glx_config *config; |
||
1244 | struct glx_config *best_config = NULL; |
||
1245 | |||
1246 | /* |
||
1247 | ** Get a list of all visuals, return if list is empty |
||
1248 | */ |
||
1249 | if (GetGLXPrivScreenConfig(dpy, screen, &priv, &psc) != Success) { |
||
1250 | return None; |
||
1251 | } |
||
1252 | |||
1253 | |||
1254 | /* |
||
1255 | ** Build a template from the defaults and the attribute list |
||
1256 | ** Free visual list and return if an unexpected token is encountered |
||
1257 | */ |
||
1258 | init_fbconfig_for_chooser(&test_config, GL_FALSE); |
||
1259 | __glXInitializeVisualConfigFromTags(&test_config, 512, |
||
1260 | (const INT32 *) attribList, |
||
1261 | GL_TRUE, GL_FALSE); |
||
1262 | |||
1263 | /* |
||
1264 | ** Eliminate visuals that don't meet minimum requirements |
||
1265 | ** Compute a score for those that do |
||
1266 | ** Remember which visual, if any, got the highest score |
||
1267 | ** If no visual is acceptable, return None |
||
1268 | ** Otherwise, create an XVisualInfo list with just the selected X visual |
||
1269 | ** and return this. |
||
1270 | */ |
||
1271 | for (config = psc->visuals; config != NULL; config = config->next) { |
||
1272 | if (fbconfigs_compatible(&test_config, config) |
||
1273 | && ((best_config == NULL) || |
||
1274 | (fbconfig_compare (&config, &best_config) < 0))) { |
||
1275 | XVisualInfo visualTemplate; |
||
1276 | XVisualInfo *newList; |
||
1277 | int i; |
||
1278 | |||
1279 | visualTemplate.screen = screen; |
||
1280 | visualTemplate.visualid = config->visualID; |
||
1281 | newList = XGetVisualInfo(dpy, VisualScreenMask | VisualIDMask, |
||
1282 | &visualTemplate, &i); |
||
1283 | |||
1284 | if (newList) { |
||
1285 | free(visualList); |
||
1286 | visualList = newList; |
||
1287 | best_config = config; |
||
1288 | } |
||
1289 | } |
||
1290 | } |
||
1291 | |||
1292 | #ifdef GLX_USE_APPLEGL |
||
1293 | if(visualList && getenv("LIBGL_DUMP_VISUALID")) { |
||
1294 | printf("visualid 0x%lx\n", visualList[0].visualid); |
||
1295 | } |
||
1296 | #endif |
||
1297 | |||
1298 | return visualList; |
||
1299 | } |
||
1300 | |||
1301 | |||
1302 | _X_EXPORT const char * |
||
1303 | glXQueryExtensionsString(Display * dpy, int screen) |
||
1304 | { |
||
1305 | struct glx_screen *psc; |
||
1306 | struct glx_display *priv; |
||
1307 | |||
1308 | if (GetGLXPrivScreenConfig(dpy, screen, &priv, &psc) != Success) { |
||
1309 | return NULL; |
||
1310 | } |
||
1311 | |||
1312 | if (!psc->effectiveGLXexts) { |
||
1313 | if (!psc->serverGLXexts) { |
||
1314 | psc->serverGLXexts = |
||
1315 | __glXQueryServerString(dpy, priv->majorOpcode, screen, |
||
1316 | GLX_EXTENSIONS); |
||
1317 | } |
||
1318 | |||
1319 | __glXCalculateUsableExtensions(psc, |
||
1320 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
1321 | (psc->driScreen != NULL), |
||
1322 | #else |
||
1323 | GL_FALSE, |
||
1324 | #endif |
||
1325 | priv->minorVersion); |
||
1326 | } |
||
1327 | |||
1328 | return psc->effectiveGLXexts; |
||
1329 | } |
||
1330 | |||
1331 | _X_EXPORT const char * |
||
1332 | glXGetClientString(Display * dpy, int name) |
||
1333 | { |
||
1334 | (void) dpy; |
||
1335 | |||
1336 | switch (name) { |
||
1337 | case GLX_VENDOR: |
||
1338 | return (__glXGLXClientVendorName); |
||
1339 | case GLX_VERSION: |
||
1340 | return (__glXGLXClientVersion); |
||
1341 | case GLX_EXTENSIONS: |
||
1342 | return (__glXGetClientExtensions()); |
||
1343 | default: |
||
1344 | return NULL; |
||
1345 | } |
||
1346 | } |
||
1347 | |||
1348 | _X_EXPORT const char * |
||
1349 | glXQueryServerString(Display * dpy, int screen, int name) |
||
1350 | { |
||
1351 | struct glx_screen *psc; |
||
1352 | struct glx_display *priv; |
||
1353 | const char **str; |
||
1354 | |||
1355 | |||
1356 | if (GetGLXPrivScreenConfig(dpy, screen, &priv, &psc) != Success) { |
||
1357 | return NULL; |
||
1358 | } |
||
1359 | |||
1360 | switch (name) { |
||
1361 | case GLX_VENDOR: |
||
1362 | str = &priv->serverGLXvendor; |
||
1363 | break; |
||
1364 | case GLX_VERSION: |
||
1365 | str = &priv->serverGLXversion; |
||
1366 | break; |
||
1367 | case GLX_EXTENSIONS: |
||
1368 | str = &psc->serverGLXexts; |
||
1369 | break; |
||
1370 | default: |
||
1371 | return NULL; |
||
1372 | } |
||
1373 | |||
1374 | if (*str == NULL) { |
||
1375 | *str = __glXQueryServerString(dpy, priv->majorOpcode, screen, name); |
||
1376 | } |
||
1377 | |||
1378 | return *str; |
||
1379 | } |
||
1380 | |||
1381 | |||
1382 | /* |
||
1383 | ** EXT_import_context |
||
1384 | */ |
||
1385 | |||
1386 | _X_EXPORT Display * |
||
1387 | glXGetCurrentDisplay(void) |
||
1388 | { |
||
1389 | struct glx_context *gc = __glXGetCurrentContext(); |
||
1390 | if (NULL == gc) |
||
1391 | return NULL; |
||
1392 | return gc->currentDpy; |
||
1393 | } |
||
1394 | |||
1395 | _X_EXPORT |
||
1396 | GLX_ALIAS(Display *, glXGetCurrentDisplayEXT, (void), (), |
||
1397 | glXGetCurrentDisplay) |
||
1398 | |||
1399 | #ifndef GLX_USE_APPLEGL |
||
1400 | _X_EXPORT GLXContext |
||
1401 | glXImportContextEXT(Display *dpy, GLXContextID contextID) |
||
1402 | { |
||
1403 | struct glx_display *priv = __glXInitialize(dpy); |
||
1404 | struct glx_screen *psc = NULL; |
||
1405 | xGLXQueryContextReply reply; |
||
1406 | CARD8 opcode; |
||
1407 | struct glx_context *ctx; |
||
1408 | |||
1409 | /* This GLX implementation knows about 5 different properties, so |
||
1410 | * allow the server to send us one of each. |
||
1411 | */ |
||
1412 | int propList[5 * 2], *pProp, nPropListBytes; |
||
1413 | int numProps; |
||
1414 | int i, renderType; |
||
1415 | XID share; |
||
1416 | struct glx_config *mode; |
||
1417 | uint32_t fbconfigID = 0; |
||
1418 | uint32_t visualID = 0; |
||
1419 | uint32_t screen = 0; |
||
1420 | Bool got_screen = False; |
||
1421 | |||
1422 | if (priv == NULL) |
||
1423 | return NULL; |
||
1424 | |||
1425 | /* The GLX_EXT_import_context spec says: |
||
1426 | * |
||
1427 | * "If |
||
1428 | * error is generated; if |
||
1429 | * context then no error is generated but glXImportContextEXT returns |
||
1430 | * NULL." |
||
1431 | * |
||
1432 | * If contextID is None, generate BadContext on the client-side. Other |
||
1433 | * sorts of invalid contexts will be detected by the server in the |
||
1434 | * __glXIsDirect call. |
||
1435 | */ |
||
1436 | if (contextID == None) { |
||
1437 | __glXSendError(dpy, GLXBadContext, contextID, X_GLXIsDirect, false); |
||
1438 | return NULL; |
||
1439 | } |
||
1440 | |||
1441 | if (__glXIsDirect(dpy, contextID)) |
||
1442 | return NULL; |
||
1443 | |||
1444 | opcode = __glXSetupForCommand(dpy); |
||
1445 | if (!opcode) |
||
1446 | return 0; |
||
1447 | |||
1448 | /* Send the glXQueryContextInfoEXT request */ |
||
1449 | LockDisplay(dpy); |
||
1450 | |||
1451 | if (priv->majorVersion > 1 || priv->minorVersion >= 3) { |
||
1452 | xGLXQueryContextReq *req; |
||
1453 | |||
1454 | GetReq(GLXQueryContext, req); |
||
1455 | |||
1456 | req->reqType = opcode; |
||
1457 | req->glxCode = X_GLXQueryContext; |
||
1458 | req->context = contextID; |
||
1459 | } |
||
1460 | else { |
||
1461 | xGLXVendorPrivateReq *vpreq; |
||
1462 | xGLXQueryContextInfoEXTReq *req; |
||
1463 | |||
1464 | GetReqExtra(GLXVendorPrivate, |
||
1465 | sz_xGLXQueryContextInfoEXTReq - sz_xGLXVendorPrivateReq, |
||
1466 | vpreq); |
||
1467 | req = (xGLXQueryContextInfoEXTReq *) vpreq; |
||
1468 | req->reqType = opcode; |
||
1469 | req->glxCode = X_GLXVendorPrivateWithReply; |
||
1470 | req->vendorCode = X_GLXvop_QueryContextInfoEXT; |
||
1471 | req->context = contextID; |
||
1472 | } |
||
1473 | |||
1474 | _XReply(dpy, (xReply *) & reply, 0, False); |
||
1475 | |||
1476 | if (reply.n <= __GLX_MAX_CONTEXT_PROPS) |
||
1477 | nPropListBytes = reply.n * 2 * sizeof propList[0]; |
||
1478 | else |
||
1479 | nPropListBytes = 0; |
||
1480 | _XRead(dpy, (char *) propList, nPropListBytes); |
||
1481 | UnlockDisplay(dpy); |
||
1482 | SyncHandle(); |
||
1483 | |||
1484 | numProps = nPropListBytes / (2 * sizeof(propList[0])); |
||
1485 | share = None; |
||
1486 | mode = NULL; |
||
1487 | renderType = GLX_RGBA_TYPE; /* By default, assume RGBA context */ |
||
1488 | pProp = propList; |
||
1489 | |||
1490 | for (i = 0, pProp = propList; i < numProps; i++, pProp += 2) |
||
1491 | switch (pProp[0]) { |
||
1492 | case GLX_SCREEN: |
||
1493 | screen = pProp[1]; |
||
1494 | got_screen = True; |
||
1495 | break; |
||
1496 | case GLX_SHARE_CONTEXT_EXT: |
||
1497 | share = pProp[1]; |
||
1498 | break; |
||
1499 | case GLX_VISUAL_ID_EXT: |
||
1500 | visualID = pProp[1]; |
||
1501 | break; |
||
1502 | case GLX_FBCONFIG_ID: |
||
1503 | fbconfigID = pProp[1]; |
||
1504 | break; |
||
1505 | case GLX_RENDER_TYPE: |
||
1506 | renderType = pProp[1]; |
||
1507 | break; |
||
1508 | } |
||
1509 | |||
1510 | if (!got_screen) |
||
1511 | return NULL; |
||
1512 | |||
1513 | psc = GetGLXScreenConfigs(dpy, screen); |
||
1514 | if (psc == NULL) |
||
1515 | return NULL; |
||
1516 | |||
1517 | if (fbconfigID != 0) { |
||
1518 | mode = glx_config_find_fbconfig(psc->configs, fbconfigID); |
||
1519 | } else if (visualID != 0) { |
||
1520 | mode = glx_config_find_visual(psc->visuals, visualID); |
||
1521 | } |
||
1522 | |||
1523 | if (mode == NULL) |
||
1524 | return NULL; |
||
1525 | |||
1526 | ctx = indirect_create_context(psc, mode, NULL, renderType); |
||
1527 | if (ctx == NULL) |
||
1528 | return NULL; |
||
1529 | |||
1530 | ctx->xid = contextID; |
||
1531 | ctx->imported = GL_TRUE; |
||
1532 | ctx->share_xid = share; |
||
1533 | |||
1534 | return (GLXContext) ctx; |
||
1535 | } |
||
1536 | |||
1537 | #endif |
||
1538 | |||
1539 | _X_EXPORT int |
||
1540 | glXQueryContext(Display * dpy, GLXContext ctx_user, int attribute, int *value) |
||
1541 | { |
||
1542 | struct glx_context *ctx = (struct glx_context *) ctx_user; |
||
1543 | |||
1544 | switch (attribute) { |
||
1545 | case GLX_SHARE_CONTEXT_EXT: |
||
1546 | *value = ctx->share_xid; |
||
1547 | break; |
||
1548 | case GLX_VISUAL_ID_EXT: |
||
1549 | *value = ctx->config ? ctx->config->visualID : None; |
||
1550 | break; |
||
1551 | case GLX_SCREEN: |
||
1552 | *value = ctx->screen; |
||
1553 | break; |
||
1554 | case GLX_FBCONFIG_ID: |
||
1555 | *value = ctx->config ? ctx->config->fbconfigID : None; |
||
1556 | break; |
||
1557 | case GLX_RENDER_TYPE: |
||
1558 | *value = ctx->renderType; |
||
1559 | break; |
||
1560 | default: |
||
1561 | return GLX_BAD_ATTRIBUTE; |
||
1562 | } |
||
1563 | return Success; |
||
1564 | } |
||
1565 | |||
1566 | _X_EXPORT |
||
1567 | GLX_ALIAS(int, glXQueryContextInfoEXT, |
||
1568 | (Display * dpy, GLXContext ctx, int attribute, int *value), |
||
1569 | (dpy, ctx, attribute, value), glXQueryContext) |
||
1570 | |||
1571 | _X_EXPORT GLXContextID glXGetContextIDEXT(const GLXContext ctx_user) |
||
1572 | { |
||
1573 | struct glx_context *ctx = (struct glx_context *) ctx_user; |
||
1574 | |||
1575 | return (ctx == NULL) ? None : ctx->xid; |
||
1576 | } |
||
1577 | |||
1578 | _X_EXPORT void |
||
1579 | glXFreeContextEXT(Display *dpy, GLXContext ctx) |
||
1580 | { |
||
1581 | struct glx_context *gc = (struct glx_context *) ctx; |
||
1582 | |||
1583 | if (gc == NULL || gc->xid == None) |
||
1584 | return; |
||
1585 | |||
1586 | /* The GLX_EXT_import_context spec says: |
||
1587 | * |
||
1588 | * "glXFreeContext does not free the server-side context information or |
||
1589 | * the XID associated with the server-side context." |
||
1590 | * |
||
1591 | * Don't send any protocol. Just destroy the client-side tracking of the |
||
1592 | * context. Also, only release the context structure if it's not current. |
||
1593 | */ |
||
1594 | __glXLock(); |
||
1595 | if (gc->currentDpy) { |
||
1596 | gc->xid = None; |
||
1597 | } else { |
||
1598 | gc->vtable->destroy(gc); |
||
1599 | } |
||
1600 | __glXUnlock(); |
||
1601 | } |
||
1602 | |||
1603 | _X_EXPORT GLXFBConfig * |
||
1604 | glXChooseFBConfig(Display * dpy, int screen, |
||
1605 | const int *attribList, int *nitems) |
||
1606 | { |
||
1607 | struct glx_config **config_list; |
||
1608 | int list_size; |
||
1609 | |||
1610 | |||
1611 | config_list = (struct glx_config **) |
||
1612 | glXGetFBConfigs(dpy, screen, &list_size); |
||
1613 | |||
1614 | if ((config_list != NULL) && (list_size > 0) && (attribList != NULL)) { |
||
1615 | list_size = choose_visual(config_list, list_size, attribList, GL_TRUE); |
||
1616 | if (list_size == 0) { |
||
1617 | free(config_list); |
||
1618 | config_list = NULL; |
||
1619 | } |
||
1620 | } |
||
1621 | |||
1622 | *nitems = list_size; |
||
1623 | return (GLXFBConfig *) config_list; |
||
1624 | } |
||
1625 | |||
1626 | |||
1627 | _X_EXPORT GLXContext |
||
1628 | glXCreateNewContext(Display * dpy, GLXFBConfig fbconfig, |
||
1629 | int renderType, GLXContext shareList, Bool allowDirect) |
||
1630 | { |
||
1631 | struct glx_config *config = (struct glx_config *) fbconfig; |
||
1632 | |||
1633 | return CreateContext(dpy, config->fbconfigID, config, shareList, |
||
1634 | allowDirect, X_GLXCreateNewContext, renderType, |
||
1635 | config->screen); |
||
1636 | } |
||
1637 | |||
1638 | |||
1639 | _X_EXPORT GLXDrawable |
||
1640 | glXGetCurrentReadDrawable(void) |
||
1641 | { |
||
1642 | struct glx_context *gc = __glXGetCurrentContext(); |
||
1643 | |||
1644 | return gc->currentReadable; |
||
1645 | } |
||
1646 | |||
1647 | |||
1648 | _X_EXPORT GLXFBConfig * |
||
1649 | glXGetFBConfigs(Display * dpy, int screen, int *nelements) |
||
1650 | { |
||
1651 | struct glx_display *priv = __glXInitialize(dpy); |
||
1652 | struct glx_config **config_list = NULL; |
||
1653 | struct glx_config *config; |
||
1654 | unsigned num_configs = 0; |
||
1655 | int i; |
||
1656 | |||
1657 | *nelements = 0; |
||
1658 | if (priv && (priv->screens != NULL) |
||
1659 | && (screen >= 0) && (screen <= ScreenCount(dpy)) |
||
1660 | && (priv->screens[screen]->configs != NULL) |
||
1661 | && (priv->screens[screen]->configs->fbconfigID |
||
1662 | != (int) GLX_DONT_CARE)) { |
||
1663 | |||
1664 | for (config = priv->screens[screen]->configs; config != NULL; |
||
1665 | config = config->next) { |
||
1666 | if (config->fbconfigID != (int) GLX_DONT_CARE) { |
||
1667 | num_configs++; |
||
1668 | } |
||
1669 | } |
||
1670 | |||
1671 | config_list = malloc(num_configs * sizeof *config_list); |
||
1672 | if (config_list != NULL) { |
||
1673 | *nelements = num_configs; |
||
1674 | i = 0; |
||
1675 | for (config = priv->screens[screen]->configs; config != NULL; |
||
1676 | config = config->next) { |
||
1677 | if (config->fbconfigID != (int) GLX_DONT_CARE) { |
||
1678 | config_list[i] = config; |
||
1679 | i++; |
||
1680 | } |
||
1681 | } |
||
1682 | } |
||
1683 | } |
||
1684 | |||
1685 | return (GLXFBConfig *) config_list; |
||
1686 | } |
||
1687 | |||
1688 | |||
1689 | _X_EXPORT int |
||
1690 | glXGetFBConfigAttrib(Display * dpy, GLXFBConfig fbconfig, |
||
1691 | int attribute, int *value) |
||
1692 | { |
||
1693 | struct glx_config *config = ValidateGLXFBConfig(dpy, fbconfig); |
||
1694 | |||
1695 | if (config == NULL) |
||
1696 | return GLXBadFBConfig; |
||
1697 | |||
1698 | return glx_config_get(config, attribute, value); |
||
1699 | } |
||
1700 | |||
1701 | |||
1702 | _X_EXPORT XVisualInfo * |
||
1703 | glXGetVisualFromFBConfig(Display * dpy, GLXFBConfig fbconfig) |
||
1704 | { |
||
1705 | XVisualInfo visualTemplate; |
||
1706 | struct glx_config *config = (struct glx_config *) fbconfig; |
||
1707 | int count; |
||
1708 | |||
1709 | /* |
||
1710 | ** Get a list of all visuals, return if list is empty |
||
1711 | */ |
||
1712 | visualTemplate.visualid = config->visualID; |
||
1713 | return XGetVisualInfo(dpy, VisualIDMask, &visualTemplate, &count); |
||
1714 | } |
||
1715 | |||
1716 | #ifndef GLX_USE_APPLEGL |
||
1717 | /* |
||
1718 | ** GLX_SGI_swap_control |
||
1719 | */ |
||
1720 | static int |
||
1721 | __glXSwapIntervalSGI(int interval) |
||
1722 | { |
||
1723 | xGLXVendorPrivateReq *req; |
||
1724 | struct glx_context *gc = __glXGetCurrentContext(); |
||
1725 | struct glx_screen *psc; |
||
1726 | Display *dpy; |
||
1727 | CARD32 *interval_ptr; |
||
1728 | CARD8 opcode; |
||
1729 | |||
1730 | if (gc == NULL) { |
||
1731 | return GLX_BAD_CONTEXT; |
||
1732 | } |
||
1733 | |||
1734 | if (interval <= 0) { |
||
1735 | return GLX_BAD_VALUE; |
||
1736 | } |
||
1737 | |||
1738 | psc = GetGLXScreenConfigs( gc->currentDpy, gc->screen); |
||
1739 | |||
1740 | #ifdef GLX_DIRECT_RENDERING |
||
1741 | if (gc->isDirect && psc && psc->driScreen && |
||
1742 | psc->driScreen->setSwapInterval) { |
||
1743 | __GLXDRIdrawable *pdraw = |
||
1744 | GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); |
||
1745 | psc->driScreen->setSwapInterval(pdraw, interval); |
||
1746 | return 0; |
||
1747 | } |
||
1748 | #endif |
||
1749 | |||
1750 | dpy = gc->currentDpy; |
||
1751 | opcode = __glXSetupForCommand(dpy); |
||
1752 | if (!opcode) { |
||
1753 | return 0; |
||
1754 | } |
||
1755 | |||
1756 | /* Send the glXSwapIntervalSGI request */ |
||
1757 | LockDisplay(dpy); |
||
1758 | GetReqExtra(GLXVendorPrivate, sizeof(CARD32), req); |
||
1759 | req->reqType = opcode; |
||
1760 | req->glxCode = X_GLXVendorPrivate; |
||
1761 | req->vendorCode = X_GLXvop_SwapIntervalSGI; |
||
1762 | req->contextTag = gc->currentContextTag; |
||
1763 | |||
1764 | interval_ptr = (CARD32 *) (req + 1); |
||
1765 | *interval_ptr = interval; |
||
1766 | |||
1767 | UnlockDisplay(dpy); |
||
1768 | SyncHandle(); |
||
1769 | XFlush(dpy); |
||
1770 | |||
1771 | return 0; |
||
1772 | } |
||
1773 | |||
1774 | |||
1775 | /* |
||
1776 | ** GLX_MESA_swap_control |
||
1777 | */ |
||
1778 | static int |
||
1779 | __glXSwapIntervalMESA(unsigned int interval) |
||
1780 | { |
||
1781 | #ifdef GLX_DIRECT_RENDERING |
||
1782 | struct glx_context *gc = __glXGetCurrentContext(); |
||
1783 | |||
1784 | if (gc != NULL && gc->isDirect) { |
||
1785 | struct glx_screen *psc; |
||
1786 | |||
1787 | psc = GetGLXScreenConfigs( gc->currentDpy, gc->screen); |
||
1788 | if (psc && psc->driScreen && psc->driScreen->setSwapInterval) { |
||
1789 | __GLXDRIdrawable *pdraw = |
||
1790 | GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); |
||
1791 | return psc->driScreen->setSwapInterval(pdraw, interval); |
||
1792 | } |
||
1793 | } |
||
1794 | #endif |
||
1795 | |||
1796 | return GLX_BAD_CONTEXT; |
||
1797 | } |
||
1798 | |||
1799 | |||
1800 | static int |
||
1801 | __glXGetSwapIntervalMESA(void) |
||
1802 | { |
||
1803 | #ifdef GLX_DIRECT_RENDERING |
||
1804 | struct glx_context *gc = __glXGetCurrentContext(); |
||
1805 | |||
1806 | if (gc != NULL && gc->isDirect) { |
||
1807 | struct glx_screen *psc; |
||
1808 | |||
1809 | psc = GetGLXScreenConfigs( gc->currentDpy, gc->screen); |
||
1810 | if (psc && psc->driScreen && psc->driScreen->getSwapInterval) { |
||
1811 | __GLXDRIdrawable *pdraw = |
||
1812 | GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); |
||
1813 | return psc->driScreen->getSwapInterval(pdraw); |
||
1814 | } |
||
1815 | } |
||
1816 | #endif |
||
1817 | |||
1818 | return 0; |
||
1819 | } |
||
1820 | |||
1821 | |||
1822 | /* |
||
1823 | ** GLX_SGI_video_sync |
||
1824 | */ |
||
1825 | static int |
||
1826 | __glXGetVideoSyncSGI(unsigned int *count) |
||
1827 | { |
||
1828 | int64_t ust, msc, sbc; |
||
1829 | int ret; |
||
1830 | struct glx_context *gc = __glXGetCurrentContext(); |
||
1831 | struct glx_screen *psc; |
||
1832 | #ifdef GLX_DIRECT_RENDERING |
||
1833 | __GLXDRIdrawable *pdraw; |
||
1834 | #endif |
||
1835 | |||
1836 | if (!gc) |
||
1837 | return GLX_BAD_CONTEXT; |
||
1838 | |||
1839 | #ifdef GLX_DIRECT_RENDERING |
||
1840 | if (!gc->isDirect) |
||
1841 | return GLX_BAD_CONTEXT; |
||
1842 | #endif |
||
1843 | |||
1844 | psc = GetGLXScreenConfigs(gc->currentDpy, gc->screen); |
||
1845 | #ifdef GLX_DIRECT_RENDERING |
||
1846 | pdraw = GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); |
||
1847 | #endif |
||
1848 | |||
1849 | /* FIXME: Looking at the GLX_SGI_video_sync spec in the extension registry, |
||
1850 | * FIXME: there should be a GLX encoding for this call. I can find no |
||
1851 | * FIXME: documentation for the GLX encoding. |
||
1852 | */ |
||
1853 | #ifdef GLX_DIRECT_RENDERING |
||
1854 | if (psc && psc->driScreen && psc->driScreen->getDrawableMSC) { |
||
1855 | ret = psc->driScreen->getDrawableMSC(psc, pdraw, &ust, &msc, &sbc); |
||
1856 | *count = (unsigned) msc; |
||
1857 | return (ret == True) ? 0 : GLX_BAD_CONTEXT; |
||
1858 | } |
||
1859 | #endif |
||
1860 | |||
1861 | return GLX_BAD_CONTEXT; |
||
1862 | } |
||
1863 | |||
1864 | static int |
||
1865 | __glXWaitVideoSyncSGI(int divisor, int remainder, unsigned int *count) |
||
1866 | { |
||
1867 | struct glx_context *gc = __glXGetCurrentContext(); |
||
1868 | struct glx_screen *psc; |
||
1869 | #ifdef GLX_DIRECT_RENDERING |
||
1870 | __GLXDRIdrawable *pdraw; |
||
1871 | #endif |
||
1872 | int64_t ust, msc, sbc; |
||
1873 | int ret; |
||
1874 | |||
1875 | if (divisor <= 0 || remainder < 0) |
||
1876 | return GLX_BAD_VALUE; |
||
1877 | |||
1878 | if (!gc) |
||
1879 | return GLX_BAD_CONTEXT; |
||
1880 | |||
1881 | #ifdef GLX_DIRECT_RENDERING |
||
1882 | if (!gc->isDirect) |
||
1883 | return GLX_BAD_CONTEXT; |
||
1884 | #endif |
||
1885 | |||
1886 | psc = GetGLXScreenConfigs( gc->currentDpy, gc->screen); |
||
1887 | #ifdef GLX_DIRECT_RENDERING |
||
1888 | pdraw = GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); |
||
1889 | #endif |
||
1890 | |||
1891 | #ifdef GLX_DIRECT_RENDERING |
||
1892 | if (psc && psc->driScreen && psc->driScreen->waitForMSC) { |
||
1893 | ret = psc->driScreen->waitForMSC(pdraw, 0, divisor, remainder, &ust, &msc, |
||
1894 | &sbc); |
||
1895 | *count = (unsigned) msc; |
||
1896 | return (ret == True) ? 0 : GLX_BAD_CONTEXT; |
||
1897 | } |
||
1898 | #endif |
||
1899 | |||
1900 | return GLX_BAD_CONTEXT; |
||
1901 | } |
||
1902 | |||
1903 | #endif /* GLX_USE_APPLEGL */ |
||
1904 | |||
1905 | /* |
||
1906 | ** GLX_SGIX_fbconfig |
||
1907 | ** Many of these functions are aliased to GLX 1.3 entry points in the |
||
1908 | ** GLX_functions table. |
||
1909 | */ |
||
1910 | |||
1911 | _X_EXPORT |
||
1912 | GLX_ALIAS(int, glXGetFBConfigAttribSGIX, |
||
1913 | (Display * dpy, GLXFBConfigSGIX config, int attribute, int *value), |
||
1914 | (dpy, config, attribute, value), glXGetFBConfigAttrib) |
||
1915 | |||
1916 | _X_EXPORT GLX_ALIAS(GLXFBConfigSGIX *, glXChooseFBConfigSGIX, |
||
1917 | (Display * dpy, int screen, int *attrib_list, |
||
1918 | int *nelements), (dpy, screen, attrib_list, nelements), |
||
1919 | glXChooseFBConfig) |
||
1920 | |||
1921 | _X_EXPORT GLX_ALIAS(XVisualInfo *, glXGetVisualFromFBConfigSGIX, |
||
1922 | (Display * dpy, GLXFBConfigSGIX config), |
||
1923 | (dpy, config), glXGetVisualFromFBConfig) |
||
1924 | |||
1925 | _X_EXPORT GLXPixmap |
||
1926 | glXCreateGLXPixmapWithConfigSGIX(Display * dpy, |
||
1927 | GLXFBConfigSGIX fbconfig, |
||
1928 | Pixmap pixmap) |
||
1929 | { |
||
1930 | #ifndef GLX_USE_APPLEGL |
||
1931 | xGLXVendorPrivateWithReplyReq *vpreq; |
||
1932 | xGLXCreateGLXPixmapWithConfigSGIXReq *req; |
||
1933 | GLXPixmap xid = None; |
||
1934 | CARD8 opcode; |
||
1935 | struct glx_screen *psc; |
||
1936 | #endif |
||
1937 | struct glx_config *config = (struct glx_config *) fbconfig; |
||
1938 | |||
1939 | |||
1940 | if ((dpy == NULL) || (config == NULL)) { |
||
1941 | return None; |
||
1942 | } |
||
1943 | #ifdef GLX_USE_APPLEGL |
||
1944 | if(apple_glx_pixmap_create(dpy, config->screen, pixmap, config)) |
||
1945 | return None; |
||
1946 | return pixmap; |
||
1947 | #else |
||
1948 | |||
1949 | psc = GetGLXScreenConfigs(dpy, config->screen); |
||
1950 | if ((psc != NULL) |
||
1951 | && __glXExtensionBitIsEnabled(psc, SGIX_fbconfig_bit)) { |
||
1952 | opcode = __glXSetupForCommand(dpy); |
||
1953 | if (!opcode) { |
||
1954 | return None; |
||
1955 | } |
||
1956 | |||
1957 | /* Send the glXCreateGLXPixmapWithConfigSGIX request */ |
||
1958 | LockDisplay(dpy); |
||
1959 | GetReqExtra(GLXVendorPrivateWithReply, |
||
1960 | sz_xGLXCreateGLXPixmapWithConfigSGIXReq - |
||
1961 | sz_xGLXVendorPrivateWithReplyReq, vpreq); |
||
1962 | req = (xGLXCreateGLXPixmapWithConfigSGIXReq *) vpreq; |
||
1963 | req->reqType = opcode; |
||
1964 | req->glxCode = X_GLXVendorPrivateWithReply; |
||
1965 | req->vendorCode = X_GLXvop_CreateGLXPixmapWithConfigSGIX; |
||
1966 | req->screen = config->screen; |
||
1967 | req->fbconfig = config->fbconfigID; |
||
1968 | req->pixmap = pixmap; |
||
1969 | req->glxpixmap = xid = XAllocID(dpy); |
||
1970 | UnlockDisplay(dpy); |
||
1971 | SyncHandle(); |
||
1972 | } |
||
1973 | |||
1974 | return xid; |
||
1975 | #endif |
||
1976 | } |
||
1977 | |||
1978 | _X_EXPORT GLXContext |
||
1979 | glXCreateContextWithConfigSGIX(Display * dpy, |
||
1980 | GLXFBConfigSGIX fbconfig, int renderType, |
||
1981 | GLXContext shareList, Bool allowDirect) |
||
1982 | { |
||
1983 | GLXContext gc = NULL; |
||
1984 | struct glx_config *config = (struct glx_config *) fbconfig; |
||
1985 | struct glx_screen *psc; |
||
1986 | |||
1987 | |||
1988 | if ((dpy == NULL) || (config == NULL)) { |
||
1989 | return None; |
||
1990 | } |
||
1991 | |||
1992 | psc = GetGLXScreenConfigs(dpy, config->screen); |
||
1993 | if ((psc != NULL) |
||
1994 | && __glXExtensionBitIsEnabled(psc, SGIX_fbconfig_bit)) { |
||
1995 | gc = CreateContext(dpy, config->fbconfigID, config, shareList, |
||
1996 | allowDirect, |
||
1997 | X_GLXvop_CreateContextWithConfigSGIX, renderType, |
||
1998 | config->screen); |
||
1999 | } |
||
2000 | |||
2001 | return gc; |
||
2002 | } |
||
2003 | |||
2004 | |||
2005 | _X_EXPORT GLXFBConfigSGIX |
||
2006 | glXGetFBConfigFromVisualSGIX(Display * dpy, XVisualInfo * vis) |
||
2007 | { |
||
2008 | struct glx_display *priv; |
||
2009 | struct glx_screen *psc = NULL; |
||
2010 | |||
2011 | if ((GetGLXPrivScreenConfig(dpy, vis->screen, &priv, &psc) == Success) |
||
2012 | && __glXExtensionBitIsEnabled(psc, SGIX_fbconfig_bit) |
||
2013 | && (psc->configs->fbconfigID != (int) GLX_DONT_CARE)) { |
||
2014 | return (GLXFBConfigSGIX) glx_config_find_visual(psc->configs, |
||
2015 | vis->visualid); |
||
2016 | } |
||
2017 | |||
2018 | return NULL; |
||
2019 | } |
||
2020 | |||
2021 | #ifndef GLX_USE_APPLEGL |
||
2022 | /* |
||
2023 | ** GLX_SGIX_swap_group |
||
2024 | */ |
||
2025 | static void |
||
2026 | __glXJoinSwapGroupSGIX(Display * dpy, GLXDrawable drawable, |
||
2027 | GLXDrawable member) |
||
2028 | { |
||
2029 | (void) dpy; |
||
2030 | (void) drawable; |
||
2031 | (void) member; |
||
2032 | } |
||
2033 | |||
2034 | |||
2035 | /* |
||
2036 | ** GLX_SGIX_swap_barrier |
||
2037 | */ |
||
2038 | static void |
||
2039 | __glXBindSwapBarrierSGIX(Display * dpy, GLXDrawable drawable, int barrier) |
||
2040 | { |
||
2041 | (void) dpy; |
||
2042 | (void) drawable; |
||
2043 | (void) barrier; |
||
2044 | } |
||
2045 | |||
2046 | static Bool |
||
2047 | __glXQueryMaxSwapBarriersSGIX(Display * dpy, int screen, int *max) |
||
2048 | { |
||
2049 | (void) dpy; |
||
2050 | (void) screen; |
||
2051 | (void) max; |
||
2052 | return False; |
||
2053 | } |
||
2054 | |||
2055 | |||
2056 | /* |
||
2057 | ** GLX_OML_sync_control |
||
2058 | */ |
||
2059 | static Bool |
||
2060 | __glXGetSyncValuesOML(Display * dpy, GLXDrawable drawable, |
||
2061 | int64_t * ust, int64_t * msc, int64_t * sbc) |
||
2062 | { |
||
2063 | struct glx_display * const priv = __glXInitialize(dpy); |
||
2064 | int ret; |
||
2065 | #ifdef GLX_DIRECT_RENDERING |
||
2066 | __GLXDRIdrawable *pdraw; |
||
2067 | #endif |
||
2068 | struct glx_screen *psc; |
||
2069 | |||
2070 | if (!priv) |
||
2071 | return False; |
||
2072 | |||
2073 | #ifdef GLX_DIRECT_RENDERING |
||
2074 | pdraw = GetGLXDRIDrawable(dpy, drawable); |
||
2075 | psc = pdraw ? pdraw->psc : NULL; |
||
2076 | if (pdraw && psc->driScreen->getDrawableMSC) { |
||
2077 | ret = psc->driScreen->getDrawableMSC(psc, pdraw, ust, msc, sbc); |
||
2078 | return ret; |
||
2079 | } |
||
2080 | #endif |
||
2081 | |||
2082 | return False; |
||
2083 | } |
||
2084 | |||
2085 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
2086 | _X_HIDDEN GLboolean |
||
2087 | __glxGetMscRate(struct glx_screen *psc, |
||
2088 | int32_t * numerator, int32_t * denominator) |
||
2089 | { |
||
2090 | #ifdef XF86VIDMODE |
||
2091 | XF86VidModeModeLine mode_line; |
||
2092 | int dot_clock; |
||
2093 | int i; |
||
2094 | |||
2095 | if (XF86VidModeQueryVersion(psc->dpy, &i, &i) && |
||
2096 | XF86VidModeGetModeLine(psc->dpy, psc->scr, &dot_clock, &mode_line)) { |
||
2097 | unsigned n = dot_clock * 1000; |
||
2098 | unsigned d = mode_line.vtotal * mode_line.htotal; |
||
2099 | |||
2100 | # define V_INTERLACE 0x010 |
||
2101 | # define V_DBLSCAN 0x020 |
||
2102 | |||
2103 | if (mode_line.flags & V_INTERLACE) |
||
2104 | n *= 2; |
||
2105 | else if (mode_line.flags & V_DBLSCAN) |
||
2106 | d *= 2; |
||
2107 | |||
2108 | /* The OML_sync_control spec requires that if the refresh rate is a |
||
2109 | * whole number, that the returned numerator be equal to the refresh |
||
2110 | * rate and the denominator be 1. |
||
2111 | */ |
||
2112 | |||
2113 | if (n % d == 0) { |
||
2114 | n /= d; |
||
2115 | d = 1; |
||
2116 | } |
||
2117 | else { |
||
2118 | static const unsigned f[] = { 13, 11, 7, 5, 3, 2, 0 }; |
||
2119 | |||
2120 | /* This is a poor man's way to reduce a fraction. It's far from |
||
2121 | * perfect, but it will work well enough for this situation. |
||
2122 | */ |
||
2123 | |||
2124 | for (i = 0; f[i] != 0; i++) { |
||
2125 | while (n % f[i] == 0 && d % f[i] == 0) { |
||
2126 | d /= f[i]; |
||
2127 | n /= f[i]; |
||
2128 | } |
||
2129 | } |
||
2130 | } |
||
2131 | |||
2132 | *numerator = n; |
||
2133 | *denominator = d; |
||
2134 | |||
2135 | return True; |
||
2136 | } |
||
2137 | else |
||
2138 | #endif |
||
2139 | |||
2140 | return False; |
||
2141 | } |
||
2142 | #endif |
||
2143 | |||
2144 | /** |
||
2145 | * Determine the refresh rate of the specified drawable and display. |
||
2146 | * |
||
2147 | * \param dpy Display whose refresh rate is to be determined. |
||
2148 | * \param drawable Drawable whose refresh rate is to be determined. |
||
2149 | * \param numerator Numerator of the refresh rate. |
||
2150 | * \param demoninator Denominator of the refresh rate. |
||
2151 | * \return If the refresh rate for the specified display and drawable could |
||
2152 | * be calculated, True is returned. Otherwise False is returned. |
||
2153 | * |
||
2154 | * \note This function is implemented entirely client-side. A lot of other |
||
2155 | * functionality is required to export GLX_OML_sync_control, so on |
||
2156 | * XFree86 this function can be called for direct-rendering contexts |
||
2157 | * when GLX_OML_sync_control appears in the client extension string. |
||
2158 | */ |
||
2159 | |||
2160 | _X_HIDDEN GLboolean |
||
2161 | __glXGetMscRateOML(Display * dpy, GLXDrawable drawable, |
||
2162 | int32_t * numerator, int32_t * denominator) |
||
2163 | { |
||
2164 | #if defined( GLX_DIRECT_RENDERING ) && defined( XF86VIDMODE ) |
||
2165 | __GLXDRIdrawable *draw = GetGLXDRIDrawable(dpy, drawable); |
||
2166 | |||
2167 | if (draw == NULL) |
||
2168 | return False; |
||
2169 | |||
2170 | return __glxGetMscRate(draw->psc, numerator, denominator); |
||
2171 | #else |
||
2172 | (void) dpy; |
||
2173 | (void) drawable; |
||
2174 | (void) numerator; |
||
2175 | (void) denominator; |
||
2176 | #endif |
||
2177 | return False; |
||
2178 | } |
||
2179 | |||
2180 | |||
2181 | static int64_t |
||
2182 | __glXSwapBuffersMscOML(Display * dpy, GLXDrawable drawable, |
||
2183 | int64_t target_msc, int64_t divisor, int64_t remainder) |
||
2184 | { |
||
2185 | struct glx_context *gc = __glXGetCurrentContext(); |
||
2186 | #ifdef GLX_DIRECT_RENDERING |
||
2187 | __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable); |
||
2188 | struct glx_screen *psc = pdraw ? pdraw->psc : NULL; |
||
2189 | #endif |
||
2190 | |||
2191 | if (!gc) /* no GLX for this */ |
||
2192 | return -1; |
||
2193 | |||
2194 | #ifdef GLX_DIRECT_RENDERING |
||
2195 | if (!pdraw || !gc->isDirect) |
||
2196 | return -1; |
||
2197 | #endif |
||
2198 | |||
2199 | /* The OML_sync_control spec says these should "generate a GLX_BAD_VALUE |
||
2200 | * error", but it also says "It [glXSwapBuffersMscOML] will return a value |
||
2201 | * of -1 if the function failed because of errors detected in the input |
||
2202 | * parameters" |
||
2203 | */ |
||
2204 | if (divisor < 0 || remainder < 0 || target_msc < 0) |
||
2205 | return -1; |
||
2206 | if (divisor > 0 && remainder >= divisor) |
||
2207 | return -1; |
||
2208 | |||
2209 | if (target_msc == 0 && divisor == 0 && remainder == 0) |
||
2210 | remainder = 1; |
||
2211 | |||
2212 | #ifdef GLX_DIRECT_RENDERING |
||
2213 | if (psc->driScreen && psc->driScreen->swapBuffers) |
||
2214 | return (*psc->driScreen->swapBuffers)(pdraw, target_msc, divisor, |
||
2215 | remainder, False); |
||
2216 | #endif |
||
2217 | |||
2218 | return -1; |
||
2219 | } |
||
2220 | |||
2221 | |||
2222 | static Bool |
||
2223 | __glXWaitForMscOML(Display * dpy, GLXDrawable drawable, |
||
2224 | int64_t target_msc, int64_t divisor, |
||
2225 | int64_t remainder, int64_t * ust, |
||
2226 | int64_t * msc, int64_t * sbc) |
||
2227 | { |
||
2228 | #ifdef GLX_DIRECT_RENDERING |
||
2229 | __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable); |
||
2230 | struct glx_screen *psc = pdraw ? pdraw->psc : NULL; |
||
2231 | int ret; |
||
2232 | #endif |
||
2233 | |||
2234 | |||
2235 | /* The OML_sync_control spec says these should "generate a GLX_BAD_VALUE |
||
2236 | * error", but the return type in the spec is Bool. |
||
2237 | */ |
||
2238 | if (divisor < 0 || remainder < 0 || target_msc < 0) |
||
2239 | return False; |
||
2240 | if (divisor > 0 && remainder >= divisor) |
||
2241 | return False; |
||
2242 | |||
2243 | #ifdef GLX_DIRECT_RENDERING |
||
2244 | if (pdraw && psc->driScreen && psc->driScreen->waitForMSC) { |
||
2245 | ret = psc->driScreen->waitForMSC(pdraw, target_msc, divisor, remainder, |
||
2246 | ust, msc, sbc); |
||
2247 | return ret; |
||
2248 | } |
||
2249 | #endif |
||
2250 | |||
2251 | return False; |
||
2252 | } |
||
2253 | |||
2254 | |||
2255 | static Bool |
||
2256 | __glXWaitForSbcOML(Display * dpy, GLXDrawable drawable, |
||
2257 | int64_t target_sbc, int64_t * ust, |
||
2258 | int64_t * msc, int64_t * sbc) |
||
2259 | { |
||
2260 | #ifdef GLX_DIRECT_RENDERING |
||
2261 | __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable); |
||
2262 | struct glx_screen *psc = pdraw ? pdraw->psc : NULL; |
||
2263 | int ret; |
||
2264 | #endif |
||
2265 | |||
2266 | /* The OML_sync_control spec says this should "generate a GLX_BAD_VALUE |
||
2267 | * error", but the return type in the spec is Bool. |
||
2268 | */ |
||
2269 | if (target_sbc < 0) |
||
2270 | return False; |
||
2271 | |||
2272 | #ifdef GLX_DIRECT_RENDERING |
||
2273 | if (pdraw && psc->driScreen && psc->driScreen->waitForSBC) { |
||
2274 | ret = psc->driScreen->waitForSBC(pdraw, target_sbc, ust, msc, sbc); |
||
2275 | return ret; |
||
2276 | } |
||
2277 | #endif |
||
2278 | |||
2279 | return False; |
||
2280 | } |
||
2281 | |||
2282 | /*@}*/ |
||
2283 | |||
2284 | |||
2285 | /** |
||
2286 | * Mesa extension stubs. These will help reduce portability problems. |
||
2287 | */ |
||
2288 | /*@{*/ |
||
2289 | |||
2290 | /** |
||
2291 | * Release all buffers associated with the specified GLX drawable. |
||
2292 | * |
||
2293 | * \todo |
||
2294 | * This function was intended for stand-alone Mesa. The issue there is that |
||
2295 | * the library doesn't get any notification when a window is closed. In |
||
2296 | * DRI there is a similar but slightly different issue. When GLX 1.3 is |
||
2297 | * supported, there are 3 different functions to destroy a drawable. It |
||
2298 | * should be possible to create GLX protocol (or have it determine which |
||
2299 | * protocol to use based on the type of the drawable) to have one function |
||
2300 | * do the work of 3. For the direct-rendering case, this function could |
||
2301 | * just call the driver's \c __DRIdrawableRec::destroyDrawable function. |
||
2302 | * This would reduce the frequency with which \c __driGarbageCollectDrawables |
||
2303 | * would need to be used. This really should be done as part of the new DRI |
||
2304 | * interface work. |
||
2305 | * |
||
2306 | * \sa http://oss.sgi.com/projects/ogl-sample/registry/MESA/release_buffers.txt |
||
2307 | * __driGarbageCollectDrawables |
||
2308 | * glXDestroyGLXPixmap |
||
2309 | * glXDestroyPbuffer glXDestroyPixmap glXDestroyWindow |
||
2310 | * glXDestroyGLXPbufferSGIX glXDestroyGLXVideoSourceSGIX |
||
2311 | */ |
||
2312 | static Bool |
||
2313 | __glXReleaseBuffersMESA(Display * dpy, GLXDrawable d) |
||
2314 | { |
||
2315 | (void) dpy; |
||
2316 | (void) d; |
||
2317 | return False; |
||
2318 | } |
||
2319 | |||
2320 | |||
2321 | _X_EXPORT GLXPixmap |
||
2322 | glXCreateGLXPixmapMESA(Display * dpy, XVisualInfo * visual, |
||
2323 | Pixmap pixmap, Colormap cmap) |
||
2324 | { |
||
2325 | (void) dpy; |
||
2326 | (void) visual; |
||
2327 | (void) pixmap; |
||
2328 | (void) cmap; |
||
2329 | return 0; |
||
2330 | } |
||
2331 | |||
2332 | /*@}*/ |
||
2333 | |||
2334 | |||
2335 | /** |
||
2336 | * GLX_MESA_copy_sub_buffer |
||
2337 | */ |
||
2338 | #define X_GLXvop_CopySubBufferMESA 5154 /* temporary */ |
||
2339 | static void |
||
2340 | __glXCopySubBufferMESA(Display * dpy, GLXDrawable drawable, |
||
2341 | int x, int y, int width, int height) |
||
2342 | { |
||
2343 | xGLXVendorPrivateReq *req; |
||
2344 | struct glx_context *gc; |
||
2345 | GLXContextTag tag; |
||
2346 | CARD32 *drawable_ptr; |
||
2347 | INT32 *x_ptr, *y_ptr, *w_ptr, *h_ptr; |
||
2348 | CARD8 opcode; |
||
2349 | |||
2350 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
2351 | __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable); |
||
2352 | if (pdraw != NULL) { |
||
2353 | struct glx_screen *psc = pdraw->psc; |
||
2354 | if (psc->driScreen->copySubBuffer != NULL) { |
||
2355 | (*psc->driScreen->copySubBuffer) (pdraw, x, y, width, height, True); |
||
2356 | } |
||
2357 | |||
2358 | return; |
||
2359 | } |
||
2360 | #endif |
||
2361 | |||
2362 | opcode = __glXSetupForCommand(dpy); |
||
2363 | if (!opcode) |
||
2364 | return; |
||
2365 | |||
2366 | /* |
||
2367 | ** The calling thread may or may not have a current context. If it |
||
2368 | ** does, send the context tag so the server can do a flush. |
||
2369 | */ |
||
2370 | gc = __glXGetCurrentContext(); |
||
2371 | if ((gc != NULL) && (dpy == gc->currentDpy) && |
||
2372 | ((drawable == gc->currentDrawable) || |
||
2373 | (drawable == gc->currentReadable))) { |
||
2374 | tag = gc->currentContextTag; |
||
2375 | } |
||
2376 | else { |
||
2377 | tag = 0; |
||
2378 | } |
||
2379 | |||
2380 | LockDisplay(dpy); |
||
2381 | GetReqExtra(GLXVendorPrivate, sizeof(CARD32) + sizeof(INT32) * 4, req); |
||
2382 | req->reqType = opcode; |
||
2383 | req->glxCode = X_GLXVendorPrivate; |
||
2384 | req->vendorCode = X_GLXvop_CopySubBufferMESA; |
||
2385 | req->contextTag = tag; |
||
2386 | |||
2387 | drawable_ptr = (CARD32 *) (req + 1); |
||
2388 | x_ptr = (INT32 *) (drawable_ptr + 1); |
||
2389 | y_ptr = (INT32 *) (drawable_ptr + 2); |
||
2390 | w_ptr = (INT32 *) (drawable_ptr + 3); |
||
2391 | h_ptr = (INT32 *) (drawable_ptr + 4); |
||
2392 | |||
2393 | *drawable_ptr = drawable; |
||
2394 | *x_ptr = x; |
||
2395 | *y_ptr = y; |
||
2396 | *w_ptr = width; |
||
2397 | *h_ptr = height; |
||
2398 | |||
2399 | UnlockDisplay(dpy); |
||
2400 | SyncHandle(); |
||
2401 | } |
||
2402 | |||
2403 | /*@{*/ |
||
2404 | static void |
||
2405 | __glXBindTexImageEXT(Display * dpy, |
||
2406 | GLXDrawable drawable, int buffer, const int *attrib_list) |
||
2407 | { |
||
2408 | struct glx_context *gc = __glXGetCurrentContext(); |
||
2409 | |||
2410 | if (gc == NULL || gc->vtable->bind_tex_image == NULL) |
||
2411 | return; |
||
2412 | |||
2413 | gc->vtable->bind_tex_image(dpy, drawable, buffer, attrib_list); |
||
2414 | } |
||
2415 | |||
2416 | static void |
||
2417 | __glXReleaseTexImageEXT(Display * dpy, GLXDrawable drawable, int buffer) |
||
2418 | { |
||
2419 | struct glx_context *gc = __glXGetCurrentContext(); |
||
2420 | |||
2421 | if (gc == NULL || gc->vtable->release_tex_image == NULL) |
||
2422 | return; |
||
2423 | |||
2424 | gc->vtable->release_tex_image(dpy, drawable, buffer); |
||
2425 | } |
||
2426 | |||
2427 | /*@}*/ |
||
2428 | |||
2429 | #endif /* GLX_USE_APPLEGL */ |
||
2430 | |||
2431 | /* |
||
2432 | ** glXGetProcAddress support |
||
2433 | */ |
||
2434 | |||
2435 | struct name_address_pair |
||
2436 | { |
||
2437 | const char *Name; |
||
2438 | GLvoid *Address; |
||
2439 | }; |
||
2440 | |||
2441 | #define GLX_FUNCTION(f) { # f, (GLvoid *) f } |
||
2442 | #define GLX_FUNCTION2(n,f) { # n, (GLvoid *) f } |
||
2443 | |||
2444 | static const struct name_address_pair GLX_functions[] = { |
||
2445 | /*** GLX_VERSION_1_0 ***/ |
||
2446 | GLX_FUNCTION(glXChooseVisual), |
||
2447 | GLX_FUNCTION(glXCopyContext), |
||
2448 | GLX_FUNCTION(glXCreateContext), |
||
2449 | GLX_FUNCTION(glXCreateGLXPixmap), |
||
2450 | GLX_FUNCTION(glXDestroyContext), |
||
2451 | GLX_FUNCTION(glXDestroyGLXPixmap), |
||
2452 | GLX_FUNCTION(glXGetConfig), |
||
2453 | GLX_FUNCTION(glXGetCurrentContext), |
||
2454 | GLX_FUNCTION(glXGetCurrentDrawable), |
||
2455 | GLX_FUNCTION(glXIsDirect), |
||
2456 | GLX_FUNCTION(glXMakeCurrent), |
||
2457 | GLX_FUNCTION(glXQueryExtension), |
||
2458 | GLX_FUNCTION(glXQueryVersion), |
||
2459 | GLX_FUNCTION(glXSwapBuffers), |
||
2460 | GLX_FUNCTION(glXUseXFont), |
||
2461 | GLX_FUNCTION(glXWaitGL), |
||
2462 | GLX_FUNCTION(glXWaitX), |
||
2463 | |||
2464 | /*** GLX_VERSION_1_1 ***/ |
||
2465 | GLX_FUNCTION(glXGetClientString), |
||
2466 | GLX_FUNCTION(glXQueryExtensionsString), |
||
2467 | GLX_FUNCTION(glXQueryServerString), |
||
2468 | |||
2469 | /*** GLX_VERSION_1_2 ***/ |
||
2470 | GLX_FUNCTION(glXGetCurrentDisplay), |
||
2471 | |||
2472 | /*** GLX_VERSION_1_3 ***/ |
||
2473 | GLX_FUNCTION(glXChooseFBConfig), |
||
2474 | GLX_FUNCTION(glXCreateNewContext), |
||
2475 | GLX_FUNCTION(glXCreatePbuffer), |
||
2476 | GLX_FUNCTION(glXCreatePixmap), |
||
2477 | GLX_FUNCTION(glXCreateWindow), |
||
2478 | GLX_FUNCTION(glXDestroyPbuffer), |
||
2479 | GLX_FUNCTION(glXDestroyPixmap), |
||
2480 | GLX_FUNCTION(glXDestroyWindow), |
||
2481 | GLX_FUNCTION(glXGetCurrentReadDrawable), |
||
2482 | GLX_FUNCTION(glXGetFBConfigAttrib), |
||
2483 | GLX_FUNCTION(glXGetFBConfigs), |
||
2484 | GLX_FUNCTION(glXGetSelectedEvent), |
||
2485 | GLX_FUNCTION(glXGetVisualFromFBConfig), |
||
2486 | GLX_FUNCTION(glXMakeContextCurrent), |
||
2487 | GLX_FUNCTION(glXQueryContext), |
||
2488 | GLX_FUNCTION(glXQueryDrawable), |
||
2489 | GLX_FUNCTION(glXSelectEvent), |
||
2490 | |||
2491 | #ifndef GLX_USE_APPLEGL |
||
2492 | /*** GLX_SGI_swap_control ***/ |
||
2493 | GLX_FUNCTION2(glXSwapIntervalSGI, __glXSwapIntervalSGI), |
||
2494 | |||
2495 | /*** GLX_SGI_video_sync ***/ |
||
2496 | GLX_FUNCTION2(glXGetVideoSyncSGI, __glXGetVideoSyncSGI), |
||
2497 | GLX_FUNCTION2(glXWaitVideoSyncSGI, __glXWaitVideoSyncSGI), |
||
2498 | |||
2499 | /*** GLX_SGI_make_current_read ***/ |
||
2500 | GLX_FUNCTION2(glXMakeCurrentReadSGI, glXMakeContextCurrent), |
||
2501 | GLX_FUNCTION2(glXGetCurrentReadDrawableSGI, glXGetCurrentReadDrawable), |
||
2502 | |||
2503 | /*** GLX_EXT_import_context ***/ |
||
2504 | GLX_FUNCTION(glXFreeContextEXT), |
||
2505 | GLX_FUNCTION(glXGetContextIDEXT), |
||
2506 | GLX_FUNCTION2(glXGetCurrentDisplayEXT, glXGetCurrentDisplay), |
||
2507 | GLX_FUNCTION(glXImportContextEXT), |
||
2508 | GLX_FUNCTION2(glXQueryContextInfoEXT, glXQueryContext), |
||
2509 | #endif |
||
2510 | |||
2511 | /*** GLX_SGIX_fbconfig ***/ |
||
2512 | GLX_FUNCTION2(glXGetFBConfigAttribSGIX, glXGetFBConfigAttrib), |
||
2513 | GLX_FUNCTION2(glXChooseFBConfigSGIX, glXChooseFBConfig), |
||
2514 | GLX_FUNCTION(glXCreateGLXPixmapWithConfigSGIX), |
||
2515 | GLX_FUNCTION(glXCreateContextWithConfigSGIX), |
||
2516 | GLX_FUNCTION2(glXGetVisualFromFBConfigSGIX, glXGetVisualFromFBConfig), |
||
2517 | GLX_FUNCTION(glXGetFBConfigFromVisualSGIX), |
||
2518 | |||
2519 | #ifndef GLX_USE_APPLEGL |
||
2520 | /*** GLX_SGIX_pbuffer ***/ |
||
2521 | GLX_FUNCTION(glXCreateGLXPbufferSGIX), |
||
2522 | GLX_FUNCTION(glXDestroyGLXPbufferSGIX), |
||
2523 | GLX_FUNCTION(glXQueryGLXPbufferSGIX), |
||
2524 | GLX_FUNCTION(glXSelectEventSGIX), |
||
2525 | GLX_FUNCTION(glXGetSelectedEventSGIX), |
||
2526 | |||
2527 | /*** GLX_SGIX_swap_group ***/ |
||
2528 | GLX_FUNCTION2(glXJoinSwapGroupSGIX, __glXJoinSwapGroupSGIX), |
||
2529 | |||
2530 | /*** GLX_SGIX_swap_barrier ***/ |
||
2531 | GLX_FUNCTION2(glXBindSwapBarrierSGIX, __glXBindSwapBarrierSGIX), |
||
2532 | GLX_FUNCTION2(glXQueryMaxSwapBarriersSGIX, __glXQueryMaxSwapBarriersSGIX), |
||
2533 | |||
2534 | /*** GLX_MESA_copy_sub_buffer ***/ |
||
2535 | GLX_FUNCTION2(glXCopySubBufferMESA, __glXCopySubBufferMESA), |
||
2536 | |||
2537 | /*** GLX_MESA_pixmap_colormap ***/ |
||
2538 | GLX_FUNCTION(glXCreateGLXPixmapMESA), |
||
2539 | |||
2540 | /*** GLX_MESA_release_buffers ***/ |
||
2541 | GLX_FUNCTION2(glXReleaseBuffersMESA, __glXReleaseBuffersMESA), |
||
2542 | |||
2543 | /*** GLX_MESA_swap_control ***/ |
||
2544 | GLX_FUNCTION2(glXSwapIntervalMESA, __glXSwapIntervalMESA), |
||
2545 | GLX_FUNCTION2(glXGetSwapIntervalMESA, __glXGetSwapIntervalMESA), |
||
2546 | #endif |
||
2547 | |||
2548 | /*** GLX_ARB_get_proc_address ***/ |
||
2549 | GLX_FUNCTION(glXGetProcAddressARB), |
||
2550 | |||
2551 | /*** GLX 1.4 ***/ |
||
2552 | GLX_FUNCTION2(glXGetProcAddress, glXGetProcAddressARB), |
||
2553 | |||
2554 | #ifndef GLX_USE_APPLEGL |
||
2555 | /*** GLX_OML_sync_control ***/ |
||
2556 | GLX_FUNCTION2(glXWaitForSbcOML, __glXWaitForSbcOML), |
||
2557 | GLX_FUNCTION2(glXWaitForMscOML, __glXWaitForMscOML), |
||
2558 | GLX_FUNCTION2(glXSwapBuffersMscOML, __glXSwapBuffersMscOML), |
||
2559 | GLX_FUNCTION2(glXGetMscRateOML, __glXGetMscRateOML), |
||
2560 | GLX_FUNCTION2(glXGetSyncValuesOML, __glXGetSyncValuesOML), |
||
2561 | |||
2562 | /*** GLX_EXT_texture_from_pixmap ***/ |
||
2563 | GLX_FUNCTION2(glXBindTexImageEXT, __glXBindTexImageEXT), |
||
2564 | GLX_FUNCTION2(glXReleaseTexImageEXT, __glXReleaseTexImageEXT), |
||
2565 | #endif |
||
2566 | |||
2567 | #if defined(GLX_DIRECT_RENDERING) && defined(GLX_USE_DRM) |
||
2568 | /*** DRI configuration ***/ |
||
2569 | GLX_FUNCTION(glXGetScreenDriver), |
||
2570 | GLX_FUNCTION(glXGetDriverConfig), |
||
2571 | #endif |
||
2572 | |||
2573 | /*** GLX_ARB_create_context and GLX_ARB_create_context_profile ***/ |
||
2574 | GLX_FUNCTION(glXCreateContextAttribsARB), |
||
2575 | |||
2576 | /*** GLX_MESA_query_renderer ***/ |
||
2577 | GLX_FUNCTION(glXQueryRendererIntegerMESA), |
||
2578 | GLX_FUNCTION(glXQueryRendererStringMESA), |
||
2579 | GLX_FUNCTION(glXQueryCurrentRendererIntegerMESA), |
||
2580 | GLX_FUNCTION(glXQueryCurrentRendererStringMESA), |
||
2581 | |||
2582 | {NULL, NULL} /* end of list */ |
||
2583 | }; |
||
2584 | |||
2585 | static const GLvoid * |
||
2586 | get_glx_proc_address(const char *funcName) |
||
2587 | { |
||
2588 | GLuint i; |
||
2589 | |||
2590 | /* try static functions */ |
||
2591 | for (i = 0; GLX_functions[i].Name; i++) { |
||
2592 | if (strcmp(GLX_functions[i].Name, funcName) == 0) |
||
2593 | return GLX_functions[i].Address; |
||
2594 | } |
||
2595 | |||
2596 | return NULL; |
||
2597 | } |
||
2598 | |||
2599 | /** |
||
2600 | * Get the address of a named GL function. This is the pre-GLX 1.4 name for |
||
2601 | * \c glXGetProcAddress. |
||
2602 | * |
||
2603 | * \param procName Name of a GL or GLX function. |
||
2604 | * \returns A pointer to the named function |
||
2605 | * |
||
2606 | * \sa glXGetProcAddress |
||
2607 | */ |
||
2608 | _X_EXPORT void (*glXGetProcAddressARB(const GLubyte * procName)) (void) |
||
2609 | { |
||
2610 | typedef void (*gl_function) (void); |
||
2611 | gl_function f; |
||
2612 | |||
2613 | |||
2614 | /* Search the table of GLX and internal functions first. If that |
||
2615 | * fails and the supplied name could be a valid core GL name, try |
||
2616 | * searching the core GL function table. This check is done to prevent |
||
2617 | * DRI based drivers from searching the core GL function table for |
||
2618 | * internal API functions. |
||
2619 | */ |
||
2620 | f = (gl_function) get_glx_proc_address((const char *) procName); |
||
2621 | if ((f == NULL) && (procName[0] == 'g') && (procName[1] == 'l') |
||
2622 | && (procName[2] != 'X')) { |
||
2623 | #ifdef GLX_SHARED_GLAPI |
||
2624 | f = (gl_function) __indirect_get_proc_address((const char *) procName); |
||
2625 | #endif |
||
2626 | if (!f) |
||
2627 | f = (gl_function) _glapi_get_proc_address((const char *) procName); |
||
2628 | if (!f) { |
||
2629 | struct glx_context *gc = __glXGetCurrentContext(); |
||
2630 | |||
2631 | if (gc != NULL && gc->vtable->get_proc_address != NULL) |
||
2632 | f = gc->vtable->get_proc_address((const char *) procName); |
||
2633 | } |
||
2634 | } |
||
2635 | return f; |
||
2636 | } |
||
2637 | |||
2638 | /** |
||
2639 | * Get the address of a named GL function. This is the GLX 1.4 name for |
||
2640 | * \c glXGetProcAddressARB. |
||
2641 | * |
||
2642 | * \param procName Name of a GL or GLX function. |
||
2643 | * \returns A pointer to the named function |
||
2644 | * |
||
2645 | * \sa glXGetProcAddressARB |
||
2646 | */ |
||
2647 | _X_EXPORT void (*glXGetProcAddress(const GLubyte * procName)) (void) |
||
2648 | #if defined(__GNUC__) && !defined(GLX_ALIAS_UNSUPPORTED) |
||
2649 | __attribute__ ((alias("glXGetProcAddressARB"))); |
||
2650 | #else |
||
2651 | { |
||
2652 | return glXGetProcAddressARB(procName); |
||
2653 | } |
||
2654 | #endif /* __GNUC__ */ |
||
2655 | |||
2656 | |||
2657 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
2658 | /** |
||
2659 | * Get the unadjusted system time (UST). Currently, the UST is measured in |
||
2660 | * microseconds since Epoc. The actual resolution of the UST may vary from |
||
2661 | * system to system, and the units may vary from release to release. |
||
2662 | * Drivers should not call this function directly. They should instead use |
||
2663 | * \c glXGetProcAddress to obtain a pointer to the function. |
||
2664 | * |
||
2665 | * \param ust Location to store the 64-bit UST |
||
2666 | * \returns Zero on success or a negative errno value on failure. |
||
2667 | * |
||
2668 | * \sa glXGetProcAddress, PFNGLXGETUSTPROC |
||
2669 | * |
||
2670 | * \since Internal API version 20030317. |
||
2671 | */ |
||
2672 | _X_HIDDEN int |
||
2673 | __glXGetUST(int64_t * ust) |
||
2674 | { |
||
2675 | struct timeval tv; |
||
2676 | |||
2677 | if (ust == NULL) { |
||
2678 | return -EFAULT; |
||
2679 | } |
||
2680 | |||
2681 | if (gettimeofday(&tv, NULL) == 0) { |
||
2682 | ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec; |
||
2683 | return 0; |
||
2684 | } |
||
2685 | else { |
||
2686 | return -errno; |
||
2687 | } |
||
2688 | } |
||
2689 | #endif /* GLX_DIRECT_RENDERING */>>>>>>>>=>=>=>>=>>>>>> |