glxcmds.c 86 KB
Newer Older
1
/* $XFree86: xc/lib/GL/glx/glxcmds.c,v 1.19 2003/01/20 21:37:18 tsi Exp $ */
daryll's avatar
daryll committed
2
/*
nathanh's avatar
nathanh committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
** License Applicability. Except to the extent portions of this file are
** made subject to an alternative license as permitted in the SGI Free
** Software License B, Version 1.1 (the "License"), the contents of this
** file are subject only to the provisions of the License. You may not use
** this file except in compliance with the License. You may obtain a copy
** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
** 
** http://oss.sgi.com/projects/FreeB
** 
** Note that, as provided in the License, the Software is distributed on an
** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
** 
** Original Code. The Original Code is: OpenGL Sample Implementation,
** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
** Copyright in any portions created by third parties is as indicated
** elsewhere herein. All Rights Reserved.
** 
** Additional Notice Provisions: The application programming interfaces
** established by SGI in conjunction with the Original Code are The
** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
** Window System(R) (Version 1.3), released October 19, 1998. This software
** was created using the OpenGL(R) version 1.2.1 Sample Implementation
** published by SGI, but has not been independently verified as being
** compliant with the OpenGL(R) version 1.2.1 Specification.
daryll's avatar
daryll committed
34
35
36
**
*/

37
38
39
40
41
/**
 * \file glxcmds.c
 * Client-side GLX interface.
 */

keithw's avatar
keithw committed
42
#include <inttypes.h>
43
#include "glxclient.h"
daryll's avatar
daryll committed
44
45
#include <extutil.h>
#include <Xext.h>
brianp's avatar
brianp committed
46
#include <assert.h>
dawes's avatar
dawes committed
47
#include <string.h>
brianp's avatar
brianp committed
48
#include "glapi.h"
daryll's avatar
daryll committed
49
50
#ifdef GLX_DIRECT_RENDERING
#include "indirect_init.h"
idr's avatar
idr committed
51
#include <extensions/xf86vmode.h>
daryll's avatar
daryll committed
52
#endif
idr's avatar
idr committed
53
#include "glxextensions.h"
54
#include "glcontextmodes.h"
idr's avatar
idr committed
55
#include <sys/time.h>
daryll's avatar
daryll committed
56

idr's avatar
idr committed
57
58
59
60
#ifdef IN_DOXYGEN
#define GLX_PREFIX(x) x
#endif /* IN_DOXYGEN */

idr's avatar
idr committed
61
const char __glXGLClientExtensions[] = 
brianp's avatar
brianp committed
62
			"GL_ARB_depth_texture "
nathanh's avatar
nathanh committed
63
			"GL_ARB_imaging "
64
			"GL_ARB_multisample "
65
			"GL_ARB_multitexture "
brianp's avatar
brianp committed
66
			"GL_ARB_point_parameters "
67
			"GL_ARB_point_sprite "
brianp's avatar
brianp committed
68
69
			"GL_ARB_shadow "
			"GL_ARB_shadow_ambient "
70
71
72
73
			"GL_ARB_texture_border_clamp "
			"GL_ARB_texture_cube_map "
			"GL_ARB_texture_env_add "
			"GL_ARB_texture_env_combine "
brianp's avatar
brianp committed
74
			"GL_ARB_texture_env_crossbar "
75
			"GL_ARB_texture_env_dot3 "
brianp's avatar
brianp committed
76
			"GL_ARB_texture_mirrored_repeat "
77
			"GL_ARB_texture_non_power_of_two "
78
			"GL_ARB_transpose_matrix "
brianp's avatar
brianp committed
79
			"GL_ARB_window_pos "
nathanh's avatar
nathanh committed
80
			"GL_EXT_abgr "
idr's avatar
idr committed
81
82
83
84
85
86
			"GL_EXT_bgra "
 			"GL_EXT_blend_color "
			"GL_EXT_blend_func_separate "
			"GL_EXT_blend_logic_op "
 			"GL_EXT_blend_minmax "
 			"GL_EXT_blend_subtract "
87
			"GL_EXT_clip_volume_hint "
idr's avatar
idr committed
88
89
90
91
92
			"GL_EXT_copy_texture "
			"GL_EXT_draw_range_elements "
			"GL_EXT_fog_coord "
			"GL_EXT_multi_draw_arrays "
			"GL_EXT_packed_pixels "
93
			"GL_EXT_paletted_texture "
idr's avatar
idr committed
94
95
96
97
			"GL_EXT_polygon_offset "
			"GL_EXT_rescale_normal "
			"GL_EXT_secondary_color "
			"GL_EXT_separate_specular_color "
98
			"GL_EXT_shadow_funcs "
99
			"GL_EXT_shared_texture_palette "
idr's avatar
idr committed
100
101
102
103
104
 			"GL_EXT_stencil_two_side "
			"GL_EXT_stencil_wrap "
			"GL_EXT_subtexture "
			"GL_EXT_texture "
			"GL_EXT_texture3D "
105
			"GL_EXT_texture_edge_clamp "
idr's avatar
idr committed
106
107
108
 			"GL_EXT_texture_env_add "
 			"GL_EXT_texture_env_combine "
 			"GL_EXT_texture_env_dot3 "
109
110
			"GL_EXT_texture_filter_anisotropic "
 			"GL_EXT_texture_lod "
idr's avatar
idr committed
111
 			"GL_EXT_texture_lod_bias "
112
 			"GL_EXT_texture_mirror_clamp "
idr's avatar
idr committed
113
			"GL_EXT_texture_object "
114
			"GL_EXT_texture_rectangle "
idr's avatar
idr committed
115
			"GL_EXT_vertex_array "
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
 			"GL_APPLE_packed_pixels "
 			"GL_APPLE_ycbcr_422 "
 			"GL_ATI_texture_env_combine3 "
 			"GL_ATI_texture_float "
 			"GL_ATI_texture_mirror_once "
 			"GL_ATIX_texture_env_combine3 "
			"GL_HP_convolution_border_modes "
#if 0
    /* This is currently removed because there seem to be some problems with
     * it and the software-only indirect rendering path.  At this point, I'm
     * not sure which side (client or server) has the problem. - idr
     */
 			"GL_HP_occlusion_test "
#endif
			"GL_IBM_cull_vertex "
			"GL_IBM_pixel_filter_hint "
			"GL_IBM_rasterpos_clip "
			"GL_IBM_texture_clamp_nodraw "
idr's avatar
idr committed
134
			"GL_IBM_texture_mirrored_repeat "
135
			"GL_INGR_blend_func_separate "
136
			"GL_INGR_interlace_read "
137
138
 			"GL_MESA_pack_invert "
 			"GL_MESA_ycbcr_texture "
idr's avatar
idr committed
139
			"GL_NV_blend_square "
140
141
142
143
144
			"GL_NV_copy_depth_to_color "
			"GL_NV_depth_clamp "
			"GL_NV_fog_distance "
			"GL_NV_light_max_exponent "
			"GL_NV_multisample_filter_hint "
145
			"GL_NV_point_sprite "
146
			"GL_NV_texgen_reflection "
147
			"GL_NV_texture_env_combine4 "
148
149
			"GL_NV_texture_rectangle "
			"GL_SGIS_generate_mipmap "
idr's avatar
idr committed
150
151
152
			"GL_SGIS_multisample "
			"GL_SGIS_texture_border_clamp "
			"GL_SGIS_texture_edge_clamp "
