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