fixed typo in GetProcAddress
[mesa.git] / src / mesa / drivers / x11 / fakeglx.c
1 /* $Id: fakeglx.c,v 1.5 1999/09/12 12:04:13 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.1
6 *
7 * Copyright (C) 1999 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28
29
30
31 /*
32 * A pseudo-GLX implementation to allow OpenGL/GLX programs to work with Mesa.
33 * The Fake_glX*() functions implemented here are called from glxapi.c
34 *
35 * Thanks to the contributors:
36 *
37 * Initial version: Philip Brown (philb@CSUA.Berkeley.EDU)
38 * Better glXGetConfig() support: Armin Liebchen (liebchen@asylum.cs.utah.edu)
39 * Further visual-handling refinements: Wolfram Gloger
40 * (wmglo@Dent.MED.Uni-Muenchen.DE).
41 *
42 * Notes:
43 * Don't be fooled, stereo isn't supported yet.
44 */
45
46
47
48 #ifdef HAVE_CONFIG_H
49 #include "conf.h"
50 #endif
51
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <X11/Xlib.h>
56 #include <X11/Xutil.h>
57 #include "GL/gl.h"
58 #include "GL/xmesa.h"
59 #include "context.h"
60 #include "config.h"
61 #include "fakeglx.h"
62 #include "macros.h"
63 #include "types.h"
64 #include "xmesaP.h"
65
66
67
68 #define DONT_CARE -1
69
70
71
72 #define MAX_VISUALS 100
73 static XMesaVisual VisualTable[MAX_VISUALS];
74 static int NumVisuals = 0;
75
76
77
78 /*
79 * This struct and some code fragments borrowed
80 * from Mark Kilgard's GLUT library.
81 */
82 typedef struct _OverlayInfo {
83 /* Avoid 64-bit portability problems by being careful to use
84 longs due to the way XGetWindowProperty is specified. Note
85 that these parameters are passed as CARD32s over X
86 protocol. */
87 unsigned long overlay_visual;
88 long transparent_type;
89 long value;
90 long layer;
91 } OverlayInfo;
92
93
94
95 /* Macro to handle c_class vs class field name in XVisualInfo struct */
96 #if defined(__cplusplus) || defined(c_plusplus)
97 #define CLASS c_class
98 #else
99 #define CLASS class
100 #endif
101
102
103
104
105 /*
106 * Test if the given XVisualInfo is usable for Mesa rendering.
107 */
108 static GLboolean is_usable_visual( XVisualInfo *vinfo )
109 {
110 switch (vinfo->CLASS) {
111 case StaticGray:
112 case GrayScale:
113 /* Any StaticGray/GrayScale visual works in RGB or CI mode */
114 return GL_TRUE;
115 case StaticColor:
116 case PseudoColor:
117 /* Any StaticColor/PseudoColor visual of at least 4 bits */
118 if (vinfo->depth>=4) {
119 return GL_TRUE;
120 }
121 else {
122 return GL_FALSE;
123 }
124 case TrueColor:
125 case DirectColor:
126 /* Any depth of TrueColor or DirectColor works in RGB mode */
127 return GL_TRUE;
128 default:
129 /* This should never happen */
130 return GL_FALSE;
131 }
132 }
133
134
135
136 /*
137 * Return the level (overlay, normal, underlay) of a given XVisualInfo.
138 * Input: dpy - the X display
139 * vinfo - the XVisualInfo to test
140 * Return: level of the visual:
141 * 0 = normal planes
142 * >0 = overlay planes
143 * <0 = underlay planes
144 */
145 static int level_of_visual( Display *dpy, XVisualInfo *vinfo )
146 {
147 Atom overlayVisualsAtom;
148 OverlayInfo *overlay_info = NULL;
149 int numOverlaysPerScreen;
150 Status status;
151 Atom actualType;
152 int actualFormat;
153 unsigned long sizeData, bytesLeft;
154 int i;
155
156 /*
157 * The SERVER_OVERLAY_VISUALS property on the root window contains
158 * a list of overlay visuals. Get that list now.
159 */
160 overlayVisualsAtom = XInternAtom(dpy,"SERVER_OVERLAY_VISUALS", True);
161 if (overlayVisualsAtom == None) {
162 return 0;
163 }
164
165 status = XGetWindowProperty(dpy, RootWindow( dpy, vinfo->screen ),
166 overlayVisualsAtom, 0L, (long) 10000, False,
167 overlayVisualsAtom, &actualType, &actualFormat,
168 &sizeData, &bytesLeft,
169 (unsigned char **) &overlay_info );
170
171 if (status != Success || actualType != overlayVisualsAtom ||
172 actualFormat != 32 || sizeData < 4) {
173 /* something went wrong */
174 XFree((void *) overlay_info);
175 return 0;
176 }
177
178 /* search the overlay visual list for the visual ID of interest */
179 numOverlaysPerScreen = (int) (sizeData / 4);
180 for (i=0;i<numOverlaysPerScreen;i++) {
181 OverlayInfo *ov;
182 ov = overlay_info + i;
183 if (ov->overlay_visual==vinfo->visualid) {
184 /* found the visual */
185 if (/*ov->transparent_type==1 &&*/ ov->layer!=0) {
186 int level = ov->layer;
187 XFree((void *) overlay_info);
188 return level;
189 }
190 else {
191 XFree((void *) overlay_info);
192 return 0;
193 }
194 }
195 }
196
197 /* The visual ID was not found in the overlay list. */
198 XFree((void *) overlay_info);
199 return 0;
200 }
201
202
203
204
205 /*
206 * Given an XVisualInfo and RGB, Double, and Depth buffer flags, save the
207 * configuration in our list of GLX visuals.
208 */
209 static XMesaVisual
210 save_glx_visual( Display *dpy, XVisualInfo *vinfo,
211 GLboolean rgbFlag, GLboolean alphaFlag, GLboolean dbFlag,
212 GLboolean stereoFlag,
213 GLint depth_size, GLint stencil_size,
214 GLint accum_size, GLint level )
215 {
216 GLboolean ximageFlag = GL_TRUE;
217 XMesaVisual xmvis;
218 GLint i;
219 GLboolean comparePointers;
220
221 if (dbFlag) {
222 /* Check if the MESA_BACK_BUFFER env var is set */
223 char *backbuffer = getenv("MESA_BACK_BUFFER");
224 if (backbuffer) {
225 if (backbuffer[0]=='p' || backbuffer[0]=='P') {
226 ximageFlag = GL_FALSE;
227 }
228 else if (backbuffer[0]=='x' || backbuffer[0]=='X') {
229 ximageFlag = GL_TRUE;
230 }
231 else {
232 fprintf(stderr, "Mesa: invalid value for MESA_BACK_BUFFER ");
233 fprintf(stderr, "environment variable, using an XImage.\n");
234 }
235 }
236 }
237
238 /* Comparing IDs uses less memory but sometimes fails. */
239 /* XXX revisit this after 3.0 is finished. */
240 if (getenv("MESA_GLX_VISUAL_HACK"))
241 comparePointers = GL_TRUE;
242 else
243 comparePointers = GL_FALSE;
244
245 /* First check if a matching visual is already in the list */
246 for (i=0; i<NumVisuals; i++) {
247 XMesaVisual v = VisualTable[i];
248 if (v->display == dpy
249 && v->level == level
250 && v->ximage_flag == ximageFlag
251 && v->gl_visual->RGBAflag == rgbFlag
252 && v->gl_visual->DBflag == dbFlag
253 && v->gl_visual->StereoFlag == stereoFlag
254 && (v->gl_visual->AlphaBits > 0) == alphaFlag
255 && (v->gl_visual->DepthBits >= depth_size || depth_size == 0)
256 && (v->gl_visual->StencilBits >= stencil_size || stencil_size == 0)
257 && (v->gl_visual->AccumBits >= accum_size || accum_size == 0)) {
258 /* now either compare XVisualInfo pointers or visual IDs */
259 if ((!comparePointers && v->vishandle->visualid == vinfo->visualid)
260 || (comparePointers && v->vishandle == vinfo)) {
261 return v;
262 }
263 }
264 }
265
266 /* Create a new visual and add it to the list. */
267
268 if (NumVisuals>=MAX_VISUALS) {
269 fprintf( stderr, "GLX Error: maximum number of visuals exceeded\n");
270 return NULL;
271 }
272
273 xmvis = XMesaCreateVisual( dpy, vinfo, rgbFlag, alphaFlag, dbFlag,
274 stereoFlag, ximageFlag,
275 depth_size, stencil_size, accum_size, level );
276 if (xmvis) {
277 VisualTable[NumVisuals] = xmvis;
278 NumVisuals++;
279 }
280 return xmvis;
281 }
282
283
284
285 /*
286 * Create a GLX visual from a regular XVisualInfo.
287 */
288 static XMesaVisual
289 create_glx_visual( Display *dpy, XVisualInfo *visinfo )
290 {
291 int vislevel;
292
293 vislevel = level_of_visual( dpy, visinfo );
294 if (vislevel) {
295 /* Configure this visual as a CI, single-buffered overlay */
296 return save_glx_visual( dpy, visinfo,
297 GL_FALSE, /* rgb */
298 GL_FALSE, /* alpha */
299 GL_FALSE, /* double */
300 GL_FALSE, /* stereo */
301 0, /* depth bits */
302 0, /* stencil bits */
303 0, /* accum bits */
304 vislevel /* level */
305 );
306 }
307 else if (is_usable_visual( visinfo )) {
308 /* Configure this visual as RGB, double-buffered, depth-buffered. */
309 /* This is surely wrong for some people's needs but what else */
310 /* can be done? They should use glXChooseVisual(). */
311 return save_glx_visual( dpy, visinfo,
312 GL_TRUE, /* rgb */
313 GL_FALSE, /* alpha */
314 GL_TRUE, /* double */
315 GL_FALSE, /* stereo */
316 8*sizeof(GLdepth),
317 8*sizeof(GLstencil),
318 8*sizeof(GLaccum),
319 0 /* level */
320 );
321 }
322 else {
323 fprintf(stderr,"Mesa: error in glXCreateContext: bad visual\n");
324 return NULL;
325 }
326 }
327
328
329
330 /*
331 * Find the GLX visual associated with an XVisualInfo.
332 */
333 static XMesaVisual
334 find_glx_visual( Display *dpy, XVisualInfo *vinfo )
335 {
336 int i;
337
338 /* First try to match pointers */
339 for (i=0;i<NumVisuals;i++) {
340 if (VisualTable[i]->display==dpy && VisualTable[i]->vishandle==vinfo) {
341 return VisualTable[i];
342 }
343 }
344 /* try to match visual id */
345 for (i=0;i<NumVisuals;i++) {
346 if (VisualTable[i]->display==dpy
347 && VisualTable[i]->visinfo->visualid == vinfo->visualid) {
348 return VisualTable[i];
349 }
350 }
351 return NULL;
352 }
353
354
355
356 /*
357 * Return the transparent pixel value for a GLX visual.
358 * Input: glxvis - the glx_visual
359 * Return: a pixel value or -1 if no transparent pixel
360 */
361 static int transparent_pixel( XMesaVisual glxvis )
362 {
363 Display *dpy = glxvis->display;
364 XVisualInfo *vinfo = glxvis->visinfo;
365 Atom overlayVisualsAtom;
366 OverlayInfo *overlay_info = NULL;
367 int numOverlaysPerScreen;
368 Status status;
369 Atom actualType;
370 int actualFormat;
371 unsigned long sizeData, bytesLeft;
372 int i;
373
374 /*
375 * The SERVER_OVERLAY_VISUALS property on the root window contains
376 * a list of overlay visuals. Get that list now.
377 */
378 overlayVisualsAtom = XInternAtom(dpy,"SERVER_OVERLAY_VISUALS", True);
379 if (overlayVisualsAtom == None) {
380 return -1;
381 }
382
383 status = XGetWindowProperty(dpy, RootWindow( dpy, vinfo->screen ),
384 overlayVisualsAtom, 0L, (long) 10000, False,
385 overlayVisualsAtom, &actualType, &actualFormat,
386 &sizeData, &bytesLeft,
387 (unsigned char **) &overlay_info );
388
389 if (status != Success || actualType != overlayVisualsAtom ||
390 actualFormat != 32 || sizeData < 4) {
391 /* something went wrong */
392 XFree((void *) overlay_info);
393 return -1;
394 }
395
396 /* search the overlay visual list for the visual ID of interest */
397 numOverlaysPerScreen = (int) (sizeData / 4);
398 for (i=0;i<numOverlaysPerScreen;i++) {
399 OverlayInfo *ov;
400 ov = overlay_info + i;
401 if (ov->overlay_visual==vinfo->visualid) {
402 /* found it! */
403 if (ov->transparent_type==0) {
404 /* type 0 indicates no transparency */
405 XFree((void *) overlay_info);
406 return -1;
407 }
408 else {
409 /* ov->value is the transparent pixel */
410 XFree((void *) overlay_info);
411 return ov->value;
412 }
413 }
414 }
415
416 /* The visual ID was not found in the overlay list. */
417 XFree((void *) overlay_info);
418 return -1;
419 }
420
421
422
423 /*
424 * Return number of bits set in n.
425 */
426 static int bitcount( unsigned long n )
427 {
428 int bits;
429 for (bits=0; n>0; n=n>>1) {
430 if (n&1) {
431 bits++;
432 }
433 }
434 return bits;
435 }
436
437
438 /*
439 * Try to get an X visual which matches the given arguments.
440 */
441 static XVisualInfo *get_visual( Display *dpy, int scr,
442 unsigned int depth, int xclass )
443 {
444 XVisualInfo temp, *vis;
445 long mask;
446 int n;
447 unsigned int default_depth;
448 int default_class;
449
450 mask = VisualScreenMask | VisualDepthMask | VisualClassMask;
451 temp.screen = scr;
452 temp.depth = depth;
453 temp.CLASS = xclass;
454
455 default_depth = DefaultDepth(dpy,scr);
456 default_class = DefaultVisual(dpy,scr)->CLASS;
457
458 if (depth==default_depth && xclass==default_class) {
459 /* try to get root window's visual */
460 temp.visualid = DefaultVisual(dpy,scr)->visualid;
461 mask |= VisualIDMask;
462 }
463
464 vis = XGetVisualInfo( dpy, mask, &temp, &n );
465
466 /* In case bits/pixel > 24, make sure color channels are still <=8 bits.
467 * An SGI Infinite Reality system, for example, can have 30bpp pixels:
468 * 10 bits per color channel. Mesa's limited to a max of 8 bits/channel.
469 */
470 if (vis && depth > 24 && (xclass==TrueColor || xclass==DirectColor)) {
471 if (bitcount(vis->red_mask) <= 8
472 && bitcount(vis->green_mask) <= 8
473 && bitcount(vis->blue_mask) <= 8) {
474 return vis;
475 }
476 else {
477 XFree((void *) vis);
478 return NULL;
479 }
480 }
481
482 return vis;
483 }
484
485
486
487 /*
488 * Retrieve the value of the given environment variable and find
489 * the X visual which matches it.
490 * Input: dpy - the display
491 * screen - the screen number
492 * varname - the name of the environment variable
493 * Return: an XVisualInfo pointer to NULL if error.
494 */
495 static XVisualInfo *get_env_visual(Display *dpy, int scr, const char *varname)
496 {
497 char value[100], type[100];
498 int depth, xclass = -1;
499 XVisualInfo *vis;
500
501 if (!getenv( varname )) {
502 return NULL;
503 }
504
505 strncpy( value, getenv(varname), 100 );
506 value[99] = 0;
507
508 sscanf( value, "%s %d", type, &depth );
509
510 if (strcmp(type,"TrueColor")==0) xclass = TrueColor;
511 else if (strcmp(type,"DirectColor")==0) xclass = DirectColor;
512 else if (strcmp(type,"PseudoColor")==0) xclass = PseudoColor;
513 else if (strcmp(type,"StaticColor")==0) xclass = StaticColor;
514 else if (strcmp(type,"GrayScale")==0) xclass = GrayScale;
515 else if (strcmp(type,"StaticGray")==0) xclass = StaticGray;
516
517 if (xclass>-1 && depth>0) {
518 vis = get_visual( dpy, scr, depth, xclass );
519 if (vis) {
520 return vis;
521 }
522 }
523
524 fprintf( stderr, "Mesa: GLX unable to find visual class=%s, depth=%d.\n",
525 type, depth );
526 return NULL;
527 }
528
529
530
531 /*
532 * Select an X visual which satisfies the RGBA/CI flag and minimum depth.
533 * Input: dpy, screen - X display and screen number
534 * rgba - GL_TRUE = RGBA mode, GL_FALSE = CI mode
535 * min_depth - minimum visual depth
536 * preferred_class - preferred GLX visual class or DONT_CARE
537 * Return: pointer to an XVisualInfo or NULL.
538 */
539 static XVisualInfo *choose_x_visual( Display *dpy, int screen,
540 GLboolean rgba, int min_depth,
541 int preferred_class )
542 {
543 XVisualInfo *vis;
544 int xclass, visclass;
545 int depth;
546
547 if (rgba) {
548 Atom hp_cr_maps = XInternAtom(dpy, "_HP_RGB_SMOOTH_MAP_LIST", True);
549 /* First see if the MESA_RGB_VISUAL env var is defined */
550 vis = get_env_visual( dpy, screen, "MESA_RGB_VISUAL" );
551 if (vis) {
552 return vis;
553 }
554 /* Otherwise, search for a suitable visual */
555 if (preferred_class==DONT_CARE) {
556 for (xclass=0;xclass<6;xclass++) {
557 switch (xclass) {
558 case 0: visclass = TrueColor; break;
559 case 1: visclass = DirectColor; break;
560 case 2: visclass = PseudoColor; break;
561 case 3: visclass = StaticColor; break;
562 case 4: visclass = GrayScale; break;
563 case 5: visclass = StaticGray; break;
564 }
565 if (min_depth==0) {
566 /* start with shallowest */
567 for (depth=0;depth<=32;depth++) {
568 if (visclass==TrueColor && depth==8 && !hp_cr_maps) {
569 /* Special case: try to get 8-bit PseudoColor before */
570 /* 8-bit TrueColor */
571 vis = get_visual( dpy, screen, 8, PseudoColor );
572 if (vis) {
573 return vis;
574 }
575 }
576 vis = get_visual( dpy, screen, depth, visclass );
577 if (vis) {
578 return vis;
579 }
580 }
581 }
582 else {
583 /* start with deepest */
584 for (depth=32;depth>=min_depth;depth--) {
585 if (visclass==TrueColor && depth==8 && !hp_cr_maps) {
586 /* Special case: try to get 8-bit PseudoColor before */
587 /* 8-bit TrueColor */
588 vis = get_visual( dpy, screen, 8, PseudoColor );
589 if (vis) {
590 return vis;
591 }
592 }
593 vis = get_visual( dpy, screen, depth, visclass );
594 if (vis) {
595 return vis;
596 }
597 }
598 }
599 }
600 }
601 else {
602 /* search for a specific visual class */
603 switch (preferred_class) {
604 case GLX_TRUE_COLOR_EXT: visclass = TrueColor; break;
605 case GLX_DIRECT_COLOR_EXT: visclass = DirectColor; break;
606 case GLX_PSEUDO_COLOR_EXT: visclass = PseudoColor; break;
607 case GLX_STATIC_COLOR_EXT: visclass = StaticColor; break;
608 case GLX_GRAY_SCALE_EXT: visclass = GrayScale; break;
609 case GLX_STATIC_GRAY_EXT: visclass = StaticGray; break;
610 default: return NULL;
611 }
612 if (min_depth==0) {
613 /* start with shallowest */
614 for (depth=0;depth<=32;depth++) {
615 vis = get_visual( dpy, screen, depth, visclass );
616 if (vis) {
617 return vis;
618 }
619 }
620 }
621 else {
622 /* start with deepest */
623 for (depth=32;depth>=min_depth;depth--) {
624 vis = get_visual( dpy, screen, depth, visclass );
625 if (vis) {
626 return vis;
627 }
628 }
629 }
630 }
631 }
632 else {
633 /* First see if the MESA_CI_VISUAL env var is defined */
634 vis = get_env_visual( dpy, screen, "MESA_CI_VISUAL" );
635 if (vis) {
636 return vis;
637 }
638 /* Otherwise, search for a suitable visual, starting with shallowest */
639 if (preferred_class==DONT_CARE) {
640 for (xclass=0;xclass<4;xclass++) {
641 switch (xclass) {
642 case 0: visclass = PseudoColor; break;
643 case 1: visclass = StaticColor; break;
644 case 2: visclass = GrayScale; break;
645 case 3: visclass = StaticGray; break;
646 }
647 /* try 8-bit up through 16-bit */
648 for (depth=8;depth<=16;depth++) {
649 vis = get_visual( dpy, screen, depth, visclass );
650 if (vis) {
651 return vis;
652 }
653 }
654 /* try min_depth up to 8-bit */
655 for (depth=min_depth;depth<8;depth++) {
656 vis = get_visual( dpy, screen, depth, visclass );
657 if (vis) {
658 return vis;
659 }
660 }
661 }
662 }
663 else {
664 /* search for a specific visual class */
665 switch (preferred_class) {
666 case GLX_TRUE_COLOR_EXT: visclass = TrueColor; break;
667 case GLX_DIRECT_COLOR_EXT: visclass = DirectColor; break;
668 case GLX_PSEUDO_COLOR_EXT: visclass = PseudoColor; break;
669 case GLX_STATIC_COLOR_EXT: visclass = StaticColor; break;
670 case GLX_GRAY_SCALE_EXT: visclass = GrayScale; break;
671 case GLX_STATIC_GRAY_EXT: visclass = StaticGray; break;
672 default: return NULL;
673 }
674 /* try 8-bit up through 16-bit */
675 for (depth=8;depth<=16;depth++) {
676 vis = get_visual( dpy, screen, depth, visclass );
677 if (vis) {
678 return vis;
679 }
680 }
681 /* try min_depth up to 8-bit */
682 for (depth=min_depth;depth<8;depth++) {
683 vis = get_visual( dpy, screen, depth, visclass );
684 if (vis) {
685 return vis;
686 }
687 }
688 }
689 }
690
691 /* didn't find a visual */
692 return NULL;
693 }
694
695
696
697 /*
698 * Find the deepest X over/underlay visual of at least min_depth.
699 * Input: dpy, screen - X display and screen number
700 * level - the over/underlay level
701 * trans_type - transparent pixel type: GLX_NONE_EXT,
702 * GLX_TRANSPARENT_RGB_EXT, GLX_TRANSPARENT_INDEX_EXT,
703 * or DONT_CARE
704 * trans_value - transparent pixel value or DONT_CARE
705 * min_depth - minimum visual depth
706 * preferred_class - preferred GLX visual class or DONT_CARE
707 * Return: pointer to an XVisualInfo or NULL.
708 */
709 static XVisualInfo *choose_x_overlay_visual( Display *dpy, int scr,
710 int level, int trans_type,
711 int trans_value,
712 int min_depth,
713 int preferred_class )
714 {
715 Atom overlayVisualsAtom;
716 OverlayInfo *overlay_info;
717 int numOverlaysPerScreen;
718 Status status;
719 Atom actualType;
720 int actualFormat;
721 unsigned long sizeData, bytesLeft;
722 int i;
723 XVisualInfo *deepvis;
724 int deepest;
725
726 /*DEBUG int tt, tv; */
727
728 switch (preferred_class) {
729 case GLX_TRUE_COLOR_EXT: preferred_class = TrueColor; break;
730 case GLX_DIRECT_COLOR_EXT: preferred_class = DirectColor; break;
731 case GLX_PSEUDO_COLOR_EXT: preferred_class = PseudoColor; break;
732 case GLX_STATIC_COLOR_EXT: preferred_class = StaticColor; break;
733 case GLX_GRAY_SCALE_EXT: preferred_class = GrayScale; break;
734 case GLX_STATIC_GRAY_EXT: preferred_class = StaticGray; break;
735 default: preferred_class = DONT_CARE;
736 }
737
738 /*
739 * The SERVER_OVERLAY_VISUALS property on the root window contains
740 * a list of overlay visuals. Get that list now.
741 */
742 overlayVisualsAtom = XInternAtom(dpy,"SERVER_OVERLAY_VISUALS", True);
743 if (overlayVisualsAtom == (Atom) None) {
744 return NULL;
745 }
746
747 status = XGetWindowProperty(dpy, RootWindow( dpy, scr ),
748 overlayVisualsAtom, 0L, (long) 10000, False,
749 overlayVisualsAtom, &actualType, &actualFormat,
750 &sizeData, &bytesLeft,
751 (unsigned char **) &overlay_info );
752
753 if (status != Success || actualType != overlayVisualsAtom ||
754 actualFormat != 32 || sizeData < 4) {
755 /* something went wrong */
756 return NULL;
757 }
758
759 /* Search for the deepest overlay which satisifies all criteria. */
760 deepest = min_depth;
761 deepvis = NULL;
762
763 numOverlaysPerScreen = (int) (sizeData / 4);
764 for (i=0;i<numOverlaysPerScreen;i++) {
765 XVisualInfo *vislist, vistemplate;
766 int count;
767 OverlayInfo *ov;
768 ov = overlay_info + i;
769
770 if (ov->layer!=level) {
771 /* failed overlay level criteria */
772 continue;
773 }
774 if (!(trans_type==DONT_CARE
775 || (trans_type==GLX_TRANSPARENT_INDEX_EXT
776 && ov->transparent_type>0)
777 || (trans_type==GLX_NONE_EXT && ov->transparent_type==0))) {
778 /* failed transparent pixel type criteria */
779 continue;
780 }
781 if (trans_value!=DONT_CARE && trans_value!=ov->value) {
782 /* failed transparent pixel value criteria */
783 continue;
784 }
785
786 /* get XVisualInfo and check the depth */
787 vistemplate.visualid = ov->overlay_visual;
788 vistemplate.screen = scr;
789 vislist = XGetVisualInfo( dpy, VisualIDMask | VisualScreenMask,
790 &vistemplate, &count );
791
792 if (count!=1) {
793 /* something went wrong */
794 continue;
795 }
796 if (preferred_class!=DONT_CARE && preferred_class!=vislist->CLASS) {
797 /* wrong visual class */
798 continue;
799 }
800
801 if (deepvis==NULL || vislist->depth > deepest) {
802 /* YES! found a satisfactory visual */
803 if (deepvis) {
804 free( deepvis );
805 }
806 deepest = vislist->depth;
807 deepvis = vislist;
808 /* DEBUG tt = ov->transparent_type;*/
809 /* DEBUG tv = ov->value; */
810 }
811 }
812
813 /*DEBUG
814 if (deepvis) {
815 printf("chose 0x%x: layer=%d depth=%d trans_type=%d trans_value=%d\n",
816 deepvis->visualid, level, deepvis->depth, tt, tv );
817 }
818 */
819 return deepvis;
820 }
821
822
823
824 XVisualInfo *Fake_glXChooseVisual( Display *dpy, int screen, int *list )
825 {
826 int *parselist;
827 XVisualInfo *vis;
828 int min_ci = 0;
829 int min_red=0, min_green=0, min_blue=0;
830 GLboolean rgb_flag = GL_FALSE;
831 GLboolean alpha_flag = GL_FALSE;
832 GLboolean double_flag = GL_FALSE;
833 GLboolean stereo_flag = GL_FALSE;
834 GLint depth_size = 0;
835 GLint stencil_size = 0;
836 GLint accum_size = 0;
837 int level = 0;
838 int visual_type = DONT_CARE;
839 int trans_type = DONT_CARE;
840 int trans_value = DONT_CARE;
841
842 parselist = list;
843
844 while (*parselist) {
845
846 switch (*parselist) {
847 case GLX_USE_GL:
848 /* ignore */
849 parselist++;
850 break;
851 case GLX_BUFFER_SIZE:
852 parselist++;
853 min_ci = *parselist++;
854 break;
855 case GLX_LEVEL:
856 parselist++;
857 level = *parselist++;
858 break;
859 case GLX_RGBA:
860 rgb_flag = GL_TRUE;
861 parselist++;
862 break;
863 case GLX_DOUBLEBUFFER:
864 double_flag = GL_TRUE;
865 parselist++;
866 break;
867 case GLX_STEREO:
868 stereo_flag = GL_TRUE;
869 return NULL;
870 case GLX_AUX_BUFFERS:
871 /* ignore */
872 parselist++;
873 parselist++;
874 break;
875 case GLX_RED_SIZE:
876 parselist++;
877 min_red = *parselist++;
878 break;
879 case GLX_GREEN_SIZE:
880 parselist++;
881 min_green = *parselist++;
882 break;
883 case GLX_BLUE_SIZE:
884 parselist++;
885 min_blue = *parselist++;
886 break;
887 case GLX_ALPHA_SIZE:
888 parselist++;
889 {
890 GLint size = *parselist++;
891 alpha_flag = size>0 ? 1 : 0;
892 }
893 break;
894 case GLX_DEPTH_SIZE:
895 parselist++;
896 depth_size = *parselist++;
897 break;
898 case GLX_STENCIL_SIZE:
899 parselist++;
900 stencil_size = *parselist++;
901 break;
902 case GLX_ACCUM_RED_SIZE:
903 case GLX_ACCUM_GREEN_SIZE:
904 case GLX_ACCUM_BLUE_SIZE:
905 case GLX_ACCUM_ALPHA_SIZE:
906 parselist++;
907 {
908 GLint size = *parselist++;
909 accum_size = MAX2( accum_size, size );
910 }
911 break;
912
913 /*
914 * GLX_EXT_visual_info extension
915 */
916 case GLX_X_VISUAL_TYPE_EXT:
917 parselist++;
918 visual_type = *parselist++;
919 break;
920 case GLX_TRANSPARENT_TYPE_EXT:
921 parselist++;
922 trans_type = *parselist++;
923 break;
924 case GLX_TRANSPARENT_INDEX_VALUE_EXT:
925 parselist++;
926 trans_value = *parselist++;
927 break;
928 case GLX_TRANSPARENT_RED_VALUE_EXT:
929 case GLX_TRANSPARENT_GREEN_VALUE_EXT:
930 case GLX_TRANSPARENT_BLUE_VALUE_EXT:
931 case GLX_TRANSPARENT_ALPHA_VALUE_EXT:
932 /* ignore */
933 parselist++;
934 parselist++;
935 break;
936
937 case None:
938 break;
939 default:
940 /* undefined attribute */
941 return NULL;
942 }
943 }
944
945 /*
946 * Since we're only simulating the GLX extension this function will never
947 * find any real GL visuals. Instead, all we can do is try to find an RGB
948 * or CI visual of appropriate depth. Other requested attributes such as
949 * double buffering, depth buffer, etc. will be associated with the X
950 * visual and stored in the VisualTable[].
951 */
952 if (level==0) {
953 /* normal color planes */
954 if (rgb_flag) {
955 /* Get an RGB visual */
956 int min_rgb = min_red + min_green + min_blue;
957 if (min_rgb>1 && min_rgb<8) {
958 /* a special case to be sure we can get a monochrome visual */
959 min_rgb = 1;
960 }
961 vis = choose_x_visual( dpy, screen, rgb_flag, min_rgb, visual_type );
962 }
963 else {
964 /* Get a color index visual */
965 vis = choose_x_visual( dpy, screen, rgb_flag, min_ci, visual_type );
966 accum_size = 0;
967 }
968 }
969 else {
970 /* over/underlay planes */
971 vis = choose_x_overlay_visual( dpy, screen, level, trans_type,
972 trans_value, min_ci, visual_type );
973 }
974
975 if (vis) {
976 if (!save_glx_visual( dpy, vis, rgb_flag, alpha_flag, double_flag,
977 stereo_flag,
978 depth_size, stencil_size, accum_size, level ))
979 return NULL;
980 }
981
982 return vis;
983 }
984
985
986
987
988 GLXContext Fake_glXCreateContext( Display *dpy, XVisualInfo *visinfo,
989 GLXContext share_list, Bool direct )
990 {
991 XMesaVisual glxvis;
992 XMesaContext xmctx;
993
994 /* deallocate unused windows/buffers */
995 XMesaGarbageCollect();
996
997 glxvis = find_glx_visual( dpy, visinfo );
998 if (!glxvis) {
999 /* This visual wasn't found with glXChooseVisual() */
1000 glxvis = create_glx_visual( dpy, visinfo );
1001 if (!glxvis) {
1002 /* unusable visual */
1003 return NULL;
1004 }
1005 }
1006
1007 xmctx = XMesaCreateContext( glxvis, (XMesaContext) share_list );
1008 if (xmctx) {
1009 /* set the direct/indirect flag */
1010 xmctx->direct = direct;
1011 }
1012 return (GLXContext) xmctx;
1013 }
1014
1015
1016 static GLXDrawable MakeCurrent_PrevDrawable = 0;
1017 static GLXContext MakeCurrent_PrevContext = 0;
1018 static XMesaBuffer MakeCurrent_PrevBuffer = 0;
1019
1020 Bool Fake_glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx )
1021 {
1022 if (ctx && drawable) {
1023 XMesaBuffer buffer;
1024
1025 if (drawable==MakeCurrent_PrevDrawable && ctx==MakeCurrent_PrevContext) {
1026 buffer = MakeCurrent_PrevBuffer;
1027 }
1028 else {
1029 buffer = XMesaFindBuffer( dpy, drawable );
1030 }
1031 if (!buffer) {
1032 /* drawable must be a new window! */
1033 buffer = XMesaCreateWindowBuffer2( ctx->xm_visual, drawable, ctx );
1034 if (!buffer) {
1035 /* Out of memory, or context/drawable depth mismatch */
1036 return False;
1037 }
1038 }
1039 MakeCurrent_PrevContext = ctx;
1040 MakeCurrent_PrevDrawable = drawable;
1041 MakeCurrent_PrevBuffer = buffer;
1042
1043 /* Now make current! */
1044 return (Bool) XMesaMakeCurrent( (XMesaContext) ctx, buffer );
1045 }
1046 else if (!ctx && !drawable) {
1047 /* release current context w/out assigning new one. */
1048 XMesaMakeCurrent( NULL, NULL );
1049 MakeCurrent_PrevContext = 0;
1050 MakeCurrent_PrevDrawable = 0;
1051 MakeCurrent_PrevBuffer = 0;
1052 return True;
1053 }
1054 else {
1055 /* ctx XOR drawable is NULL, this is an error */
1056 return False;
1057 }
1058 }
1059
1060
1061
1062 GLXPixmap Fake_glXCreateGLXPixmap( Display *dpy, XVisualInfo *visinfo,
1063 Pixmap pixmap )
1064 {
1065 XMesaVisual v;
1066 XMesaBuffer b;
1067
1068 v = find_glx_visual( dpy, visinfo );
1069 if (!v) {
1070 v = create_glx_visual( dpy, visinfo );
1071 if (!v) {
1072 /* unusable visual */
1073 return 0;
1074 }
1075 }
1076
1077 b = XMesaCreatePixmapBuffer( v, pixmap, 0 );
1078 if (!b) {
1079 return 0;
1080 }
1081 return b->frontbuffer;
1082 }
1083
1084
1085 #ifdef GLX_MESA_pixmap_colormap
1086
1087 GLXPixmap Fake_glXCreateGLXPixmapMESA( Display *dpy, XVisualInfo *visinfo,
1088 Pixmap pixmap, Colormap cmap )
1089 {
1090 XMesaVisual v;
1091 XMesaBuffer b;
1092
1093 v = find_glx_visual( dpy, visinfo );
1094 if (!v) {
1095 v = create_glx_visual( dpy, visinfo );
1096 if (!v) {
1097 /* unusable visual */
1098 return 0;
1099 }
1100 }
1101
1102 b = XMesaCreatePixmapBuffer( v, pixmap, cmap );
1103 if (!b) {
1104 return 0;
1105 }
1106 return b->frontbuffer;
1107 }
1108
1109 #endif
1110
1111
1112 void Fake_glXDestroyGLXPixmap( Display *dpy, GLXPixmap pixmap )
1113 {
1114 XMesaBuffer b = XMesaFindBuffer(dpy, pixmap);
1115 if (b) {
1116 XMesaDestroyBuffer(b);
1117 }
1118 else if (getenv("MESA_DEBUG")) {
1119 fprintf( stderr, "Mesa: glXDestroyGLXPixmap: invalid pixmap\n");
1120 }
1121 }
1122
1123
1124 void Fake_glXCopyContext( Display *dpy, GLXContext src, GLXContext dst,
1125 GLuint mask )
1126 {
1127 XMesaContext xm_src = (XMesaContext) src;
1128 XMesaContext xm_dst = (XMesaContext) dst;
1129 (void) dpy;
1130 gl_copy_context( xm_src->gl_ctx, xm_dst->gl_ctx, mask );
1131 }
1132
1133
1134
1135 Bool Fake_glXQueryExtension( Display *dpy, int *errorb, int *event )
1136 {
1137 /* Mesa's GLX isn't really an X extension but we try to act like one. */
1138 (void) dpy;
1139 (void) errorb;
1140 (void) event;
1141 return True;
1142 }
1143
1144
1145 void _kw_ungrab_all( Display *dpy )
1146 {
1147 XUngrabPointer( dpy, CurrentTime );
1148 XUngrabKeyboard( dpy, CurrentTime );
1149 }
1150
1151
1152 void Fake_glXDestroyContext( Display *dpy, GLXContext ctx )
1153 {
1154 (void) dpy;
1155 MakeCurrent_PrevContext = 0;
1156 MakeCurrent_PrevDrawable = 0;
1157 MakeCurrent_PrevBuffer = 0;
1158 XMesaDestroyContext( (XMesaContext) ctx );
1159 XMesaGarbageCollect();
1160 }
1161
1162
1163
1164 Bool Fake_glXIsDirect( Display *dpy, GLXContext ctx )
1165 {
1166 (void) dpy;
1167 return ((XMesaContext) ctx)->direct;
1168 }
1169
1170
1171
1172 void Fake_glXSwapBuffers( Display *dpy, GLXDrawable drawable )
1173 {
1174 XMesaBuffer buffer = XMesaFindBuffer( dpy, drawable );
1175
1176 if (buffer) {
1177 XMesaSwapBuffers(buffer);
1178 }
1179 else if (getenv("MESA_DEBUG")) {
1180 fprintf(stderr, "Mesa Warning: glXSwapBuffers: invalid drawable\n");
1181 }
1182 }
1183
1184
1185 void Fake_glXCopySubBufferMESA( Display *dpy, GLXDrawable drawable,
1186 int x, int y, int width, int height )
1187 {
1188 XMesaBuffer buffer = XMesaFindBuffer( dpy, drawable );
1189 if (buffer) {
1190 XMesaCopySubBuffer(buffer, x, y, width, height);
1191 }
1192 else if (getenv("MESA_DEBUG")) {
1193 fprintf(stderr, "Mesa Warning: glXCopySubBufferMESA: invalid drawable\n");
1194 }
1195 }
1196
1197
1198
1199 Bool Fake_glXQueryVersion( Display *dpy, int *maj, int *min )
1200 {
1201 (void) dpy;
1202 /* Return GLX version, not Mesa version */
1203 *maj = 1;
1204 *min = 1;
1205 return True;
1206 }
1207
1208
1209
1210 /*
1211 * Query the GLX attributes of the given XVisualInfo.
1212 */
1213 int Fake_glXGetConfig( Display *dpy, XVisualInfo *visinfo,
1214 int attrib, int *value )
1215 {
1216 XMesaVisual glxvis;
1217
1218 glxvis = find_glx_visual( dpy, visinfo );
1219 if (!glxvis) {
1220 /* this visual wasn't obtained with glXChooseVisual */
1221 glxvis = create_glx_visual( dpy, visinfo );
1222 if (!glxvis) {
1223 /* this visual can't be used for GL rendering */
1224 if (attrib==GLX_USE_GL) {
1225 *value = (int) False;
1226 return 0;
1227 }
1228 else {
1229 /*fprintf( stderr, "Mesa: Error in glXGetConfig: bad visual\n");*/
1230 return GLX_BAD_VISUAL;
1231 }
1232 }
1233 }
1234
1235 switch(attrib) {
1236 case GLX_USE_GL:
1237 *value = (int) True;
1238 return 0;
1239 case GLX_BUFFER_SIZE:
1240 *value = visinfo->depth;
1241 return 0;
1242 case GLX_LEVEL:
1243 *value = glxvis->level;
1244 return 0;
1245 case GLX_RGBA:
1246 if (glxvis->gl_visual->RGBAflag) {
1247 *value = True;
1248 }
1249 else {
1250 *value = False;
1251 }
1252 return 0;
1253 case GLX_DOUBLEBUFFER:
1254 *value = (int) glxvis->gl_visual->DBflag;
1255 return 0;
1256 case GLX_STEREO:
1257 *value = (int) glxvis->gl_visual->StereoFlag;
1258 return 0;
1259 case GLX_AUX_BUFFERS:
1260 *value = (int) False;
1261 return 0;
1262 case GLX_RED_SIZE:
1263 *value = glxvis->gl_visual->RedBits;
1264 return 0;
1265 case GLX_GREEN_SIZE:
1266 *value = glxvis->gl_visual->GreenBits;
1267 return 0;
1268 case GLX_BLUE_SIZE:
1269 *value = glxvis->gl_visual->BlueBits;
1270 return 0;
1271 case GLX_ALPHA_SIZE:
1272 *value = glxvis->gl_visual->AlphaBits;
1273 return 0;
1274 case GLX_DEPTH_SIZE:
1275 *value = glxvis->gl_visual->DepthBits;
1276 return 0;
1277 case GLX_STENCIL_SIZE:
1278 *value = glxvis->gl_visual->StencilBits;
1279 return 0;
1280 case GLX_ACCUM_RED_SIZE:
1281 case GLX_ACCUM_GREEN_SIZE:
1282 case GLX_ACCUM_BLUE_SIZE:
1283 *value = glxvis->gl_visual->AccumBits;
1284 return 0;
1285 case GLX_ACCUM_ALPHA_SIZE:
1286 if (glxvis->gl_visual->AlphaBits > 0)
1287 *value = glxvis->gl_visual->AccumBits;
1288 else
1289 *value = 0;
1290 return 0;
1291
1292 /*
1293 * GLX_EXT_visual_info extension
1294 */
1295 case GLX_X_VISUAL_TYPE_EXT:
1296 switch (glxvis->visinfo->CLASS) {
1297 case StaticGray: *value = GLX_STATIC_GRAY_EXT; return 0;
1298 case GrayScale: *value = GLX_GRAY_SCALE_EXT; return 0;
1299 case StaticColor: *value = GLX_STATIC_GRAY_EXT; return 0;
1300 case PseudoColor: *value = GLX_PSEUDO_COLOR_EXT; return 0;
1301 case TrueColor: *value = GLX_TRUE_COLOR_EXT; return 0;
1302 case DirectColor: *value = GLX_DIRECT_COLOR_EXT; return 0;
1303 }
1304 return 0;
1305 case GLX_TRANSPARENT_TYPE_EXT:
1306 if (glxvis->level==0) {
1307 /* normal planes */
1308 *value = GLX_NONE_EXT;
1309 }
1310 else if (glxvis->level>0) {
1311 /* overlay */
1312 if (glxvis->gl_visual->RGBAflag) {
1313 *value = GLX_TRANSPARENT_RGB_EXT;
1314 }
1315 else {
1316 *value = GLX_TRANSPARENT_INDEX_EXT;
1317 }
1318 }
1319 else if (glxvis->level<0) {
1320 /* underlay */
1321 *value = GLX_NONE_EXT;
1322 }
1323 return 0;
1324 case GLX_TRANSPARENT_INDEX_VALUE_EXT:
1325 {
1326 int pixel = transparent_pixel( glxvis );
1327 if (pixel>=0) {
1328 *value = pixel;
1329 }
1330 /* else undefined */
1331 }
1332 return 0;
1333 case GLX_TRANSPARENT_RED_VALUE_EXT:
1334 /* undefined */
1335 return 0;
1336 case GLX_TRANSPARENT_GREEN_VALUE_EXT:
1337 /* undefined */
1338 return 0;
1339 case GLX_TRANSPARENT_BLUE_VALUE_EXT:
1340 /* undefined */
1341 return 0;
1342 case GLX_TRANSPARENT_ALPHA_VALUE_EXT:
1343 /* undefined */
1344 return 0;
1345
1346 /*
1347 * Extensions
1348 */
1349 default:
1350 return GLX_BAD_ATTRIBUTE;
1351 }
1352 }
1353
1354
1355
1356 GLXContext Fake_glXGetCurrentContext( void )
1357 {
1358 return (GLXContext) XMesaGetCurrentContext();
1359 }
1360
1361
1362
1363 GLXDrawable Fake_glXGetCurrentDrawable( void )
1364 {
1365 XMesaBuffer b = XMesaGetCurrentBuffer();
1366 if (b) {
1367 return b->frontbuffer;
1368 }
1369 else {
1370 return 0;
1371 }
1372 }
1373
1374
1375 void Fake_glXWaitGL( void )
1376 {
1377 XMesaContext xmesa = XMesaGetCurrentContext();
1378 XMesaFlush( xmesa );
1379 }
1380
1381
1382
1383 void Fake_glXWaitX( void )
1384 {
1385 XMesaContext xmesa = XMesaGetCurrentContext();
1386 XMesaFlush( xmesa );
1387 }
1388
1389
1390
1391 #define EXTENSIONS "GLX_MESA_pixmap_colormap GLX_EXT_visual_info GLX_MESA_release_buffers GLX_MESA_copy_sub_buffer GLX_SGI_video_sync"
1392
1393
1394 /* GLX 1.1 and later */
1395 const char *Fake_glXQueryExtensionsString( Display *dpy, int screen )
1396 {
1397 static char *extensions = EXTENSIONS;
1398 (void) dpy;
1399 (void) screen;
1400 return extensions;
1401 }
1402
1403
1404
1405 /* GLX 1.1 and later */
1406 const char *Fake_glXQueryServerString( Display *dpy, int screen, int name )
1407 {
1408 static char *extensions = EXTENSIONS;
1409 static char *vendor = "Brian Paul";
1410 static char *version = "1.1 Mesa 3.0";
1411
1412 (void) dpy;
1413 (void) screen;
1414
1415 switch (name) {
1416 case GLX_EXTENSIONS:
1417 return extensions;
1418 case GLX_VENDOR:
1419 return vendor;
1420 case GLX_VERSION:
1421 return version;
1422 default:
1423 return NULL;
1424 }
1425 }
1426
1427
1428
1429 /* GLX 1.1 and later */
1430 const char *Fake_glXGetClientString( Display *dpy, int name )
1431 {
1432 static char *extensions = EXTENSIONS;
1433 static char *vendor = "Brian Paul";
1434 static char *version = "1.1 Mesa 3.0";
1435
1436 (void) dpy;
1437
1438 switch (name) {
1439 case GLX_EXTENSIONS:
1440 return extensions;
1441 case GLX_VENDOR:
1442 return vendor;
1443 case GLX_VERSION:
1444 return version;
1445 default:
1446 return NULL;
1447 }
1448 }
1449
1450
1451
1452 /*
1453 * Release the depth, stencil, accum buffers attached to a GLXDrawable
1454 * (a window or pixmap) prior to destroying the GLXDrawable.
1455 */
1456 Bool Fake_glXReleaseBuffersMESA( Display *dpy, GLXDrawable d )
1457 {
1458 XMesaBuffer b = XMesaFindBuffer(dpy, d);
1459 if (b) {
1460 XMesaDestroyBuffer(b);
1461 return True;
1462 }
1463 return False;
1464 }
1465
1466
1467 /* Silence compiler warnings */
1468 void Fake_glXDummyFunc( void )
1469 {
1470 (void) kernel8;
1471 (void) DitherValues;
1472 (void) HPCR_DRGB;
1473 (void) kernel1;
1474 }
1475
1476
1477 GLfunction Fake_glXGetProcAddress( const GLubyte *procName )
1478 {
1479 struct proc {
1480 const char *name;
1481 GLfunction address;
1482 };
1483 static struct proc procTable[] = {
1484 { "glXGetProcAddressEXT", (GLfunction) glXGetProcAddressEXT },
1485 { "glXCreateGLXPixmapMESA", (GLfunction) glXCreateGLXPixmapMESA },
1486 { "glXReleaseBuffersMESA", (GLfunction) glXReleaseBuffersMESA },
1487 { "glXCopySubBufferMESA", (GLfunction) glXCopySubBufferMESA },
1488 /* NOTE: GLX_SGI_video_sync not implemented in Mesa */
1489 { NULL, NULL } /* end of list token */
1490 };
1491 GLuint i;
1492
1493 /* First, look for core library functions */
1494 for (i = 0; procTable[i].address; i++) {
1495 if (strcmp((const char *) procName, procTable[i].name) == 0)
1496 return (GLfunction) procTable[i].address;
1497 }
1498
1499 return NULL;
1500 }