153
154
155
156
157
158
159
160
161
162
			"GL_SGIS_texture_lod "
			"GL_SGIX_blend_alpha_minmax "
			"GL_SGIX_clipmap "
			"GL_SGIX_depth_texture "
			"GL_SGIX_fog_offset "
			"GL_SGIX_shadow "
			"GL_SGIX_shadow_ambient "
			"GL_SGIX_texture_coordinate_clamp "
			"GL_SGIX_texture_lod_bias "
			"GL_SGIX_texture_range "
163
			"GL_SGIX_texture_scale_bias "
164
165
166
167
			"GL_SGIX_vertex_preclip "
			"GL_SGIX_vertex_preclip_hint "
			"GL_SGIX_ycrcb "
			"GL_SUN_convolution_border_modes "
168
			"GL_SUN_multi_draw_arrays "
169
			"GL_SUN_slice_accum "
nathanh's avatar
nathanh committed
170
171
172
			;

static const char __glXGLXClientVendorName[] = "SGI";
idr's avatar
idr committed
173
static const char __glXGLXClientVersion[] = "1.4";
keithw's avatar
keithw committed
174

175

176
#ifdef GLX_DIRECT_RENDERING
177
#include "xf86dri.h"
idr's avatar
idr committed
178

179
180
static Bool __glXWindowExists(Display *dpy, GLXDrawable draw);

idr's avatar
idr committed
181
static void * DriverCreateContextWrapper( const __GLXscreenConfigs *psc,
182
    Display *dpy, XVisualInfo *vis, void *shared, __DRIcontext *ctx,
idr's avatar
idr committed
183
    const __GLcontextModes *fbconfig, int render_type );
184
185
186
187
188
189
190
191
192

static Bool dummyBindContext2( Display *dpy, int scrn,
    GLXDrawable draw, GLXDrawable read, GLXContext gc );

static Bool dummyUnbindContext2( Display *dpy, int scrn,
    GLXDrawable draw, GLXDrawable read, GLXContext gc );

/****************************************************************************/

193
194
195
196
197
198
/**
 * Used as glue when a driver does not support
 * \c __DRIcontextRec::bindContext2.
 * 
 * \sa DriverCreateContextWrapper, __DRIcontextRec::bindContext2
 */
199
200
201
202
203
204
205
206
static Bool dummyBindContext2( Display *dpy, int scrn,
			       GLXDrawable draw, GLXDrawable read,
			       GLXContext gc )
{
    assert( draw == read );
    return (*gc->driContext.bindContext)( dpy, scrn, draw, gc );
}

207
208
209
210
211
212
/**
 * Used as glue when a driver does not support
 * \c __DRIcontextRec::unbindContext2.
 * 
 * \sa DriverCreateContextWrapper, __DRIcontextRec::unbindContext2
 */
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
static Bool dummyUnbindContext2( Display *dpy, int scrn,
				 GLXDrawable draw, GLXDrawable read,
				 GLXContext gc )
{
    assert( draw == read );
    return (*gc->driContext.unbindContext)( dpy, scrn, draw, gc, GL_FALSE );
}


/****************************************************************************/
/**
 * Wrap the call to the driver's \c createContext function.
 *
 * The \c createContext function is wrapped because not all drivers support
 * the "new" \c unbindContext2 and \c bindContext2 interfaces.  libGL should
 * not have to check to see which functions the driver supports.  Instead,
 * if either function is not supported it is wrapped.  The wrappers test to
 * make sure that both drawables are the same and pass control to the old
 * interface.
232
233
234
 *
 * \sa dummyBindContext2, dummyUnbindContext2,
 *      __DRIcontextRec::bindContext2, __DRIcontextRec::unbindContext2
235
236
 */

idr's avatar
idr committed
237
static void * DriverCreateContextWrapper( const __GLXscreenConfigs *psc,
238
239
240
					  Display *dpy, XVisualInfo *vis,
					  void *shared,
					  __DRIcontext *ctx,
idr's avatar
idr committed
241
242
					  const __GLcontextModes *modes,
					  int render_type )
243
{
idr's avatar
idr committed
244
    void * ctx_priv = NULL;
245

idr's avatar
idr committed
246
247
248
249
250
251
    if ( psc->driScreen.createNewContext != NULL ) {
	assert( modes != NULL );
	ctx_priv = (*psc->driScreen.createNewContext)(dpy, modes, render_type,
						      shared, ctx);

	/* If the driver supports the createNewContext interface, then 
252
253
	 * it MUST also support either the bindContext2 / unbindContext2
	 * interface or the bindContext3 / unbindContext3 interface.
idr's avatar
idr committed
254
255
	 */

256
257
258
259
	assert( (ctx_priv == NULL) || (ctx->unbindContext2 != NULL)
		|| (ctx->unbindContext3 != NULL) );
	assert( (ctx_priv == NULL) || (ctx->bindContext2 != NULL)
		|| (ctx->bindContext3 != NULL) );
idr's avatar
idr committed
260
261
262
263
    }
    else {
	if ( vis != NULL ) {
	    ctx_priv = (*psc->driScreen.createContext)(dpy, vis, shared, ctx);
264

idr's avatar
idr committed
265
266
267
268
269
270
271
272
273
	    if ( ctx_priv != NULL ) {
		if ( ctx->unbindContext2 == NULL ) {
		    ctx->unbindContext2 = dummyUnbindContext2;
		}

		if ( ctx->bindContext2 == NULL ) {
		    ctx->bindContext2 = dummyBindContext2;
		}
	    }
274
275
	}
    }
idr's avatar
idr committed
276

277
278
    return ctx_priv;
}
279
#endif
280
281


282
283
/****************************************************************************/
/**
284
 * Get the __DRIdrawable for the drawable associated with a GLXContext
285
 * 
286
 * \param dpy       The display associated with \c drawable.
287
 * \param drawable  GLXDrawable whose __DRIdrawable part is to be retrieved.
288
 * \returns  A pointer to the context's __DRIdrawable on success, or NULL if
289
 *           the drawable is not associated with a direct-rendering context.
290
291
 */

292
#ifdef GLX_DIRECT_RENDERING
293
static __DRIdrawable *
294
GetDRIDrawable( Display *dpy, GLXDrawable drawable, int * const scrn_num )
295
{
296
297
298
299
300
    __GLXdisplayPrivate * const priv = __glXInitialize(dpy);

    if ( (priv != NULL) && (priv->driDisplay.private != NULL) ) {
	const unsigned  screen_count = ScreenCount(dpy);
	unsigned   i;
301

302
	for ( i = 0 ; i < screen_count ; i++ ) {
303
	    __DRIscreen * const psc = &priv->screenConfigs[i].driScreen;
304
305
	    __DRIdrawable * const pdraw = (psc->private != NULL)
	       ? (*psc->getDrawable)(dpy, drawable, psc->private) : NULL;
306

307
308
309
	    if ( pdraw != NULL ) {
		if ( scrn_num != NULL ) {
		    *scrn_num = i;
310
		}
311
		return pdraw;
312
313
314
	    }
	}
    }
315
316

    return NULL;
317
}
318
#endif
319
320


321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
/**
 * Get the GLX per-screen data structure associated with a GLX context.
 * 
 * \param dpy   Display for which the GLX per-screen information is to be
 *              retrieved.
 * \param scrn  Screen on \c dpy for which the GLX per-screen information is
 *              to be retrieved.
 * \returns A pointer to the GLX per-screen data if \c dpy and \c scrn
 *          specify a valid GLX screen, or NULL otherwise.
 * 
 * \todo Should this function validate that \c scrn is within the screen
 *       number range for \c dpy?
 */

