2 * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
3 * Copyright © 2008 Red Hat, Inc.
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.
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.
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.
31 * Kevin E. Martin <kevin@precisioninsight.com>
32 * Brian Paul <brian@precisioninsight.com>
33 * Kristian Høgsberg (krh@redhat.com)
36 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
41 #include "glxclient.h"
42 #include "dri_common.h"
53 dri_message(int level
, const char *f
, ...)
56 int threshold
= _LOADER_WARNING
;
57 const char *libgl_debug
;
59 libgl_debug
= getenv("LIBGL_DEBUG");
61 if (strstr(libgl_debug
, "quiet"))
62 threshold
= _LOADER_FATAL
;
63 else if (strstr(libgl_debug
, "verbose"))
64 threshold
= _LOADER_DEBUG
;
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" : "");
71 vfprintf(stderr
, f
, args
);
76 #ifndef DEFAULT_DRIVER_DIR
77 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
78 #define DEFAULT_DRIVER_DIR "/usr/local/lib/dri"
82 * Try to \c dlopen the named driver.
84 * This function adds the "_dri.so" suffix to the driver name and searches the
85 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
86 * order to find the driver.
88 * \param driverName - a name like "i965", "radeon", "nouveau", etc.
91 * A handle from \c dlopen, or \c NULL if driver file not found.
94 driOpenDriver(const char *driverName
)
96 void *glhandle
, *handle
;
97 const char *libPaths
, *p
, *next
;
98 char realDriverName
[200];
101 /* Attempt to make sure libGL symbols will be visible to the driver */
102 glhandle
= dlopen("libGL.so.1", RTLD_NOW
| RTLD_GLOBAL
);
105 if (geteuid() == getuid()) {
106 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
107 libPaths
= getenv("LIBGL_DRIVERS_PATH");
109 libPaths
= getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
111 if (libPaths
== NULL
)
112 libPaths
= DEFAULT_DRIVER_DIR
;
115 for (p
= libPaths
; *p
; p
= next
) {
116 next
= strchr(p
, ':');
127 snprintf(realDriverName
, sizeof realDriverName
,
128 "%.*s/tls/%s_dri.so", len
, p
, driverName
);
129 InfoMessageF("OpenDriver: trying %s\n", realDriverName
);
130 handle
= dlopen(realDriverName
, RTLD_NOW
| RTLD_GLOBAL
);
133 if (handle
== NULL
) {
134 snprintf(realDriverName
, sizeof realDriverName
,
135 "%.*s/%s_dri.so", len
, p
, driverName
);
136 InfoMessageF("OpenDriver: trying %s\n", realDriverName
);
137 handle
= dlopen(realDriverName
, RTLD_NOW
| RTLD_GLOBAL
);
143 InfoMessageF("dlopen %s failed (%s)\n", realDriverName
, dlerror());
147 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName
);
155 _X_HIDDEN
const __DRIextension
**
156 driGetDriverExtensions(void *handle
, const char *driver_name
)
158 const __DRIextension
**extensions
= NULL
;
159 const __DRIextension
**(*get_extensions
)(void);
160 char *get_extensions_name
;
162 if (asprintf(&get_extensions_name
, "%s_%s",
163 __DRI_DRIVER_GET_EXTENSIONS
, driver_name
) != -1) {
164 get_extensions
= dlsym(handle
, get_extensions_name
);
165 if (get_extensions
) {
166 free(get_extensions_name
);
167 return get_extensions();
169 InfoMessageF("driver does not expose %s(): %s\n",
170 get_extensions_name
, dlerror());
171 free(get_extensions_name
);
175 extensions
= dlsym(handle
, __DRI_DRIVER_EXTENSIONS
);
176 if (extensions
== NULL
) {
177 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
185 __driGetMSCRate(__DRIdrawable
*draw
,
186 int32_t * numerator
, int32_t * denominator
,
189 __GLXDRIdrawable
*glxDraw
= loaderPrivate
;
191 return __glxGetMscRate(glxDraw
->psc
, numerator
, denominator
);
194 _X_HIDDEN
const __DRIsystemTimeExtension systemTimeExtension
= {
195 .base
= {__DRI_SYSTEM_TIME
, 1 },
197 .getUST
= __glXGetUST
,
198 .getMSCRate
= __driGetMSCRate
201 #define __ATTRIB(attrib, field) \
202 { attrib, offsetof(struct glx_config, field) }
206 unsigned int attrib
, offset
;
208 __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE
, rgbBits
),
209 __ATTRIB(__DRI_ATTRIB_LEVEL
, level
),
210 __ATTRIB(__DRI_ATTRIB_RED_SIZE
, redBits
),
211 __ATTRIB(__DRI_ATTRIB_GREEN_SIZE
, greenBits
),
212 __ATTRIB(__DRI_ATTRIB_BLUE_SIZE
, blueBits
),
213 __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE
, alphaBits
),
214 __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE
, depthBits
),
215 __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE
, stencilBits
),
216 __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE
, accumRedBits
),
217 __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE
, accumGreenBits
),
218 __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE
, accumBlueBits
),
219 __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE
, accumAlphaBits
),
220 __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS
, sampleBuffers
),
221 __ATTRIB(__DRI_ATTRIB_SAMPLES
, samples
),
222 __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER
, doubleBufferMode
),
223 __ATTRIB(__DRI_ATTRIB_STEREO
, stereoMode
),
224 __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS
, numAuxBuffers
),
226 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE
, transparentPixel
),
227 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE
, transparentIndex
),
228 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE
, transparentRed
),
229 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE
, transparentGreen
),
230 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE
, transparentBlue
),
231 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE
, transparentAlpha
),
232 __ATTRIB(__DRI_ATTRIB_RED_MASK
, redMask
),
233 __ATTRIB(__DRI_ATTRIB_GREEN_MASK
, greenMask
),
234 __ATTRIB(__DRI_ATTRIB_BLUE_MASK
, blueMask
),
235 __ATTRIB(__DRI_ATTRIB_ALPHA_MASK
, alphaMask
),
237 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH
, maxPbufferWidth
),
238 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT
, maxPbufferHeight
),
239 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS
, maxPbufferPixels
),
240 __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH
, optimalPbufferWidth
),
241 __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT
, optimalPbufferHeight
),
243 __ATTRIB(__DRI_ATTRIB_SWAP_METHOD
, swapMethod
),
245 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB
, bindToTextureRgb
),
246 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA
, bindToTextureRgba
),
247 __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE
,
248 bindToMipmapTexture
),
249 __ATTRIB(__DRI_ATTRIB_YINVERTED
, yInverted
),
250 __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE
, sRGBCapable
)
254 scalarEqual(struct glx_config
*mode
, unsigned int attrib
, unsigned int value
)
256 unsigned int glxValue
;
259 for (i
= 0; i
< ARRAY_SIZE(attribMap
); i
++)
260 if (attribMap
[i
].attrib
== attrib
) {
261 glxValue
= *(unsigned int *) ((char *) mode
+ attribMap
[i
].offset
);
262 return glxValue
== GLX_DONT_CARE
|| glxValue
== value
;
265 return GL_TRUE
; /* Is a non-existing attribute equal to value? */
269 scalarGreaterEqual(struct glx_config
*mode
, unsigned int attrib
, unsigned int value
)
271 unsigned int glxValue
;
274 for (i
= 0; i
< ARRAY_SIZE(attribMap
); i
++)
275 if (attribMap
[i
].attrib
== attrib
) {
276 glxValue
= *(unsigned int *) ((char *) mode
+ attribMap
[i
].offset
);
277 return glxValue
== GLX_DONT_CARE
|| glxValue
>= value
;
280 return GL_TRUE
; /* Is a non-existing attribute greater than or equal to value? */
284 booleanSupported(struct glx_config
*mode
, unsigned int attrib
, unsigned int value
)
286 unsigned int glxValue
;
289 for (i
= 0; i
< ARRAY_SIZE(attribMap
); i
++)
290 if (attribMap
[i
].attrib
== attrib
) {
291 glxValue
= *(unsigned int *) ((char *) mode
+ attribMap
[i
].offset
);
292 return glxValue
== GLX_DONT_CARE
|| glxValue
;
295 return GL_TRUE
; /* Is a non-existing attribute supported? */
299 driConfigEqual(const __DRIcoreExtension
*core
,
300 struct glx_config
*config
, const __DRIconfig
*driConfig
)
302 unsigned int attrib
, value
, glxValue
;
306 while (core
->indexConfigAttrib(driConfig
, i
++, &attrib
, &value
)) {
308 case __DRI_ATTRIB_RENDER_TYPE
:
310 if (value
& __DRI_ATTRIB_RGBA_BIT
) {
311 glxValue
|= GLX_RGBA_BIT
;
313 if (value
& __DRI_ATTRIB_COLOR_INDEX_BIT
) {
314 glxValue
|= GLX_COLOR_INDEX_BIT
;
316 if (value
& __DRI_ATTRIB_FLOAT_BIT
) {
317 glxValue
|= GLX_RGBA_FLOAT_BIT_ARB
;
319 if (value
& __DRI_ATTRIB_UNSIGNED_FLOAT_BIT
) {
320 glxValue
|= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT
;
322 if (glxValue
!= config
->renderType
)
326 case __DRI_ATTRIB_CONFIG_CAVEAT
:
327 if (value
& __DRI_ATTRIB_NON_CONFORMANT_CONFIG
)
328 glxValue
= GLX_NON_CONFORMANT_CONFIG
;
329 else if (value
& __DRI_ATTRIB_SLOW_BIT
)
330 glxValue
= GLX_SLOW_CONFIG
;
333 if (glxValue
!= config
->visualRating
)
337 case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS
:
339 if (value
& __DRI_ATTRIB_TEXTURE_1D_BIT
)
340 glxValue
|= GLX_TEXTURE_1D_BIT_EXT
;
341 if (value
& __DRI_ATTRIB_TEXTURE_2D_BIT
)
342 glxValue
|= GLX_TEXTURE_2D_BIT_EXT
;
343 if (value
& __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT
)
344 glxValue
|= GLX_TEXTURE_RECTANGLE_BIT_EXT
;
345 if (config
->bindToTextureTargets
!= GLX_DONT_CARE
&&
346 glxValue
!= (config
->bindToTextureTargets
& glxValue
))
350 case __DRI_ATTRIB_STENCIL_SIZE
:
351 case __DRI_ATTRIB_ACCUM_RED_SIZE
:
352 case __DRI_ATTRIB_ACCUM_GREEN_SIZE
:
353 case __DRI_ATTRIB_ACCUM_BLUE_SIZE
:
354 case __DRI_ATTRIB_ACCUM_ALPHA_SIZE
:
355 if (value
!= 0 && !scalarEqual(config
, attrib
, value
))
359 case __DRI_ATTRIB_DOUBLE_BUFFER
:
360 case __DRI_ATTRIB_BIND_TO_TEXTURE_RGB
:
361 case __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA
:
362 case __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE
:
363 case __DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE
:
364 if (value
&& !booleanSupported(config
, attrib
, value
))
368 case __DRI_ATTRIB_SAMPLE_BUFFERS
:
369 case __DRI_ATTRIB_SAMPLES
:
370 case __DRI_ATTRIB_AUX_BUFFERS
:
371 case __DRI_ATTRIB_MAX_PBUFFER_WIDTH
:
372 case __DRI_ATTRIB_MAX_PBUFFER_HEIGHT
:
373 case __DRI_ATTRIB_MAX_PBUFFER_PIXELS
:
374 if (!scalarGreaterEqual(config
, attrib
, value
))
378 if (!scalarEqual(config
, attrib
, value
))
386 static struct glx_config
*
387 createDriMode(const __DRIcoreExtension
* core
,
388 struct glx_config
*config
, const __DRIconfig
**driConfigs
)
390 __GLXDRIconfigPrivate
*driConfig
;
393 for (i
= 0; driConfigs
[i
]; i
++) {
394 if (driConfigEqual(core
, config
, driConfigs
[i
]))
398 if (driConfigs
[i
] == NULL
)
401 driConfig
= malloc(sizeof *driConfig
);
402 if (driConfig
== NULL
)
405 driConfig
->base
= *config
;
406 driConfig
->driConfig
= driConfigs
[i
];
408 return &driConfig
->base
;
411 _X_HIDDEN
struct glx_config
*
412 driConvertConfigs(const __DRIcoreExtension
* core
,
413 struct glx_config
*configs
, const __DRIconfig
**driConfigs
)
415 struct glx_config head
, *tail
, *m
;
419 for (m
= configs
; m
; m
= m
->next
) {
420 tail
->next
= createDriMode(core
, m
, driConfigs
);
421 if (tail
->next
== NULL
) {
422 /* no matching dri config for m */
434 driDestroyConfigs(const __DRIconfig
**configs
)
438 for (i
= 0; configs
[i
]; i
++)
439 free((__DRIconfig
*) configs
[i
]);
443 _X_HIDDEN __GLXDRIdrawable
*
444 driFetchDrawable(struct glx_context
*gc
, GLXDrawable glxDrawable
)
446 struct glx_display
*const priv
= __glXInitialize(gc
->psc
->dpy
);
447 __GLXDRIdrawable
*pdraw
;
448 struct glx_screen
*psc
;
453 if (glxDrawable
== None
)
456 psc
= priv
->screens
[gc
->screen
];
457 if (priv
->drawHash
== NULL
)
460 if (__glxHashLookup(priv
->drawHash
, glxDrawable
, (void *) &pdraw
) == 0) {
465 pdraw
= psc
->driScreen
->createDrawable(psc
, glxDrawable
,
466 glxDrawable
, gc
->config
);
469 ErrorMessageF("failed to create drawable\n");
473 if (__glxHashInsert(priv
->drawHash
, glxDrawable
, pdraw
)) {
474 (*pdraw
->destroyDrawable
) (pdraw
);
483 driReleaseDrawables(struct glx_context
*gc
)
485 const struct glx_display
*priv
= gc
->psc
->display
;
486 __GLXDRIdrawable
*pdraw
;
491 if (__glxHashLookup(priv
->drawHash
,
492 gc
->currentDrawable
, (void *) &pdraw
) == 0) {
493 if (pdraw
->drawable
== pdraw
->xDrawable
) {
495 if (pdraw
->refcount
== 0) {
496 (*pdraw
->destroyDrawable
)(pdraw
);
497 __glxHashDelete(priv
->drawHash
, gc
->currentDrawable
);
502 if (__glxHashLookup(priv
->drawHash
,
503 gc
->currentReadable
, (void *) &pdraw
) == 0) {
504 if (pdraw
->drawable
== pdraw
->xDrawable
) {
506 if (pdraw
->refcount
== 0) {
507 (*pdraw
->destroyDrawable
)(pdraw
);
508 __glxHashDelete(priv
->drawHash
, gc
->currentReadable
);
513 gc
->currentDrawable
= None
;
514 gc
->currentReadable
= None
;
519 dri2_convert_glx_attribs(unsigned num_attribs
, const uint32_t *attribs
,
520 unsigned *major_ver
, unsigned *minor_ver
,
521 uint32_t *render_type
, uint32_t *flags
, unsigned *api
,
522 int *reset
, unsigned *error
)
525 bool got_profile
= false;
530 *render_type
= GLX_RGBA_TYPE
;
531 *reset
= __DRI_CTX_RESET_NO_NOTIFICATION
;
533 *api
= __DRI_API_OPENGL
;
535 if (num_attribs
== 0) {
539 /* This is actually an internal error, but what the heck.
541 if (attribs
== NULL
) {
542 *error
= __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE
;
546 for (i
= 0; i
< num_attribs
; i
++) {
547 switch (attribs
[i
* 2]) {
548 case GLX_CONTEXT_MAJOR_VERSION_ARB
:
549 *major_ver
= attribs
[i
* 2 + 1];
551 case GLX_CONTEXT_MINOR_VERSION_ARB
:
552 *minor_ver
= attribs
[i
* 2 + 1];
554 case GLX_CONTEXT_FLAGS_ARB
:
555 *flags
= attribs
[i
* 2 + 1];
557 case GLX_CONTEXT_PROFILE_MASK_ARB
:
558 profile
= attribs
[i
* 2 + 1];
561 case GLX_RENDER_TYPE
:
562 *render_type
= attribs
[i
* 2 + 1];
564 case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB
:
565 switch (attribs
[i
* 2 + 1]) {
566 case GLX_NO_RESET_NOTIFICATION_ARB
:
567 *reset
= __DRI_CTX_RESET_NO_NOTIFICATION
;
569 case GLX_LOSE_CONTEXT_ON_RESET_ARB
:
570 *reset
= __DRI_CTX_RESET_LOSE_CONTEXT
;
573 *error
= __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE
;
578 /* If an unknown attribute is received, fail.
580 *error
= __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE
;
586 if (*major_ver
> 3 || (*major_ver
== 3 && *minor_ver
>= 2))
587 *api
= __DRI_API_OPENGL_CORE
;
590 case GLX_CONTEXT_CORE_PROFILE_BIT_ARB
:
591 /* There are no profiles before OpenGL 3.2. The
592 * GLX_ARB_create_context_profile spec says:
594 * "If the requested OpenGL version is less than 3.2,
595 * GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
596 * of the context is determined solely by the requested version."
598 *api
= (*major_ver
> 3 || (*major_ver
== 3 && *minor_ver
>= 2))
599 ? __DRI_API_OPENGL_CORE
: __DRI_API_OPENGL
;
601 case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
:
602 *api
= __DRI_API_OPENGL
;
604 case GLX_CONTEXT_ES2_PROFILE_BIT_EXT
:
605 *api
= __DRI_API_GLES2
;
608 *error
= __DRI_CTX_ERROR_BAD_API
;
613 /* Unknown flag value.
615 if (*flags
& ~(__DRI_CTX_FLAG_DEBUG
| __DRI_CTX_FLAG_FORWARD_COMPATIBLE
616 | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS
)) {
617 *error
= __DRI_CTX_ERROR_UNKNOWN_FLAG
;
621 /* There are no forward-compatible contexts before OpenGL 3.0. The
622 * GLX_ARB_create_context spec says:
624 * "Forward-compatible contexts are defined only for OpenGL versions
627 if (*major_ver
< 3 && (*flags
& __DRI_CTX_FLAG_FORWARD_COMPATIBLE
) != 0) {
628 *error
= __DRI_CTX_ERROR_BAD_FLAG
;
632 if (*major_ver
>= 3 && *render_type
== GLX_COLOR_INDEX_TYPE
) {
633 *error
= __DRI_CTX_ERROR_BAD_FLAG
;
637 /* The GLX_EXT_create_context_es2_profile spec says:
639 * "... If the version requested is 2.0, and the
640 * GLX_CONTEXT_ES2_PROFILE_BIT_EXT bit is set in the
641 * GLX_CONTEXT_PROFILE_MASK_ARB attribute (see below), then the context
642 * returned will implement OpenGL ES 2.0. This is the only way in which
643 * an implementation may request an OpenGL ES 2.0 context."
645 if (*api
== __DRI_API_GLES2
&& (*major_ver
!= 2 || *minor_ver
!= 0)) {
646 *error
= __DRI_CTX_ERROR_BAD_API
;
650 *error
= __DRI_CTX_ERROR_SUCCESS
;
654 #endif /* GLX_DIRECT_RENDERING */