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