1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. 3bf215546Sopenharmony_ci * Copyright © 2008 Red Hat, Inc. 4bf215546Sopenharmony_ci * 5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Soft- 7bf215546Sopenharmony_ci * ware"), to deal in the Software without restriction, including without 8bf215546Sopenharmony_ci * limitation the rights to use, copy, modify, merge, publish, distribute, 9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 10bf215546Sopenharmony_ci * Software is furnished to do so, provided that the above copyright 11bf215546Sopenharmony_ci * notice(s) and this permission notice appear in all copies of the Soft- 12bf215546Sopenharmony_ci * ware and that both the above copyright notice(s) and this permission 13bf215546Sopenharmony_ci * notice appear in supporting documentation. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 16bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 17bf215546Sopenharmony_ci * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 18bf215546Sopenharmony_ci * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 19bf215546Sopenharmony_ci * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 20bf215546Sopenharmony_ci * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21bf215546Sopenharmony_ci * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22bf215546Sopenharmony_ci * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 23bf215546Sopenharmony_ci * MANCE OF THIS SOFTWARE. 24bf215546Sopenharmony_ci * 25bf215546Sopenharmony_ci * Except as contained in this notice, the name of a copyright holder shall 26bf215546Sopenharmony_ci * not be used in advertising or otherwise to promote the sale, use or 27bf215546Sopenharmony_ci * other dealings in this Software without prior written authorization of 28bf215546Sopenharmony_ci * the copyright holder. 29bf215546Sopenharmony_ci * 30bf215546Sopenharmony_ci * Authors: 31bf215546Sopenharmony_ci * Kevin E. Martin <kevin@precisioninsight.com> 32bf215546Sopenharmony_ci * Brian Paul <brian@precisioninsight.com> 33bf215546Sopenharmony_ci * Kristian Høgsberg (krh@redhat.com) 34bf215546Sopenharmony_ci */ 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_ci#include <unistd.h> 39bf215546Sopenharmony_ci#include <dlfcn.h> 40bf215546Sopenharmony_ci#include <stdarg.h> 41bf215546Sopenharmony_ci#include "glxclient.h" 42bf215546Sopenharmony_ci#include "dri_common.h" 43bf215546Sopenharmony_ci#include "loader.h" 44bf215546Sopenharmony_ci#include <X11/Xlib-xcb.h> 45bf215546Sopenharmony_ci#include <xcb/xproto.h> 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci#ifndef RTLD_NOW 48bf215546Sopenharmony_ci#define RTLD_NOW 0 49bf215546Sopenharmony_ci#endif 50bf215546Sopenharmony_ci#ifndef RTLD_GLOBAL 51bf215546Sopenharmony_ci#define RTLD_GLOBAL 0 52bf215546Sopenharmony_ci#endif 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_ci#ifndef GL_LIB_NAME 55bf215546Sopenharmony_ci#define GL_LIB_NAME "libGL.so.1" 56bf215546Sopenharmony_ci#endif 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci/** 59bf215546Sopenharmony_ci * Try to \c dlopen the named driver. 60bf215546Sopenharmony_ci * 61bf215546Sopenharmony_ci * This function adds the "_dri.so" suffix to the driver name and searches the 62bf215546Sopenharmony_ci * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in 63bf215546Sopenharmony_ci * order to find the driver. 64bf215546Sopenharmony_ci * 65bf215546Sopenharmony_ci * \param driverName - a name like "i965", "radeon", "nouveau", etc. 66bf215546Sopenharmony_ci * \param out_driver_handle - Address to return the resulting dlopen() handle. 67bf215546Sopenharmony_ci * 68bf215546Sopenharmony_ci * \returns 69bf215546Sopenharmony_ci * The __DRIextension entrypoint table for the driver, or \c NULL if driver 70bf215546Sopenharmony_ci * file not found. 71bf215546Sopenharmony_ci */ 72bf215546Sopenharmony_ci_X_HIDDEN const __DRIextension ** 73bf215546Sopenharmony_cidriOpenDriver(const char *driverName, void **out_driver_handle) 74bf215546Sopenharmony_ci{ 75bf215546Sopenharmony_ci void *glhandle; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci /* Attempt to make sure libGL symbols will be visible to the driver */ 78bf215546Sopenharmony_ci glhandle = dlopen(GL_LIB_NAME, RTLD_NOW | RTLD_GLOBAL); 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci static const char *search_path_vars[] = { 81bf215546Sopenharmony_ci "LIBGL_DRIVERS_PATH", 82bf215546Sopenharmony_ci "LIBGL_DRIVERS_DIR", /* deprecated */ 83bf215546Sopenharmony_ci NULL 84bf215546Sopenharmony_ci }; 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci const __DRIextension **extensions = 87bf215546Sopenharmony_ci loader_open_driver(driverName, out_driver_handle, search_path_vars); 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci if (glhandle) 90bf215546Sopenharmony_ci dlclose(glhandle); 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci return extensions; 93bf215546Sopenharmony_ci} 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci#define __ATTRIB(attrib, field) \ 96bf215546Sopenharmony_ci { attrib, offsetof(struct glx_config, field) } 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_cistatic const struct 99bf215546Sopenharmony_ci{ 100bf215546Sopenharmony_ci unsigned int attrib, offset; 101bf215546Sopenharmony_ci} attribMap[] = { 102bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits), 103bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_LEVEL, level), 104bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits), 105bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits), 106bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits), 107bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits), 108bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits), 109bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits), 110bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits), 111bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits), 112bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits), 113bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits), 114bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers), 115bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_SAMPLES, samples), 116bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode), 117bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode), 118bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers), 119bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod), 120bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb), 121bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba), 122bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture), 123bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted), 124bf215546Sopenharmony_ci __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable) 125bf215546Sopenharmony_ci}; 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_cistatic int 128bf215546Sopenharmony_ciscalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value) 129bf215546Sopenharmony_ci{ 130bf215546Sopenharmony_ci unsigned glxValue, i; 131bf215546Sopenharmony_ci 132bf215546Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(attribMap); i++) 133bf215546Sopenharmony_ci if (attribMap[i].attrib == attrib) { 134bf215546Sopenharmony_ci glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset); 135bf215546Sopenharmony_ci return glxValue == GLX_DONT_CARE || glxValue == value; 136bf215546Sopenharmony_ci } 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci return GL_TRUE; /* Is a non-existing attribute equal to value? */ 139bf215546Sopenharmony_ci} 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_cistatic int 142bf215546Sopenharmony_cidriConfigEqual(const __DRIcoreExtension *core, 143bf215546Sopenharmony_ci struct glx_config *config, const __DRIconfig *driConfig) 144bf215546Sopenharmony_ci{ 145bf215546Sopenharmony_ci unsigned int attrib, value, glxValue; 146bf215546Sopenharmony_ci int i; 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci i = 0; 149bf215546Sopenharmony_ci while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) { 150bf215546Sopenharmony_ci switch (attrib) { 151bf215546Sopenharmony_ci case __DRI_ATTRIB_RENDER_TYPE: 152bf215546Sopenharmony_ci glxValue = 0; 153bf215546Sopenharmony_ci if (value & __DRI_ATTRIB_RGBA_BIT) { 154bf215546Sopenharmony_ci glxValue |= GLX_RGBA_BIT; 155bf215546Sopenharmony_ci } 156bf215546Sopenharmony_ci if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) { 157bf215546Sopenharmony_ci glxValue |= GLX_COLOR_INDEX_BIT; 158bf215546Sopenharmony_ci } 159bf215546Sopenharmony_ci if (value & __DRI_ATTRIB_FLOAT_BIT) { 160bf215546Sopenharmony_ci glxValue |= GLX_RGBA_FLOAT_BIT_ARB; 161bf215546Sopenharmony_ci } 162bf215546Sopenharmony_ci if (value & __DRI_ATTRIB_UNSIGNED_FLOAT_BIT) { 163bf215546Sopenharmony_ci glxValue |= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT; 164bf215546Sopenharmony_ci } 165bf215546Sopenharmony_ci if (glxValue != config->renderType) 166bf215546Sopenharmony_ci return GL_FALSE; 167bf215546Sopenharmony_ci break; 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS: 170bf215546Sopenharmony_ci glxValue = 0; 171bf215546Sopenharmony_ci if (value & __DRI_ATTRIB_TEXTURE_1D_BIT) 172bf215546Sopenharmony_ci glxValue |= GLX_TEXTURE_1D_BIT_EXT; 173bf215546Sopenharmony_ci if (value & __DRI_ATTRIB_TEXTURE_2D_BIT) 174bf215546Sopenharmony_ci glxValue |= GLX_TEXTURE_2D_BIT_EXT; 175bf215546Sopenharmony_ci if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT) 176bf215546Sopenharmony_ci glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT; 177bf215546Sopenharmony_ci if (config->bindToTextureTargets != GLX_DONT_CARE && 178bf215546Sopenharmony_ci glxValue != config->bindToTextureTargets) 179bf215546Sopenharmony_ci return GL_FALSE; 180bf215546Sopenharmony_ci break; 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci case __DRI_ATTRIB_SWAP_METHOD: 183bf215546Sopenharmony_ci if (value == __DRI_ATTRIB_SWAP_EXCHANGE) 184bf215546Sopenharmony_ci glxValue = GLX_SWAP_EXCHANGE_OML; 185bf215546Sopenharmony_ci else if (value == __DRI_ATTRIB_SWAP_COPY) 186bf215546Sopenharmony_ci glxValue = GLX_SWAP_COPY_OML; 187bf215546Sopenharmony_ci else 188bf215546Sopenharmony_ci glxValue = GLX_SWAP_UNDEFINED_OML; 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci if (!scalarEqual(config, attrib, glxValue)) 191bf215546Sopenharmony_ci return GL_FALSE; 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ci break; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci /* Nerf some attributes we can safely ignore if the server claims to 196bf215546Sopenharmony_ci * support them but the driver does not. 197bf215546Sopenharmony_ci */ 198bf215546Sopenharmony_ci case __DRI_ATTRIB_CONFIG_CAVEAT: 199bf215546Sopenharmony_ci if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) 200bf215546Sopenharmony_ci glxValue = GLX_NON_CONFORMANT_CONFIG; 201bf215546Sopenharmony_ci else if (value & __DRI_ATTRIB_SLOW_BIT) 202bf215546Sopenharmony_ci glxValue = GLX_SLOW_CONFIG; 203bf215546Sopenharmony_ci else 204bf215546Sopenharmony_ci glxValue = GLX_NONE; 205bf215546Sopenharmony_ci if (glxValue != config->visualRating) { 206bf215546Sopenharmony_ci if (config->visualRating == GLX_NONE) { 207bf215546Sopenharmony_ci static int warned; 208bf215546Sopenharmony_ci if (!warned) { 209bf215546Sopenharmony_ci DebugMessageF("Not downgrading visual rating\n"); 210bf215546Sopenharmony_ci warned = 1; 211bf215546Sopenharmony_ci } 212bf215546Sopenharmony_ci } else { 213bf215546Sopenharmony_ci return GL_FALSE; 214bf215546Sopenharmony_ci } 215bf215546Sopenharmony_ci } 216bf215546Sopenharmony_ci break; 217bf215546Sopenharmony_ci 218bf215546Sopenharmony_ci case __DRI_ATTRIB_AUX_BUFFERS: 219bf215546Sopenharmony_ci if (!scalarEqual(config, attrib, value)) { 220bf215546Sopenharmony_ci static int warned; 221bf215546Sopenharmony_ci if (!warned) { 222bf215546Sopenharmony_ci DebugMessageF("Disabling server's aux buffer support\n"); 223bf215546Sopenharmony_ci warned = 1; 224bf215546Sopenharmony_ci } 225bf215546Sopenharmony_ci config->numAuxBuffers = 0; 226bf215546Sopenharmony_ci } 227bf215546Sopenharmony_ci break; 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_ci case __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE: 230bf215546Sopenharmony_ci if (!scalarEqual(config, attrib, value)) { 231bf215546Sopenharmony_ci static int warned; 232bf215546Sopenharmony_ci if (!warned) { 233bf215546Sopenharmony_ci DebugMessageF("Disabling server's tfp mipmap support\n"); 234bf215546Sopenharmony_ci warned = 1; 235bf215546Sopenharmony_ci } 236bf215546Sopenharmony_ci config->bindToMipmapTexture = 0; 237bf215546Sopenharmony_ci } 238bf215546Sopenharmony_ci break; 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci default: 241bf215546Sopenharmony_ci if (!scalarEqual(config, attrib, value)) 242bf215546Sopenharmony_ci return GL_FALSE; 243bf215546Sopenharmony_ci } 244bf215546Sopenharmony_ci } 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci return GL_TRUE; 247bf215546Sopenharmony_ci} 248bf215546Sopenharmony_ci 249bf215546Sopenharmony_cistatic struct glx_config * 250bf215546Sopenharmony_cicreateDriMode(const __DRIcoreExtension * core, 251bf215546Sopenharmony_ci struct glx_config *config, const __DRIconfig **driConfigs) 252bf215546Sopenharmony_ci{ 253bf215546Sopenharmony_ci __GLXDRIconfigPrivate *driConfig; 254bf215546Sopenharmony_ci int i; 255bf215546Sopenharmony_ci 256bf215546Sopenharmony_ci for (i = 0; driConfigs[i]; i++) { 257bf215546Sopenharmony_ci if (driConfigEqual(core, config, driConfigs[i])) 258bf215546Sopenharmony_ci break; 259bf215546Sopenharmony_ci } 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci if (driConfigs[i] == NULL) 262bf215546Sopenharmony_ci return NULL; 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci driConfig = malloc(sizeof *driConfig); 265bf215546Sopenharmony_ci if (driConfig == NULL) 266bf215546Sopenharmony_ci return NULL; 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci driConfig->base = *config; 269bf215546Sopenharmony_ci driConfig->driConfig = driConfigs[i]; 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci return &driConfig->base; 272bf215546Sopenharmony_ci} 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci_X_HIDDEN struct glx_config * 275bf215546Sopenharmony_cidriConvertConfigs(const __DRIcoreExtension * core, 276bf215546Sopenharmony_ci struct glx_config *configs, const __DRIconfig **driConfigs) 277bf215546Sopenharmony_ci{ 278bf215546Sopenharmony_ci struct glx_config head, *tail, *m; 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci tail = &head; 281bf215546Sopenharmony_ci head.next = NULL; 282bf215546Sopenharmony_ci for (m = configs; m; m = m->next) { 283bf215546Sopenharmony_ci tail->next = createDriMode(core, m, driConfigs); 284bf215546Sopenharmony_ci if (tail->next == NULL) { 285bf215546Sopenharmony_ci /* no matching dri config for m */ 286bf215546Sopenharmony_ci continue; 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci tail = tail->next; 291bf215546Sopenharmony_ci } 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci return head.next; 294bf215546Sopenharmony_ci} 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_ci_X_HIDDEN void 297bf215546Sopenharmony_cidriDestroyConfigs(const __DRIconfig **configs) 298bf215546Sopenharmony_ci{ 299bf215546Sopenharmony_ci int i; 300bf215546Sopenharmony_ci 301bf215546Sopenharmony_ci for (i = 0; configs[i]; i++) 302bf215546Sopenharmony_ci free((__DRIconfig *) configs[i]); 303bf215546Sopenharmony_ci free(configs); 304bf215546Sopenharmony_ci} 305bf215546Sopenharmony_ci 306bf215546Sopenharmony_cistatic struct glx_config * 307bf215546Sopenharmony_cidriInferDrawableConfig(struct glx_screen *psc, GLXDrawable draw) 308bf215546Sopenharmony_ci{ 309bf215546Sopenharmony_ci unsigned int fbconfig = 0; 310bf215546Sopenharmony_ci xcb_get_window_attributes_cookie_t cookie = { 0 }; 311bf215546Sopenharmony_ci xcb_get_window_attributes_reply_t *attr = NULL; 312bf215546Sopenharmony_ci xcb_connection_t *conn = XGetXCBConnection(psc->dpy); 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci /* In practice here, either the XID is a bare Window or it was created 315bf215546Sopenharmony_ci * by some other client. First let's see if the X server can tell us 316bf215546Sopenharmony_ci * the answer. Xorg first added GLX_EXT_no_config_context in 1.20, where 317bf215546Sopenharmony_ci * this usually works except for bare Windows that haven't been made 318bf215546Sopenharmony_ci * current yet. 319bf215546Sopenharmony_ci */ 320bf215546Sopenharmony_ci if (__glXGetDrawableAttribute(psc->dpy, draw, GLX_FBCONFIG_ID, &fbconfig)) { 321bf215546Sopenharmony_ci return glx_config_find_fbconfig(psc->configs, fbconfig); 322bf215546Sopenharmony_ci } 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci /* Well this had better be a Window then. Figure out its visual and 325bf215546Sopenharmony_ci * then find the corresponding GLX visual. 326bf215546Sopenharmony_ci */ 327bf215546Sopenharmony_ci cookie = xcb_get_window_attributes(conn, draw); 328bf215546Sopenharmony_ci attr = xcb_get_window_attributes_reply(conn, cookie, NULL); 329bf215546Sopenharmony_ci 330bf215546Sopenharmony_ci if (attr) { 331bf215546Sopenharmony_ci uint32_t vid = attr->visual; 332bf215546Sopenharmony_ci free(attr); 333bf215546Sopenharmony_ci return glx_config_find_visual(psc->visuals, vid); 334bf215546Sopenharmony_ci } 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci return NULL; 337bf215546Sopenharmony_ci} 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_ci_X_HIDDEN __GLXDRIdrawable * 340bf215546Sopenharmony_cidriFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable) 341bf215546Sopenharmony_ci{ 342bf215546Sopenharmony_ci Display *dpy = gc->psc->dpy; 343bf215546Sopenharmony_ci struct glx_display *const priv = __glXInitialize(dpy); 344bf215546Sopenharmony_ci __GLXDRIdrawable *pdraw; 345bf215546Sopenharmony_ci struct glx_screen *psc; 346bf215546Sopenharmony_ci struct glx_config *config = gc->config; 347bf215546Sopenharmony_ci unsigned int type; 348bf215546Sopenharmony_ci 349bf215546Sopenharmony_ci if (priv == NULL) 350bf215546Sopenharmony_ci return NULL; 351bf215546Sopenharmony_ci 352bf215546Sopenharmony_ci if (glxDrawable == None) 353bf215546Sopenharmony_ci return NULL; 354bf215546Sopenharmony_ci 355bf215546Sopenharmony_ci psc = priv->screens[gc->screen]; 356bf215546Sopenharmony_ci if (priv->drawHash == NULL) 357bf215546Sopenharmony_ci return NULL; 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_ci if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) { 360bf215546Sopenharmony_ci /* Resurrected, so remove from the alive-query-set if exist. */ 361bf215546Sopenharmony_ci _mesa_set_remove_key(priv->zombieGLXDrawable, pdraw); 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_ci pdraw->refcount ++; 364bf215546Sopenharmony_ci return pdraw; 365bf215546Sopenharmony_ci } 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci /* if this is a no-config context, infer the fbconfig from the drawable */ 368bf215546Sopenharmony_ci if (config == NULL) 369bf215546Sopenharmony_ci config = driInferDrawableConfig(gc->psc, glxDrawable); 370bf215546Sopenharmony_ci if (config == NULL) 371bf215546Sopenharmony_ci return NULL; 372bf215546Sopenharmony_ci 373bf215546Sopenharmony_ci /* We can't find this GLX drawable above because it's either: 374bf215546Sopenharmony_ci * 375bf215546Sopenharmony_ci * 1. An X window ID instead of a GLX window ID. This could happend when 376bf215546Sopenharmony_ci * glXMakeCurrent() is passed an X window directly instead of creating 377bf215546Sopenharmony_ci * GLXWindow with glXCreateWindow() first. 378bf215546Sopenharmony_ci * 379bf215546Sopenharmony_ci * 2. A GLXPbuffer created on other display: 380bf215546Sopenharmony_ci * 381bf215546Sopenharmony_ci * From the GLX spec: 382bf215546Sopenharmony_ci * 383bf215546Sopenharmony_ci * Like other drawable types, GLXPbuffers are shared; any client which 384bf215546Sopenharmony_ci * knows the associated XID can use a GLXPbuffer. 385bf215546Sopenharmony_ci * 386bf215546Sopenharmony_ci * So client other than the creator of this GLXPbuffer could use its 387bf215546Sopenharmony_ci * XID to do something like glXMakeCurrent(). I can't find explicite 388bf215546Sopenharmony_ci * statement in GLX spec that also allow GLXWindow and GLXPixmap. 389bf215546Sopenharmony_ci * 390bf215546Sopenharmony_ci * But even GLXWindow and GLXPixmap is allowed, currently client other 391bf215546Sopenharmony_ci * than the GLX drawable creator has no way to find which X drawable 392bf215546Sopenharmony_ci * (window or pixmap) this GLX drawable uses, except the GLXPbuffer 393bf215546Sopenharmony_ci * case which use the same XID for both X pixmap and GLX drawable. 394bf215546Sopenharmony_ci */ 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ci /* Infer the GLX drawable type. */ 397bf215546Sopenharmony_ci if (__glXGetDrawableAttribute(dpy, glxDrawable, GLX_DRAWABLE_TYPE, &type)) { 398bf215546Sopenharmony_ci /* Xserver may support query with raw X11 window. */ 399bf215546Sopenharmony_ci if (type == GLX_PIXMAP_BIT) { 400bf215546Sopenharmony_ci ErrorMessageF("GLXPixmap drawable type is not supported\n"); 401bf215546Sopenharmony_ci return NULL; 402bf215546Sopenharmony_ci } 403bf215546Sopenharmony_ci } else { 404bf215546Sopenharmony_ci /* Xserver may not implement GLX_DRAWABLE_TYPE query yet. */ 405bf215546Sopenharmony_ci type = GLX_PBUFFER_BIT | GLX_WINDOW_BIT; 406bf215546Sopenharmony_ci } 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci pdraw = psc->driScreen->createDrawable(psc, glxDrawable, glxDrawable, 409bf215546Sopenharmony_ci type, config); 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci if (pdraw == NULL) { 412bf215546Sopenharmony_ci ErrorMessageF("failed to create drawable\n"); 413bf215546Sopenharmony_ci return NULL; 414bf215546Sopenharmony_ci } 415bf215546Sopenharmony_ci 416bf215546Sopenharmony_ci if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) { 417bf215546Sopenharmony_ci (*pdraw->destroyDrawable) (pdraw); 418bf215546Sopenharmony_ci return NULL; 419bf215546Sopenharmony_ci } 420bf215546Sopenharmony_ci /* This sure does look suspicious, doesn't it? We're on this path because 421bf215546Sopenharmony_ci * this is a naked Window. GLX 1.3 drawables have an explicit creation 422bf215546Sopenharmony_ci * step (setting refcount to 1), and those we would have found in the 423bf215546Sopenharmony_ci * hash lookup above, bumped their refcount for the bind_context we're 424bf215546Sopenharmony_ci * being called for, and then returned. But since we just created the 425bf215546Sopenharmony_ci * internal naked-Window state, we need to account for both here. 426bf215546Sopenharmony_ci */ 427bf215546Sopenharmony_ci pdraw->refcount = 2; 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci return pdraw; 430bf215546Sopenharmony_ci} 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_cistatic int 433bf215546Sopenharmony_cidiscardGLXBadDrawableHandler(Display *display, xError *err, XExtCodes *codes, 434bf215546Sopenharmony_ci int *ret_code) 435bf215546Sopenharmony_ci{ 436bf215546Sopenharmony_ci int code = codes->first_error + GLXBadDrawable; 437bf215546Sopenharmony_ci 438bf215546Sopenharmony_ci /* Only discard error which is expected. */ 439bf215546Sopenharmony_ci if (err->majorCode == codes->major_opcode && 440bf215546Sopenharmony_ci err->minorCode == X_GLXGetDrawableAttributes && 441bf215546Sopenharmony_ci /* newer xserver use GLXBadDrawable, old one use BadDrawable */ 442bf215546Sopenharmony_ci (err->errorCode == code || err->errorCode == BadDrawable)) { 443bf215546Sopenharmony_ci *ret_code = 1; 444bf215546Sopenharmony_ci return 1; 445bf215546Sopenharmony_ci } 446bf215546Sopenharmony_ci 447bf215546Sopenharmony_ci return 0; 448bf215546Sopenharmony_ci} 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_cistatic void 451bf215546Sopenharmony_cicheckServerGLXDrawableAlive(const struct glx_display *priv) 452bf215546Sopenharmony_ci{ 453bf215546Sopenharmony_ci ErrorType old = XESetError(priv->dpy, priv->codes.extension, 454bf215546Sopenharmony_ci discardGLXBadDrawableHandler); 455bf215546Sopenharmony_ci 456bf215546Sopenharmony_ci set_foreach(priv->zombieGLXDrawable, entry) { 457bf215546Sopenharmony_ci __GLXDRIdrawable *pdraw = (__GLXDRIdrawable *)entry->key; 458bf215546Sopenharmony_ci GLXDrawable drawable = pdraw->drawable; 459bf215546Sopenharmony_ci unsigned int dummy; 460bf215546Sopenharmony_ci 461bf215546Sopenharmony_ci /* Fail to query, so the window has been closed. Release the GLXDrawable. */ 462bf215546Sopenharmony_ci if (!__glXGetDrawableAttribute(priv->dpy, drawable, GLX_WIDTH, &dummy)) { 463bf215546Sopenharmony_ci pdraw->destroyDrawable(pdraw); 464bf215546Sopenharmony_ci __glxHashDelete(priv->drawHash, drawable); 465bf215546Sopenharmony_ci _mesa_set_remove(priv->zombieGLXDrawable, entry); 466bf215546Sopenharmony_ci } 467bf215546Sopenharmony_ci } 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ci XESetError(priv->dpy, priv->codes.extension, old); 470bf215546Sopenharmony_ci} 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_cistatic void 473bf215546Sopenharmony_cireleaseDrawable(const struct glx_display *priv, GLXDrawable drawable) 474bf215546Sopenharmony_ci{ 475bf215546Sopenharmony_ci __GLXDRIdrawable *pdraw; 476bf215546Sopenharmony_ci 477bf215546Sopenharmony_ci if (__glxHashLookup(priv->drawHash, drawable, (void *) &pdraw) == 0) { 478bf215546Sopenharmony_ci /* Only native window and pbuffer have same GLX and X11 drawable ID. */ 479bf215546Sopenharmony_ci if (pdraw->drawable == pdraw->xDrawable) { 480bf215546Sopenharmony_ci pdraw->refcount --; 481bf215546Sopenharmony_ci /* If pbuffer's refcount reaches 0, it must be imported from other 482bf215546Sopenharmony_ci * display. Because pbuffer created from this display will always 483bf215546Sopenharmony_ci * hold the last refcount until destroy the GLXPbuffer object. 484bf215546Sopenharmony_ci */ 485bf215546Sopenharmony_ci if (pdraw->refcount == 0) { 486bf215546Sopenharmony_ci if (pdraw->psc->keep_native_window_glx_drawable) { 487bf215546Sopenharmony_ci checkServerGLXDrawableAlive(priv); 488bf215546Sopenharmony_ci _mesa_set_add(priv->zombieGLXDrawable, pdraw); 489bf215546Sopenharmony_ci } else { 490bf215546Sopenharmony_ci pdraw->destroyDrawable(pdraw); 491bf215546Sopenharmony_ci __glxHashDelete(priv->drawHash, drawable); 492bf215546Sopenharmony_ci } 493bf215546Sopenharmony_ci } 494bf215546Sopenharmony_ci } 495bf215546Sopenharmony_ci } 496bf215546Sopenharmony_ci} 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci_X_HIDDEN void 499bf215546Sopenharmony_cidriReleaseDrawables(struct glx_context *gc) 500bf215546Sopenharmony_ci{ 501bf215546Sopenharmony_ci const struct glx_display *priv = (gc && gc->psc) ? gc->psc->display : NULL; 502bf215546Sopenharmony_ci 503bf215546Sopenharmony_ci if (priv == NULL) 504bf215546Sopenharmony_ci return; 505bf215546Sopenharmony_ci 506bf215546Sopenharmony_ci releaseDrawable(priv, gc->currentDrawable); 507bf215546Sopenharmony_ci releaseDrawable(priv, gc->currentReadable); 508bf215546Sopenharmony_ci 509bf215546Sopenharmony_ci gc->currentDrawable = None; 510bf215546Sopenharmony_ci gc->currentReadable = None; 511bf215546Sopenharmony_ci 512bf215546Sopenharmony_ci} 513bf215546Sopenharmony_ci 514bf215546Sopenharmony_ci_X_HIDDEN int 515bf215546Sopenharmony_cidri_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs, 516bf215546Sopenharmony_ci struct dri_ctx_attribs *dca) 517bf215546Sopenharmony_ci{ 518bf215546Sopenharmony_ci unsigned i; 519bf215546Sopenharmony_ci uint32_t profile = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; 520bf215546Sopenharmony_ci 521bf215546Sopenharmony_ci dca->major_ver = 1; 522bf215546Sopenharmony_ci dca->minor_ver = 0; 523bf215546Sopenharmony_ci dca->render_type = GLX_RGBA_TYPE; 524bf215546Sopenharmony_ci dca->reset = __DRI_CTX_RESET_NO_NOTIFICATION; 525bf215546Sopenharmony_ci dca->release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH; 526bf215546Sopenharmony_ci dca->flags = 0; 527bf215546Sopenharmony_ci dca->api = __DRI_API_OPENGL; 528bf215546Sopenharmony_ci dca->no_error = 0; 529bf215546Sopenharmony_ci 530bf215546Sopenharmony_ci if (num_attribs == 0) 531bf215546Sopenharmony_ci return __DRI_CTX_ERROR_SUCCESS; 532bf215546Sopenharmony_ci 533bf215546Sopenharmony_ci /* This is actually an internal error, but what the heck. */ 534bf215546Sopenharmony_ci if (attribs == NULL) 535bf215546Sopenharmony_ci return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 536bf215546Sopenharmony_ci 537bf215546Sopenharmony_ci for (i = 0; i < num_attribs; i++) { 538bf215546Sopenharmony_ci switch (attribs[i * 2]) { 539bf215546Sopenharmony_ci case GLX_CONTEXT_MAJOR_VERSION_ARB: 540bf215546Sopenharmony_ci dca->major_ver = attribs[i * 2 + 1]; 541bf215546Sopenharmony_ci break; 542bf215546Sopenharmony_ci case GLX_CONTEXT_MINOR_VERSION_ARB: 543bf215546Sopenharmony_ci dca->minor_ver = attribs[i * 2 + 1]; 544bf215546Sopenharmony_ci break; 545bf215546Sopenharmony_ci case GLX_CONTEXT_FLAGS_ARB: 546bf215546Sopenharmony_ci dca->flags = attribs[i * 2 + 1]; 547bf215546Sopenharmony_ci break; 548bf215546Sopenharmony_ci case GLX_CONTEXT_OPENGL_NO_ERROR_ARB: 549bf215546Sopenharmony_ci dca->no_error = attribs[i * 2 + 1]; 550bf215546Sopenharmony_ci break; 551bf215546Sopenharmony_ci case GLX_CONTEXT_PROFILE_MASK_ARB: 552bf215546Sopenharmony_ci profile = attribs[i * 2 + 1]; 553bf215546Sopenharmony_ci break; 554bf215546Sopenharmony_ci case GLX_RENDER_TYPE: 555bf215546Sopenharmony_ci dca->render_type = attribs[i * 2 + 1]; 556bf215546Sopenharmony_ci break; 557bf215546Sopenharmony_ci case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB: 558bf215546Sopenharmony_ci switch (attribs[i * 2 + 1]) { 559bf215546Sopenharmony_ci case GLX_NO_RESET_NOTIFICATION_ARB: 560bf215546Sopenharmony_ci dca->reset = __DRI_CTX_RESET_NO_NOTIFICATION; 561bf215546Sopenharmony_ci break; 562bf215546Sopenharmony_ci case GLX_LOSE_CONTEXT_ON_RESET_ARB: 563bf215546Sopenharmony_ci dca->reset = __DRI_CTX_RESET_LOSE_CONTEXT; 564bf215546Sopenharmony_ci break; 565bf215546Sopenharmony_ci default: 566bf215546Sopenharmony_ci return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 567bf215546Sopenharmony_ci } 568bf215546Sopenharmony_ci break; 569bf215546Sopenharmony_ci case GLX_CONTEXT_RELEASE_BEHAVIOR_ARB: 570bf215546Sopenharmony_ci switch (attribs[i * 2 + 1]) { 571bf215546Sopenharmony_ci case GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB: 572bf215546Sopenharmony_ci dca->release = __DRI_CTX_RELEASE_BEHAVIOR_NONE; 573bf215546Sopenharmony_ci break; 574bf215546Sopenharmony_ci case GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB: 575bf215546Sopenharmony_ci dca->release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH; 576bf215546Sopenharmony_ci break; 577bf215546Sopenharmony_ci default: 578bf215546Sopenharmony_ci return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 579bf215546Sopenharmony_ci } 580bf215546Sopenharmony_ci break; 581bf215546Sopenharmony_ci case GLX_SCREEN: 582bf215546Sopenharmony_ci /* Implies GLX_EXT_no_config_context */ 583bf215546Sopenharmony_ci dca->render_type = GLX_DONT_CARE; 584bf215546Sopenharmony_ci break; 585bf215546Sopenharmony_ci default: 586bf215546Sopenharmony_ci /* If an unknown attribute is received, fail. 587bf215546Sopenharmony_ci */ 588bf215546Sopenharmony_ci return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 589bf215546Sopenharmony_ci } 590bf215546Sopenharmony_ci } 591bf215546Sopenharmony_ci 592bf215546Sopenharmony_ci switch (profile) { 593bf215546Sopenharmony_ci case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: 594bf215546Sopenharmony_ci /* This is the default value, but there are no profiles before OpenGL 595bf215546Sopenharmony_ci * 3.2. The GLX_ARB_create_context_profile spec says: 596bf215546Sopenharmony_ci * 597bf215546Sopenharmony_ci * "If the requested OpenGL version is less than 3.2, 598bf215546Sopenharmony_ci * GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality 599bf215546Sopenharmony_ci * of the context is determined solely by the requested version." 600bf215546Sopenharmony_ci */ 601bf215546Sopenharmony_ci dca->api = (dca->major_ver > 3 || (dca->major_ver == 3 && dca->minor_ver >= 2)) 602bf215546Sopenharmony_ci ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL; 603bf215546Sopenharmony_ci break; 604bf215546Sopenharmony_ci case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: 605bf215546Sopenharmony_ci dca->api = __DRI_API_OPENGL; 606bf215546Sopenharmony_ci break; 607bf215546Sopenharmony_ci case GLX_CONTEXT_ES_PROFILE_BIT_EXT: 608bf215546Sopenharmony_ci if (dca->major_ver >= 3) 609bf215546Sopenharmony_ci dca->api = __DRI_API_GLES3; 610bf215546Sopenharmony_ci else if (dca->major_ver == 2 && dca->minor_ver == 0) 611bf215546Sopenharmony_ci dca->api = __DRI_API_GLES2; 612bf215546Sopenharmony_ci else if (dca->major_ver == 1 && dca->minor_ver < 2) 613bf215546Sopenharmony_ci dca->api = __DRI_API_GLES; 614bf215546Sopenharmony_ci else { 615bf215546Sopenharmony_ci return __DRI_CTX_ERROR_BAD_API; 616bf215546Sopenharmony_ci } 617bf215546Sopenharmony_ci break; 618bf215546Sopenharmony_ci default: 619bf215546Sopenharmony_ci return __DRI_CTX_ERROR_BAD_API; 620bf215546Sopenharmony_ci } 621bf215546Sopenharmony_ci 622bf215546Sopenharmony_ci /* Unknown flag value */ 623bf215546Sopenharmony_ci if (dca->flags & ~(__DRI_CTX_FLAG_DEBUG | 624bf215546Sopenharmony_ci __DRI_CTX_FLAG_FORWARD_COMPATIBLE | 625bf215546Sopenharmony_ci __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS | 626bf215546Sopenharmony_ci __DRI_CTX_FLAG_RESET_ISOLATION)) 627bf215546Sopenharmony_ci return __DRI_CTX_ERROR_UNKNOWN_FLAG; 628bf215546Sopenharmony_ci 629bf215546Sopenharmony_ci /* There are no forward-compatible contexts before OpenGL 3.0. The 630bf215546Sopenharmony_ci * GLX_ARB_create_context spec says: 631bf215546Sopenharmony_ci * 632bf215546Sopenharmony_ci * "Forward-compatible contexts are defined only for OpenGL versions 633bf215546Sopenharmony_ci * 3.0 and later." 634bf215546Sopenharmony_ci */ 635bf215546Sopenharmony_ci if (dca->major_ver < 3 && (dca->flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0) 636bf215546Sopenharmony_ci return __DRI_CTX_ERROR_BAD_FLAG; 637bf215546Sopenharmony_ci 638bf215546Sopenharmony_ci if (dca->major_ver >= 3 && dca->render_type == GLX_COLOR_INDEX_TYPE) 639bf215546Sopenharmony_ci return __DRI_CTX_ERROR_BAD_FLAG; 640bf215546Sopenharmony_ci 641bf215546Sopenharmony_ci /* The KHR_no_error specs say: 642bf215546Sopenharmony_ci * 643bf215546Sopenharmony_ci * Requires OpenGL ES 2.0 or OpenGL 2.0. 644bf215546Sopenharmony_ci */ 645bf215546Sopenharmony_ci if (dca->no_error && dca->major_ver < 2) 646bf215546Sopenharmony_ci return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE; 647bf215546Sopenharmony_ci 648bf215546Sopenharmony_ci /* The GLX_ARB_create_context_no_error specs say: 649bf215546Sopenharmony_ci * 650bf215546Sopenharmony_ci * BadMatch is generated if the GLX_CONTEXT_OPENGL_NO_ERROR_ARB is TRUE at 651bf215546Sopenharmony_ci * the same time as a debug or robustness context is specified. 652bf215546Sopenharmony_ci * 653bf215546Sopenharmony_ci */ 654bf215546Sopenharmony_ci if (dca->no_error && ((dca->flags & __DRI_CTX_FLAG_DEBUG) || 655bf215546Sopenharmony_ci (dca->flags & __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS))) 656bf215546Sopenharmony_ci return __DRI_CTX_ERROR_BAD_FLAG; 657bf215546Sopenharmony_ci 658bf215546Sopenharmony_ci return __DRI_CTX_ERROR_SUCCESS; 659bf215546Sopenharmony_ci} 660bf215546Sopenharmony_ci 661bf215546Sopenharmony_cistruct glx_context * 662bf215546Sopenharmony_cidri_common_create_context(struct glx_screen *base, 663bf215546Sopenharmony_ci struct glx_config *config_base, 664bf215546Sopenharmony_ci struct glx_context *shareList, 665bf215546Sopenharmony_ci int renderType) 666bf215546Sopenharmony_ci{ 667bf215546Sopenharmony_ci unsigned int error; 668bf215546Sopenharmony_ci uint32_t attribs[2] = { GLX_RENDER_TYPE, renderType }; 669bf215546Sopenharmony_ci 670bf215546Sopenharmony_ci return base->vtable->create_context_attribs(base, config_base, shareList, 671bf215546Sopenharmony_ci 1, attribs, &error); 672bf215546Sopenharmony_ci} 673bf215546Sopenharmony_ci 674bf215546Sopenharmony_ci 675bf215546Sopenharmony_ci/* 676bf215546Sopenharmony_ci * Given a display pointer and screen number, determine the name of 677bf215546Sopenharmony_ci * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc). 678bf215546Sopenharmony_ci * Return True for success, False for failure. 679bf215546Sopenharmony_ci */ 680bf215546Sopenharmony_cistatic Bool 681bf215546Sopenharmony_cidriGetDriverName(Display * dpy, int scrNum, char **driverName) 682bf215546Sopenharmony_ci{ 683bf215546Sopenharmony_ci struct glx_screen *glx_screen = GetGLXScreenConfigs(dpy, scrNum); 684bf215546Sopenharmony_ci 685bf215546Sopenharmony_ci if (!glx_screen || !glx_screen->vtable->get_driver_name) 686bf215546Sopenharmony_ci return False; 687bf215546Sopenharmony_ci 688bf215546Sopenharmony_ci *driverName = glx_screen->vtable->get_driver_name(glx_screen); 689bf215546Sopenharmony_ci return True; 690bf215546Sopenharmony_ci} 691bf215546Sopenharmony_ci 692bf215546Sopenharmony_ci/* 693bf215546Sopenharmony_ci * Exported function for querying the DRI driver for a given screen. 694bf215546Sopenharmony_ci * 695bf215546Sopenharmony_ci * The returned char pointer points to a static array that will be 696bf215546Sopenharmony_ci * overwritten by subsequent calls. 697bf215546Sopenharmony_ci */ 698bf215546Sopenharmony_ci_GLX_PUBLIC const char * 699bf215546Sopenharmony_ciglXGetScreenDriver(Display * dpy, int scrNum) 700bf215546Sopenharmony_ci{ 701bf215546Sopenharmony_ci static char ret[32]; 702bf215546Sopenharmony_ci char *driverName; 703bf215546Sopenharmony_ci 704bf215546Sopenharmony_ci if (driGetDriverName(dpy, scrNum, &driverName)) { 705bf215546Sopenharmony_ci int len; 706bf215546Sopenharmony_ci if (!driverName) 707bf215546Sopenharmony_ci return NULL; 708bf215546Sopenharmony_ci len = strlen(driverName); 709bf215546Sopenharmony_ci if (len >= 31) 710bf215546Sopenharmony_ci return NULL; 711bf215546Sopenharmony_ci memcpy(ret, driverName, len + 1); 712bf215546Sopenharmony_ci free(driverName); 713bf215546Sopenharmony_ci return ret; 714bf215546Sopenharmony_ci } 715bf215546Sopenharmony_ci return NULL; 716bf215546Sopenharmony_ci} 717bf215546Sopenharmony_ci 718bf215546Sopenharmony_ci/* glXGetDriverConfig must return a pointer with a static lifetime. To avoid 719bf215546Sopenharmony_ci * keeping drivers loaded and other leaks, we keep a cache of results here that 720bf215546Sopenharmony_ci * is cleared by an atexit handler. 721bf215546Sopenharmony_ci */ 722bf215546Sopenharmony_cistruct driver_config_entry { 723bf215546Sopenharmony_ci struct driver_config_entry *next; 724bf215546Sopenharmony_ci char *driverName; 725bf215546Sopenharmony_ci char *config; 726bf215546Sopenharmony_ci}; 727bf215546Sopenharmony_ci 728bf215546Sopenharmony_cistatic pthread_mutex_t driver_config_mutex = PTHREAD_MUTEX_INITIALIZER; 729bf215546Sopenharmony_cistatic struct driver_config_entry *driver_config_cache = NULL; 730bf215546Sopenharmony_ci 731bf215546Sopenharmony_ci/* Called as an atexit function. Otherwise, this would have to be called with 732bf215546Sopenharmony_ci * driver_config_mutex locked. 733bf215546Sopenharmony_ci */ 734bf215546Sopenharmony_cistatic void 735bf215546Sopenharmony_ciclear_driver_config_cache() 736bf215546Sopenharmony_ci{ 737bf215546Sopenharmony_ci while (driver_config_cache) { 738bf215546Sopenharmony_ci struct driver_config_entry *e = driver_config_cache; 739bf215546Sopenharmony_ci driver_config_cache = e->next; 740bf215546Sopenharmony_ci 741bf215546Sopenharmony_ci free(e->driverName); 742bf215546Sopenharmony_ci free(e->config); 743bf215546Sopenharmony_ci free(e); 744bf215546Sopenharmony_ci } 745bf215546Sopenharmony_ci} 746bf215546Sopenharmony_ci 747bf215546Sopenharmony_cistatic char * 748bf215546Sopenharmony_ciget_driver_config(const char *driverName) 749bf215546Sopenharmony_ci{ 750bf215546Sopenharmony_ci void *handle; 751bf215546Sopenharmony_ci char *config = NULL; 752bf215546Sopenharmony_ci const __DRIextension **extensions = driOpenDriver(driverName, &handle); 753bf215546Sopenharmony_ci if (extensions) { 754bf215546Sopenharmony_ci for (int i = 0; extensions[i]; i++) { 755bf215546Sopenharmony_ci if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) != 0) 756bf215546Sopenharmony_ci continue; 757bf215546Sopenharmony_ci 758bf215546Sopenharmony_ci __DRIconfigOptionsExtension *ext = 759bf215546Sopenharmony_ci (__DRIconfigOptionsExtension *)extensions[i]; 760bf215546Sopenharmony_ci 761bf215546Sopenharmony_ci if (ext->base.version >= 2) 762bf215546Sopenharmony_ci config = ext->getXml(driverName); 763bf215546Sopenharmony_ci else 764bf215546Sopenharmony_ci config = strdup(ext->xml); 765bf215546Sopenharmony_ci 766bf215546Sopenharmony_ci break; 767bf215546Sopenharmony_ci } 768bf215546Sopenharmony_ci } 769bf215546Sopenharmony_ci 770bf215546Sopenharmony_ci if (!config) { 771bf215546Sopenharmony_ci /* Fall back to the old method */ 772bf215546Sopenharmony_ci config = dlsym(handle, "__driConfigOptions"); 773bf215546Sopenharmony_ci if (config) 774bf215546Sopenharmony_ci config = strdup(config); 775bf215546Sopenharmony_ci } 776bf215546Sopenharmony_ci 777bf215546Sopenharmony_ci dlclose(handle); 778bf215546Sopenharmony_ci 779bf215546Sopenharmony_ci return config; 780bf215546Sopenharmony_ci} 781bf215546Sopenharmony_ci 782bf215546Sopenharmony_ci/* 783bf215546Sopenharmony_ci * Exported function for obtaining a driver's option list (UTF-8 encoded XML). 784bf215546Sopenharmony_ci * 785bf215546Sopenharmony_ci * The returned char pointer points directly into the driver. Therefore 786bf215546Sopenharmony_ci * it should be treated as a constant. 787bf215546Sopenharmony_ci * 788bf215546Sopenharmony_ci * If the driver was not found or does not support configuration NULL is 789bf215546Sopenharmony_ci * returned. 790bf215546Sopenharmony_ci */ 791bf215546Sopenharmony_ci_GLX_PUBLIC const char * 792bf215546Sopenharmony_ciglXGetDriverConfig(const char *driverName) 793bf215546Sopenharmony_ci{ 794bf215546Sopenharmony_ci struct driver_config_entry *e; 795bf215546Sopenharmony_ci 796bf215546Sopenharmony_ci pthread_mutex_lock(&driver_config_mutex); 797bf215546Sopenharmony_ci 798bf215546Sopenharmony_ci for (e = driver_config_cache; e; e = e->next) { 799bf215546Sopenharmony_ci if (strcmp(e->driverName, driverName) == 0) 800bf215546Sopenharmony_ci goto out; 801bf215546Sopenharmony_ci } 802bf215546Sopenharmony_ci 803bf215546Sopenharmony_ci e = malloc(sizeof(*e)); 804bf215546Sopenharmony_ci if (!e) 805bf215546Sopenharmony_ci goto out; 806bf215546Sopenharmony_ci 807bf215546Sopenharmony_ci e->config = get_driver_config(driverName); 808bf215546Sopenharmony_ci e->driverName = strdup(driverName); 809bf215546Sopenharmony_ci if (!e->config || !e->driverName) { 810bf215546Sopenharmony_ci free(e->config); 811bf215546Sopenharmony_ci free(e->driverName); 812bf215546Sopenharmony_ci free(e); 813bf215546Sopenharmony_ci e = NULL; 814bf215546Sopenharmony_ci goto out; 815bf215546Sopenharmony_ci } 816bf215546Sopenharmony_ci 817bf215546Sopenharmony_ci e->next = driver_config_cache; 818bf215546Sopenharmony_ci driver_config_cache = e; 819bf215546Sopenharmony_ci 820bf215546Sopenharmony_ci if (!e->next) 821bf215546Sopenharmony_ci atexit(clear_driver_config_cache); 822bf215546Sopenharmony_ci 823bf215546Sopenharmony_ciout: 824bf215546Sopenharmony_ci pthread_mutex_unlock(&driver_config_mutex); 825bf215546Sopenharmony_ci 826bf215546Sopenharmony_ci return e ? e->config : NULL; 827bf215546Sopenharmony_ci} 828bf215546Sopenharmony_ci 829bf215546Sopenharmony_ci#endif /* GLX_DIRECT_RENDERING */ 830