1/*
2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice including the dates of first publication and
13 * either this permission notice or a reference to
14 * http://oss.sgi.com/projects/FreeB/
15 * shall be included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 * Except as contained in this notice, the name of Silicon Graphics, Inc.
26 * shall not be used in advertising or otherwise to promote the sale, use or
27 * other dealings in this Software without prior written authorization from
28 * Silicon Graphics, Inc.
29 */
30
31#ifdef HAVE_DMX_CONFIG_H
32#include <dmx-config.h>
33#endif
34
35#include "dmx.h"
36#include <GL/glx.h>
37#include <GL/glxproto.h>
38#include <X11/extensions/Xext.h>
39#include <X11/extensions/extutil.h>
40
41#include "dmx_glxvisuals.h"
42
43__GLXvisualConfig *GetGLXVisualConfigs(Display *dpy, int screen, int *nconfigs)
44{
45    xGLXGetVisualConfigsReq *req;
46    xGLXGetVisualConfigsReply reply;
47    __GLXvisualConfig *config, *configs;
48    GLint i, j, nvisuals, nprops;
49    INT32 *props, *p;
50    int   majorOpcode, dummy;
51    int   num_good_visuals;
52
53    if (!XQueryExtension(dpy, "GLX", &majorOpcode, &dummy, &dummy)) {
54       return NULL;
55    }
56
57    /* Send the glXGetVisualConfigs request */
58    LockDisplay(dpy);
59    GetReq(GLXGetVisualConfigs,req);
60    req->reqType = majorOpcode;
61    req->glxCode = X_GLXGetVisualConfigs;
62    req->screen = screen;
63    if (!_XReply(dpy, (xReply*) &reply, 0, False)) {
64	/* Something is busted. Punt. */
65	UnlockDisplay(dpy);
66	SyncHandle();
67	return NULL;
68    }
69
70    nvisuals = (int)reply.numVisuals;
71    if (!nvisuals) {
72	/* This screen does not support GL rendering */
73	UnlockDisplay(dpy);
74	SyncHandle();
75	return NULL;
76    }
77
78    /* Check number of properties per visual */
79    nprops = (int)reply.numProps;
80    if (nprops < __GLX_MIN_CONFIG_PROPS)  {
81	/* Huh?  Not in protocol defined limits.  Punt */
82	UnlockDisplay(dpy);
83	SyncHandle();
84	return NULL;
85    }
86    props = (INT32*) Xmalloc(nprops * __GLX_SIZE_CARD32);
87    if (!props) {
88	UnlockDisplay(dpy);
89	SyncHandle();
90	return NULL;
91    }
92
93    /* Allocate memory for our config structure */
94    config = (__GLXvisualConfig*)
95	Xmalloc(nvisuals * sizeof(__GLXvisualConfig));
96    if (!config) {
97	free(props);
98	UnlockDisplay(dpy);
99	SyncHandle();
100	return NULL;
101    }
102    memset(config, 0, nvisuals * sizeof(__GLXvisualConfig));
103    configs = config;
104    num_good_visuals = 0;
105
106    /* Convert config structure into our format */
107    for (i=0; i<nvisuals; i++) {
108
109	/* Read config structure */
110	_XRead(dpy, (char *)props, (nprops * __GLX_SIZE_CARD32));
111
112	/* fill in default values */
113	config->visualRating = GLX_NONE_EXT;
114	config->transparentPixel = GLX_NONE_EXT;
115
116	/* Copy in the first set of properties */
117	config->vid = props[0];
118	config->class = props[1];
119
120	config->rgba = (Bool) props[2];
121
122	config->redSize = props[3];
123	config->greenSize = props[4];
124	config->blueSize = props[5];
125	config->alphaSize = props[6];
126
127	config->accumRedSize = props[7];
128	config->accumGreenSize = props[8];
129	config->accumBlueSize = props[9];
130	config->accumAlphaSize = props[10];
131
132	config->doubleBuffer = (Bool) props[11];
133	config->stereo = (Bool) props[12];
134
135	config->bufferSize = props[13];
136	config->depthSize = props[14];
137	config->stencilSize = props[15];
138
139	config->auxBuffers = props[16];
140	config->level = props[17];
141
142	/* Process remaining properties */
143	p = &props[18];
144	for (j=__GLX_MIN_CONFIG_PROPS; j<nprops; j+=2) {
145	    int property = *p++;
146	    int value = *p++;
147
148	    switch (property) {
149	      case GLX_SAMPLES_SGIS:
150		config->multiSampleSize = value;
151		break;
152	      case GLX_SAMPLE_BUFFERS_SGIS:
153		config->nMultiSampleBuffers = value;
154		break;
155
156	      case GLX_TRANSPARENT_TYPE_EXT:
157		config->transparentPixel = value;
158		break;
159	      case GLX_TRANSPARENT_INDEX_VALUE_EXT:
160		config->transparentIndex = value;
161		break;
162	      case GLX_TRANSPARENT_RED_VALUE_EXT:
163		config->transparentRed = value;
164		break;
165	      case GLX_TRANSPARENT_GREEN_VALUE_EXT:
166		config->transparentGreen = value;
167		break;
168	      case GLX_TRANSPARENT_BLUE_VALUE_EXT:
169		config->transparentBlue = value;
170		break;
171	      case GLX_TRANSPARENT_ALPHA_VALUE_EXT:
172		config->transparentAlpha = value;
173		break;
174
175	      case GLX_VISUAL_CAVEAT_EXT:
176		config->visualRating = value;
177		break;
178
179	      /* visualSelectGroup is an internal used property */
180	      case GLX_VISUAL_SELECT_GROUP_SGIX:
181		config->visualSelectGroup = value;
182		break;
183
184	      default :
185		/* Ignore properties we don't recognize */
186		break;
187	    }
188	} /* for j */
189
190	/*
191	// filter out overlay visuals (dmx does not support overlays)
192	*/
193	if (config->level == 0) {
194	   config++;
195	   num_good_visuals++;
196	}
197
198    } /* for i */
199
200    UnlockDisplay(dpy);
201
202    nvisuals = num_good_visuals;
203
204    config = configs;
205    for (i=0; i<nvisuals; i++) {
206	/* XXX hack to fill-in mask info (need a better way to do this) */
207	{
208	    XVisualInfo *vis, template;
209	    int n;
210
211	    template.screen = screen;
212	    template.visualid = config->vid;
213	    vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask,
214				 &template, &n);
215
216	    if (vis != NULL) {
217		config->redMask = vis->red_mask;
218		config->greenMask = vis->green_mask;
219		config->blueMask = vis->blue_mask;
220		config->alphaMask = 0; 	/* XXX */
221		free(vis);
222	    }
223	}
224	config++;
225    } /* for i */
226
227    XFree(props);
228    SyncHandle();
229
230    *nconfigs = nvisuals;
231    return configs;
232}
233
234
235__GLXFBConfig *GetGLXFBConfigs(Display *dpy, int glxMajorOpcode, int *nconfigs)
236{
237    xGLXGetFBConfigsReq *req;
238    xGLXGetFBConfigsReply reply;
239    __GLXFBConfig *config, *fbconfigs;
240    GLint i, j, numFBConfigs, numAttribs;
241    INT32 *attrs, *p;
242    int screen = DefaultScreen( dpy );
243    int numValidConfigs = 0;
244
245    /* Send the glXGetFBConfigs request */
246    LockDisplay(dpy);
247    GetReq(GLXGetFBConfigs, req);
248    req->reqType = glxMajorOpcode;
249    req->glxCode = X_GLXGetFBConfigs;
250    req->screen = screen;
251
252    *nconfigs = 0;
253
254    if (!_XReply(dpy, (xReply*) &reply, 0, False)) {
255	/* Something is busted. Punt. */
256	UnlockDisplay(dpy);
257	SyncHandle();
258	return NULL;
259    }
260
261    numFBConfigs = (int)reply.numFBConfigs;
262    if (!numFBConfigs) {
263	/* This screen does not support GL rendering */
264	UnlockDisplay(dpy);
265	SyncHandle();
266	return NULL;
267    }
268
269    numAttribs = (int)reply.numAttribs;
270    if (!numAttribs)  {
271	UnlockDisplay(dpy);
272	SyncHandle();
273	return NULL;
274    }
275
276    attrs = (INT32*) Xmalloc(2*numAttribs * __GLX_SIZE_CARD32);
277    if (!attrs) {
278	UnlockDisplay(dpy);
279	SyncHandle();
280	return NULL;
281    }
282
283    /* Allocate memory for our config structure */
284    config = (__GLXFBConfig*)
285	Xmalloc(numFBConfigs * sizeof(__GLXFBConfig));
286    if (!config) {
287	free(attrs);
288	UnlockDisplay(dpy);
289	SyncHandle();
290	return NULL;
291    }
292    memset(config, 0, numFBConfigs * sizeof(__GLXFBConfig));
293    fbconfigs = config;
294
295    /* Convert attribute list into our format */
296    for (i=0; i<numFBConfigs; i++) {
297
298	/* Fill in default properties */
299	config->transparentType = GLX_NONE_EXT;
300	config->visualCaveat = GLX_NONE_EXT;
301	config->minRed = 0.;
302	config->maxRed = 1.;
303	config->minGreen = 0.;
304	config->maxGreen = 1.;
305	config->minBlue = 0.;
306	config->maxBlue = 1.;
307	config->minAlpha = 0.;
308	config->maxAlpha = 1.;
309
310	/* Read attribute list */
311	_XRead(dpy, (char *)attrs, (2*numAttribs * __GLX_SIZE_CARD32));
312
313	p = attrs;
314	for (j=0; j<numAttribs; j++) {
315	    int attribute = *p++;
316	    int value = *p++;
317
318	    switch (attribute) {
319	      /* core attributes */
320	      case GLX_FBCONFIG_ID:
321		config->id = value;
322		break;
323	      case GLX_BUFFER_SIZE:
324		config->indexBits = value;
325		break;
326	      case GLX_LEVEL:
327		config->level = value;
328		break;
329	      case GLX_DOUBLEBUFFER:
330		config->doubleBufferMode = value;
331		break;
332	      case GLX_STEREO:
333		config->stereoMode = value;
334		break;
335	      case GLX_AUX_BUFFERS:
336		config->maxAuxBuffers = value;
337		break;
338	      case GLX_RED_SIZE:
339		config->redBits = value;
340		break;
341	      case GLX_GREEN_SIZE:
342		config->greenBits = value;
343		break;
344	      case GLX_BLUE_SIZE:
345		config->blueBits = value;
346		break;
347	      case GLX_ALPHA_SIZE:
348		config->alphaBits = value;
349		break;
350	      case GLX_DEPTH_SIZE:
351		config->depthBits = value;
352		break;
353	      case GLX_STENCIL_SIZE:
354		config->stencilBits = value;
355		break;
356	      case GLX_ACCUM_RED_SIZE:
357		config->accumRedBits = value;
358		break;
359	      case GLX_ACCUM_GREEN_SIZE:
360		config->accumGreenBits = value;
361		break;
362	      case GLX_ACCUM_BLUE_SIZE:
363		config->accumBlueBits = value;
364		break;
365	      case GLX_ACCUM_ALPHA_SIZE:
366		config->accumAlphaBits = value;
367		break;
368	      case GLX_RENDER_TYPE:
369		config->renderType = value;
370		break;
371	      case GLX_DRAWABLE_TYPE:
372		config->drawableType = value;
373		break;
374	      case GLX_X_VISUAL_TYPE:
375		config->visualType = value;
376		break;
377	      case GLX_CONFIG_CAVEAT:
378		config->visualCaveat = value;
379		break;
380	      case GLX_TRANSPARENT_TYPE:
381		config->transparentType = value;
382		break;
383	      case GLX_TRANSPARENT_INDEX_VALUE:
384		config->transparentIndex = value;
385		break;
386	      case GLX_TRANSPARENT_RED_VALUE:
387		config->transparentRed = value;
388		break;
389	      case GLX_TRANSPARENT_GREEN_VALUE:
390		config->transparentGreen = value;
391		break;
392	      case GLX_TRANSPARENT_BLUE_VALUE:
393		config->transparentBlue = value;
394		break;
395	      case GLX_TRANSPARENT_ALPHA_VALUE:
396		config->transparentAlpha = value;
397		break;
398	      case GLX_MAX_PBUFFER_WIDTH:
399		config->maxPbufferWidth = value;
400		break;
401	      case GLX_MAX_PBUFFER_HEIGHT:
402		config->maxPbufferHeight = value;
403		break;
404	      case GLX_MAX_PBUFFER_PIXELS:
405		config->maxPbufferPixels = value;
406		break;
407	      case GLX_VISUAL_ID:
408		config->associatedVisualId = value;
409		break;
410
411	      /* visualSelectGroup is an internal used property */
412	      case GLX_VISUAL_SELECT_GROUP_SGIX:
413		config->visualSelectGroup = value;
414		break;
415
416	      /* SGIS_multisample attributes */
417	      case GLX_SAMPLES_SGIS:
418		config->multiSampleSize = value;
419		break;
420	      case GLX_SAMPLE_BUFFERS_SGIS:
421		config->nMultiSampleBuffers = value;
422		break;
423
424	      /* SGIX_pbuffer specific attributes */
425	      case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX:
426		config->optimalPbufferWidth = value;
427		break;
428	      case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX:
429		config->optimalPbufferHeight = value;
430		break;
431
432	      default:
433		/* Ignore attributes we don't recognize */
434		break;
435	    }
436	} /* for j */
437
438	/* Fill in derived values */
439	config->screen = screen;
440
441	config->rgbMode = config->renderType & GLX_RGBA_BIT;
442	config->colorIndexMode = !config->rgbMode;
443
444	config->haveAccumBuffer =
445	    config->accumRedBits > 0 ||
446	    config->accumGreenBits > 0 ||
447	    config->accumBlueBits > 0;
448	    /* Can't have alpha without color */
449
450	config->haveDepthBuffer = config->depthBits > 0;
451	config->haveStencilBuffer =  config->stencilBits > 0;
452
453	/* overlay visuals are not valid for now */
454	if (!config->level) {
455	   config++;
456	   numValidConfigs++;
457	}
458
459    } /* for i */
460    UnlockDisplay(dpy);
461
462    config = fbconfigs;
463    for (i=0; i<numValidConfigs; i++) {
464
465	/* XXX hack to fill-in mask info (need a better way to do this) */
466	if (config->associatedVisualId != 0) {
467	    XVisualInfo *vis, template;
468	    int n;
469
470	    template.screen = screen;
471	    template.visualid = config->associatedVisualId;
472	    vis = XGetVisualInfo(dpy, VisualScreenMask|VisualIDMask,
473				 &template, &n);
474
475	    if (vis != NULL) {
476		config->redMask = (GLuint)vis->red_mask;
477		config->greenMask = (GLuint)vis->green_mask;
478		config->blueMask = (GLuint)vis->blue_mask;
479		config->alphaMask = 0; 	/* XXX */
480		free(vis);
481	    }
482	}
483
484	config++;
485    } /* for i */
486
487    XFree(attrs);
488    SyncHandle();
489
490    *nconfigs = numValidConfigs;
491    return fbconfigs;
492}
493
494__GLXvisualConfig *
495GetGLXVisualConfigsFromFBConfigs(__GLXFBConfig *fbconfigs, int nfbconfigs,
496                                 XVisualInfo *visuals, int nvisuals,
497				 __GLXvisualConfig *glxConfigs, int nGlxConfigs,
498                                 int *nconfigs)
499{
500    __GLXvisualConfig *configs = NULL;
501    int i;
502
503    if (!fbconfigs || !nfbconfigs || !nconfigs) return NULL;
504    *nconfigs = 0;
505
506    /* Allocate memory for our config structure */
507    configs = (__GLXvisualConfig*)
508	Xmalloc(nfbconfigs * sizeof(__GLXvisualConfig));
509    if (!configs) {
510	return NULL;
511    }
512    memset(configs, 0, nfbconfigs * sizeof(__GLXvisualConfig));
513
514    for (i=0; i<nfbconfigs; i++) {
515       __GLXFBConfig *fbcfg = &fbconfigs[i];
516
517       if (fbcfg->associatedVisualId > 0) {
518	  __GLXvisualConfig *cfg = configs + (*nconfigs);
519	  int j;
520	  XVisualInfo *vinfo = NULL;
521
522	  for (j=0; j<nvisuals; j++) {
523	     if (visuals[j].visualid == fbcfg->associatedVisualId) {
524		vinfo = &visuals[j];
525		break;
526	     }
527	  }
528	  if (!vinfo) continue;
529
530	  /* skip 16 bit colormap visuals */
531	  if (vinfo->depth == 16 &&
532              vinfo->class != TrueColor &&
533              vinfo->class != DirectColor ) {
534	     continue;
535	  }
536
537	  (*nconfigs)++;
538
539	  /*
540           * if the same visualid exists in the glx configs,
541	   * copy the glx attributes from the glx config
542	   */
543	  for (j=0; j<nGlxConfigs; j++) {
544	     if (glxConfigs[j].vid == vinfo->visualid)
545		break;
546	  }
547	  if (j < nGlxConfigs) {
548	     memcpy(cfg, &glxConfigs[j], sizeof(__GLXvisualConfig) );
549	     continue;
550	  }
551
552	  /*
553           * make glx attributes from the FB config attributes
554	   */
555	  cfg->vid = fbcfg->associatedVisualId;
556	  cfg->class = vinfo->class;
557	  cfg->rgba = !(fbcfg->renderType & GLX_COLOR_INDEX_BIT_SGIX);
558	  cfg->redSize = fbcfg->redBits;
559	  cfg->greenSize = fbcfg->greenBits;
560	  cfg->blueSize = fbcfg->blueBits;
561	  cfg->alphaSize = fbcfg->alphaBits;
562	  cfg->redMask = fbcfg->redMask;
563	  cfg->greenMask = fbcfg->greenMask;
564	  cfg->blueMask = fbcfg->blueMask;
565	  cfg->alphaMask = fbcfg->alphaMask;
566	  cfg->accumRedSize = fbcfg->accumRedBits;
567	  cfg->accumGreenSize = fbcfg->accumGreenBits;
568	  cfg->accumBlueSize = fbcfg->accumBlueBits;
569	  cfg->accumAlphaSize = fbcfg->accumAlphaBits;
570	  cfg->doubleBuffer = fbcfg->doubleBufferMode;
571	  cfg->stereo = fbcfg->stereoMode;
572    	  if (vinfo->class == TrueColor || vinfo->class == DirectColor) {
573	     cfg->bufferSize = (fbcfg->rgbMode ? (fbcfg->redBits +
574		                               fbcfg->greenBits +
575    		                               fbcfg->blueBits +
576		                               fbcfg->alphaBits)
577	                                    : fbcfg->indexBits );
578	  }
579	  else {
580	     cfg->bufferSize = vinfo->depth;
581	  }
582      	  cfg->depthSize = fbcfg->depthBits;
583	  cfg->stencilSize = fbcfg->stencilBits;
584	  cfg->auxBuffers = fbcfg->maxAuxBuffers;
585	  cfg->level = fbcfg->level;
586	  cfg->visualRating = fbcfg->visualCaveat;
587	  cfg->transparentPixel = fbcfg->transparentType;
588	  cfg->transparentRed = fbcfg->transparentRed;
589	  cfg->transparentGreen = fbcfg->transparentGreen;
590	  cfg->transparentBlue = fbcfg->transparentBlue;
591	  cfg->transparentAlpha = fbcfg->transparentAlpha;
592	  cfg->transparentIndex = fbcfg->transparentIndex;
593	  cfg->multiSampleSize = fbcfg->multiSampleSize;
594	  cfg->nMultiSampleBuffers = fbcfg->nMultiSampleBuffers;
595	  cfg->visualSelectGroup = fbcfg->visualSelectGroup;
596       }
597    }
598
599    return configs;
600}
601
602