ba6132788a7fd9e58ba8ebc119a7f0b820280f83
[mesa.git] / src / gallium / state_trackers / egl / x11 / glxinit.c
1 /**
2 * GLX initialization. Code based on glxext.c, glx_query.c, and
3 * glcontextmodes.c under src/glx/x11/. 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 typedef 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
33 static char *__glXExtensionName = GLX_EXTENSION_NAME;
34 static XExtensionInfo *__glXExtensionInfo = NULL;
35
36 static int
37 __glXCloseDisplay(Display * dpy, XExtCodes * codes)
38 {
39 return XextRemoveDisplay(__glXExtensionInfo, dpy);
40 }
41
42 static /* 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
56 XEXT_GENERATE_FIND_DISPLAY(__glXFindDisplay, __glXExtensionInfo,
57 __glXExtensionName, &__glXExtensionHooks,
58 __GLX_NUMBER_EVENTS, NULL)
59
60 static 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
74 static __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 */
179 static void
180 FreeScreenConfigs(__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 */
207 static 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 */
233 static Bool
234 QueryVersion(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
457 static __GLcontextModes *
458 createConfigsFromProperties(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
504 static GLboolean
505 getVisualConfigs(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
533 static GLboolean
534 getFBConfigs(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
581 static GLboolean
582 AllocAndFetchScreenConfigs(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 }