• 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 
45 #ifndef RTLD_NOW
46 #define RTLD_NOW 0
47 #endif
48 #ifndef RTLD_GLOBAL
49 #define RTLD_GLOBAL 0
50 #endif
51 
52 _X_HIDDEN void
dri_message(int level,const char * f,...)53 dri_message(int level, const char *f, ...)
54 {
55    va_list args;
56    int threshold = _LOADER_WARNING;
57    const char *libgl_debug;
58 
59    libgl_debug = getenv("LIBGL_DEBUG");
60    if (libgl_debug) {
61       if (strstr(libgl_debug, "quiet"))
62          threshold = _LOADER_FATAL;
63       else if (strstr(libgl_debug, "verbose"))
64          threshold = _LOADER_DEBUG;
65    }
66 
67    /* Note that the _LOADER_* levels are lower numbers for more severe. */
68    if (level <= threshold) {
69       fprintf(stderr, "libGL%s: ", level <= _LOADER_WARNING ? " error" : "");
70       va_start(args, f);
71       vfprintf(stderr, f, args);
72       va_end(args);
73    }
74 }
75 
76 #ifndef GL_LIB_NAME
77 #define GL_LIB_NAME "libGL.so.1"
78 #endif
79 
80 /**
81  * Try to \c dlopen the named driver.
82  *
83  * This function adds the "_dri.so" suffix to the driver name and searches the
84  * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
85  * order to find the driver.
86  *
87  * \param driverName - a name like "i965", "radeon", "nouveau", etc.
88  * \param out_driver_handle - Address to return the resulting dlopen() handle.
89  *
90  * \returns
91  * The __DRIextension entrypoint table for the driver, or \c NULL if driver
92  * file not found.
93  */
94 _X_HIDDEN const __DRIextension **
driOpenDriver(const char * driverName,void ** out_driver_handle)95 driOpenDriver(const char *driverName, void **out_driver_handle)
96 {
97    void *glhandle;
98 
99    /* Attempt to make sure libGL symbols will be visible to the driver */
100    glhandle = dlopen(GL_LIB_NAME, RTLD_NOW | RTLD_GLOBAL);
101 
102    static const char *search_path_vars[] = {
103       "LIBGL_DRIVERS_PATH",
104       "LIBGL_DRIVERS_DIR", /* deprecated */
105       NULL
106    };
107 
108    const __DRIextension **extensions =
109       loader_open_driver(driverName, out_driver_handle, search_path_vars);
110 
111    if (glhandle)
112       dlclose(glhandle);
113 
114    return extensions;
115 }
116 
117 #define __ATTRIB(attrib, field) \
118     { attrib, offsetof(struct glx_config, field) }
119 
120 static const struct
121 {
122    unsigned int attrib, offset;
123 } attribMap[] = {
124    __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
125       __ATTRIB(__DRI_ATTRIB_LEVEL, level),
126       __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
127       __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
128       __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
129       __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
130       __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
131       __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
132       __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
133       __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
134       __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
135       __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
136       __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
137       __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
138       __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
139       __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
140       __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
141 #if 0
142       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel),
143       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentIndex),
144       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed),
145       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen),
146       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue),
147       __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
148       __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask),
149       __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask),
150       __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask),
151       __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask),
152       __ATTRIB(__DRI_ATTRIB_RED_SHIFT, redShift),
153       __ATTRIB(__DRI_ATTRIB_GREEN_SHIFT, greenShift),
154       __ATTRIB(__DRI_ATTRIB_BLUE_SHIFT, blueShift),
155       __ATTRIB(__DRI_ATTRIB_ALPHA_SHIFT, alphaShift),
156 #endif
157       __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth),
158       __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
159       __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels),
160       __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth),
161       __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight),
162       __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod),
163       __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
164       __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
165       __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE,
166                      bindToMipmapTexture),
167       __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
168       __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable)
169 };
170 
171 static int
scalarEqual(struct glx_config * mode,unsigned int attrib,unsigned int value)172 scalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value)
173 {
174    unsigned glxValue, i;
175 
176    for (i = 0; i < ARRAY_SIZE(attribMap); i++)
177       if (attribMap[i].attrib == attrib) {
178          glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset);
179          return glxValue == GLX_DONT_CARE || glxValue == value;
180       }
181 
182    return GL_TRUE;              /* Is a non-existing attribute equal to value? */
183 }
184 
185 static int
driConfigEqual(const __DRIcoreExtension * core,struct glx_config * config,const __DRIconfig * driConfig)186 driConfigEqual(const __DRIcoreExtension *core,
187                struct glx_config *config, const __DRIconfig *driConfig)
188 {
189    unsigned int attrib, value, glxValue;
190    int i;
191 
192    i = 0;
193    while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) {
194       switch (attrib) {
195       case __DRI_ATTRIB_RENDER_TYPE:
196          glxValue = 0;
197          if (value & __DRI_ATTRIB_RGBA_BIT) {
198             glxValue |= GLX_RGBA_BIT;
199          }
200          if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) {
201             glxValue |= GLX_COLOR_INDEX_BIT;
202          }
203          if (value & __DRI_ATTRIB_FLOAT_BIT) {
204             glxValue |= GLX_RGBA_FLOAT_BIT_ARB;
205          }
206          if (value & __DRI_ATTRIB_UNSIGNED_FLOAT_BIT) {
207             glxValue |= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT;
208          }
209          if (glxValue != config->renderType)
210             return GL_FALSE;
211          break;
212 
213       case __DRI_ATTRIB_CONFIG_CAVEAT:
214          if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
215             glxValue = GLX_NON_CONFORMANT_CONFIG;
216          else if (value & __DRI_ATTRIB_SLOW_BIT)
217             glxValue = GLX_SLOW_CONFIG;
218          else
219             glxValue = GLX_NONE;
220          if (glxValue != config->visualRating)
221             return GL_FALSE;
222          break;
223 
224       case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS:
225          glxValue = 0;
226          if (value & __DRI_ATTRIB_TEXTURE_1D_BIT)
227             glxValue |= GLX_TEXTURE_1D_BIT_EXT;
228          if (value & __DRI_ATTRIB_TEXTURE_2D_BIT)
229             glxValue |= GLX_TEXTURE_2D_BIT_EXT;
230          if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT)
231             glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT;
232          if (config->bindToTextureTargets != GLX_DONT_CARE &&
233              glxValue != config->bindToTextureTargets)
234             return GL_FALSE;
235          break;
236 
237       case __DRI_ATTRIB_SWAP_METHOD:
238          if (value == __DRI_ATTRIB_SWAP_EXCHANGE)
239             glxValue = GLX_SWAP_EXCHANGE_OML;
240          else if (value == __DRI_ATTRIB_SWAP_COPY)
241             glxValue = GLX_SWAP_COPY_OML;
242          else
243             glxValue = GLX_SWAP_UNDEFINED_OML;
244 
245          if (!scalarEqual(config, attrib, glxValue))
246             return GL_FALSE;
247 
248          break;
249 
250       default:
251          if (!scalarEqual(config, attrib, value))
252             return GL_FALSE;
253       }
254    }
255 
256    return GL_TRUE;
257 }
258 
259 static struct glx_config *
createDriMode(const __DRIcoreExtension * core,struct glx_config * config,const __DRIconfig ** driConfigs)260 createDriMode(const __DRIcoreExtension * core,
261 	      struct glx_config *config, const __DRIconfig **driConfigs)
262 {
263    __GLXDRIconfigPrivate *driConfig;
264    int i;
265 
266    for (i = 0; driConfigs[i]; i++) {
267       if (driConfigEqual(core, config, driConfigs[i]))
268          break;
269    }
270 
271    if (driConfigs[i] == NULL)
272       return NULL;
273 
274    driConfig = malloc(sizeof *driConfig);
275    if (driConfig == NULL)
276       return NULL;
277 
278    driConfig->base = *config;
279    driConfig->driConfig = driConfigs[i];
280 
281    return &driConfig->base;
282 }
283 
284 _X_HIDDEN struct glx_config *
driConvertConfigs(const __DRIcoreExtension * core,struct glx_config * configs,const __DRIconfig ** driConfigs)285 driConvertConfigs(const __DRIcoreExtension * core,
286                   struct glx_config *configs, const __DRIconfig **driConfigs)
287 {
288    struct glx_config head, *tail, *m;
289 
290    tail = &head;
291    head.next = NULL;
292    for (m = configs; m; m = m->next) {
293       tail->next = createDriMode(core, m, driConfigs);
294       if (tail->next == NULL) {
295          /* no matching dri config for m */
296          continue;
297       }
298 
299 
300       tail = tail->next;
301    }
302 
303    return head.next;
304 }
305 
306 _X_HIDDEN void
driDestroyConfigs(const __DRIconfig ** configs)307 driDestroyConfigs(const __DRIconfig **configs)
308 {
309    int i;
310 
311    for (i = 0; configs[i]; i++)
312       free((__DRIconfig *) configs[i]);
313    free(configs);
314 }
315 
316 static struct glx_config *
driInferDrawableConfig(struct glx_screen * psc,GLXDrawable draw)317 driInferDrawableConfig(struct glx_screen *psc, GLXDrawable draw)
318 {
319    unsigned int fbconfig = 0;
320 
321    if (__glXGetDrawableAttribute(psc->dpy, draw, GLX_FBCONFIG_ID, &fbconfig)) {
322       return glx_config_find_fbconfig(psc->configs, fbconfig);
323    }
324 
325    return NULL;
326 }
327 
328 _X_HIDDEN __GLXDRIdrawable *
driFetchDrawable(struct glx_context * gc,GLXDrawable glxDrawable)329 driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable)
330 {
331    struct glx_display *const priv = __glXInitialize(gc->psc->dpy);
332    __GLXDRIdrawable *pdraw;
333    struct glx_screen *psc;
334    struct glx_config *config = gc->config;
335 
336    if (priv == NULL)
337       return NULL;
338 
339    if (glxDrawable == None)
340       return NULL;
341 
342    psc = priv->screens[gc->screen];
343    if (priv->drawHash == NULL)
344       return NULL;
345 
346    if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) {
347       pdraw->refcount ++;
348       return pdraw;
349    }
350 
351    if (config == NULL)
352       config = driInferDrawableConfig(gc->psc, glxDrawable);
353    if (config == NULL)
354       return NULL;
355 
356    pdraw = psc->driScreen->createDrawable(psc, glxDrawable, glxDrawable,
357                                           config);
358 
359    if (pdraw == NULL) {
360       ErrorMessageF("failed to create drawable\n");
361       return NULL;
362    }
363 
364    if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) {
365       (*pdraw->destroyDrawable) (pdraw);
366       return NULL;
367    }
368    pdraw->refcount = 1;
369 
370    return pdraw;
371 }
372 
373 _X_HIDDEN void
driReleaseDrawables(struct glx_context * gc)374 driReleaseDrawables(struct glx_context *gc)
375 {
376    const struct glx_display *priv = gc->psc->display;
377    __GLXDRIdrawable *pdraw;
378 
379    if (priv == NULL)
380       return;
381 
382    if (__glxHashLookup(priv->drawHash,
383 		       gc->currentDrawable, (void *) &pdraw) == 0) {
384       if (pdraw->drawable == pdraw->xDrawable) {
385 	 pdraw->refcount --;
386 	 if (pdraw->refcount == 0) {
387 	    pdraw->destroyDrawable(pdraw);
388 	    __glxHashDelete(priv->drawHash, gc->currentDrawable);
389 	 }
390       }
391    }
392 
393    if (__glxHashLookup(priv->drawHash,
394 		       gc->currentReadable, (void *) &pdraw) == 0) {
395       if (pdraw->drawable == pdraw->xDrawable) {
396 	 pdraw->refcount --;
397 	 if (pdraw->refcount == 0) {
398 	    pdraw->destroyDrawable(pdraw);
399 	    __glxHashDelete(priv->drawHash, gc->currentReadable);
400 	 }
401       }
402    }
403 
404    gc->currentDrawable = None;
405    gc->currentReadable = None;
406 
407 }
408 
409 _X_HIDDEN bool
dri2_convert_glx_attribs(unsigned num_attribs,const uint32_t * attribs,unsigned * major_ver,unsigned * minor_ver,uint32_t * render_type,uint32_t * flags,unsigned * api,int * reset,int * release,unsigned * error)410 dri2_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs,
411                          unsigned *major_ver, unsigned *minor_ver,
412                          uint32_t *render_type, uint32_t *flags, unsigned *api,
413                          int *reset, int *release, unsigned *error)
414 {
415    unsigned i;
416    bool got_profile = false;
417    int no_error = 0;
418    uint32_t profile;
419 
420    *major_ver = 1;
421    *minor_ver = 0;
422    *render_type = GLX_RGBA_TYPE;
423    *reset = __DRI_CTX_RESET_NO_NOTIFICATION;
424    *release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
425    *flags = 0;
426    *api = __DRI_API_OPENGL;
427 
428    if (num_attribs == 0) {
429       return true;
430    }
431 
432    /* This is actually an internal error, but what the heck.
433     */
434    if (attribs == NULL) {
435       *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
436       return false;
437    }
438 
439    for (i = 0; i < num_attribs; i++) {
440       switch (attribs[i * 2]) {
441       case GLX_CONTEXT_MAJOR_VERSION_ARB:
442 	 *major_ver = attribs[i * 2 + 1];
443 	 break;
444       case GLX_CONTEXT_MINOR_VERSION_ARB:
445 	 *minor_ver = attribs[i * 2 + 1];
446 	 break;
447       case GLX_CONTEXT_FLAGS_ARB:
448 	 *flags = attribs[i * 2 + 1];
449 	 break;
450       case GLX_CONTEXT_OPENGL_NO_ERROR_ARB:
451 	 no_error = attribs[i * 2 + 1];
452 	 break;
453       case GLX_CONTEXT_PROFILE_MASK_ARB:
454 	 profile = attribs[i * 2 + 1];
455 	 got_profile = true;
456 	 break;
457       case GLX_RENDER_TYPE:
458          *render_type = attribs[i * 2 + 1];
459 	 break;
460       case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB:
461          switch (attribs[i * 2 + 1]) {
462          case GLX_NO_RESET_NOTIFICATION_ARB:
463             *reset = __DRI_CTX_RESET_NO_NOTIFICATION;
464             break;
465          case GLX_LOSE_CONTEXT_ON_RESET_ARB:
466             *reset = __DRI_CTX_RESET_LOSE_CONTEXT;
467             break;
468          default:
469             *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
470             return false;
471          }
472          break;
473       case GLX_CONTEXT_RELEASE_BEHAVIOR_ARB:
474          switch (attribs[i * 2 + 1]) {
475          case GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB:
476             *release = __DRI_CTX_RELEASE_BEHAVIOR_NONE;
477             break;
478          case GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB:
479             *release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
480             break;
481          default:
482             *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
483             return false;
484          }
485          break;
486       default:
487 	 /* If an unknown attribute is received, fail.
488 	  */
489 	 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
490 	 return false;
491       }
492    }
493 
494    if (no_error) {
495       *flags |= __DRI_CTX_FLAG_NO_ERROR;
496    }
497 
498    if (!got_profile) {
499       if (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2))
500 	 *api = __DRI_API_OPENGL_CORE;
501    } else {
502       switch (profile) {
503       case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
504 	 /* There are no profiles before OpenGL 3.2.  The
505 	  * GLX_ARB_create_context_profile spec says:
506 	  *
507 	  *     "If the requested OpenGL version is less than 3.2,
508 	  *     GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
509 	  *     of the context is determined solely by the requested version."
510 	  */
511 	 *api = (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2))
512 	    ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL;
513 	 break;
514       case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
515 	 *api = __DRI_API_OPENGL;
516 	 break;
517       case GLX_CONTEXT_ES_PROFILE_BIT_EXT:
518          if (*major_ver >= 3)
519             *api = __DRI_API_GLES3;
520          else if (*major_ver == 2 && *minor_ver == 0)
521             *api = __DRI_API_GLES2;
522          else if (*major_ver == 1 && *minor_ver < 2)
523             *api = __DRI_API_GLES;
524          else {
525             *error = __DRI_CTX_ERROR_BAD_API;
526             return false;
527          }
528          break;
529       default:
530 	 *error = __DRI_CTX_ERROR_BAD_API;
531 	 return false;
532       }
533    }
534 
535    /* Unknown flag value.
536     */
537    if (*flags & ~(__DRI_CTX_FLAG_DEBUG | __DRI_CTX_FLAG_FORWARD_COMPATIBLE
538                   | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS
539                   | __DRI_CTX_FLAG_NO_ERROR)) {
540       *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
541       return false;
542    }
543 
544    /* There are no forward-compatible contexts before OpenGL 3.0.  The
545     * GLX_ARB_create_context spec says:
546     *
547     *     "Forward-compatible contexts are defined only for OpenGL versions
548     *     3.0 and later."
549     */
550    if (*major_ver < 3 && (*flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) {
551       *error = __DRI_CTX_ERROR_BAD_FLAG;
552       return false;
553    }
554 
555    if (*major_ver >= 3 && *render_type == GLX_COLOR_INDEX_TYPE) {
556       *error = __DRI_CTX_ERROR_BAD_FLAG;
557       return false;
558    }
559 
560    *error = __DRI_CTX_ERROR_SUCCESS;
561    return true;
562 }
563 
564 _X_HIDDEN bool
dri2_check_no_error(uint32_t flags,struct glx_context * share_context,int major,unsigned * error)565 dri2_check_no_error(uint32_t flags, struct glx_context *share_context,
566                     int major, unsigned *error)
567 {
568    Bool noError = flags & __DRI_CTX_FLAG_NO_ERROR;
569 
570    /* The KHR_no_error specs say:
571     *
572     *    Requires OpenGL ES 2.0 or OpenGL 2.0.
573     */
574    if (noError && major < 2) {
575       *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
576       return false;
577    }
578 
579    /* The GLX_ARB_create_context_no_error specs say:
580     *
581     *    BadMatch is generated if the value of GLX_CONTEXT_OPENGL_NO_ERROR_ARB
582     *    used to create <share_context> does not match the value of
583     *    GLX_CONTEXT_OPENGL_NO_ERROR_ARB for the context being created.
584     */
585    if (share_context && !!share_context->noError != !!noError) {
586       *error = __DRI_CTX_ERROR_BAD_FLAG;
587       return false;
588    }
589 
590    /* The GLX_ARB_create_context_no_error specs say:
591     *
592     *    BadMatch is generated if the GLX_CONTEXT_OPENGL_NO_ERROR_ARB is TRUE at
593     *    the same time as a debug or robustness context is specified.
594     *
595     */
596    if (noError && ((flags & __DRI_CTX_FLAG_DEBUG) ||
597                    (flags & __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS))) {
598       *error = __DRI_CTX_ERROR_BAD_FLAG;
599       return false;
600    }
601 
602    return true;
603 }
604 
605 /*
606  * Given a display pointer and screen number, determine the name of
607  * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc).
608  * Return True for success, False for failure.
609  */
610 static Bool
driGetDriverName(Display * dpy,int scrNum,char ** driverName)611 driGetDriverName(Display * dpy, int scrNum, char **driverName)
612 {
613    struct glx_screen *glx_screen = GetGLXScreenConfigs(dpy, scrNum);
614 
615    if (!glx_screen || !glx_screen->vtable->get_driver_name)
616       return False;
617 
618    *driverName = glx_screen->vtable->get_driver_name(glx_screen);
619    return True;
620 }
621 
622 /*
623  * Exported function for querying the DRI driver for a given screen.
624  *
625  * The returned char pointer points to a static array that will be
626  * overwritten by subsequent calls.
627  */
628 _GLX_PUBLIC const char *
glXGetScreenDriver(Display * dpy,int scrNum)629 glXGetScreenDriver(Display * dpy, int scrNum)
630 {
631    static char ret[32];
632    char *driverName;
633 
634    if (driGetDriverName(dpy, scrNum, &driverName)) {
635       int len;
636       if (!driverName)
637          return NULL;
638       len = strlen(driverName);
639       if (len >= 31)
640          return NULL;
641       memcpy(ret, driverName, len + 1);
642       free(driverName);
643       return ret;
644    }
645    return NULL;
646 }
647 
648 /* glXGetDriverConfig must return a pointer with a static lifetime. To avoid
649  * keeping drivers loaded and other leaks, we keep a cache of results here that
650  * is cleared by an atexit handler.
651  */
652 struct driver_config_entry {
653    struct driver_config_entry *next;
654    char *driverName;
655    char *config;
656 };
657 
658 static pthread_mutex_t driver_config_mutex = PTHREAD_MUTEX_INITIALIZER;
659 static struct driver_config_entry *driver_config_cache = NULL;
660 
661 /* Called as an atexit function. Otherwise, this would have to be called with
662  * driver_config_mutex locked.
663  */
664 static void
clear_driver_config_cache()665 clear_driver_config_cache()
666 {
667    while (driver_config_cache) {
668       struct driver_config_entry *e = driver_config_cache;
669       driver_config_cache = e->next;
670 
671       free(e->driverName);
672       free(e->config);
673       free(e);
674    }
675 }
676 
677 static char *
get_driver_config(const char * driverName)678 get_driver_config(const char *driverName)
679 {
680    void *handle;
681    char *config = NULL;
682    const __DRIextension **extensions = driOpenDriver(driverName, &handle);
683    if (extensions) {
684       for (int i = 0; extensions[i]; i++) {
685          if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) != 0)
686             continue;
687 
688          __DRIconfigOptionsExtension *ext =
689             (__DRIconfigOptionsExtension *)extensions[i];
690 
691          if (ext->base.version >= 2)
692             config = ext->getXml(driverName);
693          else
694             config = strdup(ext->xml);
695 
696          break;
697       }
698    }
699 
700    if (!config) {
701       /* Fall back to the old method */
702       config = dlsym(handle, "__driConfigOptions");
703       if (config)
704          config = strdup(config);
705    }
706 
707    dlclose(handle);
708 
709    return config;
710 }
711 
712 /*
713  * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
714  *
715  * The returned char pointer points directly into the driver. Therefore
716  * it should be treated as a constant.
717  *
718  * If the driver was not found or does not support configuration NULL is
719  * returned.
720  */
721 _GLX_PUBLIC const char *
glXGetDriverConfig(const char * driverName)722 glXGetDriverConfig(const char *driverName)
723 {
724    struct driver_config_entry *e;
725 
726    pthread_mutex_lock(&driver_config_mutex);
727 
728    for (e = driver_config_cache; e; e = e->next) {
729       if (strcmp(e->driverName, driverName) == 0)
730          goto out;
731    }
732 
733    e = malloc(sizeof(*e));
734    if (!e)
735       goto out;
736 
737    e->config = get_driver_config(driverName);
738    e->driverName = strdup(driverName);
739    if (!e->config || !e->driverName) {
740       free(e->config);
741       free(e->driverName);
742       free(e);
743       e = NULL;
744       goto out;
745    }
746 
747    e->next = driver_config_cache;
748    driver_config_cache = e;
749 
750    if (!e->next)
751       atexit(clear_driver_config_cache);
752 
753 out:
754    pthread_mutex_unlock(&driver_config_mutex);
755 
756    return e ? e->config : NULL;
757 }
758 
759 #endif /* GLX_DIRECT_RENDERING */
760