1 /*
2 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
3 * Copyright © 2008 Red Hat, Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Soft-
7 * ware"), to deal in the Software without restriction, including without
8 * limitation the rights to use, copy, modify, merge, publish, distribute,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, provided that the above copyright
11 * notice(s) and this permission notice appear in all copies of the Soft-
12 * ware and that both the above copyright notice(s) and this permission
13 * notice appear in supporting documentation.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
18 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
19 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
20 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
23 * MANCE OF THIS SOFTWARE.
24 *
25 * Except as contained in this notice, the name of a copyright holder shall
26 * not be used in advertising or otherwise to promote the sale, use or
27 * other dealings in this Software without prior written authorization of
28 * the copyright holder.
29 *
30 * Authors:
31 * Kevin E. Martin <kevin@precisioninsight.com>
32 * Brian Paul <brian@precisioninsight.com>
33 * Kristian Høgsberg (krh@redhat.com)
34 */
35
36 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
37
38 #include <unistd.h>
39 #include <dlfcn.h>
40 #include <stdarg.h>
41 #include "glxclient.h"
42 #include "dri_common.h"
43 #include "loader.h"
44 #include <X11/Xlib-xcb.h>
45 #include <xcb/xproto.h>
46
47 #ifndef RTLD_NOW
48 #define RTLD_NOW 0
49 #endif
50 #ifndef RTLD_GLOBAL
51 #define RTLD_GLOBAL 0
52 #endif
53
54 #ifndef GL_LIB_NAME
55 #define GL_LIB_NAME "libGL.so.1"
56 #endif
57
58 /**
59 * Try to \c dlopen the named driver.
60 *
61 * This function adds the "_dri.so" suffix to the driver name and searches the
62 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
63 * order to find the driver.
64 *
65 * \param driverName - a name like "i965", "radeon", "nouveau", etc.
66 * \param out_driver_handle - Address to return the resulting dlopen() handle.
67 *
68 * \returns
69 * The __DRIextension entrypoint table for the driver, or \c NULL if driver
70 * file not found.
71 */
72 _X_HIDDEN const __DRIextension **
driOpenDriver(const char * driverName,void ** out_driver_handle)73 driOpenDriver(const char *driverName, void **out_driver_handle)
74 {
75 void *glhandle;
76
77 /* Attempt to make sure libGL symbols will be visible to the driver */
78 glhandle = dlopen(GL_LIB_NAME, RTLD_NOW | RTLD_GLOBAL);
79
80 static const char *search_path_vars[] = {
81 "LIBGL_DRIVERS_PATH",
82 "LIBGL_DRIVERS_DIR", /* deprecated */
83 NULL
84 };
85
86 const __DRIextension **extensions =
87 loader_open_driver(driverName, out_driver_handle, search_path_vars);
88
89 if (glhandle)
90 dlclose(glhandle);
91
92 return extensions;
93 }
94
95 #define __ATTRIB(attrib, field) \
96 { attrib, offsetof(struct glx_config, field) }
97
98 static const struct
99 {
100 unsigned int attrib, offset;
101 } attribMap[] = {
102 __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
103 __ATTRIB(__DRI_ATTRIB_LEVEL, level),
104 __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
105 __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
106 __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
107 __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
108 __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
109 __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
110 __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
111 __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
112 __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
113 __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
114 __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
115 __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
116 __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
117 __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
118 __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
119 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
120 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
121 __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture),
122 __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
123 __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable)
124 };
125
126 static int
scalarEqual(struct glx_config * mode,unsigned int attrib,unsigned int value)127 scalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value)
128 {
129 unsigned glxValue, i;
130
131 for (i = 0; i < ARRAY_SIZE(attribMap); i++)
132 if (attribMap[i].attrib == attrib) {
133 glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset);
134 return glxValue == GLX_DONT_CARE || glxValue == value;
135 }
136
137 return GL_TRUE; /* Is a non-existing attribute equal to value? */
138 }
139
140 static int
driConfigEqual(const __DRIcoreExtension * core,struct glx_config * config,const __DRIconfig * driConfig)141 driConfigEqual(const __DRIcoreExtension *core,
142 struct glx_config *config, const __DRIconfig *driConfig)
143 {
144 unsigned int attrib, value, glxValue;
145 int i;
146
147 i = 0;
148 while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) {
149 switch (attrib) {
150 case __DRI_ATTRIB_RENDER_TYPE:
151 glxValue = 0;
152 if (value & __DRI_ATTRIB_RGBA_BIT) {
153 glxValue |= GLX_RGBA_BIT;
154 }
155 if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) {
156 glxValue |= GLX_COLOR_INDEX_BIT;
157 }
158 if (value & __DRI_ATTRIB_FLOAT_BIT) {
159 glxValue |= GLX_RGBA_FLOAT_BIT_ARB;
160 }
161 if (value & __DRI_ATTRIB_UNSIGNED_FLOAT_BIT) {
162 glxValue |= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT;
163 }
164 if (glxValue != config->renderType)
165 return GL_FALSE;
166 break;
167
168 case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS:
169 glxValue = 0;
170 if (value & __DRI_ATTRIB_TEXTURE_1D_BIT)
171 glxValue |= GLX_TEXTURE_1D_BIT_EXT;
172 if (value & __DRI_ATTRIB_TEXTURE_2D_BIT)
173 glxValue |= GLX_TEXTURE_2D_BIT_EXT;
174 if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT)
175 glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT;
176 if (config->bindToTextureTargets != GLX_DONT_CARE &&
177 glxValue != config->bindToTextureTargets)
178 return GL_FALSE;
179 break;
180
181 /* Nerf some attributes we can safely ignore if the server claims to
182 * support them but the driver does not.
183 */
184 case __DRI_ATTRIB_CONFIG_CAVEAT:
185 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
186 glxValue = GLX_NON_CONFORMANT_CONFIG;
187 else if (value & __DRI_ATTRIB_SLOW_BIT)
188 glxValue = GLX_SLOW_CONFIG;
189 else
190 glxValue = GLX_NONE;
191 if (glxValue != config->visualRating) {
192 if (config->visualRating == GLX_NONE) {
193 static int warned;
194 if (!warned) {
195 DebugMessageF("Not downgrading visual rating\n");
196 warned = 1;
197 }
198 } else {
199 return GL_FALSE;
200 }
201 }
202 break;
203
204 case __DRI_ATTRIB_AUX_BUFFERS:
205 if (!scalarEqual(config, attrib, value)) {
206 static int warned;
207 if (!warned) {
208 DebugMessageF("Disabling server's aux buffer support\n");
209 warned = 1;
210 }
211 config->numAuxBuffers = 0;
212 }
213 break;
214
215 case __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE:
216 if (!scalarEqual(config, attrib, value)) {
217 static int warned;
218 if (!warned) {
219 DebugMessageF("Disabling server's tfp mipmap support\n");
220 warned = 1;
221 }
222 config->bindToMipmapTexture = 0;
223 }
224 break;
225
226 default:
227 if (!scalarEqual(config, attrib, value))
228 return GL_FALSE;
229 }
230 }
231
232 return GL_TRUE;
233 }
234
235 static struct glx_config *
createDriMode(const __DRIcoreExtension * core,struct glx_config * config,const __DRIconfig ** driConfigs)236 createDriMode(const __DRIcoreExtension * core,
237 struct glx_config *config, const __DRIconfig **driConfigs)
238 {
239 __GLXDRIconfigPrivate *driConfig;
240 int i;
241
242 for (i = 0; driConfigs[i]; i++) {
243 if (driConfigEqual(core, config, driConfigs[i]))
244 break;
245 }
246
247 if (driConfigs[i] == NULL)
248 return NULL;
249
250 driConfig = malloc(sizeof *driConfig);
251 if (driConfig == NULL)
252 return NULL;
253
254 driConfig->base = *config;
255 driConfig->driConfig = driConfigs[i];
256
257 return &driConfig->base;
258 }
259
260 _X_HIDDEN struct glx_config *
driConvertConfigs(const __DRIcoreExtension * core,struct glx_config * configs,const __DRIconfig ** driConfigs)261 driConvertConfigs(const __DRIcoreExtension * core,
262 struct glx_config *configs, const __DRIconfig **driConfigs)
263 {
264 struct glx_config head, *tail, *m;
265
266 tail = &head;
267 head.next = NULL;
268 for (m = configs; m; m = m->next) {
269 tail->next = createDriMode(core, m, driConfigs);
270 if (tail->next == NULL) {
271 /* no matching dri config for m */
272 continue;
273 }
274
275
276 tail = tail->next;
277 }
278
279 return head.next;
280 }
281
282 _X_HIDDEN void
driDestroyConfigs(const __DRIconfig ** configs)283 driDestroyConfigs(const __DRIconfig **configs)
284 {
285 int i;
286
287 for (i = 0; configs[i]; i++)
288 free((__DRIconfig *) configs[i]);
289 free(configs);
290 }
291
292 static struct glx_config *
driInferDrawableConfig(struct glx_screen * psc,GLXDrawable draw)293 driInferDrawableConfig(struct glx_screen *psc, GLXDrawable draw)
294 {
295 unsigned int fbconfig = 0;
296 xcb_get_window_attributes_cookie_t cookie = { 0 };
297 xcb_get_window_attributes_reply_t *attr = NULL;
298 xcb_connection_t *conn = XGetXCBConnection(psc->dpy);
299
300 /* In practice here, either the XID is a bare Window or it was created
301 * by some other client. First let's see if the X server can tell us
302 * the answer. Xorg first added GLX_EXT_no_config_context in 1.20, where
303 * this usually works except for bare Windows that haven't been made
304 * current yet.
305 */
306 if (__glXGetDrawableAttribute(psc->dpy, draw, GLX_FBCONFIG_ID, &fbconfig)) {
307 return glx_config_find_fbconfig(psc->configs, fbconfig);
308 }
309
310 /* Well this had better be a Window then. Figure out its visual and
311 * then find the corresponding GLX visual.
312 */
313 cookie = xcb_get_window_attributes(conn, draw);
314 attr = xcb_get_window_attributes_reply(conn, cookie, NULL);
315
316 if (attr) {
317 uint32_t vid = attr->visual;
318 free(attr);
319 return glx_config_find_visual(psc->visuals, vid);
320 }
321
322 return NULL;
323 }
324
325 _X_HIDDEN __GLXDRIdrawable *
driFetchDrawable(struct glx_context * gc,GLXDrawable glxDrawable)326 driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable)
327 {
328 Display *dpy = gc->psc->dpy;
329 struct glx_display *const priv = __glXInitialize(dpy);
330 __GLXDRIdrawable *pdraw;
331 struct glx_screen *psc = gc->psc;
332 struct glx_config *config = gc->config;
333 unsigned int type;
334
335 if (priv == NULL)
336 return NULL;
337
338 if (glxDrawable == None)
339 return NULL;
340
341 if (priv->drawHash == NULL)
342 return NULL;
343
344 if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) {
345 /* Resurrected, so remove from the alive-query-set if exist. */
346 _mesa_set_remove_key(priv->zombieGLXDrawable, pdraw);
347
348 pdraw->refcount ++;
349 return pdraw;
350 }
351
352 /* if this is a no-config context, infer the fbconfig from the drawable */
353 if (config == NULL)
354 config = driInferDrawableConfig(psc, glxDrawable);
355 if (config == NULL)
356 return NULL;
357
358 /* We can't find this GLX drawable above because it's either:
359 *
360 * 1. An X window ID instead of a GLX window ID. This could happend when
361 * glXMakeCurrent() is passed an X window directly instead of creating
362 * GLXWindow with glXCreateWindow() first.
363 *
364 * 2. A GLXPbuffer created on other display:
365 *
366 * From the GLX spec:
367 *
368 * Like other drawable types, GLXPbuffers are shared; any client which
369 * knows the associated XID can use a GLXPbuffer.
370 *
371 * So client other than the creator of this GLXPbuffer could use its
372 * XID to do something like glXMakeCurrent(). I can't find explicite
373 * statement in GLX spec that also allow GLXWindow and GLXPixmap.
374 *
375 * But even GLXWindow and GLXPixmap is allowed, currently client other
376 * than the GLX drawable creator has no way to find which X drawable
377 * (window or pixmap) this GLX drawable uses, except the GLXPbuffer
378 * case which use the same XID for both X pixmap and GLX drawable.
379 */
380
381 /* Infer the GLX drawable type. */
382 if (__glXGetDrawableAttribute(dpy, glxDrawable, GLX_DRAWABLE_TYPE, &type)) {
383 /* Xserver may support query with raw X11 window. */
384 if (type == GLX_PIXMAP_BIT) {
385 ErrorMessageF("GLXPixmap drawable type is not supported\n");
386 return NULL;
387 }
388 } else {
389 /* Xserver may not implement GLX_DRAWABLE_TYPE query yet. */
390 type = GLX_PBUFFER_BIT | GLX_WINDOW_BIT;
391 }
392
393 pdraw = psc->driScreen->createDrawable(psc, glxDrawable, glxDrawable,
394 type, config);
395
396 if (pdraw == NULL) {
397 ErrorMessageF("failed to create drawable\n");
398 return NULL;
399 }
400
401 if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) {
402 pdraw->destroyDrawable(pdraw);
403 return NULL;
404 }
405 pdraw->refcount = 1;
406
407 return pdraw;
408 }
409
410 static int
discardGLXBadDrawableHandler(Display * display,xError * err,XExtCodes * codes,int * ret_code)411 discardGLXBadDrawableHandler(Display *display, xError *err, XExtCodes *codes,
412 int *ret_code)
413 {
414 int code = codes->first_error + GLXBadDrawable;
415
416 /* Only discard error which is expected. */
417 if (err->majorCode == codes->major_opcode &&
418 err->minorCode == X_GLXGetDrawableAttributes &&
419 /* newer xserver use GLXBadDrawable, old one use BadDrawable */
420 (err->errorCode == code || err->errorCode == BadDrawable)) {
421 *ret_code = 1;
422 return 1;
423 }
424
425 return 0;
426 }
427
428 static void
checkServerGLXDrawableAlive(const struct glx_display * priv)429 checkServerGLXDrawableAlive(const struct glx_display *priv)
430 {
431 ErrorType old = XESetError(priv->dpy, priv->codes.extension,
432 discardGLXBadDrawableHandler);
433
434 set_foreach(priv->zombieGLXDrawable, entry) {
435 __GLXDRIdrawable *pdraw = (__GLXDRIdrawable *)entry->key;
436 GLXDrawable drawable = pdraw->drawable;
437 unsigned int dummy;
438
439 /* Fail to query, so the window has been closed. Release the GLXDrawable. */
440 if (!__glXGetDrawableAttribute(priv->dpy, drawable, GLX_WIDTH, &dummy)) {
441 pdraw->destroyDrawable(pdraw);
442 __glxHashDelete(priv->drawHash, drawable);
443 _mesa_set_remove(priv->zombieGLXDrawable, entry);
444 }
445 }
446
447 XESetError(priv->dpy, priv->codes.extension, old);
448 }
449
450 static void
releaseDrawable(const struct glx_display * priv,GLXDrawable drawable)451 releaseDrawable(const struct glx_display *priv, GLXDrawable drawable)
452 {
453 __GLXDRIdrawable *pdraw;
454
455 if (__glxHashLookup(priv->drawHash, drawable, (void *) &pdraw) == 0) {
456 /* Only native window and pbuffer have same GLX and X11 drawable ID. */
457 if (pdraw->drawable == pdraw->xDrawable) {
458 pdraw->refcount --;
459 /* If pbuffer's refcount reaches 0, it must be imported from other
460 * display. Because pbuffer created from this display will always
461 * hold the last refcount until destroy the GLXPbuffer object.
462 */
463 if (pdraw->refcount == 0) {
464 if (pdraw->psc->keep_native_window_glx_drawable) {
465 checkServerGLXDrawableAlive(priv);
466 _mesa_set_add(priv->zombieGLXDrawable, pdraw);
467 } else {
468 pdraw->destroyDrawable(pdraw);
469 __glxHashDelete(priv->drawHash, drawable);
470 }
471 }
472 }
473 }
474 }
475
476 _X_HIDDEN void
driReleaseDrawables(struct glx_context * gc)477 driReleaseDrawables(struct glx_context *gc)
478 {
479 const struct glx_display *priv = gc->psc->display;
480
481 releaseDrawable(priv, gc->currentDrawable);
482 releaseDrawable(priv, gc->currentReadable);
483
484 gc->currentDrawable = None;
485 gc->currentReadable = None;
486
487 }
488
489 _X_HIDDEN int
dri_convert_glx_attribs(unsigned num_attribs,const uint32_t * attribs,struct dri_ctx_attribs * dca)490 dri_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs,
491 struct dri_ctx_attribs *dca)
492 {
493 unsigned i;
494 uint32_t profile = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
495
496 dca->major_ver = 1;
497 dca->minor_ver = 0;
498 dca->render_type = GLX_RGBA_TYPE;
499 dca->reset = __DRI_CTX_RESET_NO_NOTIFICATION;
500 dca->release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
501 dca->flags = 0;
502 dca->api = __DRI_API_OPENGL;
503 dca->no_error = 0;
504
505 for (i = 0; i < num_attribs; i++) {
506 switch (attribs[i * 2]) {
507 case GLX_CONTEXT_MAJOR_VERSION_ARB:
508 dca->major_ver = attribs[i * 2 + 1];
509 break;
510 case GLX_CONTEXT_MINOR_VERSION_ARB:
511 dca->minor_ver = attribs[i * 2 + 1];
512 break;
513 case GLX_CONTEXT_FLAGS_ARB:
514 dca->flags = attribs[i * 2 + 1];
515 break;
516 case GLX_CONTEXT_OPENGL_NO_ERROR_ARB:
517 dca->no_error = attribs[i * 2 + 1];
518 break;
519 case GLX_CONTEXT_PROFILE_MASK_ARB:
520 profile = attribs[i * 2 + 1];
521 break;
522 case GLX_RENDER_TYPE:
523 dca->render_type = attribs[i * 2 + 1];
524 break;
525 case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB:
526 switch (attribs[i * 2 + 1]) {
527 case GLX_NO_RESET_NOTIFICATION_ARB:
528 dca->reset = __DRI_CTX_RESET_NO_NOTIFICATION;
529 break;
530 case GLX_LOSE_CONTEXT_ON_RESET_ARB:
531 dca->reset = __DRI_CTX_RESET_LOSE_CONTEXT;
532 break;
533 default:
534 return BadValue;
535 }
536 break;
537 case GLX_CONTEXT_RELEASE_BEHAVIOR_ARB:
538 switch (attribs[i * 2 + 1]) {
539 case GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB:
540 dca->release = __DRI_CTX_RELEASE_BEHAVIOR_NONE;
541 break;
542 case GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB:
543 dca->release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
544 break;
545 default:
546 return BadValue;
547 }
548 break;
549 case GLX_SCREEN:
550 /* Implies GLX_EXT_no_config_context */
551 dca->render_type = GLX_DONT_CARE;
552 break;
553 default:
554 /* If an unknown attribute is received, fail.
555 */
556 return BadValue;
557 }
558 }
559
560 switch (profile) {
561 case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
562 /* This is the default value, but there are no profiles before OpenGL
563 * 3.2. The GLX_ARB_create_context_profile spec says:
564 *
565 * "If the requested OpenGL version is less than 3.2,
566 * GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
567 * of the context is determined solely by the requested version."
568 */
569 dca->api = (dca->major_ver > 3 || (dca->major_ver == 3 && dca->minor_ver >= 2))
570 ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL;
571 break;
572 case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
573 dca->api = __DRI_API_OPENGL;
574 break;
575 case GLX_CONTEXT_ES_PROFILE_BIT_EXT:
576 if (dca->major_ver >= 3)
577 dca->api = __DRI_API_GLES3;
578 else if (dca->major_ver == 2 && dca->minor_ver == 0)
579 dca->api = __DRI_API_GLES2;
580 else if (dca->major_ver == 1 && dca->minor_ver < 2)
581 dca->api = __DRI_API_GLES;
582 else {
583 return BadValue;
584 }
585 break;
586 default:
587 return GLXBadProfileARB;
588 }
589
590 /* Unknown flag value */
591 if (dca->flags & ~(__DRI_CTX_FLAG_DEBUG |
592 __DRI_CTX_FLAG_FORWARD_COMPATIBLE |
593 __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS |
594 __DRI_CTX_FLAG_RESET_ISOLATION))
595 return BadValue;
596
597 /* There are no forward-compatible contexts before OpenGL 3.0. The
598 * GLX_ARB_create_context spec says:
599 *
600 * "Forward-compatible contexts are defined only for OpenGL versions
601 * 3.0 and later."
602 */
603 if (dca->major_ver < 3 && (dca->flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0)
604 return BadMatch;
605
606 /* It also says:
607 *
608 * "OpenGL contexts supporting version 3.0 or later of the API do not
609 * support color index rendering, even if a color index <config> is
610 * available."
611 */
612 if (dca->major_ver >= 3 && dca->render_type == GLX_COLOR_INDEX_TYPE)
613 return BadMatch;
614
615 /* The KHR_no_error specs say:
616 *
617 * Requires OpenGL ES 2.0 or OpenGL 2.0.
618 */
619 if (dca->no_error && dca->major_ver < 2)
620 return BadMatch;
621
622 /* The GLX_ARB_create_context_no_error specs say:
623 *
624 * BadMatch is generated if the GLX_CONTEXT_OPENGL_NO_ERROR_ARB is TRUE at
625 * the same time as a debug or robustness context is specified.
626 *
627 */
628 if (dca->no_error && ((dca->flags & __DRI_CTX_FLAG_DEBUG) ||
629 (dca->flags & __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)))
630 return BadMatch;
631
632 return Success;
633 }
634
635 unsigned
dri_context_error_to_glx_error(unsigned error)636 dri_context_error_to_glx_error(unsigned error)
637 {
638 if (error == __DRI_CTX_ERROR_SUCCESS)
639 return Success;
640 if (error == __DRI_CTX_ERROR_NO_MEMORY)
641 return BadAlloc;
642 else if (error == __DRI_CTX_ERROR_BAD_API)
643 return BadMatch;
644 else if (error == __DRI_CTX_ERROR_BAD_VERSION)
645 return GLXBadFBConfig;
646 else if (error == __DRI_CTX_ERROR_BAD_FLAG)
647 return BadMatch;
648 else if (error == __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE)
649 return BadValue;
650 else if (error == __DRI_CTX_ERROR_UNKNOWN_FLAG)
651 return BadValue;
652 else
653 unreachable("Impossible DRI context error");
654 }
655
656 struct glx_context *
dri_common_create_context(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,int renderType)657 dri_common_create_context(struct glx_screen *base,
658 struct glx_config *config_base,
659 struct glx_context *shareList,
660 int renderType)
661 {
662 unsigned int error;
663 uint32_t attribs[2] = { GLX_RENDER_TYPE, renderType };
664
665 return base->vtable->create_context_attribs(base, config_base, shareList,
666 1, attribs, &error);
667 }
668
669
670 /*
671 * Given a display pointer and screen number, determine the name of
672 * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc).
673 * Return True for success, False for failure.
674 */
675 static Bool
driGetDriverName(Display * dpy,int scrNum,char ** driverName)676 driGetDriverName(Display * dpy, int scrNum, char **driverName)
677 {
678 struct glx_screen *glx_screen = GetGLXScreenConfigs(dpy, scrNum);
679
680 if (!glx_screen || !glx_screen->vtable->get_driver_name)
681 return False;
682
683 *driverName = glx_screen->vtable->get_driver_name(glx_screen);
684 return True;
685 }
686
687 /*
688 * Exported function for querying the DRI driver for a given screen.
689 *
690 * The returned char pointer points to a static array that will be
691 * overwritten by subsequent calls.
692 */
693 _GLX_PUBLIC const char *
glXGetScreenDriver(Display * dpy,int scrNum)694 glXGetScreenDriver(Display * dpy, int scrNum)
695 {
696 static char ret[32];
697 char *driverName;
698
699 if (driGetDriverName(dpy, scrNum, &driverName)) {
700 int len;
701 if (!driverName)
702 return NULL;
703 len = strlen(driverName);
704 if (len >= 31)
705 return NULL;
706 memcpy(ret, driverName, len + 1);
707 free(driverName);
708 return ret;
709 }
710 return NULL;
711 }
712
713 /* glXGetDriverConfig must return a pointer with a static lifetime. To avoid
714 * keeping drivers loaded and other leaks, we keep a cache of results here that
715 * is cleared by an atexit handler.
716 */
717 struct driver_config_entry {
718 struct driver_config_entry *next;
719 char *driverName;
720 char *config;
721 };
722
723 static pthread_mutex_t driver_config_mutex = PTHREAD_MUTEX_INITIALIZER;
724 static struct driver_config_entry *driver_config_cache = NULL;
725
726 /* Called as an atexit function. Otherwise, this would have to be called with
727 * driver_config_mutex locked.
728 */
729 static void
clear_driver_config_cache()730 clear_driver_config_cache()
731 {
732 while (driver_config_cache) {
733 struct driver_config_entry *e = driver_config_cache;
734 driver_config_cache = e->next;
735
736 free(e->driverName);
737 free(e->config);
738 free(e);
739 }
740 }
741
742 static char *
get_driver_config(const char * driverName)743 get_driver_config(const char *driverName)
744 {
745 void *handle;
746 char *config = NULL;
747 const __DRIextension **extensions = driOpenDriver(driverName, &handle);
748 if (extensions) {
749 for (int i = 0; extensions[i]; i++) {
750 if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) != 0)
751 continue;
752
753 __DRIconfigOptionsExtension *ext =
754 (__DRIconfigOptionsExtension *)extensions[i];
755
756 if (ext->base.version >= 2)
757 config = ext->getXml(driverName);
758
759 break;
760 }
761 }
762
763 dlclose(handle);
764
765 return config;
766 }
767
768 /*
769 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
770 *
771 * The returned char pointer points directly into the driver. Therefore
772 * it should be treated as a constant.
773 *
774 * If the driver was not found or does not support configuration NULL is
775 * returned.
776 */
777 _GLX_PUBLIC const char *
glXGetDriverConfig(const char * driverName)778 glXGetDriverConfig(const char *driverName)
779 {
780 struct driver_config_entry *e;
781
782 pthread_mutex_lock(&driver_config_mutex);
783
784 for (e = driver_config_cache; e; e = e->next) {
785 if (strcmp(e->driverName, driverName) == 0)
786 goto out;
787 }
788
789 e = malloc(sizeof(*e));
790 if (!e)
791 goto out;
792
793 e->config = get_driver_config(driverName);
794 e->driverName = strdup(driverName);
795 if (!e->config || !e->driverName) {
796 free(e->config);
797 free(e->driverName);
798 free(e);
799 e = NULL;
800 goto out;
801 }
802
803 e->next = driver_config_cache;
804 driver_config_cache = e;
805
806 if (!e->next)
807 atexit(clear_driver_config_cache);
808
809 out:
810 pthread_mutex_unlock(&driver_config_mutex);
811
812 return e ? e->config : NULL;
813 }
814
815 #endif /* GLX_DIRECT_RENDERING */
816