static __GLXscreenConfigs *
GetGLXScreenConfigs(Display *dpy, int scrn)
{
    __GLXdisplayPrivate * const priv = __glXInitialize(dpy);

    return (priv->screenConfigs != NULL) ? &priv->screenConfigs[scrn] : NULL;
}


static int
GetGLXPrivScreenConfig( Display *dpy, int scrn, __GLXdisplayPrivate ** ppriv,
			__GLXscreenConfigs ** ppsc )
{
    /* Initialize the extension, if needed .  This has the added value
     * of initializing/allocating the display private 
     */
    
    if ( dpy == NULL ) {
	return GLX_NO_EXTENSION;
    }

    *ppriv = __glXInitialize(dpy);
    if ( *ppriv == NULL ) {
	return GLX_NO_EXTENSION;
    }

    /* Check screen number to see if its valid */
    if ((scrn < 0) || (scrn >= ScreenCount(dpy))) {
	return GLX_BAD_SCREEN;
    }

    /* Check to see if the GL is supported on this screen */
    *ppsc = &((*ppriv)->screenConfigs[scrn]);
368
    if ( (*ppsc)->configs == NULL ) {
369
370
371
372
373
374
375
	/* No support for GL on this screen regardless of visual */
	return GLX_BAD_VISUAL;
    }

    return Success;
}

376

377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
/**
 * Determine if a \c GLXFBConfig supplied by the application is valid.
 *
 * \param dpy     Application supplied \c Display pointer.
 * \param config  Application supplied \c GLXFBConfig.
 *
 * \returns If the \c GLXFBConfig is valid, the a pointer to the matching
 *          \c __GLcontextModes structure is returned.  Otherwise, \c NULL
 *          is returned.
 */
static __GLcontextModes *
ValidateGLXFBConfig( Display * dpy, GLXFBConfig config )
{
    __GLXdisplayPrivate * const priv = __glXInitialize(dpy);
    const unsigned num_screens = ScreenCount(dpy);
    unsigned   i;
    const __GLcontextModes * modes;


    if ( priv != NULL ) {
	for ( i = 0 ; i < num_screens ; i++ ) {
	    for ( modes = priv->screenConfigs[i].configs
		  ; modes != NULL
		  ; modes = modes->next ) {
		if ( modes == (__GLcontextModes *) config ) {
		    return (__GLcontextModes *) config;
		}
	    }
	}
    }

    return NULL;
}


412
413
414
415
416
417
418
419
420
421
/**
 * \todo It should be possible to move the allocate of \c client_state_private
 * later in the function for direct-rendering contexts.  Direct-rendering
 * contexts don't need to track client state, so they don't need that memory
 * at all.
 * 
 * \todo Eliminate \c __glXInitVertexArrayState.  Replace it with a new
 * function called \c __glXAllocateClientState that allocates the memory and
 * does all the initialization (including the pixel pack / unpack).
 */
daryll's avatar
daryll committed
422
static
idr's avatar
idr committed
423
GLXContext AllocateGLXContext( Display *dpy )
daryll's avatar
daryll committed
424
{
idr's avatar
idr committed
425
     GLXContext gc;
426
     int bufSize;
idr's avatar
idr committed
427
     CARD8 opcode;
428
    __GLXattribute *state;
429

idr's avatar
idr committed
430
431
    if (!dpy)
        return NULL;
432

daryll's avatar
daryll committed
433
434
435
436
437
438
439
440
441
442
443
444
445
    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return NULL;
    }

    /* Allocate our context record */
    gc = (GLXContext) Xmalloc(sizeof(struct __GLXcontextRec));
    if (!gc) {
	/* Out of memory */
	return NULL;
    }
    memset(gc, 0, sizeof(struct __GLXcontextRec));

446
447
448
449
450
451
452
453
    state = Xmalloc(sizeof(struct __GLXattributeRec));
    if (state == NULL) {
	/* Out of memory */
	Xfree(gc);
	return NULL;
    }
    gc->client_state_private = state;
    memset(gc->client_state_private, 0, sizeof(struct __GLXattributeRec));
454
    state->NoDrawArraysProtocol = (getenv("LIBGL_NO_DRAWARRAYS") != NULL);
455

456
457
458
459
460
461
462
463
    /*
    ** Create a temporary buffer to hold GLX rendering commands.  The size
    ** of the buffer is selected so that the maximum number of GLX rendering
    ** commands can fit in a single X packet and still have room in the X
    ** packet for the GLXRenderReq header.
    */

    bufSize = (XMaxRequestSize(dpy) * 4) - sz_xGLXRenderReq;
daryll's avatar
daryll committed
464
465
    gc->buf = (GLubyte *) Xmalloc(bufSize);
    if (!gc->buf) {
466
	Xfree(gc->client_state_private);
daryll's avatar
daryll committed
467
468
469
470
471
472
473
474
	Xfree(gc);
	return NULL;
    }
    gc->bufSize = bufSize;

    /* Fill in the new context */
    gc->renderMode = GL_RENDER;

475
476
    state->storePack.alignment = 4;
    state->storeUnpack.alignment = 4;
daryll's avatar
daryll committed
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515

    __glXInitVertexArrayState(gc);

    gc->attributes.stackPointer = &gc->attributes.stack[0];

    /*
    ** PERFORMANCE NOTE: A mode dependent fill image can speed things up.
    ** Other code uses the fastImageUnpack bit, but it is never set
    ** to GL_TRUE.
    */
    gc->fastImageUnpack = GL_FALSE;
    gc->fillImage = __glFillImage;
    gc->isDirect = GL_FALSE;
    gc->pc = gc->buf;
    gc->bufEnd = gc->buf + bufSize;
    if (__glXDebug) {
	/*
	** Set limit register so that there will be one command per packet
	*/
	gc->limit = gc->buf;
    } else {
	gc->limit = gc->buf + bufSize - __GLX_BUFFER_LIMIT_SIZE;
    }
    gc->createDpy = dpy;
    gc->majorOpcode = opcode;

    /*
    ** Constrain the maximum drawing command size allowed to be
    ** transfered using the X_GLXRender protocol request.  First
    ** constrain by a software limit, then constrain by the protocl
    ** limit.
    */
    if (bufSize > __GLX_RENDER_CMD_SIZE_LIMIT) {
        bufSize = __GLX_RENDER_CMD_SIZE_LIMIT;
    }
    if (bufSize > __GLX_MAX_RENDER_CMD_SIZE) {
        bufSize = __GLX_MAX_RENDER_CMD_SIZE;
    }
    gc->maxSmallRenderCommandSize = bufSize;
idr's avatar
idr committed
516
517
518
    return gc;
}

519
520
521
522
523
524
525
526
527
528

/**
 * Create a new context.  Exactly one of \c vis and \c fbconfig should be
 * non-NULL.
 * 
 * \param use_glx_1_3  For FBConfigs, should GLX 1.3 protocol or
 *                     SGIX_fbconfig protocol be used?
 * \param renderType   For FBConfigs, what is the rendering type?
 */

idr's avatar
idr committed
529
530
531
532
533
534
static GLXContext
CreateContext(Display *dpy, XVisualInfo *vis,
	      const __GLcontextModes * const fbconfig,
	      GLXContext shareList,
	      Bool allowDirect, GLXContextID contextID,
	      Bool use_glx_1_3, int renderType)
