glxinit.c revision e3c1c5377c7fcd17085bfb22fbc1cf30646751ba
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
27typedef 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
41static char *__glXExtensionName = GLX_EXTENSION_NAME;
42static XExtensionInfo *__glXExtensionInfo = NULL;
43
44static int
45__glXCloseDisplay(Display * dpy, XExtCodes * codes)
46{
47   return XextRemoveDisplay(__glXExtensionInfo, dpy);
48}
49
50static /* 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
64static XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo,
65				  __glXExtensionName, &__glXExtensionHooks,
66				  __GLX_NUMBER_EVENTS, NULL)
67
68static GLint
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
82static void
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
93static __GLcontextModes *
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
136static char *
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*/
187static void
188FreeScreenConfigs(__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*/
213static int
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
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#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
272static void
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
467static __GLcontextModes *
468createConfigsFromProperties(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
514static GLboolean
515getFBConfigs(__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
561static GLboolean
562AllocAndFetchScreenConfigs(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 *
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