• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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