idr's avatar
idr committed
535
536
{
    GLXContext gc;
daryll's avatar
daryll committed
537

538
    if ( dpy == NULL )
idr's avatar
idr committed
539
540
541
542
543
       return NULL;

    gc = AllocateGLXContext(dpy);
    if (!gc)
	return NULL;
daryll's avatar
daryll committed
544
545

    if (None == contextID) {
546
547
	if ( (vis == NULL) && (fbconfig == NULL) )
	    return NULL;
idr's avatar
idr committed
548
549

#ifdef GLX_DIRECT_RENDERING
550
551
552
	if (allowDirect) {
	    int screen = (fbconfig == NULL) ? vis->screen : fbconfig->screen;
	    __GLXscreenConfigs * const psc = GetGLXScreenConfigs(dpy, screen);
idr's avatar
idr committed
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
	    const __GLcontextModes * mode;

	    /* The value of fbconfig cannot change because it is tested
	     * later in the function.
	     */
	    if ( fbconfig == NULL ) {
		/* FIXME: Is it possible for the __GLcontextModes structure
		 * FIXME: to not be found?
		 */
		mode = _gl_context_modes_find_visual( psc->configs,
						      vis->visualid );
		assert( mode != NULL );
		assert( mode->screen == screen );
	    }
	    else {
		mode = fbconfig;
	    }
570

daryll's avatar
daryll committed
571
	    if (psc && psc->driScreen.private) {
572
573
		void * const shared = (shareList != NULL)
		    ? shareList->driContext.private : NULL;
daryll's avatar
daryll committed
574
		gc->driContext.private =
575
		    DriverCreateContextWrapper( psc, dpy, vis, shared,
idr's avatar
idr committed
576
577
						&gc->driContext, mode,
						renderType );
daryll's avatar
daryll committed
578
579
		if (gc->driContext.private) {
		    gc->isDirect = GL_TRUE;
idr's avatar
idr committed
580
581
582
		    gc->screen = mode->screen;
		    gc->vid = mode->visualID;
		    gc->fbconfigID = mode->fbconfigID;
583
		    gc->driContext.mode = mode;
daryll's avatar
daryll committed
584
585
586
587
588
589
		}
	    }
	}
#endif

	LockDisplay(dpy);
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
	if ( fbconfig == NULL ) {
	    xGLXCreateContextReq *req;

	    /* Send the glXCreateContext request */
	    GetReq(GLXCreateContext,req);
	    req->reqType = gc->majorOpcode;
	    req->glxCode = X_GLXCreateContext;
	    req->context = gc->xid = XAllocID(dpy);
	    req->visual = vis->visualid;
	    req->screen = vis->screen;
	    req->shareList = shareList ? shareList->xid : None;
	    req->isDirect = gc->isDirect;
	}
	else if ( use_glx_1_3 ) {
	    xGLXCreateNewContextReq *req;

	    /* Send the glXCreateNewContext request */
	    GetReq(GLXCreateNewContext,req);
	    req->reqType = gc->majorOpcode;
	    req->glxCode = X_GLXCreateNewContext;
	    req->context = gc->xid = XAllocID(dpy);
	    req->fbconfig = fbconfig->fbconfigID;
	    req->screen = fbconfig->screen;
	    req->renderType = renderType;
	    req->shareList = shareList ? shareList->xid : None;
	    req->isDirect = gc->isDirect;
	}
	else {
idr's avatar
idr committed
618
	    xGLXVendorPrivateWithReplyReq *vpreq;
619
620
621
	    xGLXCreateContextWithConfigSGIXReq *req;

	    /* Send the glXCreateNewContext request */
idr's avatar
idr committed
622
623
	    GetReqExtra(GLXVendorPrivateWithReply,
			sz_xGLXCreateContextWithConfigSGIXReq-sz_xGLXVendorPrivateWithReplyReq,vpreq);
624
625
	    req = (xGLXCreateContextWithConfigSGIXReq *)vpreq;
	    req->reqType = gc->majorOpcode;
idr's avatar
idr committed
626
	    req->glxCode = X_GLXVendorPrivateWithReply;
627
628
629
630
631
632
633
634
635
	    req->vendorCode = X_GLXvop_CreateContextWithConfigSGIX;
	    req->context = gc->xid = XAllocID(dpy);
	    req->fbconfig = fbconfig->fbconfigID;
	    req->screen = fbconfig->screen;
	    req->renderType = renderType;
	    req->shareList = shareList ? shareList->xid : None;
	    req->isDirect = gc->isDirect;
	}

daryll's avatar
daryll committed
636
637
638
639
640
641
642
643
644
645
646
647
	UnlockDisplay(dpy);
	SyncHandle();
	gc->imported = GL_FALSE;
    }
    else {
	gc->xid = contextID;
	gc->imported = GL_TRUE;
    }

    return gc;
}

648

649
GLXContext GLX_PREFIX(glXCreateContext)(Display *dpy, XVisualInfo *vis,
daryll's avatar
daryll committed
650
651
			    GLXContext shareList, Bool allowDirect)
{
652
653
   return CreateContext(dpy, vis, NULL, shareList, allowDirect, None,
			False, 0);
daryll's avatar
daryll committed
654
655
656
657
658
659
660
661
662
663
}

void __glXFreeContext(__GLXcontext *gc)
{
    if (gc->vendor) XFree((char *) gc->vendor);
    if (gc->renderer) XFree((char *) gc->renderer);
    if (gc->version) XFree((char *) gc->version);
    if (gc->extensions) XFree((char *) gc->extensions);
    __glFreeAttributeState(gc);
    XFree((char *) gc->buf);
664
    Xfree((char *) gc->client_state_private);
daryll's avatar
daryll committed
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
    XFree((char *) gc);
    
}

/*
** Destroy the named context
*/
static void 
DestroyContext(Display *dpy, GLXContext gc)
{
    xGLXDestroyContextReq *req;
    GLXContextID xid;
    CARD8 opcode;
    GLboolean imported;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode || !gc) {
	return;
    }

    __glXLock();
    xid = gc->xid;
    imported = gc->imported;
    gc->xid = None;
689
690
691
692
693
694
695
696
697
698
699
700

#ifdef GLX_DIRECT_RENDERING
    /* Destroy the direct rendering context */
    if (gc->isDirect) {
	if (gc->driContext.private) {
	    (*gc->driContext.destroyContext)(dpy, gc->screen,
					     gc->driContext.private);
	    gc->driContext.private = NULL;
	}
    }
#endif

daryll's avatar
daryll committed
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
    if (gc->currentDpy) {
	/* Have to free later cuz it's in use now */
	__glXUnlock();
    } else {
	/* Destroy the handle if not current to anybody */
	__glXUnlock();
	__glXFreeContext(gc);
    }

    if (!imported) {
	/* 
	** This dpy also created the server side part of the context.
	** Send the glXDestroyContext request.
	*/
	LockDisplay(dpy);
	GetReq(GLXDestroyContext,req);
	req->reqType = opcode;
	req->glxCode = X_GLXDestroyContext;
	req->context = xid;
	UnlockDisplay(dpy);
	SyncHandle();
    }
}
724
void GLX_PREFIX(glXDestroyContext)(Display *dpy, GLXContext gc)
daryll's avatar
daryll committed
725
726
727
728
729
730
731
{
    DestroyContext(dpy, gc);
}

/*
** Return the major and minor version #s for the GLX extension
*/
732
Bool GLX_PREFIX(glXQueryVersion)(Display *dpy, int *major, int *minor)
daryll's avatar
daryll committed
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
{
    __GLXdisplayPrivate *priv;

    /* Init the extension.  This fetches the major and minor version. */
    priv = __glXInitialize(dpy);
    if (!priv) return GL_FALSE;

    if (major) *major = priv->majorVersion;
    if (minor) *minor = priv->minorVersion;
    return GL_TRUE;
}

