+/* glXGetDriverConfig must return a pointer with a static lifetime. To avoid
+ * keeping drivers loaded and other leaks, we keep a cache of results here that
+ * is cleared by an atexit handler.
+ */
+struct driver_config_entry {
+ struct driver_config_entry *next;
+ char *driverName;
+ char *config;
+};
+
+static pthread_mutex_t driver_config_mutex = PTHREAD_MUTEX_INITIALIZER;
+static struct driver_config_entry *driver_config_cache = NULL;
+
+/* Called as an atexit function. Otherwise, this would have to be called with
+ * driver_config_mutex locked.
+ */
+static void
+clear_driver_config_cache()
+{
+ while (driver_config_cache) {
+ struct driver_config_entry *e = driver_config_cache;
+ driver_config_cache = e->next;
+
+ free(e->driverName);
+ free(e->config);
+ free(e);
+ }
+}
+
+static char *
+get_driver_config(const char *driverName)
+{
+ void *handle;
+ char *config = NULL;
+ const __DRIextension **extensions = driOpenDriver(driverName, &handle);
+ if (extensions) {
+ for (int i = 0; extensions[i]; i++) {
+ if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) != 0)
+ continue;
+
+ __DRIconfigOptionsExtension *ext =
+ (__DRIconfigOptionsExtension *)extensions[i];
+
+ if (ext->base.version >= 2)
+ config = ext->getXml(driverName);
+ else
+ config = strdup(ext->xml);
+
+ break;
+ }
+ }
+
+ if (!config) {
+ /* Fall back to the old method */
+ config = dlsym(handle, "__driConfigOptions");
+ if (config)
+ config = strdup(config);
+ }
+
+ dlclose(handle);
+
+ return config;
+}
+