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