/*
** Query the existance of the GLX extension
*/
748
Bool GLX_PREFIX(glXQueryExtension)(Display *dpy, int *errorBase, int *eventBase)
daryll's avatar
daryll committed
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
{
    int major_op, erb, evb;
    Bool rv;

    rv = XQueryExtension(dpy, GLX_EXTENSION_NAME, &major_op, &evb, &erb);
    if (rv) {
	if (errorBase) *errorBase = erb;
	if (eventBase) *eventBase = evb;
    }
    return rv;
}

/*
** Put a barrier in the token stream that forces the GL to finish its
** work before X can proceed.
*/
765
void GLX_PREFIX(glXWaitGL)(void)
daryll's avatar
daryll committed
766
767
768
769
770
771
772
773
774
775
776
777
{
    xGLXWaitGLReq *req;
    GLXContext gc = __glXGetCurrentContext();
    Display *dpy = gc->currentDpy;

    if (!dpy) return;

    /* Flush any pending commands out */
    __glXFlushRenderBuffer(gc, gc->pc);

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
778
779
780
781
/* This bit of ugliness unwraps the glFinish function */
#ifdef glFinish
#undef glFinish
#endif
daryll's avatar
daryll committed
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
	glFinish();
	return;
    }
#endif

    /* Send the glXWaitGL request */
    LockDisplay(dpy);
    GetReq(GLXWaitGL,req);
    req->reqType = gc->majorOpcode;
    req->glxCode = X_GLXWaitGL;
    req->contextTag = gc->currentContextTag;
    UnlockDisplay(dpy);
    SyncHandle();
}

/*
** Put a barrier in the token stream that forces X to finish its
** work before GL can proceed.
*/
801
void GLX_PREFIX(glXWaitX)(void)
daryll's avatar
daryll committed
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
{
    xGLXWaitXReq *req;
    GLXContext gc = __glXGetCurrentContext();
    Display *dpy = gc->currentDpy;

    if (!dpy) return;

    /* Flush any pending commands out */
    __glXFlushRenderBuffer(gc, gc->pc);

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
	XSync(dpy, False);
	return;
    }
#endif

    /*
    ** Send the glXWaitX request.
    */
    LockDisplay(dpy);
    GetReq(GLXWaitX,req);
    req->reqType = gc->majorOpcode;
    req->glxCode = X_GLXWaitX;
    req->contextTag = gc->currentContextTag;
    UnlockDisplay(dpy);
    SyncHandle();
}

831
void GLX_PREFIX(glXUseXFont)(Font font, int first, int count, int listBase)
daryll's avatar
daryll committed
832
833
834
835
836
837
838
839
840
841
842
843
{
    xGLXUseXFontReq *req;
    GLXContext gc = __glXGetCurrentContext();
    Display *dpy = gc->currentDpy;

    if (!dpy) return;

    /* Flush any pending commands out */
    (void) __glXFlushRenderBuffer(gc, gc->pc);

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
daryll's avatar
 
daryll committed
844
845
      DRI_glXUseXFont(font, first, count, listBase);
      return;
daryll's avatar
daryll committed
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
    }
#endif

    /* Send the glXUseFont request */
    LockDisplay(dpy);
    GetReq(GLXUseXFont,req);
    req->reqType = gc->majorOpcode;
    req->glxCode = X_GLXUseXFont;
    req->contextTag = gc->currentContextTag;
    req->font = font;
    req->first = first;
    req->count = count;
    req->listBase = listBase;
    UnlockDisplay(dpy);
    SyncHandle();
}

/************************************************************************/

/*
** Copy the source context to the destination context using the
** attribute "mask".
*/
869
void GLX_PREFIX(glXCopyContext)(Display *dpy, GLXContext source, GLXContext dest,
brianp's avatar
brianp committed
870
		    unsigned long mask)
daryll's avatar
daryll committed
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
{
    xGLXCopyContextReq *req;
    GLXContext gc = __glXGetCurrentContext();
    GLXContextTag tag;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return;
    }

#ifdef GLX_DIRECT_RENDERING
    if (gc->isDirect) {
	/* NOT_DONE: This does not work yet */
    }
#endif

    /*
    ** If the source is the current context, send its tag so that the context
    ** can be flushed before the copy.
    */
    if (source == gc && dpy == gc->currentDpy) {
	tag = gc->currentContextTag;
    } else {
	tag = 0;
    }

    /* Send the glXCopyContext request */
    LockDisplay(dpy);
    GetReq(GLXCopyContext,req);
    req->reqType = opcode;
    req->glxCode = X_GLXCopyContext;
    req->source = source ? source->xid : None;
    req->dest = dest ? dest->xid : None;
    req->mask = mask;
    req->contextTag = tag;
    UnlockDisplay(dpy);
    SyncHandle();
}


912
913
914
915
916
917
918
919
/**
 * Determine if a context uses direct rendering.
 *
 * \param dpy        Display where the context was created.
 * \param contextID  ID of the context to be tested.
 *
 * \returns \c GL_TRUE if the context is direct rendering or not.
 */
daryll's avatar
daryll committed
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
static Bool __glXIsDirect(Display *dpy, GLXContextID contextID)
{
    xGLXIsDirectReq *req;
    xGLXIsDirectReply reply;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return GL_FALSE;
    }

    /* Send the glXIsDirect request */
    LockDisplay(dpy);
    GetReq(GLXIsDirect,req);
    req->reqType = opcode;
    req->glxCode = X_GLXIsDirect;
    req->context = contextID;
    _XReply(dpy, (xReply*) &reply, 0, False);
    UnlockDisplay(dpy);
    SyncHandle();

    return reply.isDirect;
}

944
Bool GLX_PREFIX(glXIsDirect)(Display *dpy, GLXContext gc)
daryll's avatar
daryll committed
945
946
947
948
949
950
951
952
953
954
955
{
    if (!gc) {
	return GL_FALSE;
#ifdef GLX_DIRECT_RENDERING
    } else if (gc->isDirect) {
	return GL_TRUE;
#endif
    }
    return __glXIsDirect(dpy, gc->xid);
}

956
GLXPixmap GLX_PREFIX(glXCreateGLXPixmap)(Display *dpy, XVisualInfo *vis, Pixmap pixmap)
daryll's avatar
daryll committed
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
{
    xGLXCreateGLXPixmapReq *req;
    GLXPixmap xid;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return None;
    }

    /* Send the glXCreateGLXPixmap request */
    LockDisplay(dpy);
    GetReq(GLXCreateGLXPixmap,req);
    req->reqType = opcode;
    req->glxCode = X_GLXCreateGLXPixmap;
    req->screen = vis->screen;
    req->visual = vis->visualid;
    req->pixmap = pixmap;
    req->glxpixmap = xid = XAllocID(dpy);
    UnlockDisplay(dpy);
    SyncHandle();
    return xid;
}

/*
** Destroy the named pixmap
*/
984
void GLX_PREFIX(glXDestroyGLXPixmap)(Display *dpy, GLXPixmap glxpixmap)
daryll's avatar
daryll committed
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
{
    xGLXDestroyGLXPixmapReq *req;
    CARD8 opcode;

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return;
    }
    
    /* Send the glXDestroyGLXPixmap request */
    LockDisplay(dpy);
    GetReq(GLXDestroyGLXPixmap,req);
    req->reqType = opcode;
    req->glxCode = X_GLXDestroyGLXPixmap;
    req->glxpixmap = glxpixmap;
    UnlockDisplay(dpy);
    SyncHandle();
}

