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 <[email protected]>
32 * Brian Paul <[email protected]>
33 * Kristian Høgsberg ([email protected])
34 */
35
36 #if defined(GLX_DIRECT_RENDERING) && (!defined(GLX_USE_APPLEGL) || defined(GLX_USE_APPLE))
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 #include <X11/Xlib-xcb.h>
45 #include <xcb/xproto.h>
46 #include "dri_util.h"
47 #include "pipe-loader/pipe_loader.h"
48
49 #define __ATTRIB(attrib, field) \
50 { attrib, offsetof(struct glx_config, field) }
51
52 static const struct
53 {
54 unsigned int attrib, offset;
55 } attribMap[] = {
56 __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
57 __ATTRIB(__DRI_ATTRIB_LEVEL, level),
58 __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
59 __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
60 __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
61 __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
62 __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
63 __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
64 __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
65 __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
66 __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
67 __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
68 __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
69 __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
70 __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
71 __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
72 __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
73 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
74 __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
75 __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture),
76 __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
77 __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable)
78 };
79
80 static int
scalarEqual(struct glx_config * mode,unsigned int attrib,unsigned int value)81 scalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value)
82 {
83 unsigned glxValue, i;
84
85 for (i = 0; i < ARRAY_SIZE(attribMap); i++)
86 if (attribMap[i].attrib == attrib) {
87 glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset);
88 return glxValue == GLX_DONT_CARE || glxValue == value;
89 }
90
91 return GL_TRUE; /* Is a non-existing attribute equal to value? */
92 }
93
94 static int
driConfigEqual(struct glx_config * config,const __DRIconfig * driConfig)95 driConfigEqual(struct glx_config *config, const __DRIconfig *driConfig)
96 {
97 unsigned int attrib, value, glxValue;
98 int i;
99
100 i = 0;
101 while (driIndexConfigAttrib(driConfig, i++, &attrib, &value)) {
102 switch (attrib) {
103 case __DRI_ATTRIB_RENDER_TYPE:
104 glxValue = 0;
105 if (value & __DRI_ATTRIB_RGBA_BIT) {
106 glxValue |= GLX_RGBA_BIT;
107 }
108 if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) {
109 glxValue |= GLX_COLOR_INDEX_BIT;
110 }
111 if (value & __DRI_ATTRIB_FLOAT_BIT) {
112 glxValue |= GLX_RGBA_FLOAT_BIT_ARB;
113 }
114 if (value & __DRI_ATTRIB_UNSIGNED_FLOAT_BIT) {
115 glxValue |= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT;
116 }
117 if (glxValue != config->renderType)
118 return GL_FALSE;
119 break;
120
121 case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS:
122 glxValue = 0;
123 if (value & __DRI_ATTRIB_TEXTURE_1D_BIT)
124 glxValue |= GLX_TEXTURE_1D_BIT_EXT;
125 if (value & __DRI_ATTRIB_TEXTURE_2D_BIT)
126 glxValue |= GLX_TEXTURE_2D_BIT_EXT;
127 if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT)
128 glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT;
129 if (config->bindToTextureTargets != GLX_DONT_CARE &&
130 glxValue != config->bindToTextureTargets)
131 return GL_FALSE;
132 break;
133
134 /* Nerf some attributes we can safely ignore if the server claims to
135 * support them but the driver does not.
136 */
137 case __DRI_ATTRIB_CONFIG_CAVEAT:
138 if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
139 glxValue = GLX_NON_CONFORMANT_CONFIG;
140 else if (value & __DRI_ATTRIB_SLOW_BIT)
141 glxValue = GLX_SLOW_CONFIG;
142 else
143 glxValue = GLX_NONE;
144 if (glxValue != config->visualRating) {
145 if (config->visualRating == GLX_NONE) {
146 static int warned;
147 if (!warned) {
148 DebugMessageF("Not downgrading visual rating\n");
149 warned = 1;
150 }
151 } else {
152 return GL_FALSE;
153 }
154 }
155 break;
156
157 case __DRI_ATTRIB_AUX_BUFFERS:
158 if (!scalarEqual(config, attrib, value)) {
159 static int warned;
160 if (!warned) {
161 DebugMessageF("Disabling server's aux buffer support\n");
162 warned = 1;
163 }
164 config->numAuxBuffers = 0;
165 }
166 break;
167
168 case __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE:
169 if (!scalarEqual(config, attrib, value)) {
170 static int warned;
171 if (!warned) {
172 DebugMessageF("Disabling server's tfp mipmap support\n");
173 warned = 1;
174 }
175 config->bindToMipmapTexture = 0;
176 }
177 break;
178
179 default:
180 if (!scalarEqual(config, attrib, value))
181 return GL_FALSE;
182 }
183 }
184
185 return GL_TRUE;
186 }
187
188 static struct glx_config *
createDriMode(struct glx_config * config,const __DRIconfig ** driConfigs)189 createDriMode(struct glx_config *config, const __DRIconfig **driConfigs)
190 {
191 __GLXDRIconfigPrivate *driConfig;
192 int i;
193
194 for (i = 0; driConfigs[i]; i++) {
195 if (driConfigEqual(config, driConfigs[i]))
196 break;
197 }
198
199 if (driConfigs[i] == NULL)
200 return NULL;
201
202 driConfig = malloc(sizeof *driConfig);
203 if (driConfig == NULL)
204 return NULL;
205
206 driConfig->base = *config;
207 driConfig->driConfig = driConfigs[i];
208
209 return &driConfig->base;
210 }
211
212 _X_HIDDEN struct glx_config *
driConvertConfigs(struct glx_config * configs,const __DRIconfig ** driConfigs)213 driConvertConfigs(struct glx_config *configs, const __DRIconfig **driConfigs)
214 {
215 struct glx_config head, *tail, *m;
216
217 tail = &head;
218 head.next = NULL;
219 for (m = configs; m; m = m->next) {
220 tail->next = createDriMode(m, driConfigs);
221 if (tail->next == NULL) {
222 /* no matching dri config for m */
223 continue;
224 }
225
226
227 tail = tail->next;
228 }
229
230 return head.next;
231 }
232
233 _X_HIDDEN void
driDestroyConfigs(const __DRIconfig ** configs)234 driDestroyConfigs(const __DRIconfig **configs)
235 {
236 int i;
237
238 for (i = 0; configs[i]; i++)
239 free((__DRIconfig *) configs[i]);
240 free(configs);
241 }
242
243 static struct glx_config *
driInferDrawableConfig(struct glx_screen * psc,GLXDrawable draw)244 driInferDrawableConfig(struct glx_screen *psc, GLXDrawable draw)
245 {
246 unsigned int fbconfig = 0;
247 xcb_get_window_attributes_cookie_t cookie = { 0 };
248 xcb_get_window_attributes_reply_t *attr = NULL;
249 xcb_connection_t *conn = XGetXCBConnection(psc->dpy);
250
251 /* In practice here, either the XID is a bare Window or it was created
252 * by some other client. First let's see if the X server can tell us
253 * the answer. Xorg first added GLX_EXT_no_config_context in 1.20, where
254 * this usually works except for bare Windows that haven't been made
255 * current yet.
256 */
257 if (__glXGetDrawableAttribute(psc->dpy, draw, GLX_FBCONFIG_ID, &fbconfig)) {
258 return glx_config_find_fbconfig(psc->configs, fbconfig);
259 }
260
261 /* Well this had better be a Window then. Figure out its visual and
262 * then find the corresponding GLX visual.
263 */
264 cookie = xcb_get_window_attributes(conn, draw);
265 attr = xcb_get_window_attributes_reply(conn, cookie, NULL);
266
267 if (attr) {
268 uint32_t vid = attr->visual;
269 free(attr);
270 return glx_config_find_visual(psc->visuals, vid);
271 }
272
273 return NULL;
274 }
275
276 _X_HIDDEN __GLXDRIdrawable *
driFetchDrawable(struct glx_context * gc,GLXDrawable glxDrawable)277 driFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable)
278 {
279 Display *dpy = gc->psc->dpy;
280 struct glx_display *const priv = __glXInitialize(dpy);
281 __GLXDRIdrawable *pdraw;
282 struct glx_screen *psc = gc->psc;
283 struct glx_config *config = gc->config;
284 unsigned int type;
285
286 if (priv == NULL)
287 return NULL;
288
289 if (glxDrawable == None)
290 return NULL;
291
292 if (priv->drawHash == NULL)
293 return NULL;
294
295 if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) {
296 /* Resurrected, so remove from the alive-query-set if exist. */
297 _mesa_set_remove_key(priv->zombieGLXDrawable, pdraw);
298
299 pdraw->refcount ++;
300 return pdraw;
301 }
302
303 /* if this is a no-config context, infer the fbconfig from the drawable */
304 if (config == NULL)
305 config = driInferDrawableConfig(psc, glxDrawable);
306 if (config == NULL)
307 return NULL;
308
309 /* We can't find this GLX drawable above because it's either:
310 *
311 * 1. An X window ID instead of a GLX window ID. This could happend when
312 * glXMakeCurrent() is passed an X window directly instead of creating
313 * GLXWindow with glXCreateWindow() first.
314 *
315 * 2. A GLXPbuffer created on other display:
316 *
317 * From the GLX spec:
318 *
319 * Like other drawable types, GLXPbuffers are shared; any client which
320 * knows the associated XID can use a GLXPbuffer.
321 *
322 * So client other than the creator of this GLXPbuffer could use its
323 * XID to do something like glXMakeCurrent(). I can't find explicite
324 * statement in GLX spec that also allow GLXWindow and GLXPixmap.
325 *
326 * But even GLXWindow and GLXPixmap is allowed, currently client other
327 * than the GLX drawable creator has no way to find which X drawable
328 * (window or pixmap) this GLX drawable uses, except the GLXPbuffer
329 * case which use the same XID for both X pixmap and GLX drawable.
330 */
331
332 /* Infer the GLX drawable type. */
333 if (__glXGetDrawableAttribute(dpy, glxDrawable, GLX_DRAWABLE_TYPE, &type)) {
334 /* Xserver may support query with raw X11 window. */
335 if (type == GLX_PIXMAP_BIT) {
336 ErrorMessageF("GLXPixmap drawable type is not supported\n");
337 return NULL;
338 }
339 } else {
340 /* Xserver may not implement GLX_DRAWABLE_TYPE query yet. */
341 type = GLX_PBUFFER_BIT | GLX_WINDOW_BIT;
342 }
343
344 pdraw = psc->driScreen.createDrawable(psc, glxDrawable, glxDrawable,
345 type, config);
346
347 if (pdraw == NULL) {
348 ErrorMessageF("failed to create drawable\n");
349 return NULL;
350 }
351
352 if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) {
353 pdraw->destroyDrawable(pdraw);
354 return NULL;
355 }
356 pdraw->refcount = 1;
357
358 return pdraw;
359 }
360
361 static int
discardGLXBadDrawableHandler(Display * display,xError * err,XExtCodes * codes,int * ret_code)362 discardGLXBadDrawableHandler(Display *display, xError *err, XExtCodes *codes,
363 int *ret_code)
364 {
365 int code = codes->first_error + GLXBadDrawable;
366
367 /* Only discard error which is expected. */
368 if (err->majorCode == codes->major_opcode &&
369 err->minorCode == X_GLXGetDrawableAttributes &&
370 /* newer xserver use GLXBadDrawable, old one use BadDrawable */
371 (err->errorCode == code || err->errorCode == BadDrawable)) {
372 *ret_code = 1;
373 return 1;
374 }
375
376 return 0;
377 }
378
379 static void
checkServerGLXDrawableAlive(const struct glx_display * priv)380 checkServerGLXDrawableAlive(const struct glx_display *priv)
381 {
382 ErrorType old = XESetError(priv->dpy, priv->codes.extension,
383 discardGLXBadDrawableHandler);
384
385 set_foreach(priv->zombieGLXDrawable, entry) {
386 __GLXDRIdrawable *pdraw = (__GLXDRIdrawable *)entry->key;
387 GLXDrawable drawable = pdraw->drawable;
388 unsigned int dummy;
389
390 /* Fail to query, so the window has been closed. Release the GLXDrawable. */
391 if (!__glXGetDrawableAttribute(priv->dpy, drawable, GLX_WIDTH, &dummy)) {
392 pdraw->destroyDrawable(pdraw);
393 __glxHashDelete(priv->drawHash, drawable);
394 _mesa_set_remove(priv->zombieGLXDrawable, entry);
395 }
396 }
397
398 XESetError(priv->dpy, priv->codes.extension, old);
399 }
400
401 static void
releaseDrawable(const struct glx_display * priv,GLXDrawable drawable)402 releaseDrawable(const struct glx_display *priv, GLXDrawable drawable)
403 {
404 __GLXDRIdrawable *pdraw;
405
406 if (__glxHashLookup(priv->drawHash, drawable, (void *) &pdraw) == 0) {
407 /* Only native window and pbuffer have same GLX and X11 drawable ID. */
408 if (pdraw->drawable == pdraw->xDrawable) {
409 pdraw->refcount --;
410 /* If pbuffer's refcount reaches 0, it must be imported from other
411 * display. Because pbuffer created from this display will always
412 * hold the last refcount until destroy the GLXPbuffer object.
413 */
414 if (pdraw->refcount == 0) {
415 if (pdraw->psc->keep_native_window_glx_drawable) {
416 checkServerGLXDrawableAlive(priv);
417 _mesa_set_add(priv->zombieGLXDrawable, pdraw);
418 } else {
419 pdraw->destroyDrawable(pdraw);
420 __glxHashDelete(priv->drawHash, drawable);
421 }
422 }
423 }
424 }
425 }
426
427 _X_HIDDEN void
driReleaseDrawables(struct glx_context * gc)428 driReleaseDrawables(struct glx_context *gc)
429 {
430 const struct glx_display *priv = gc->psc->display;
431
432 releaseDrawable(priv, gc->currentDrawable);
433 releaseDrawable(priv, gc->currentReadable);
434
435 gc->currentDrawable = None;
436 gc->currentReadable = None;
437
438 }
439
440 _X_HIDDEN int
dri_convert_glx_attribs(unsigned num_attribs,const uint32_t * attribs,struct dri_ctx_attribs * dca)441 dri_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs,
442 struct dri_ctx_attribs *dca)
443 {
444 unsigned i;
445 uint32_t profile = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
446
447 dca->major_ver = 1;
448 dca->minor_ver = 0;
449 dca->render_type = GLX_RGBA_TYPE;
450 dca->reset = __DRI_CTX_RESET_NO_NOTIFICATION;
451 dca->release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
452 dca->flags = 0;
453 dca->api = __DRI_API_OPENGL;
454 dca->no_error = 0;
455
456 for (i = 0; i < num_attribs; i++) {
457 switch (attribs[i * 2]) {
458 case GLX_CONTEXT_MAJOR_VERSION_ARB:
459 dca->major_ver = attribs[i * 2 + 1];
460 break;
461 case GLX_CONTEXT_MINOR_VERSION_ARB:
462 dca->minor_ver = attribs[i * 2 + 1];
463 break;
464 case GLX_CONTEXT_FLAGS_ARB:
465 dca->flags = attribs[i * 2 + 1];
466 break;
467 case GLX_CONTEXT_OPENGL_NO_ERROR_ARB:
468 dca->no_error = attribs[i * 2 + 1];
469 break;
470 case GLX_CONTEXT_PROFILE_MASK_ARB:
471 profile = attribs[i * 2 + 1];
472 break;
473 case GLX_RENDER_TYPE:
474 dca->render_type = attribs[i * 2 + 1];
475 break;
476 case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB:
477 switch (attribs[i * 2 + 1]) {
478 case GLX_NO_RESET_NOTIFICATION_ARB:
479 dca->reset = __DRI_CTX_RESET_NO_NOTIFICATION;
480 break;
481 case GLX_LOSE_CONTEXT_ON_RESET_ARB:
482 dca->reset = __DRI_CTX_RESET_LOSE_CONTEXT;
483 break;
484 default:
485 return BadValue;
486 }
487 break;
488 case GLX_CONTEXT_RELEASE_BEHAVIOR_ARB:
489 switch (attribs[i * 2 + 1]) {
490 case GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB:
491 dca->release = __DRI_CTX_RELEASE_BEHAVIOR_NONE;
492 break;
493 case GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB:
494 dca->release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
495 break;
496 default:
497 return BadValue;
498 }
499 break;
500 case GLX_SCREEN:
501 /* Implies GLX_EXT_no_config_context */
502 dca->render_type = GLX_DONT_CARE;
503 break;
504 default:
505 /* If an unknown attribute is received, fail.
506 */
507 return BadValue;
508 }
509 }
510
511 switch (profile) {
512 case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
513 /* This is the default value, but there are no profiles before OpenGL
514 * 3.2. The GLX_ARB_create_context_profile spec says:
515 *
516 * "If the requested OpenGL version is less than 3.2,
517 * GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
518 * of the context is determined solely by the requested version."
519 */
520 dca->api = (dca->major_ver > 3 || (dca->major_ver == 3 && dca->minor_ver >= 2))
521 ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL;
522 break;
523 case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
524 dca->api = __DRI_API_OPENGL;
525 break;
526 case GLX_CONTEXT_ES_PROFILE_BIT_EXT:
527 if (dca->major_ver >= 3)
528 dca->api = __DRI_API_GLES3;
529 else if (dca->major_ver == 2 && dca->minor_ver == 0)
530 dca->api = __DRI_API_GLES2;
531 else if (dca->major_ver == 1 && dca->minor_ver < 2)
532 dca->api = __DRI_API_GLES;
533 else {
534 return BadValue;
535 }
536 break;
537 default:
538 return GLXBadProfileARB;
539 }
540
541 /* Unknown flag value */
542 if (dca->flags & ~(__DRI_CTX_FLAG_DEBUG |
543 __DRI_CTX_FLAG_FORWARD_COMPATIBLE |
544 __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS |
545 __DRI_CTX_FLAG_RESET_ISOLATION))
546 return BadValue;
547
548 /* There are no forward-compatible contexts before OpenGL 3.0. The
549 * GLX_ARB_create_context spec says:
550 *
551 * "Forward-compatible contexts are defined only for OpenGL versions
552 * 3.0 and later."
553 */
554 if (dca->major_ver < 3 && (dca->flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0)
555 return BadMatch;
556
557 /* It also says:
558 *
559 * "OpenGL contexts supporting version 3.0 or later of the API do not
560 * support color index rendering, even if a color index <config> is
561 * available."
562 */
563 if (dca->major_ver >= 3 && dca->render_type == GLX_COLOR_INDEX_TYPE)
564 return BadMatch;
565
566 /* The KHR_no_error specs say:
567 *
568 * Requires OpenGL ES 2.0 or OpenGL 2.0.
569 */
570 if (dca->no_error && dca->major_ver < 2)
571 return BadMatch;
572
573 /* The GLX_ARB_create_context_no_error specs say:
574 *
575 * BadMatch is generated if the GLX_CONTEXT_OPENGL_NO_ERROR_ARB is TRUE at
576 * the same time as a debug or robustness context is specified.
577 *
578 */
579 if (dca->no_error && ((dca->flags & __DRI_CTX_FLAG_DEBUG) ||
580 (dca->flags & __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)))
581 return BadMatch;
582
583 return Success;
584 }
585
586 unsigned
dri_context_error_to_glx_error(unsigned error)587 dri_context_error_to_glx_error(unsigned error)
588 {
589 if (error == __DRI_CTX_ERROR_SUCCESS)
590 return Success;
591 if (error == __DRI_CTX_ERROR_NO_MEMORY)
592 return BadAlloc;
593 else if (error == __DRI_CTX_ERROR_BAD_API)
594 return BadMatch;
595 else if (error == __DRI_CTX_ERROR_BAD_VERSION)
596 return GLXBadFBConfig;
597 else if (error == __DRI_CTX_ERROR_BAD_FLAG)
598 return BadMatch;
599 else if (error == __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE)
600 return BadValue;
601 else if (error == __DRI_CTX_ERROR_UNKNOWN_FLAG)
602 return BadValue;
603 else
604 unreachable("Impossible DRI context error");
605 }
606
607 struct glx_context *
dri_common_create_context(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,int renderType)608 dri_common_create_context(struct glx_screen *base,
609 struct glx_config *config_base,
610 struct glx_context *shareList,
611 int renderType)
612 {
613 unsigned int error;
614 uint32_t attribs[2] = { GLX_RENDER_TYPE, renderType };
615
616 return base->vtable->create_context_attribs(base, config_base, shareList,
617 1, attribs, &error);
618 }
619
620
621 /*
622 * Given a display pointer and screen number, determine the name of
623 * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc).
624 * Return True for success, False for failure.
625 */
626 static Bool
driGetDriverName(Display * dpy,int scrNum,char ** driverName)627 driGetDriverName(Display * dpy, int scrNum, char **driverName)
628 {
629 struct glx_screen *glx_screen = GetGLXScreenConfigs(dpy, scrNum);
630
631 if (!glx_screen || !glx_screen->vtable->get_driver_name)
632 return False;
633
634 *driverName = glx_screen->vtable->get_driver_name(glx_screen);
635 return True;
636 }
637
638 /*
639 * Exported function for querying the DRI driver for a given screen.
640 *
641 * The returned char pointer points to a static array that will be
642 * overwritten by subsequent calls.
643 */
644 _GLX_PUBLIC const char *
glXGetScreenDriver(Display * dpy,int scrNum)645 glXGetScreenDriver(Display * dpy, int scrNum)
646 {
647 static char ret[32];
648 char *driverName;
649
650 if (driGetDriverName(dpy, scrNum, &driverName)) {
651 int len;
652 if (!driverName)
653 return NULL;
654 len = strlen(driverName);
655 if (len >= 31)
656 return NULL;
657 memcpy(ret, driverName, len + 1);
658 free(driverName);
659 return ret;
660 }
661 return NULL;
662 }
663
664 /* glXGetDriverConfig must return a pointer with a static lifetime. To avoid
665 * keeping drivers loaded and other leaks, we keep a cache of results here that
666 * is cleared by an atexit handler.
667 */
668 struct driver_config_entry {
669 struct driver_config_entry *next;
670 char *driverName;
671 char *config;
672 };
673
674 static pthread_mutex_t driver_config_mutex = PTHREAD_MUTEX_INITIALIZER;
675 static struct driver_config_entry *driver_config_cache = NULL;
676
677 /* Called as an atexit function. Otherwise, this would have to be called with
678 * driver_config_mutex locked.
679 */
680 static void
clear_driver_config_cache()681 clear_driver_config_cache()
682 {
683 while (driver_config_cache) {
684 struct driver_config_entry *e = driver_config_cache;
685 driver_config_cache = e->next;
686
687 free(e->driverName);
688 free(e->config);
689 free(e);
690 }
691 }
692
693 /*
694 * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
695 *
696 * The returned char pointer points directly into the driver. Therefore
697 * it should be treated as a constant.
698 *
699 * If the driver was not found or does not support configuration NULL is
700 * returned.
701 */
702 _GLX_PUBLIC const char *
glXGetDriverConfig(const char * driverName)703 glXGetDriverConfig(const char *driverName)
704 {
705 struct driver_config_entry *e;
706
707 pthread_mutex_lock(&driver_config_mutex);
708
709 for (e = driver_config_cache; e; e = e->next) {
710 if (strcmp(e->driverName, driverName) == 0)
711 goto out;
712 }
713
714 e = malloc(sizeof(*e));
715 if (!e)
716 goto out;
717
718 e->config = pipe_loader_get_driinfo_xml(driverName);
719 e->driverName = strdup(driverName);
720 if (!e->config || !e->driverName) {
721 free(e->config);
722 free(e->driverName);
723 free(e);
724 e = NULL;
725 goto out;
726 }
727
728 e->next = driver_config_cache;
729 driver_config_cache = e;
730
731 if (!e->next)
732 atexit(clear_driver_config_cache);
733
734 out:
735 pthread_mutex_unlock(&driver_config_mutex);
736
737 return e ? e->config : NULL;
738 }
739
740 static void
driSetBackgroundContext(void * loaderPrivate)741 driSetBackgroundContext(void *loaderPrivate)
742 {
743 __glXSetCurrentContext(loaderPrivate);
744 }
745
746 static GLboolean
driIsThreadSafe(void * loaderPrivate)747 driIsThreadSafe(void *loaderPrivate)
748 {
749 struct glx_context *pcp = (struct glx_context *) loaderPrivate;
750 /* Check Xlib is running in thread safe mode
751 *
752 * 'lock_fns' is the XLockDisplay function pointer of the X11 display 'dpy'.
753 * It will be NULL if XInitThreads wasn't called.
754 */
755 return pcp->psc->dpy->lock_fns != NULL;
756 }
757
758 const __DRIbackgroundCallableExtension driBackgroundCallable = {
759 .base = { __DRI_BACKGROUND_CALLABLE, 2 },
760
761 .setBackgroundContext = driSetBackgroundContext,
762 .isThreadSafe = driIsThreadSafe,
763 };
764
765 const __DRIuseInvalidateExtension dri2UseInvalidate = {
766 .base = { __DRI_USE_INVALIDATE, 1 }
767 };
768
769 Bool
dri_bind_context(struct glx_context * context,GLXDrawable draw,GLXDrawable read)770 dri_bind_context(struct glx_context *context, GLXDrawable draw, GLXDrawable read)
771 {
772 __GLXDRIdrawable *pdraw, *pread;
773 __DRIdrawable *dri_draw = NULL, *dri_read = NULL;
774
775 pdraw = driFetchDrawable(context, draw);
776 pread = driFetchDrawable(context, read);
777
778 driReleaseDrawables(context);
779
780 if (pdraw)
781 dri_draw = pdraw->dri_drawable;
782 else if (draw != None)
783 return GLXBadDrawable;
784
785 if (pread)
786 dri_read = pread->dri_drawable;
787 else if (read != None)
788 return GLXBadDrawable;
789
790 if (!driBindContext(context->driContext, dri_draw, dri_read))
791 return GLXBadContext;
792
793 if (context->psc->display->driver == GLX_DRIVER_DRI3 ||
794 context->psc->display->driver == GLX_DRIVER_ZINK_YES) {
795 if (dri_draw)
796 dri_invalidate_drawable(dri_draw);
797 if (dri_read && dri_read != dri_draw)
798 dri_invalidate_drawable(dri_read);
799 }
800
801 return Success;
802 }
803
804 void
dri_unbind_context(struct glx_context * context)805 dri_unbind_context(struct glx_context *context)
806 {
807 driUnbindContext(context->driContext);
808 }
809
810 void
dri_destroy_context(struct glx_context * context)811 dri_destroy_context(struct glx_context *context)
812 {
813 driReleaseDrawables(context);
814
815 free((char *) context->extensions);
816
817 driDestroyContext(context->driContext);
818
819 free(context);
820 }
821
822 struct glx_context *
dri_create_context_attribs(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,unsigned num_attribs,const uint32_t * attribs,unsigned * error)823 dri_create_context_attribs(struct glx_screen *base,
824 struct glx_config *config_base,
825 struct glx_context *shareList,
826 unsigned num_attribs,
827 const uint32_t *attribs,
828 unsigned *error)
829 {
830 struct glx_context *pcp = NULL;
831 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
832 __DRIcontext *shared = NULL;
833
834 struct dri_ctx_attribs dca;
835 uint32_t ctx_attribs[2 * 6];
836 unsigned num_ctx_attribs = 0;
837
838 *error = dri_convert_glx_attribs(num_attribs, attribs, &dca);
839 if (*error != __DRI_CTX_ERROR_SUCCESS)
840 goto error_exit;
841
842 /* Check the renderType value */
843 if (!validate_renderType_against_config(config_base, dca.render_type)) {
844 *error = BadValue;
845 goto error_exit;
846 }
847
848 if (shareList) {
849 /* We can't share with an indirect context */
850 if (!shareList->isDirect)
851 return NULL;
852
853 /* The GLX_ARB_create_context_no_error specs say:
854 *
855 * BadMatch is generated if the value of GLX_CONTEXT_OPENGL_NO_ERROR_ARB
856 * used to create <share_context> does not match the value of
857 * GLX_CONTEXT_OPENGL_NO_ERROR_ARB for the context being created.
858 */
859 if (!!shareList->noError != !!dca.no_error) {
860 *error = BadMatch;
861 return NULL;
862 }
863
864 shared = shareList->driContext;
865 }
866
867 pcp = calloc(1, sizeof *pcp);
868 if (pcp == NULL) {
869 *error = BadAlloc;
870 goto error_exit;
871 }
872
873 if (!glx_context_init(pcp, base, config_base))
874 goto error_exit;
875
876 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
877 ctx_attribs[num_ctx_attribs++] = dca.major_ver;
878 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
879 ctx_attribs[num_ctx_attribs++] = dca.minor_ver;
880
881 /* Only send a value when the non-default value is requested. By doing
882 * this we don't have to check the driver's DRI3 version before sending the
883 * default value.
884 */
885 if (dca.reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
886 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
887 ctx_attribs[num_ctx_attribs++] = dca.reset;
888 }
889
890 if (dca.release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) {
891 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR;
892 ctx_attribs[num_ctx_attribs++] = dca.release;
893 }
894
895 if (dca.no_error) {
896 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_NO_ERROR;
897 ctx_attribs[num_ctx_attribs++] = dca.no_error;
898 pcp->noError = GL_TRUE;
899 }
900
901 if (dca.flags != 0) {
902 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
903 ctx_attribs[num_ctx_attribs++] = dca.flags;
904 }
905
906 /* The renderType is retrieved from attribs, or set to default
907 * of GLX_RGBA_TYPE.
908 */
909 pcp->renderType = dca.render_type;
910
911 pcp->driContext =
912 driCreateContextAttribs(base->frontend_screen,
913 dca.api,
914 config ? config->driConfig : NULL,
915 shared,
916 num_ctx_attribs / 2,
917 ctx_attribs,
918 error,
919 pcp);
920
921 *error = dri_context_error_to_glx_error(*error);
922
923 if (pcp->driContext == NULL)
924 goto error_exit;
925
926 pcp->vtable = base->context_vtable;
927
928 return pcp;
929
930 error_exit:
931 free(pcp);
932
933 return NULL;
934 }
935
936 char *
dri_get_driver_name(struct glx_screen * glx_screen)937 dri_get_driver_name(struct glx_screen *glx_screen)
938 {
939 return strdup(glx_screen->driverName);
940 }
941
942 const struct glx_screen_vtable dri_screen_vtable = {
943 .create_context = dri_common_create_context,
944 .create_context_attribs = dri_create_context_attribs,
945 .query_renderer_integer = glx_dri_query_renderer_integer,
946 .query_renderer_string = glx_dri_query_renderer_string,
947 .get_driver_name = dri_get_driver_name,
948 };
949
950 void
dri_bind_tex_image(__GLXDRIdrawable * base,int buffer,const int * attrib_list)951 dri_bind_tex_image(__GLXDRIdrawable *base, int buffer, const int *attrib_list)
952 {
953 struct glx_context *gc = __glXGetCurrentContext();
954
955 if (!base)
956 return;
957
958 if (base->psc->display->driver == GLX_DRIVER_DRI3) {
959 dri_invalidate_drawable(base->dri_drawable);
960
961 XSync(gc->currentDpy, false);
962 }
963
964 dri_set_tex_buffer2(gc->driContext,
965 base->textureTarget,
966 base->textureFormat,
967 base->dri_drawable);
968 }
969
970 bool
dri_screen_init(struct glx_screen * psc,struct glx_display * priv,int screen,int fd,const __DRIextension ** loader_extensions,bool driver_name_is_inferred)971 dri_screen_init(struct glx_screen *psc, struct glx_display *priv, int screen, int fd, const __DRIextension **loader_extensions, bool driver_name_is_inferred)
972 {
973 const __DRIconfig **driver_configs;
974 struct glx_config *configs = NULL, *visuals = NULL;
975
976 if (!glx_screen_init(psc, screen, priv))
977 return false;
978
979 enum dri_screen_type type;
980 switch (psc->display->driver) {
981 case GLX_DRIVER_DRI3:
982 case GLX_DRIVER_DRI2:
983 type = DRI_SCREEN_DRI3;
984 break;
985 case GLX_DRIVER_ZINK_YES:
986 type = DRI_SCREEN_KOPPER;
987 break;
988 case GLX_DRIVER_SW:
989 type = DRI_SCREEN_SWRAST;
990 break;
991 default:
992 unreachable("unknown glx driver type");
993 }
994
995 psc->frontend_screen = driCreateNewScreen3(screen, fd,
996 loader_extensions,
997 type,
998 &driver_configs, driver_name_is_inferred,
999 psc->display->has_multibuffer, psc);
1000
1001 if (psc->frontend_screen == NULL) {
1002 goto handle_error;
1003 }
1004
1005 configs = driConvertConfigs(psc->configs, driver_configs);
1006 visuals = driConvertConfigs(psc->visuals, driver_configs);
1007
1008 if (!configs || !visuals) {
1009 ErrorMessageF("No matching fbConfigs or visuals found\n");
1010 goto handle_error;
1011 }
1012
1013 glx_config_destroy_list(psc->configs);
1014 psc->configs = configs;
1015 glx_config_destroy_list(psc->visuals);
1016 psc->visuals = visuals;
1017
1018 psc->driver_configs = driver_configs;
1019
1020 psc->vtable = &dri_screen_vtable;
1021 psc->driScreen.bindTexImage = dri_bind_tex_image;
1022
1023 return true;
1024
1025 handle_error:
1026 if (configs)
1027 glx_config_destroy_list(configs);
1028 if (visuals)
1029 glx_config_destroy_list(visuals);
1030
1031 return false;
1032 }
1033 #endif /* GLX_DIRECT_RENDERING */
1034