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