1004
void GLX_PREFIX(glXSwapBuffers)(Display *dpy, GLXDrawable drawable)
daryll's avatar
daryll committed
1005
1006
{
    xGLXSwapBuffersReq *req;
1007
    GLXContext gc;
daryll's avatar
daryll committed
1008
1009
1010
    GLXContextTag tag;
    CARD8 opcode;
#ifdef GLX_DIRECT_RENDERING
1011
    __DRIdrawable *pdraw = GetDRIDrawable( dpy, drawable, NULL );
daryll's avatar
daryll committed
1012

1013
1014
1015
    if ( pdraw != NULL ) {
	(*pdraw->swapBuffers)(dpy, pdraw->private);
	return;
daryll's avatar
daryll committed
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
    }
#endif

    opcode = __glXSetupForCommand(dpy);
    if (!opcode) {
	return;
    }

    /*
    ** The calling thread may or may not have a current context.  If it
    ** does, send the context tag so the server can do a flush.
    */
1028
1029
    gc = __glXGetCurrentContext();
    if ((gc != NULL) && (dpy == gc->currentDpy) && 
1030
 	((drawable == gc->currentDrawable) || (drawable == gc->currentReadable)) ) {
daryll's avatar
daryll committed
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
	tag = gc->currentContextTag;
    } else {
	tag = 0;
    }

    /* Send the glXSwapBuffers request */
    LockDisplay(dpy);
    GetReq(GLXSwapBuffers,req);
    req->reqType = opcode;
    req->glxCode = X_GLXSwapBuffers;
    req->drawable = drawable;
    req->contextTag = tag;
    UnlockDisplay(dpy);
    SyncHandle();
    XFlush(dpy);
}

idr's avatar
idr committed
1048

daryll's avatar
daryll committed
1049
1050
1051
1052
/*
** Return configuration information for the given display, screen and
** visual combination.
*/
1053
int GLX_PREFIX(glXGetConfig)(Display *dpy, XVisualInfo *vis, int attribute,
daryll's avatar
daryll committed
1054
1055
1056
		 int *value_return)
{
    __GLXdisplayPrivate *priv;
1057
1058
    __GLXscreenConfigs *psc;
    int   status;
daryll's avatar
daryll committed
1059

1060
1061
    status = GetGLXPrivScreenConfig( dpy, vis->screen, & priv, & psc );
    if ( status == Success ) {
idr's avatar
idr committed
1062
1063
	const __GLcontextModes * const modes = _gl_context_modes_find_visual(
					     psc->configs, vis->visualid );
daryll's avatar
daryll committed
1064

1065
	/* Lookup attribute after first finding a match on the visual */
idr's avatar
idr committed
1066
1067
	if ( modes != NULL ) {
	    return _gl_get_context_mode_data( modes, attribute, value_return );
daryll's avatar
daryll committed
1068
	}
1069
1070
	
	status = GLX_BAD_VISUAL;
daryll's avatar
daryll committed
1071
1072
1073
1074
1075
1076
    }

    /*
    ** If we can't find the config for this visual, this visual is not
    ** supported by the OpenGL implementation on the server.
    */
1077
    if ( (status == GLX_BAD_VISUAL) && (attribute == GLX_USE_GL) ) {
daryll's avatar
daryll committed
1078
	*value_return = GL_FALSE;
1079
	status = Success;
daryll's avatar
daryll committed
1080
    }
1081
1082

    return status;
daryll's avatar
daryll committed
1083
1084
1085
1086
}

/************************************************************************/

