1 /**
2  * GLX initialization.  Code based on glxext.c, glx_query.c, and
3  * glcontextmodes.c under src/glx/.  The major difference is that DRI
4  * related code is stripped out.
5  *
6  * If the maintenance of this file takes too much time, we should consider
7  * refactoring glxext.c.
8  */
9 
10 #include <assert.h>
11 #include <X11/Xlib.h>
12 #include <X11/Xproto.h>
13 #include <X11/Xlibint.h>
14 #include <X11/extensions/Xext.h>
15 #include <X11/extensions/extutil.h>
16 #include <sys/time.h>
17 
18 #include "GL/glxproto.h"
19 #include "GL/glxtokens.h"
20 #include "GL/gl.h" /* for GL types needed by __GLcontextModes */
21 #include "glcore.h"  /* for __GLcontextModes */
22 
23 #include "glxinit.h"
24 
25 #ifdef GLX_DIRECT_RENDERING
26 
27 typedef struct GLXGenericGetString
28 {
29    CARD8 reqType;
30    CARD8 glxCode;
31    CARD16 length B16;
32    CARD32 for_whom B32;
33    CARD32 name B32;
34 } xGLXGenericGetStringReq;
35 
36 #define sz_xGLXGenericGetStringReq 12
37 #define X_GLXGenericGetString 0
38 
39 /* Extension required boiler plate */
40 
41 static char *__glXExtensionName = GLX_EXTENSION_NAME;
42 static XExtensionInfo *__glXExtensionInfo = NULL;
43 
44 static int
__glXCloseDisplay(Display * dpy,XExtCodes * codes)45 __glXCloseDisplay(Display * dpy, XExtCodes * codes)
46 {
47    return XextRemoveDisplay(__glXExtensionInfo, dpy);
48 }
49 
50 static /* const */ XExtensionHooks __glXExtensionHooks = {
51   NULL,                   /* create_gc */
52   NULL,                   /* copy_gc */
53   NULL,                   /* flush_gc */
54   NULL,                   /* free_gc */
55   NULL,                   /* create_font */
56   NULL,                   /* free_font */
57   __glXCloseDisplay,      /* close_display */
58   NULL,                   /* wire_to_event */
59   NULL,                   /* event_to_wire */
60   NULL,                   /* error */
61   NULL,                   /* error_string */
62 };
63 
64 static XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo,
65 				  __glXExtensionName, &__glXExtensionHooks,
66 				  __GLX_NUMBER_EVENTS, NULL)
67 
68 static GLint
_gl_convert_from_x_visual_type(int visualType)69 _gl_convert_from_x_visual_type(int visualType)
70 {
71 #define NUM_VISUAL_TYPES   6
72    static const int glx_visual_types[NUM_VISUAL_TYPES] = {
73       GLX_STATIC_GRAY, GLX_GRAY_SCALE,
74       GLX_STATIC_COLOR, GLX_PSEUDO_COLOR,
75       GLX_TRUE_COLOR, GLX_DIRECT_COLOR
76    };
77 
78    return ((unsigned) visualType < NUM_VISUAL_TYPES)
79       ? glx_visual_types[visualType] : GLX_NONE;
80 }
81 
82 static void
_gl_context_modes_destroy(__GLcontextModes * modes)83 _gl_context_modes_destroy(__GLcontextModes * modes)
84 {
85    while (modes != NULL) {
86       __GLcontextModes *const next = modes->next;
87 
88       Xfree(modes);
89       modes = next;
90    }
91 }
92 
93 static __GLcontextModes *
_gl_context_modes_create(unsigned count,size_t minimum_size)94 _gl_context_modes_create(unsigned count, size_t minimum_size)
95 {
96    const size_t size = (minimum_size > sizeof(__GLcontextModes))
97       ? minimum_size : sizeof(__GLcontextModes);
98    __GLcontextModes *base = NULL;
99    __GLcontextModes **next;
100    unsigned i;
101 
102    next = &base;
103    for (i = 0; i < count; i++) {
104       *next = (__GLcontextModes *) Xmalloc(size);
105       if (*next == NULL) {
106          _gl_context_modes_destroy(base);
107          base = NULL;
108          break;
109       }
110 
111       memset(*next, 0, size);
112       (*next)->visualID = GLX_DONT_CARE;
113       (*next)->visualType = GLX_DONT_CARE;
114       (*next)->visualRating = GLX_NONE;
115       (*next)->transparentPixel = GLX_NONE;
116       (*next)->transparentRed = GLX_DONT_CARE;
117       (*next)->transparentGreen = GLX_DONT_CARE;
118       (*next)->transparentBlue = GLX_DONT_CARE;
119       (*next)->transparentAlpha = GLX_DONT_CARE;
120       (*next)->transparentIndex = GLX_DONT_CARE;
121       (*next)->xRenderable = GLX_DONT_CARE;
122       (*next)->fbconfigID = GLX_DONT_CARE;
123       (*next)->swapMethod = GLX_SWAP_UNDEFINED_OML;
124       (*next)->bindToTextureRgb = GLX_DONT_CARE;
125       (*next)->bindToTextureRgba = GLX_DONT_CARE;
126       (*next)->bindToMipmapTexture = GLX_DONT_CARE;
127       (*next)->bindToTextureTargets = GLX_DONT_CARE;
128       (*next)->yInverted = GLX_DONT_CARE;
129 
130       next = &((*next)->next);
131    }
132 
133    return base;
134 }
135 
136 static char *
__glXQueryServerString(Display * dpy,int opcode,CARD32 screen,CARD32 name)137 __glXQueryServerString(Display * dpy, int opcode, CARD32 screen, CARD32 name)
138 {
139    xGLXGenericGetStringReq *req;
140    xGLXSingleReply reply;
141    int length;
142    int numbytes;
143    char *buf;
144    CARD32 for_whom = screen;
145    CARD32 glxCode = X_GLXQueryServerString;
146 
147 
148    LockDisplay(dpy);
149 
150 
151    /* All of the GLX protocol requests for getting a string from the server
152     * look the same.  The exact meaning of the for_whom field is usually
153     * either the screen number (for glXQueryServerString) or the context tag
154     * (for GLXSingle).
155     */
156 
157    GetReq(GLXGenericGetString, req);
158    req->reqType = opcode;
159    req->glxCode = glxCode;
160    req->for_whom = for_whom;
161    req->name = name;
162 
163    _XReply(dpy, (xReply *) & reply, 0, False);
164 
165    length = reply.length * 4;
166    numbytes = reply.size;
167 
168    buf = (char *) Xmalloc(numbytes);
169    if (buf != NULL) {
170       _XRead(dpy, buf, numbytes);
171       length -= numbytes;
172    }
173 
174    _XEatData(dpy, length);
175 
176    UnlockDisplay(dpy);
177    SyncHandle();
178 
179    return buf;
180 }
181 
182 /************************************************************************/
183 /*
184 ** Free the per screen configs data as well as the array of
185 ** __glXScreenConfigs.
186 */
187 static void
FreeScreenConfigs(__GLXdisplayPrivate * priv)188 FreeScreenConfigs(__GLXdisplayPrivate * priv)
189 {
190    __GLXscreenConfigs *psc;
191    GLint i, screens;
192 
193    /* Free screen configuration information */
194    screens = ScreenCount(priv->dpy);
195    for (i = 0; i < screens; i++) {
196       psc = priv->screenConfigs[i];
197       if (!psc)
198          continue;
199       if (psc->configs) {
200          _gl_context_modes_destroy(psc->configs);
201          psc->configs = NULL;   /* NOTE: just for paranoia */
202       }
203       Xfree((char *) psc->serverGLXexts);
204    }
205    XFree((char *) priv->screenConfigs);
206    priv->screenConfigs = NULL;
207 }
208 
209 /*
210 ** Release the private memory referred to in a display private
211 ** structure.  The caller will free the extension structure.
212 */
213 static int
__glXFreeDisplayPrivate(XExtData * extension)214 __glXFreeDisplayPrivate(XExtData * extension)
215 {
216    __GLXdisplayPrivate *priv;
217 
218    priv = (__GLXdisplayPrivate *) extension->private_data;
219    FreeScreenConfigs(priv);
220    if (priv->serverGLXversion)
221       Xfree((char *) priv->serverGLXversion);
222 
223    Xfree((char *) priv);
224    return 0;
225 }
226 
227 /************************************************************************/
228 
229 /*
230 ** Query the version of the GLX extension.  This procedure works even if
231 ** the client extension is not completely set up.
232 */
233 
234 #define GLX_MAJOR_VERSION 1       /* current version numbers */
235 #define GLX_MINOR_VERSION 4
236 
237 static Bool
QueryVersion(Display * dpy,int opcode,int * major,int * minor)238 QueryVersion(Display * dpy, int opcode, int *major, int *minor)
239 {
240    xGLXQueryVersionReq *req;
241    xGLXQueryVersionReply reply;
242 
243    /* Send the glXQueryVersion request */
244    LockDisplay(dpy);
245    GetReq(GLXQueryVersion, req);
246    req->reqType = opcode;
247    req->glxCode = X_GLXQueryVersion;
248    req->majorVersion = GLX_MAJOR_VERSION;
249    req->minorVersion = GLX_MINOR_VERSION;
250    _XReply(dpy, (xReply *) & reply, 0, False);
251    UnlockDisplay(dpy);
252    SyncHandle();
253 
254    if (reply.majorVersion != GLX_MAJOR_VERSION) {
255       /*
256        ** The server does not support the same major release as this
257        ** client.
258        */
259       return GL_FALSE;
260    }
261    *major = reply.majorVersion;
262    *minor = min(reply.minorVersion, GLX_MINOR_VERSION);
263    return GL_TRUE;
264 }
265 
266 #define __GLX_MIN_CONFIG_PROPS	18
267 #define __GLX_MAX_CONFIG_PROPS	500
268 #define __GLX_EXT_CONFIG_PROPS 	10
269 #define __GLX_TOTAL_CONFIG       (__GLX_MIN_CONFIG_PROPS +      \
270                                     2 * __GLX_EXT_CONFIG_PROPS)
271 
272 static void
__glXInitializeVisualConfigFromTags(__GLcontextModes * config,int count,const INT32 * bp,Bool tagged_only,Bool fbconfig_style_tags)273 __glXInitializeVisualConfigFromTags(__GLcontextModes * config, int count,
274                                     const INT32 * bp, Bool tagged_only,
275                                     Bool fbconfig_style_tags)
276 {
277    int i;
278 
279    if (!tagged_only) {
280       /* Copy in the first set of properties */
281       config->visualID = *bp++;
282 
283       config->visualType = _gl_convert_from_x_visual_type(*bp++);
284 
285       config->rgbMode = *bp++;
286 
287       config->redBits = *bp++;
288       config->greenBits = *bp++;
289       config->blueBits = *bp++;
290       config->alphaBits = *bp++;
291       config->accumRedBits = *bp++;
292       config->accumGreenBits = *bp++;
293       config->accumBlueBits = *bp++;
294       config->accumAlphaBits = *bp++;
295 
296       config->doubleBufferMode = *bp++;
297       config->stereoMode = *bp++;
298 
299       config->rgbBits = *bp++;
300       config->depthBits = *bp++;
301       config->stencilBits = *bp++;
302       config->numAuxBuffers = *bp++;
303       config->level = *bp++;
304 
305       count -= __GLX_MIN_CONFIG_PROPS;
306    }
307 
308    /*
309     ** Additional properties may be in a list at the end
310     ** of the reply.  They are in pairs of property type
311     ** and property value.
312     */
313 
314 #define FETCH_OR_SET(tag) \
315     config-> tag = ( fbconfig_style_tags ) ? *bp++ : 1
316 
317    for (i = 0; i < count; i += 2) {
318       switch (*bp++) {
319       case GLX_RGBA:
320          FETCH_OR_SET(rgbMode);
321          break;
322       case GLX_BUFFER_SIZE:
323          config->rgbBits = *bp++;
324          break;
325       case GLX_LEVEL:
326          config->level = *bp++;
327          break;
328       case GLX_DOUBLEBUFFER:
329          FETCH_OR_SET(doubleBufferMode);
330          break;
331       case GLX_STEREO:
332          FETCH_OR_SET(stereoMode);
333          break;
334       case GLX_AUX_BUFFERS:
335          config->numAuxBuffers = *bp++;
336          break;
337       case GLX_RED_SIZE:
338          config->redBits = *bp++;
339          break;
340       case GLX_GREEN_SIZE:
341          config->greenBits = *bp++;
342          break;
343       case GLX_BLUE_SIZE:
344          config->blueBits = *bp++;
345          break;
346       case GLX_ALPHA_SIZE:
347          config->alphaBits = *bp++;
348          break;
349       case GLX_DEPTH_SIZE:
350          config->depthBits = *bp++;
351          break;
352       case GLX_STENCIL_SIZE:
353          config->stencilBits = *bp++;
354          break;
355       case GLX_ACCUM_RED_SIZE:
356          config->accumRedBits = *bp++;
357          break;
358       case GLX_ACCUM_GREEN_SIZE:
359          config->accumGreenBits = *bp++;
360          break;
361       case GLX_ACCUM_BLUE_SIZE:
362          config->accumBlueBits = *bp++;
363          break;
364       case GLX_ACCUM_ALPHA_SIZE:
365          config->accumAlphaBits = *bp++;
366          break;
367       case GLX_VISUAL_CAVEAT_EXT:
368          config->visualRating = *bp++;
369          break;
370       case GLX_X_VISUAL_TYPE:
371          config->visualType = *bp++;
372          break;
373       case GLX_TRANSPARENT_TYPE:
374          config->transparentPixel = *bp++;
375          break;
376       case GLX_TRANSPARENT_INDEX_VALUE:
377          config->transparentIndex = *bp++;
378          break;
379       case GLX_TRANSPARENT_RED_VALUE:
380          config->transparentRed = *bp++;
381          break;
382       case GLX_TRANSPARENT_GREEN_VALUE:
383          config->transparentGreen = *bp++;
384          break;
385       case GLX_TRANSPARENT_BLUE_VALUE:
386          config->transparentBlue = *bp++;
387          break;
388       case GLX_TRANSPARENT_ALPHA_VALUE:
389          config->transparentAlpha = *bp++;
390          break;
391       case GLX_VISUAL_ID:
392          config->visualID = *bp++;
393          break;
394       case GLX_DRAWABLE_TYPE:
395          config->drawableType = *bp++;
396          break;
397       case GLX_RENDER_TYPE:
398          config->renderType = *bp++;
399          break;
400       case GLX_X_RENDERABLE:
401          config->xRenderable = *bp++;
402          break;
403       case GLX_FBCONFIG_ID:
404          config->fbconfigID = *bp++;
405          break;
406       case GLX_MAX_PBUFFER_WIDTH:
407          config->maxPbufferWidth = *bp++;
408          break;
409       case GLX_MAX_PBUFFER_HEIGHT:
410          config->maxPbufferHeight = *bp++;
411          break;
412       case GLX_MAX_PBUFFER_PIXELS:
413          config->maxPbufferPixels = *bp++;
414          break;
415       case GLX_OPTIMAL_PBUFFER_WIDTH_SGIX:
416          config->optimalPbufferWidth = *bp++;
417          break;
418       case GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX:
419          config->optimalPbufferHeight = *bp++;
420          break;
421       case GLX_VISUAL_SELECT_GROUP_SGIX:
422          config->visualSelectGroup = *bp++;
423          break;
424       case GLX_SWAP_METHOD_OML:
425          config->swapMethod = *bp++;
426          break;
427       case GLX_SAMPLE_BUFFERS_SGIS:
428          config->sampleBuffers = *bp++;
429          break;
430       case GLX_SAMPLES_SGIS:
431          config->samples = *bp++;
432          break;
433       case GLX_BIND_TO_TEXTURE_RGB_EXT:
434          config->bindToTextureRgb = *bp++;
435          break;
436       case GLX_BIND_TO_TEXTURE_RGBA_EXT:
437          config->bindToTextureRgba = *bp++;
438          break;
439       case GLX_BIND_TO_MIPMAP_TEXTURE_EXT:
440          config->bindToMipmapTexture = *bp++;
441          break;
442       case GLX_BIND_TO_TEXTURE_TARGETS_EXT:
443          config->bindToTextureTargets = *bp++;
444          break;
445       case GLX_Y_INVERTED_EXT:
446          config->yInverted = *bp++;
447          break;
448       case None:
449          i = count;
450          break;
451       default:
452          break;
453       }
454    }
455 
456    config->renderType =
457       (config->rgbMode) ? GLX_RGBA_BIT : GLX_COLOR_INDEX_BIT;
458 
459    config->haveAccumBuffer = ((config->accumRedBits +
460                                config->accumGreenBits +
461                                config->accumBlueBits +
462                                config->accumAlphaBits) > 0);
463    config->haveDepthBuffer = (config->depthBits > 0);
464    config->haveStencilBuffer = (config->stencilBits > 0);
465 }
466 
467 static __GLcontextModes *
createConfigsFromProperties(Display * dpy,int nvisuals,int nprops,int screen,GLboolean tagged_only)468 createConfigsFromProperties(Display * dpy, int nvisuals, int nprops,
469                             int screen, GLboolean tagged_only)
470 {
471    INT32 buf[__GLX_TOTAL_CONFIG], *props;
472    unsigned prop_size;
473    __GLcontextModes *modes, *m;
474    int i;
475 
476    if (nprops == 0)
477       return NULL;
478 
479    /* FIXME: Is the __GLX_MIN_CONFIG_PROPS test correct for FBconfigs? */
480 
481    /* Check number of properties */
482    if (nprops < __GLX_MIN_CONFIG_PROPS || nprops > __GLX_MAX_CONFIG_PROPS)
483       return NULL;
484 
485    /* Allocate memory for our config structure */
486    modes = _gl_context_modes_create(nvisuals, sizeof(__GLcontextModes));
487    if (!modes)
488       return NULL;
489 
490    prop_size = nprops * __GLX_SIZE_INT32;
491    if (prop_size <= sizeof(buf))
492       props = buf;
493    else
494       props = Xmalloc(prop_size);
495 
496    /* Read each config structure and convert it into our format */
497    m = modes;
498    for (i = 0; i < nvisuals; i++) {
499       _XRead(dpy, (char *) props, prop_size);
500       /* Older X servers don't send this so we default it here. */
501       m->drawableType = GLX_WINDOW_BIT;
502       __glXInitializeVisualConfigFromTags(m, nprops, props,
503                                      tagged_only, GL_TRUE);
504       m->screen = screen;
505       m = m->next;
506    }
507 
508    if (props != buf)
509       Xfree(props);
510 
511    return modes;
512 }
513 
514 static GLboolean
getFBConfigs(__GLXscreenConfigs * psc,__GLXdisplayPrivate * priv,int screen)515 getFBConfigs(__GLXscreenConfigs *psc, __GLXdisplayPrivate *priv, int screen)
516 {
517    xGLXGetFBConfigsReq *fb_req;
518    xGLXGetFBConfigsSGIXReq *sgi_req;
519    xGLXVendorPrivateWithReplyReq *vpreq;
520    xGLXGetFBConfigsReply reply;
521    Display *dpy = priv->dpy;
522 
523    psc->serverGLXexts =
524       __glXQueryServerString(dpy, priv->majorOpcode, screen, GLX_EXTENSIONS);
525 
526    LockDisplay(dpy);
527 
528    psc->configs = NULL;
529    if (atof(priv->serverGLXversion) >= 1.3) {
530       GetReq(GLXGetFBConfigs, fb_req);
531       fb_req->reqType = priv->majorOpcode;
532       fb_req->glxCode = X_GLXGetFBConfigs;
533       fb_req->screen = screen;
534    }
535    else if (strstr(psc->serverGLXexts, "GLX_SGIX_fbconfig") != NULL) {
536       GetReqExtra(GLXVendorPrivateWithReply,
537                   sz_xGLXGetFBConfigsSGIXReq +
538                   sz_xGLXVendorPrivateWithReplyReq, vpreq);
539       sgi_req = (xGLXGetFBConfigsSGIXReq *) vpreq;
540       sgi_req->reqType = priv->majorOpcode;
541       sgi_req->glxCode = X_GLXVendorPrivateWithReply;
542       sgi_req->vendorCode = X_GLXvop_GetFBConfigsSGIX;
543       sgi_req->screen = screen;
544    }
545    else
546       goto out;
547 
548    if (!_XReply(dpy, (xReply *) & reply, 0, False))
549       goto out;
550 
551    psc->configs = createConfigsFromProperties(dpy,
552                                               reply.numFBConfigs,
553                                               reply.numAttribs * 2,
554                                               screen, GL_TRUE);
555 
556  out:
557    UnlockDisplay(dpy);
558    return psc->configs != NULL;
559 }
560 
561 static GLboolean
AllocAndFetchScreenConfigs(Display * dpy,__GLXdisplayPrivate * priv)562 AllocAndFetchScreenConfigs(Display * dpy, __GLXdisplayPrivate * priv)
563 {
564    __GLXscreenConfigs *psc;
565    GLint i, screens;
566 
567    /*
568     ** First allocate memory for the array of per screen configs.
569     */
570    screens = ScreenCount(dpy);
571    priv->screenConfigs = Xmalloc(screens * sizeof *priv->screenConfigs);
572    if (!priv->screenConfigs) {
573       return GL_FALSE;
574    }
575 
576    priv->serverGLXversion =
577       __glXQueryServerString(dpy, priv->majorOpcode, 0, GLX_VERSION);
578    if (priv->serverGLXversion == NULL) {
579       FreeScreenConfigs(priv);
580       return GL_FALSE;
581    }
582 
583    for (i = 0; i < screens; i++) {
584       psc = Xcalloc(1, sizeof *psc);
585       if (!psc)
586          return GL_FALSE;
587       getFBConfigs(psc, priv, i);
588       priv->screenConfigs[i] = psc;
589    }
590 
591    SyncHandle();
592 
593    return GL_TRUE;
594 }
595 
596 _X_HIDDEN __GLXdisplayPrivate *
__glXInitialize(Display * dpy)597 __glXInitialize(Display * dpy)
598 {
599    XExtDisplayInfo *info = __glXFindDisplay(dpy);
600    XExtData **privList, *private, *found;
601    __GLXdisplayPrivate *dpyPriv;
602    XEDataObject dataObj;
603    int major, minor;
604 
605    if (!XextHasExtension(info))
606       return NULL;
607 
608    /* See if a display private already exists.  If so, return it */
609    dataObj.display = dpy;
610    privList = XEHeadOfExtensionList(dataObj);
611    found = XFindOnExtensionList(privList, info->codes->extension);
612    if (found)
613       return (__GLXdisplayPrivate *) found->private_data;
614 
615    /* See if the versions are compatible */
616    if (!QueryVersion(dpy, info->codes->major_opcode, &major, &minor))
617       return NULL;
618 
619    /*
620     ** Allocate memory for all the pieces needed for this buffer.
621     */
622    private = (XExtData *) Xmalloc(sizeof(XExtData));
623    if (!private)
624       return NULL;
625    dpyPriv = (__GLXdisplayPrivate *) Xcalloc(1, sizeof(__GLXdisplayPrivate));
626    if (!dpyPriv) {
627       Xfree(private);
628       return NULL;
629    }
630 
631    /*
632     ** Init the display private and then read in the screen config
633     ** structures from the server.
634     */
635    dpyPriv->majorOpcode = info->codes->major_opcode;
636    dpyPriv->dpy = dpy;
637 
638    if (!AllocAndFetchScreenConfigs(dpy, dpyPriv)) {
639       Xfree(dpyPriv);
640       Xfree(private);
641       return NULL;
642    }
643 
644    /*
645     ** Fill in the private structure.  This is the actual structure that
646     ** hangs off of the Display structure.  Our private structure is
647     ** referred to by this structure.  Got that?
648     */
649    private->number = info->codes->extension;
650    private->next = 0;
651    private->free_private = __glXFreeDisplayPrivate;
652    private->private_data = (char *) dpyPriv;
653    XAddToExtensionList(privList, private);
654 
655    return dpyPriv;
656 }
657 
658 #endif /* GLX_DIRECT_RENDERING */
659