xref: /OK3568_Linux_fs/external/xserver/glx/glxdricommon.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright © 2008 Red Hat, Inc
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Permission to use, copy, modify, distribute, and sell this software
5*4882a593Smuzhiyun  * and its documentation for any purpose is hereby granted without
6*4882a593Smuzhiyun  * fee, provided that the above copyright notice appear in all copies
7*4882a593Smuzhiyun  * and that both that copyright notice and this permission notice
8*4882a593Smuzhiyun  * appear in supporting documentation, and that the name of the
9*4882a593Smuzhiyun  * copyright holders not be used in advertising or publicity
10*4882a593Smuzhiyun  * pertaining to distribution of the software without specific,
11*4882a593Smuzhiyun  * written prior permission.  The copyright holders make no
12*4882a593Smuzhiyun  * representations about the suitability of this software for any
13*4882a593Smuzhiyun  * purpose.  It is provided "as is" without express or implied
14*4882a593Smuzhiyun  * warranty.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
17*4882a593Smuzhiyun  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
18*4882a593Smuzhiyun  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
19*4882a593Smuzhiyun  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20*4882a593Smuzhiyun  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
21*4882a593Smuzhiyun  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
22*4882a593Smuzhiyun  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23*4882a593Smuzhiyun  * SOFTWARE.
24*4882a593Smuzhiyun  */
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #ifdef HAVE_DIX_CONFIG_H
27*4882a593Smuzhiyun #include <dix-config.h>
28*4882a593Smuzhiyun #endif
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #include <stdint.h>
31*4882a593Smuzhiyun #include <errno.h>
32*4882a593Smuzhiyun #include <dlfcn.h>
33*4882a593Smuzhiyun #include <sys/time.h>
34*4882a593Smuzhiyun #include <GL/gl.h>
35*4882a593Smuzhiyun #include <GL/glxtokens.h>
36*4882a593Smuzhiyun #include <GL/internal/dri_interface.h>
37*4882a593Smuzhiyun #include <os.h>
38*4882a593Smuzhiyun #include "extinit.h"
39*4882a593Smuzhiyun #include "glxserver.h"
40*4882a593Smuzhiyun #include "glxext.h"
41*4882a593Smuzhiyun #include "glxcontext.h"
42*4882a593Smuzhiyun #include "glxscreens.h"
43*4882a593Smuzhiyun #include "glxdricommon.h"
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define __ATTRIB(attrib, field) \
46*4882a593Smuzhiyun     { attrib, offsetof(__GLXconfig, field) }
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun static const struct {
49*4882a593Smuzhiyun     unsigned int attrib, offset;
50*4882a593Smuzhiyun } attribMap[] = {
51*4882a593Smuzhiyun __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
52*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_LEVEL, level),
53*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
54*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
55*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
56*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
57*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
58*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
59*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
60*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
61*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
62*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
63*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
64*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
65*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
66*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
67*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
68*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel),
69*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentPixel),
70*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed),
71*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen),
72*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue),
73*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
74*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask),
75*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask),
76*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask),
77*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask),
78*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth),
79*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
80*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels),
81*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth),
82*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight),
83*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod),
84*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
85*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
86*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture),
87*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
88*4882a593Smuzhiyun         __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable),
89*4882a593Smuzhiyun         };
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun static void
setScalar(__GLXconfig * config,unsigned int attrib,unsigned int value)92*4882a593Smuzhiyun setScalar(__GLXconfig * config, unsigned int attrib, unsigned int value)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun     int i;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun     for (i = 0; i < ARRAY_SIZE(attribMap); i++)
97*4882a593Smuzhiyun         if (attribMap[i].attrib == attrib) {
98*4882a593Smuzhiyun             *(unsigned int *) ((char *) config + attribMap[i].offset) = value;
99*4882a593Smuzhiyun             return;
100*4882a593Smuzhiyun         }
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun static Bool
render_type_is_pbuffer_only(unsigned renderType)104*4882a593Smuzhiyun render_type_is_pbuffer_only(unsigned renderType)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun     /* The GL_ARB_color_buffer_float spec says:
107*4882a593Smuzhiyun      *
108*4882a593Smuzhiyun      *     "Note that floating point rendering is only supported for
109*4882a593Smuzhiyun      *     GLXPbuffer drawables.  The GLX_DRAWABLE_TYPE attribute of the
110*4882a593Smuzhiyun      *     GLXFBConfig must have the GLX_PBUFFER_BIT bit set and the
111*4882a593Smuzhiyun      *     GLX_RENDER_TYPE attribute must have the GLX_RGBA_FLOAT_BIT set."
112*4882a593Smuzhiyun      */
113*4882a593Smuzhiyun     return !!(renderType & (__DRI_ATTRIB_UNSIGNED_FLOAT_BIT
114*4882a593Smuzhiyun                             | __DRI_ATTRIB_FLOAT_BIT));
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun static __GLXconfig *
createModeFromConfig(const __DRIcoreExtension * core,const __DRIconfig * driConfig,unsigned int visualType,GLboolean duplicateForComp)118*4882a593Smuzhiyun createModeFromConfig(const __DRIcoreExtension * core,
119*4882a593Smuzhiyun                      const __DRIconfig * driConfig,
120*4882a593Smuzhiyun                      unsigned int visualType,
121*4882a593Smuzhiyun                      GLboolean duplicateForComp)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun     __GLXDRIconfig *config;
124*4882a593Smuzhiyun     GLint renderType = 0;
125*4882a593Smuzhiyun     unsigned int attrib, value, drawableType = GLX_PBUFFER_BIT;
126*4882a593Smuzhiyun     int i;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun     config = calloc(1, sizeof *config);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun     config->driConfig = driConfig;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun     i = 0;
134*4882a593Smuzhiyun     while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) {
135*4882a593Smuzhiyun         switch (attrib) {
136*4882a593Smuzhiyun         case __DRI_ATTRIB_RENDER_TYPE:
137*4882a593Smuzhiyun             if (value & __DRI_ATTRIB_RGBA_BIT)
138*4882a593Smuzhiyun                 renderType |= GLX_RGBA_BIT;
139*4882a593Smuzhiyun             if (value & __DRI_ATTRIB_COLOR_INDEX_BIT)
140*4882a593Smuzhiyun                 renderType |= GLX_COLOR_INDEX_BIT;
141*4882a593Smuzhiyun             if (value & __DRI_ATTRIB_FLOAT_BIT)
142*4882a593Smuzhiyun                 renderType |= GLX_RGBA_FLOAT_BIT_ARB;
143*4882a593Smuzhiyun             if (value & __DRI_ATTRIB_UNSIGNED_FLOAT_BIT)
144*4882a593Smuzhiyun                 renderType |= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT;
145*4882a593Smuzhiyun             break;
146*4882a593Smuzhiyun         case __DRI_ATTRIB_CONFIG_CAVEAT:
147*4882a593Smuzhiyun             if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
148*4882a593Smuzhiyun                 config->config.visualRating = GLX_NON_CONFORMANT_CONFIG;
149*4882a593Smuzhiyun             else if (value & __DRI_ATTRIB_SLOW_BIT)
150*4882a593Smuzhiyun                 config->config.visualRating = GLX_SLOW_CONFIG;
151*4882a593Smuzhiyun             else
152*4882a593Smuzhiyun                 config->config.visualRating = GLX_NONE;
153*4882a593Smuzhiyun             break;
154*4882a593Smuzhiyun         case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS:
155*4882a593Smuzhiyun             config->config.bindToTextureTargets = 0;
156*4882a593Smuzhiyun             if (value & __DRI_ATTRIB_TEXTURE_1D_BIT)
157*4882a593Smuzhiyun                 config->config.bindToTextureTargets |= GLX_TEXTURE_1D_BIT_EXT;
158*4882a593Smuzhiyun             if (value & __DRI_ATTRIB_TEXTURE_2D_BIT)
159*4882a593Smuzhiyun                 config->config.bindToTextureTargets |= GLX_TEXTURE_2D_BIT_EXT;
160*4882a593Smuzhiyun             if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT)
161*4882a593Smuzhiyun                 config->config.bindToTextureTargets |=
162*4882a593Smuzhiyun                     GLX_TEXTURE_RECTANGLE_BIT_EXT;
163*4882a593Smuzhiyun             break;
164*4882a593Smuzhiyun         case __DRI_ATTRIB_SWAP_METHOD:
165*4882a593Smuzhiyun             /* Workaround for broken dri drivers */
166*4882a593Smuzhiyun             if (value != GLX_SWAP_UNDEFINED_OML &&
167*4882a593Smuzhiyun                 value != GLX_SWAP_COPY_OML &&
168*4882a593Smuzhiyun                 value != GLX_SWAP_EXCHANGE_OML)
169*4882a593Smuzhiyun                 value = GLX_SWAP_UNDEFINED_OML;
170*4882a593Smuzhiyun             /* Fall through. */
171*4882a593Smuzhiyun         default:
172*4882a593Smuzhiyun             setScalar(&config->config, attrib, value);
173*4882a593Smuzhiyun             break;
174*4882a593Smuzhiyun         }
175*4882a593Smuzhiyun     }
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun     if (!render_type_is_pbuffer_only(renderType))
178*4882a593Smuzhiyun         drawableType |= GLX_WINDOW_BIT | GLX_PIXMAP_BIT;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun     config->config.next = NULL;
181*4882a593Smuzhiyun     config->config.visualType = visualType;
182*4882a593Smuzhiyun     config->config.renderType = renderType;
183*4882a593Smuzhiyun     config->config.drawableType = drawableType;
184*4882a593Smuzhiyun     config->config.yInverted = GL_TRUE;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun #ifdef COMPOSITE
187*4882a593Smuzhiyun     if (!noCompositeExtension) {
188*4882a593Smuzhiyun         /*
189*4882a593Smuzhiyun         * Here we decide what fbconfigs will be duplicated for compositing.
190*4882a593Smuzhiyun         * fgbconfigs marked with duplicatedForConf will be reserved for
191*4882a593Smuzhiyun         * compositing visuals.
192*4882a593Smuzhiyun         * It might look strange to do this decision this late when translation
193*4882a593Smuzhiyun         * from a __DRIConfig is already done, but using the __DRIConfig
194*4882a593Smuzhiyun         * accessor function becomes worse both with respect to code complexity
195*4882a593Smuzhiyun         * and CPU usage.
196*4882a593Smuzhiyun         */
197*4882a593Smuzhiyun         if (duplicateForComp &&
198*4882a593Smuzhiyun             (render_type_is_pbuffer_only(renderType) ||
199*4882a593Smuzhiyun             config->config.rgbBits != 32 ||
200*4882a593Smuzhiyun             config->config.redBits != 8 ||
201*4882a593Smuzhiyun             config->config.greenBits != 8 ||
202*4882a593Smuzhiyun             config->config.blueBits != 8 ||
203*4882a593Smuzhiyun             config->config.visualRating != GLX_NONE ||
204*4882a593Smuzhiyun             config->config.sampleBuffers != 0)) {
205*4882a593Smuzhiyun             free(config);
206*4882a593Smuzhiyun             return NULL;
207*4882a593Smuzhiyun         }
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun         config->config.duplicatedForComp = duplicateForComp;
210*4882a593Smuzhiyun     }
211*4882a593Smuzhiyun #endif
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun     return &config->config;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun __GLXconfig *
glxConvertConfigs(const __DRIcoreExtension * core,const __DRIconfig ** configs)217*4882a593Smuzhiyun glxConvertConfigs(const __DRIcoreExtension * core,
218*4882a593Smuzhiyun                   const __DRIconfig ** configs)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun     __GLXconfig head, *tail;
221*4882a593Smuzhiyun     int i;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun     tail = &head;
224*4882a593Smuzhiyun     head.next = NULL;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun     for (i = 0; configs[i]; i++) {
227*4882a593Smuzhiyun         tail->next = createModeFromConfig(core, configs[i], GLX_TRUE_COLOR,
228*4882a593Smuzhiyun                                           GL_FALSE);
229*4882a593Smuzhiyun         if (tail->next == NULL)
230*4882a593Smuzhiyun             break;
231*4882a593Smuzhiyun         tail = tail->next;
232*4882a593Smuzhiyun     }
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun     for (i = 0; configs[i]; i++) {
235*4882a593Smuzhiyun         tail->next = createModeFromConfig(core, configs[i], GLX_DIRECT_COLOR,
236*4882a593Smuzhiyun                                           GL_FALSE);
237*4882a593Smuzhiyun         if (tail->next == NULL)
238*4882a593Smuzhiyun             break;
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun         tail = tail->next;
241*4882a593Smuzhiyun     }
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun #ifdef COMPOSITE
244*4882a593Smuzhiyun     if (!noCompositeExtension) {
245*4882a593Smuzhiyun         /* Duplicate fbconfigs for use with compositing visuals */
246*4882a593Smuzhiyun         for (i = 0; configs[i]; i++) {
247*4882a593Smuzhiyun             tail->next = createModeFromConfig(core, configs[i], GLX_TRUE_COLOR,
248*4882a593Smuzhiyun                                             GL_TRUE);
249*4882a593Smuzhiyun             if (tail->next == NULL)
250*4882a593Smuzhiyun                 continue;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun             tail = tail->next;
253*4882a593Smuzhiyun         }
254*4882a593Smuzhiyun     }
255*4882a593Smuzhiyun #endif
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun     return head.next;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun static const char dri_driver_path[] = DRI_DRIVER_PATH;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun /* Temporary define to allow building without a dri_interface.h from
263*4882a593Smuzhiyun  * updated Mesa.  Some day when we don't care about Mesa that old any
264*4882a593Smuzhiyun  * more this can be removed.
265*4882a593Smuzhiyun  */
266*4882a593Smuzhiyun #ifndef __DRI_DRIVER_GET_EXTENSIONS
267*4882a593Smuzhiyun #define __DRI_DRIVER_GET_EXTENSIONS "__driDriverGetExtensions"
268*4882a593Smuzhiyun #endif
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun void *
glxProbeDriver(const char * driverName,void ** coreExt,const char * coreName,int coreVersion,void ** renderExt,const char * renderName,int renderVersion)271*4882a593Smuzhiyun glxProbeDriver(const char *driverName,
272*4882a593Smuzhiyun                void **coreExt, const char *coreName, int coreVersion,
273*4882a593Smuzhiyun                void **renderExt, const char *renderName, int renderVersion)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun     int i;
276*4882a593Smuzhiyun     void *driver;
277*4882a593Smuzhiyun     char filename[PATH_MAX];
278*4882a593Smuzhiyun     char *get_extensions_name;
279*4882a593Smuzhiyun     const __DRIextension **extensions = NULL;
280*4882a593Smuzhiyun     const char *path = NULL;
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun     /* Search in LIBGL_DRIVERS_PATH if we're not setuid. */
283*4882a593Smuzhiyun     if (!PrivsElevated())
284*4882a593Smuzhiyun         path = getenv("LIBGL_DRIVERS_PATH");
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun     if (!path)
287*4882a593Smuzhiyun         path = dri_driver_path;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun     do {
290*4882a593Smuzhiyun         const char *next;
291*4882a593Smuzhiyun         int path_len;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun         next = strchr(path, ':');
294*4882a593Smuzhiyun         if (next) {
295*4882a593Smuzhiyun             path_len = next - path;
296*4882a593Smuzhiyun             next++;
297*4882a593Smuzhiyun         } else {
298*4882a593Smuzhiyun             path_len = strlen(path);
299*4882a593Smuzhiyun             next = NULL;
300*4882a593Smuzhiyun         }
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun         snprintf(filename, sizeof filename, "%.*s/%s_dri.so", path_len, path,
303*4882a593Smuzhiyun                  driverName);
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun         driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
306*4882a593Smuzhiyun         if (driver != NULL)
307*4882a593Smuzhiyun             break;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun         LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n",
310*4882a593Smuzhiyun                    filename, dlerror());
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun         path = next;
313*4882a593Smuzhiyun     } while (path);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun     if (driver == NULL) {
316*4882a593Smuzhiyun         LogMessage(X_ERROR, "AIGLX error: unable to load driver %s\n",
317*4882a593Smuzhiyun                   driverName);
318*4882a593Smuzhiyun         goto cleanup_failure;
319*4882a593Smuzhiyun     }
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun     if (asprintf(&get_extensions_name, "%s_%s",
322*4882a593Smuzhiyun                  __DRI_DRIVER_GET_EXTENSIONS, driverName) != -1) {
323*4882a593Smuzhiyun         const __DRIextension **(*get_extensions)(void);
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun         get_extensions = dlsym(driver, get_extensions_name);
326*4882a593Smuzhiyun         if (get_extensions)
327*4882a593Smuzhiyun             extensions = get_extensions();
328*4882a593Smuzhiyun         free(get_extensions_name);
329*4882a593Smuzhiyun     }
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun     if (!extensions)
332*4882a593Smuzhiyun         extensions = dlsym(driver, __DRI_DRIVER_EXTENSIONS);
333*4882a593Smuzhiyun     if (extensions == NULL) {
334*4882a593Smuzhiyun         LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n",
335*4882a593Smuzhiyun                    driverName, dlerror());
336*4882a593Smuzhiyun         goto cleanup_failure;
337*4882a593Smuzhiyun     }
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun     for (i = 0; extensions[i]; i++) {
340*4882a593Smuzhiyun         if (strcmp(extensions[i]->name, coreName) == 0 &&
341*4882a593Smuzhiyun             extensions[i]->version >= coreVersion) {
342*4882a593Smuzhiyun             *coreExt = (void *) extensions[i];
343*4882a593Smuzhiyun         }
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun         if (strcmp(extensions[i]->name, renderName) == 0 &&
346*4882a593Smuzhiyun             extensions[i]->version >= renderVersion) {
347*4882a593Smuzhiyun             *renderExt = (void *) extensions[i];
348*4882a593Smuzhiyun         }
349*4882a593Smuzhiyun     }
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun     if (*coreExt == NULL || *renderExt == NULL) {
352*4882a593Smuzhiyun         LogMessage(X_ERROR,
353*4882a593Smuzhiyun                    "AIGLX error: %s does not export required DRI extension\n",
354*4882a593Smuzhiyun                    driverName);
355*4882a593Smuzhiyun         goto cleanup_failure;
356*4882a593Smuzhiyun     }
357*4882a593Smuzhiyun     return driver;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun  cleanup_failure:
360*4882a593Smuzhiyun     if (driver)
361*4882a593Smuzhiyun         dlclose(driver);
362*4882a593Smuzhiyun     *coreExt = *renderExt = NULL;
363*4882a593Smuzhiyun     return NULL;
364*4882a593Smuzhiyun }
365