idr's avatar
idr committed
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
static void
init_fbconfig_for_chooser( __GLcontextModes * config,
			   GLboolean fbconfig_style_tags )
{
    memset( config, 0, sizeof( __GLcontextModes ) );
    config->visualID = (XID) GLX_DONT_CARE;
    config->visualType = GLX_DONT_CARE;

    /* glXChooseFBConfig specifies different defaults for these two than
     * glXChooseVisual.
     */
    if ( fbconfig_style_tags ) {
	config->rgbMode = GL_TRUE;
	config->doubleBufferMode = GLX_DONT_CARE;
    }

    config->visualRating = GLX_DONT_CARE;
    config->transparentPixel = GLX_NONE;
    config->transparentRed = GLX_DONT_CARE;
    config->transparentGreen = GLX_DONT_CARE;
    config->transparentBlue = GLX_DONT_CARE;
    config->transparentAlpha = GLX_DONT_CARE;
    config->transparentIndex = GLX_DONT_CARE;

    config->drawableType = GLX_WINDOW_BIT;
    config->renderType = (config->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
    config->xRenderable = GLX_DONT_CARE;
    config->fbconfigID = (GLXFBConfigID)(GLX_DONT_CARE);

    config->swapMethod = GLX_DONT_CARE;
}

idr's avatar
idr committed
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
#define MATCH_DONT_CARE( param ) \
	do { \
	    if ( (a-> param != GLX_DONT_CARE) \
		 && (a-> param != b-> param) ) { \
		return False; \
	    } \
	} while ( 0 )

#define MATCH_MINIMUM( param ) \
	do { \
1129
1130
	    if ( (a-> param != GLX_DONT_CARE) \
		 && (a-> param > b-> param) ) { \
idr's avatar
idr committed
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
		return False; \
	    } \
	} while ( 0 )

#define MATCH_EXACT( param ) \
	do { \
	    if ( a-> param != b-> param) { \
		return False; \
	    } \
	} while ( 0 )

/**
 * Determine if two GLXFBConfigs are compatible.
 *
 * \param a  Application specified config to test.
 * \param b  Server specified config to test against \c a.
 */
static Bool
1149
1150
fbconfigs_compatible( const __GLcontextModes * const a,
		      const __GLcontextModes * const b )
idr's avatar
idr committed
1151
{
1152
1153
    MATCH_DONT_CARE( doubleBufferMode );
    MATCH_DONT_CARE( visualType );
idr's avatar
idr committed
1154
1155
1156
1157
1158
    MATCH_DONT_CARE( visualRating );
    MATCH_DONT_CARE( xRenderable );
    MATCH_DONT_CARE( fbconfigID );
    MATCH_DONT_CARE( swapMethod );

1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
    MATCH_MINIMUM( rgbBits );
    MATCH_MINIMUM( numAuxBuffers );
    MATCH_MINIMUM( redBits );
    MATCH_MINIMUM( greenBits );
    MATCH_MINIMUM( blueBits );
    MATCH_MINIMUM( alphaBits );
    MATCH_MINIMUM( depthBits );
    MATCH_MINIMUM( stencilBits );
    MATCH_MINIMUM( accumRedBits );
    MATCH_MINIMUM( accumGreenBits );
    MATCH_MINIMUM( accumBlueBits );
    MATCH_MINIMUM( accumAlphaBits );
idr's avatar
idr committed
1171
1172
1173
1174
1175
1176
    MATCH_MINIMUM( sampleBuffers );
    MATCH_MINIMUM( maxPbufferWidth );
    MATCH_MINIMUM( maxPbufferHeight );
    MATCH_MINIMUM( maxPbufferPixels );
    MATCH_MINIMUM( samples );

1177
    MATCH_DONT_CARE( stereoMode );
idr's avatar
idr committed
1178
1179
1180
1181
1182
1183
    MATCH_EXACT( level );

    if ( ((a->drawableType & b->drawableType) == 0)
	 || ((a->renderType & b->renderType) == 0) ) {
	return False;
    }
daryll's avatar
daryll committed
1184
1185


1186
1187
1188
1189
1190
1191
1192
1193
    /* There is a bug in a few of the XFree86 DDX drivers.  They contain
     * visuals with a "transparent type" of 0 when they really mean GLX_NONE.
     * Technically speaking, it is a bug in the DDX driver, but there is
     * enough of an installed base to work around the problem here.  In any
     * case, 0 is not a valid value of the transparent type, so we'll treat 0 
     * from the app as GLX_DONT_CARE. We'll consider GLX_NONE from the app and
     * 0 from the server to be a match to maintain backward compatibility with
     * the (broken) drivers.
idr's avatar
idr committed
1194
     */
daryll's avatar
daryll committed
1195

1196
1197
1198
1199
1200
1201
1202
1203
    if ( a->transparentPixel != GLX_DONT_CARE
         && a->transparentPixel != 0 ) {
        if ( a->transparentPixel == GLX_NONE ) {
            if ( b->transparentPixel != GLX_NONE && b->transparentPixel != 0 )
                return False;
        } else {
            MATCH_EXACT( transparentPixel );
        }
daryll's avatar
daryll committed
1204

idr's avatar
idr committed
1205
1206
1207
1208
1209
1210
1211
	switch ( a->transparentPixel ) {
	  case GLX_TRANSPARENT_RGB:
	    MATCH_DONT_CARE( transparentRed );
	    MATCH_DONT_CARE( transparentGreen );
	    MATCH_DONT_CARE( transparentBlue );
	    MATCH_DONT_CARE( transparentAlpha );
	    break;
daryll's avatar
daryll committed
1212

idr's avatar
idr committed
1213
1214
1215
	  case GLX_TRANSPARENT_INDEX:
	    MATCH_DONT_CARE( transparentIndex );
	    break;
1216
1217

	  default:
idr's avatar
idr committed
1218
1219
1220
1221
1222
1223
1224
1225
	    break;
	}
    }

    return True;
}


idr's avatar
idr committed
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
/* There's some trickly language in the GLX spec about how this is supposed
 * to work.  Basically, if a given component size is either not specified
 * or the requested size is zero, it is supposed to act like PERFER_SMALLER.
 * Well, that's really hard to do with the code as-is.  This behavior is
 * closer to correct, but still not technically right.
 */
#define PREFER_LARGER_OR_ZERO(comp) \
    do { \
	if ( ((*a)-> comp) != ((*b)-> comp) ) { \
	    if ( ((*a)-> comp) == 0 ) { \
		return -1; \
	    } \
	    else if ( ((*b)-> comp) == 0 ) { \
		return 1; \
	    } \
	    else { \
		return ((*b)-> comp) - ((*a)-> comp) ; \
	    } \
	} \
    } while( 0 )

idr's avatar
idr committed
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
#define PREFER_LARGER(comp) \
    do { \
	if ( ((*a)-> comp) != ((*b)-> comp) ) { \
	    return ((*b)-> comp) - ((*a)-> comp) ; \
	} \
    } while( 0 )

#define PREFER_SMALLER(comp) \
    do { \
	if ( ((*a)-> comp) != ((*b)-> comp) ) { \
	    return ((*a)-> comp) - ((*b)-> comp) ; \
	} \
    } while( 0 )

/**
 * Compare two GLXFBConfigs.  This function is intended to be used as the
 * compare function passed in to qsort.
 * 
 * \returns If \c a is a "better" config, according to the specification of
 *          SGIX_fbconfig, a number less than zero is returned.  If \c b is
 *          better, then a number greater than zero is return.  If both are
 *          equal, zero is returned.
 * \sa qsort, glXChooseVisual, glXChooseFBConfig, glXChooseFBConfigSGIX
 */
static int
1272
1273
fbconfig_compare( const __GLcontextModes * const * const a,
		  const __GLcontextModes * const * const b )
daryll's avatar
daryll committed
1274
{
idr's avatar
idr committed
1275
    /* The order of these comparisons must NOT change.  It is defined by
idr's avatar
idr committed
1276
     * the GLX 1.3 spec and ARB_multisample.
idr's avatar
idr committed
1277
1278
1279
     */

    PREFER_SMALLER( visualSelectGroup );
1280
1281
1282
1283
1284
1285
1286

    /* The sort order for the visualRating is GLX_NONE, GLX_SLOW, and
     * GLX_NON_CONFORMANT_CONFIG.  It just so happens that this is the
     * numerical sort order of the enums (0x8000, 0x8001, and 0x800D).
     */
    PREFER_SMALLER( visualRating );

idr's avatar
idr committed
1287
1288
1289
1290
1291
1292
1293
1294
    /* This isn't quite right.  It is supposed to compare the sum of the
     * components the user specifically set minimums for.
     */
    PREFER_LARGER_OR_ZERO( redBits );
    PREFER_LARGER_OR_ZERO( greenBits );
    PREFER_LARGER_OR_ZERO( blueBits );
    PREFER_LARGER_OR_ZERO( alphaBits );

1295
    PREFER_SMALLER( rgbBits );
idr's avatar
idr committed
1296

1297
    if ( ((*a)->doubleBufferMode != (*b)->doubleBufferMode) ) {
idr's avatar
idr committed
1298
1299
	/* Prefer single-buffer.
	 */
1300
	return ( !(*a)->doubleBufferMode ) ? -1 : 1;
idr's avatar
idr committed
1301
1302
    }

1303
    PREFER_SMALLER( numAuxBuffers );
idr's avatar
idr committed
1304

idr's avatar
idr committed
1305
1306
    PREFER_LARGER_OR_ZERO( depthBits );
    PREFER_SMALLER( stencilBits );
idr's avatar
idr committed
1307

idr's avatar
idr committed
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
    /* This isn't quite right.  It is supposed to compare the sum of the
     * components the user specifically set minimums for.
     */
    PREFER_LARGER_OR_ZERO( accumRedBits );
    PREFER_LARGER_OR_ZERO( accumGreenBits );
    PREFER_LARGER_OR_ZERO( accumBlueBits );
    PREFER_LARGER_OR_ZERO( accumAlphaBits );

    PREFER_SMALLER( visualType );

    /* None of the multisample specs say where this comparison should happen,
     * so I put it near the end.
     */
idr's avatar
idr committed
1321
1322
1323
    PREFER_SMALLER( sampleBuffers );
    PREFER_SMALLER( samples );

idr's avatar
idr committed
1324
1325
1326
    /* None of the pbuffer or fbconfig specs say that this comparison needs
     * to happen at all, but it seems like it should.
     */
idr's avatar
idr committed
1327
1328
1329
1330
1331
    PREFER_LARGER( maxPbufferWidth );
    PREFER_LARGER( maxPbufferHeight );
    PREFER_LARGER( maxPbufferPixels );

    return 0;
daryll's avatar
daryll committed
1332
1333
1334
}


idr's avatar
idr committed
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
/**
 * Selects and sorts a subset of the supplied configs based on the attributes.
 * This function forms to basis of \c glXChooseVisual, \c glXChooseFBConfig,
 * and \c glXChooseFBConfigSGIX.
 * 
 * \param configs   Array of pointers to possible configs.  The elements of
 *                  this array that do not meet the criteria will be set to
 *                  NULL.  The remaining elements will be sorted according to
 *                  the various visual / FBConfig selection rules.
 * \param num_configs  Number of elements in the \c configs array.
 * \param attribList   Attributes used select from \c configs.  This array is
 *                     terminated by a \c None tag.  The array can either take
 *                     the form expected by \c glXChooseVisual (where boolean
 *                     tags do not have a value) or by \c glXChooseFBConfig
 *                     (where every tag has a value).
1350
1351
1352
 * \param fbconfig_style_tags  Selects whether \c attribList is in
 *                             \c glXChooseVisual style or
 *                             \c glXChooseFBConfig style.
idr's avatar
idr committed
1353
1354
1355
1356
1357
 * \returns The number of valid elements left in \c configs.
 * 
 * \sa glXChooseVisual, glXChooseFBConfig, glXChooseFBConfigSGIX
 */
static int
1358
choose_visual( __GLcontextModes ** configs, int num_configs,
1359
	       const int *attribList, GLboolean fbconfig_style_tags )
idr's avatar
idr committed
1360
{
1361
    __GLcontextModes    test_config;
idr's avatar
idr committed
1362
1363
1364
1365
1366
1367
1368
1369
1370
    int   base;
    int   i;

    /* This is a fairly direct implementation of the selection method
     * described by GLX_SGIX_fbconfig.  Start by culling out all the
     * configs that are not compatible with the selected parameter
     * list.
     */

idr's avatar
idr committed
1371
1372
    init_fbconfig_for_chooser( & test_config, fbconfig_style_tags );
    __glXInitializeVisualConfigFromTags( & test_config, 512,
idr's avatar
idr committed
1373
					 (const INT32 *) attribList,
1374
					 GL_TRUE, fbconfig_style_tags );
idr's avatar
idr committed
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385

    base = 0;
    for ( i = 0 ; i < num_configs ; i++ ) {
	if ( fbconfigs_compatible( & test_config, configs[i] ) ) {
	    configs[ base ] = configs[ i ];
	    base++;
	}
    }

    if ( base == 0 ) {
	return 0;
daryll's avatar
daryll committed
1386
    }
idr's avatar
idr committed
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
 
    if ( base < num_configs ) {
	(void) memset( & configs[ base ], 0, 
		       sizeof( void * ) * (num_configs - base) );
    }

    /* After the incompatible configs are removed, the resulting
     * list is sorted according to the rules set out in the various
     * specifications.
     */
    
1398
    qsort( configs, base, sizeof( __GLcontextModes * ),
idr's avatar
idr committed
1399
1400
1401
1402
1403
	   (int (*)(const void*, const void*)) fbconfig_compare );
    return base;
}


daryll's avatar
daryll committed
1404
1405
1406
1407
1408
1409


/*
** Return the visual that best matches the template.  Return None if no
** visual matches the template.
*/
1410
XVisualInfo *GLX_PREFIX(glXChooseVisual)(Display *dpy, int screen, int *attribList)
daryll's avatar
daryll committed
1411
{
1412
    XVisualInfo *visualList = NULL;
1413
1414
    __GLXdisplayPrivate *priv;
    __GLXscreenConfigs *psc;
1415
    __GLcontextModes  test_config;
1416
    __GLcontextModes *modes;
1417
    const __GLcontextModes *best_config = NULL;
daryll's avatar
daryll committed
1418
1419
1420
1421

    /*
    ** Get a list of all visuals, return if list is empty
    */
1422
    if ( GetGLXPrivScreenConfig( dpy, screen, & priv, & psc ) != Success ) {
daryll's avatar
daryll committed
1423
	return None;
idr's avatar
idr committed
1424
    }
1425
   
daryll's avatar
daryll committed
1426
1427
1428
1429
1430

    /*
    ** Build a template from the defaults and the attribute list
    ** Free visual list and return if an unexpected token is encountered
    */
idr's avatar
idr committed
1431
    init_fbconfig_for_chooser( & test_config, GL_FALSE );
idr's avatar
idr committed
1432
1433
1434
    __glXInitializeVisualConfigFromTags( & test_config, 512, 
					 (const INT32 *) attribList,
					 GL_TRUE, GL_FALSE );
daryll's avatar
daryll committed
1435
1436
1437
1438
1439
1440

    /*
    ** Eliminate visuals that don't meet minimum requirements
    ** Compute a score for those that do
    ** Remember which visual, if any, got the highest score
    */
1441
1442
1443
    for ( modes = psc->configs ; modes != NULL ; modes = modes->next ) {
	if ( fbconfigs_compatible( & test_config, modes )
	     && ((best_config == NULL)
idr's avatar
idr committed
1444
		 || (fbconfig_compare( (const __GLcontextModes * const * const)&modes, &best_config ) < 0)) ) {
1445
	    best_config = modes;
daryll's avatar
daryll committed
1446
1447
1448
1449
1450
1451
	}
    }

    /*
    ** If no visual is acceptable, return None
    ** Otherwise, create an XVisualInfo list with just the selected X visual
1452
    ** and return this.
daryll's avatar
daryll committed
1453
    */
idr's avatar
idr committed
1454
    if (best_config != NULL) {
1455
1456
1457
	XVisualInfo visualTemplate;
	int  i;

idr's avatar
idr committed
1458
	visualTemplate.screen = screen;
1459
	visualTemplate.visualid = best_config->visualID;
idr's avatar
idr committed
1460
	visualList = XGetVisualInfo( dpy, VisualScreenMask|VisualIDMask,
1461
				     &visualTemplate, &i );
daryll's avatar
daryll committed
1462
    }
idr's avatar
idr committed
1463
1464

    return visualList;
daryll's avatar
daryll committed
1465
1466
}

1467
1468
1469
1470
/**
 * Query the Server GLX string and cache it in the display private.
 * This routine will allocate the necessay space for the string.
 */
idr's avatar
idr committed
1471
1472
char *__glXInternalQueryServerString( Display *dpy, int opcode,
				      int screen, int name )
daryll's avatar
daryll committed
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
{
    xGLXQueryServerStringReq *req;
    xGLXQueryServerStringReply reply;
    int length, numbytes, slop;
    char *buf;

    /* Send the glXQueryServerString request */
    LockDisplay(dpy);
    GetReq(GLXQueryServerString,req);
    req->reqType = opcode;
    req->glxCode = X_GLXQueryServerString;
    req->screen = screen;
    req->name = name;
    _XReply(dpy, (xReply*) &reply, 0, False);

    length = reply.length;
    numbytes = reply.n;
    slop = numbytes * __GLX_SIZE_INT8 & 3;
    buf = (char *)Xmalloc(numbytes);
    if (!buf) {
        /* Throw data on the floor */
        _XEatData(dpy, length);
    } else {
        _XRead(dpy, (char *)buf, numbytes);
        if (slop) _XEatData(dpy,4-slop);
    }
    UnlockDisplay(dpy);
    SyncHandle();
    return buf;
}


1505
const char *GLX_PREFIX(glXQueryExtensionsString)( Display *dpy, int screen )
daryll's avatar
daryll committed
1506
1507
1508
1509
{
    __GLXscreenConfigs *psc;
    __GLXdisplayPrivate *priv;

1510
    if ( GetGLXPrivScreenConfig( dpy, screen, & priv, & psc ) != Success ) {
daryll's avatar
daryll committed
1511
1512
1513
1514
1515
	return NULL;
    }

    if (!psc->effectiveGLXexts) {
        if (!psc->serverGLXexts) {
idr's avatar
idr committed
1516
	    psc->serverGLXexts = __glXInternalQueryServerString(dpy, priv->majorOpcode,
daryll's avatar
daryll committed
1517
1518
					  	   screen, GLX_EXTENSIONS);
	}
idr's avatar
idr committed
1519