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