dri: Clarify comments on InfoMessageF and ErrorMessageF macros.
[mesa.git] / src / glx / dri_common.c
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
44 #ifndef RTLD_NOW
45 #define RTLD_NOW 0
46 #endif
47 #ifndef RTLD_GLOBAL
48 #define RTLD_GLOBAL 0
49 #endif
50
51 /**
52 * Print informational message to stderr if LIBGL_DEBUG is set to
53 * "verbose".
54 */
55 _X_HIDDEN void
56 InfoMessageF(const char *f, ...)
57 {
58 va_list args;
59 const char *env;
60
61 if ((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) {
62 fprintf(stderr, "libGL: ");
63 va_start(args, f);
64 vfprintf(stderr, f, args);
65 va_end(args);
66 }
67 }
68
69 /**
70 * Print error message to stderr if LIBGL_DEBUG is set to anything but
71 * "quiet", (do nothing if LIBGL_DEBUG is unset).
72 */
73 _X_HIDDEN void
74 ErrorMessageF(const char *f, ...)
75 {
76 va_list args;
77 const char *env;
78
79 if ((env = getenv("LIBGL_DEBUG")) && !strstr(env, "quiet")) {
80 fprintf(stderr, "libGL error: ");
81 va_start(args, f);
82 vfprintf(stderr, f, args);
83 va_end(args);
84 }
85 }
86
87 #ifndef DEFAULT_DRIVER_DIR
88 /* this is normally defined in Mesa/configs/default with DRI_DRIVER_SEARCH_PATH */
89 #define DEFAULT_DRIVER_DIR "/usr/local/lib/dri"
90 #endif
91
92 /**
93 * Try to \c dlopen the named driver.
94 *
95 * This function adds the "_dri.so" suffix to the driver name and searches the
96 * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
97 * order to find the driver.
98 *
99 * \param driverName - a name like "i965", "radeon", "nouveau", etc.
100 *
101 * \returns
102 * A handle from \c dlopen, or \c NULL if driver file not found.
103 */
104 _X_HIDDEN void *
105 driOpenDriver(const char *driverName)
106 {
107 void *glhandle, *handle;
108 const char *libPaths, *p, *next;
109 char realDriverName[200];
110 int len;
111
112 /* Attempt to make sure libGL symbols will be visible to the driver */
113 glhandle = dlopen("libGL.so.1", RTLD_NOW | RTLD_GLOBAL);
114
115 libPaths = NULL;
116 if (geteuid() == getuid()) {
117 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
118 libPaths = getenv("LIBGL_DRIVERS_PATH");
119 if (!libPaths)
120 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
121 }
122 if (libPaths == NULL)
123 libPaths = DEFAULT_DRIVER_DIR;
124
125 handle = NULL;
126 for (p = libPaths; *p; p = next) {
127 next = strchr(p, ':');
128 if (next == NULL) {
129 len = strlen(p);
130 next = p + len;
131 }
132 else {
133 len = next - p;
134 next++;
135 }
136
137 #ifdef GLX_USE_TLS
138 snprintf(realDriverName, sizeof realDriverName,
139 "%.*s/tls/%s_dri.so", len, p, driverName);
140 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
141 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
142 #endif
143
144 if (handle == NULL) {
145 snprintf(realDriverName, sizeof realDriverName,
146 "%.*s/%s_dri.so", len, p, driverName);
147 InfoMessageF("OpenDriver: trying %s\n", realDriverName);
148 handle = dlopen(realDriverName, RTLD_NOW | RTLD_GLOBAL);
149 }
150
151 if (handle != NULL)
152 break;
153 else
154 ErrorMessageF("dlopen %s failed (%s)\n", realDriverName, dlerror());
155 }
156
157 if (!handle)
158 ErrorMessageF("unable to load driver: %s_dri.so\n", driverName);
159
160 if (glhandle)
161 dlclose(glhandle);
162
163 return handle;
164 }
165
166 static GLboolean
167 __driGetMSCRate(__DRIdrawable *draw,
168 int32_t * numerator, int32_t * denominator,
169 void *loaderPrivate)
170 {
171 __GLXDRIdrawable *glxDraw = loaderPrivate;
172
173 return __glxGetMscRate(glxDraw, numerator, denominator);
174 }
175
176 _X_HIDDEN const __DRIsystemTimeExtension systemTimeExtension = {
177 {__DRI_SYSTEM_TIME, __DRI_SYSTEM_TIME_VERSION},
178 __glXGetUST,
179 __driGetMSCRate
180 };
181
182 #define __ATTRIB(attrib, field) \
183 { attrib, offsetof(struct glx_config, field) }
184
185 static const struct
186 {
187 unsigned int attrib, offset;
188 } attribMap[] = {
189 __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
190 __ATTRIB(__DRI_ATTRIB_LEVEL, level),
191 __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
192 __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
193 __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
194 __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
195 __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
196 __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
197 __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
198 __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
199 __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
200 __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
201 __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
202 __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
203 __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
204 __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
205 __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
206 #if 0
207 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_TYPE, transparentPixel),
208 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_INDEX_VALUE, transparentIndex),
209 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_RED_VALUE, transparentRed),
210 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_GREEN_VALUE, transparentGreen),
211 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_BLUE_VALUE, transparentBlue),
212 __ATTRIB(__DRI_ATTRIB_TRANSPARENT_ALPHA_VALUE, transparentAlpha),
213 __ATTRIB(__DRI_ATTRIB_RED_MASK, redMask),
214 __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask),
215 __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask),
216 __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask),
217 #endif
218 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth),
219 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight),
220 __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels),
221 __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH, optimalPbufferWidth),
222 __ATTRIB(__DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT, optimalPbufferHeight),
223 #if 0
224 __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod),
225 #endif
226 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
227 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
228 __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE,
229 bindToMipmapTexture),
230 __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
231 __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable)
232 };
233
234 static int
235 scalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value)
236 {
237 unsigned int glxValue;
238 int i;
239
240 for (i = 0; i < ARRAY_SIZE(attribMap); i++)
241 if (attribMap[i].attrib == attrib) {
242 glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset);
243 return glxValue == GLX_DONT_CARE || glxValue == value;
244 }
245
246 return GL_TRUE; /* Is a non-existing attribute equal to value? */
247 }
248
249 static int
250 driConfigEqual(const __DRIcoreExtension *core,
251 struct glx_config *config, const __DRIconfig *driConfig)
252 {
253 unsigned int attrib, value, glxValue;
254 int i;
255
256 i = 0;
257 while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) {
258 switch (attrib) {
259 case __DRI_ATTRIB_RENDER_TYPE:
260 glxValue = 0;
261 if (value & __DRI_ATTRIB_RGBA_BIT) {
262 glxValue |= GLX_RGBA_BIT;
263 }
264 else if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) {
265 glxValue |= GLX_COLOR_INDEX_BIT;
266 }
267 if (glxValue != config->renderType)
268 return GL_FALSE;
269 break;
270
271 case __DRI_ATTRIB_CONFIG_CAVEAT:
272 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
273 glxValue = GLX_NON_CONFORMANT_CONFIG;
274 else if (value & __DRI_ATTRIB_SLOW_BIT)
275 glxValue = GLX_SLOW_CONFIG;
276 else
277 glxValue = GLX_NONE;
278 if (glxValue != config->visualRating)
279 return GL_FALSE;
280 break;
281
282 case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS:
283 glxValue = 0;
284 if (value & __DRI_ATTRIB_TEXTURE_1D_BIT)
285 glxValue |= GLX_TEXTURE_1D_BIT_EXT;
286 if (value & __DRI_ATTRIB_TEXTURE_2D_BIT)
287 glxValue |= GLX_TEXTURE_2D_BIT_EXT;
288 if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT)
289 glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT;
290 if (config->bindToTextureTargets != GLX_DONT_CARE &&
291 glxValue != config->bindToTextureTargets)
292 return GL_FALSE;
293 break;
294
295 default:
296 if (!scalarEqual(config, attrib, value))
297 return GL_FALSE;
298 }
299 }
300
301 return GL_TRUE;
302 }
303
304 static struct glx_config *
305 createDriMode(const __DRIcoreExtension * core,
306 struct glx_config *config, const __DRIconfig **driConfigs)
307 {
308 __GLXDRIconfigPrivate *driConfig;
309 int i;
310
311 for (i = 0; driConfigs[i]; i++) {
312 if (driConfigEqual(core, config, driConfigs[i]))
313 break;
314 }
315
316 if (driConfigs[i] == NULL)
317 return NULL;
318
319 driConfig = Xmalloc(sizeof *driConfig);
320 if (driConfig == NULL)
321 return NULL;
322
323 driConfig->base = *config;
324 driConfig->driConfig = driConfigs[i];
325
326 return &driConfig->base;
327 }
328
329 _X_HIDDEN struct glx_config *
330 driConvertConfigs(const __DRIcoreExtension * core,
331 struct glx_config *configs, const __DRIconfig **driConfigs)
332 {
333 struct glx_config head, *tail, *m;
334
335 tail = &head;
336 head.next = NULL;
337 for (m = configs; m; m = m->next) {
338 tail->next = createDriMode(core, m, driConfigs);
339 if (tail->next == NULL) {
340 /* no matching dri config for m */
341 continue;
342 }
343
344
345 tail = tail->next;
346 }
347
348 return head.next;
349 }
350
351 _X_HIDDEN void
352 driDestroyConfigs(const __DRIconfig **configs)
353 {
354 int i;
355
356 for (i = 0; configs[i]; i++)
357 free((__DRIconfig *) configs[i]);
358 free(configs);
359 }
360
361 _X_HIDDEN __GLXDRIdrawable *
362 driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable)
363 {
364 struct glx_display *const priv = __glXInitialize(gc->psc->dpy);
365 __GLXDRIdrawable *pdraw;
366 struct glx_screen *psc;
367
368 if (priv == NULL)
369 return NULL;
370
371 psc = priv->screens[gc->screen];
372 if (priv->drawHash == NULL)
373 return NULL;
374
375 if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) {
376 pdraw->refcount ++;
377 return pdraw;
378 }
379
380 pdraw = psc->driScreen->createDrawable(psc, glxDrawable,
381 glxDrawable, gc->config);
382 if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) {
383 (*pdraw->destroyDrawable) (pdraw);
384 return NULL;
385 }
386 pdraw->refcount = 1;
387
388 return pdraw;
389 }
390
391 _X_HIDDEN void
392 driReleaseDrawables(struct glx_context *gc)
393 {
394 const struct glx_display *priv = gc->psc->display;
395 __GLXDRIdrawable *pdraw;
396
397 if (priv == NULL)
398 return;
399
400 if (__glxHashLookup(priv->drawHash,
401 gc->currentDrawable, (void *) &pdraw) == 0) {
402 if (pdraw->drawable == pdraw->xDrawable) {
403 pdraw->refcount --;
404 if (pdraw->refcount == 0) {
405 (*pdraw->destroyDrawable)(pdraw);
406 __glxHashDelete(priv->drawHash, gc->currentDrawable);
407 }
408 }
409 }
410
411 if (__glxHashLookup(priv->drawHash,
412 gc->currentReadable, (void *) &pdraw) == 0) {
413 if (pdraw->drawable == pdraw->xDrawable) {
414 pdraw->refcount --;
415 if (pdraw->refcount == 0) {
416 (*pdraw->destroyDrawable)(pdraw);
417 __glxHashDelete(priv->drawHash, gc->currentReadable);
418 }
419 }
420 }
421
422 gc->currentDrawable = None;
423 gc->currentReadable = None;
424
425 }
426
427 _X_HIDDEN bool
428 dri2_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs,
429 unsigned *major_ver, unsigned *minor_ver,
430 uint32_t *flags, unsigned *api, unsigned *error)
431 {
432 unsigned i;
433 bool got_profile = false;
434 uint32_t profile;
435 int render_type = GLX_RGBA_TYPE;
436
437 if (num_attribs == 0) {
438 *api = __DRI_API_OPENGL;
439 return true;
440 }
441
442 /* This is actually an internal error, but what the heck.
443 */
444 if (attribs == NULL) {
445 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
446 return false;
447 }
448
449 *major_ver = 1;
450 *minor_ver = 0;
451
452 for (i = 0; i < num_attribs; i++) {
453 switch (attribs[i * 2]) {
454 case GLX_CONTEXT_MAJOR_VERSION_ARB:
455 *major_ver = attribs[i * 2 + 1];
456 break;
457 case GLX_CONTEXT_MINOR_VERSION_ARB:
458 *minor_ver = attribs[i * 2 + 1];
459 break;
460 case GLX_CONTEXT_FLAGS_ARB:
461 *flags = attribs[i * 2 + 1];
462 break;
463 case GLX_CONTEXT_PROFILE_MASK_ARB:
464 profile = attribs[i * 2 + 1];
465 got_profile = true;
466 break;
467 case GLX_RENDER_TYPE:
468 render_type = attribs[i * 2 + 1];
469 break;
470 default:
471 /* If an unknown attribute is received, fail.
472 */
473 *error = __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
474 return false;
475 }
476 }
477
478 *api = __DRI_API_OPENGL;
479 if (!got_profile) {
480 if (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2))
481 *api = __DRI_API_OPENGL_CORE;
482 } else {
483 switch (profile) {
484 case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
485 /* There are no profiles before OpenGL 3.2. The
486 * GLX_ARB_create_context_profile spec says:
487 *
488 * "If the requested OpenGL version is less than 3.2,
489 * GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
490 * of the context is determined solely by the requested version."
491 */
492 *api = (*major_ver > 3 || (*major_ver == 3 && *minor_ver >= 2))
493 ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL;
494 break;
495 case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
496 *api = __DRI_API_OPENGL;
497 break;
498 case GLX_CONTEXT_ES2_PROFILE_BIT_EXT:
499 *api = __DRI_API_GLES2;
500 break;
501 default:
502 *error = __DRI_CTX_ERROR_BAD_API;
503 return false;
504 }
505 }
506
507 /* Unknown flag value.
508 */
509 if (*flags & ~(__DRI_CTX_FLAG_DEBUG | __DRI_CTX_FLAG_FORWARD_COMPATIBLE)) {
510 *error = __DRI_CTX_ERROR_UNKNOWN_FLAG;
511 return false;
512 }
513
514 /* There are no forward-compatible contexts before OpenGL 3.0. The
515 * GLX_ARB_create_context spec says:
516 *
517 * "Forward-compatible contexts are defined only for OpenGL versions
518 * 3.0 and later."
519 */
520 if (*major_ver < 3 && (*flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) {
521 *error = __DRI_CTX_ERROR_BAD_FLAG;
522 return false;
523 }
524
525 if (*major_ver >= 3 && render_type == GLX_COLOR_INDEX_TYPE) {
526 *error = __DRI_CTX_ERROR_BAD_FLAG;
527 return false;
528 }
529
530 /* The GLX_EXT_create_context_es2_profile spec says:
531 *
532 * "... If the version requested is 2.0, and the
533 * GLX_CONTEXT_ES2_PROFILE_BIT_EXT bit is set in the
534 * GLX_CONTEXT_PROFILE_MASK_ARB attribute (see below), then the context
535 * returned will implement OpenGL ES 2.0. This is the only way in which
536 * an implementation may request an OpenGL ES 2.0 context."
537 */
538 if (*api == __DRI_API_GLES2 && (*major_ver != 2 || *minor_ver != 0)) {
539 *error = __DRI_CTX_ERROR_BAD_API;
540 return false;
541 }
542
543 *error = __DRI_CTX_ERROR_SUCCESS;
544 return true;
545 }
546
547 #endif /* GLX_DIRECT_RENDERING */