loader_dri3/glx/egl: Remove the loader_dri3_vtable get_dri_screen callback
[mesa.git] / src / glx / dri_glx.c
index d0877519308c5b02a933330a5f173700b9de3d17..2d435f0ee192700680f72941ec8b01412b1a3329 100644 (file)
@@ -148,7 +148,7 @@ driGetDriverName(Display * dpy, int scrNum, char **driverName)
  * The returned char pointer points to a static array that will be
  * overwritten by subsequent calls.
  */
-_X_EXPORT const char *
+_GLX_PUBLIC const char *
 glXGetScreenDriver(Display * dpy, int scrNum)
 {
    static char ret[32];
@@ -167,19 +167,37 @@ glXGetScreenDriver(Display * dpy, int scrNum)
    return NULL;
 }
 
-/*
- * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
- *
- * The returned char pointer points directly into the driver. Therefore
- * it should be treated as a constant.
- *
- * If the driver was not found or does not support configuration NULL is
- * returned.
- *
- * Note: The driver remains opened after this function returns.
+/* 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.
  */
-_X_EXPORT const char *
-glXGetDriverConfig(const char *driverName)
+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 = driOpenDriver(driverName);
    const __DRIextension **extensions;
@@ -187,19 +205,84 @@ glXGetDriverConfig(const char *driverName)
    if (!handle)
       return NULL;
 
+   char *config = NULL;
+
    extensions = driGetDriverExtensions(handle, driverName);
    if (extensions) {
       for (int i = 0; extensions[i]; i++) {
-         if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) == 0)
-            return ((__DRIconfigOptionsExtension *)extensions[i])->xml;
+         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;
       }
    }
 
-   /* Fall back to the old method */
-   return dlsym(handle, "__driConfigOptions");
+   if (!config) {
+      /* Fall back to the old method */
+      config = dlsym(handle, "__driConfigOptions");
+      if (config)
+         config = strdup(config);
+   }
+
+   dlclose(handle);
+
+   return config;
 }
 
-#ifdef XDAMAGE_1_1_INTERFACE
+/*
+ * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
+ *
+ * The returned char pointer points directly into the driver. Therefore
+ * it should be treated as a constant.
+ *
+ * If the driver was not found or does not support configuration NULL is
+ * returned.
+ */
+_GLX_PUBLIC const char *
+glXGetDriverConfig(const char *driverName)
+{
+   struct driver_config_entry *e;
+
+   pthread_mutex_lock(&driver_config_mutex);
+
+   for (e = driver_config_cache; e; e = e->next) {
+      if (strcmp(e->driverName, driverName) == 0)
+         goto out;
+   }
+
+   e = malloc(sizeof(*e));
+   if (!e)
+      goto out;
+
+   e->config = get_driver_config(driverName);
+   e->driverName = strdup(driverName);
+   if (!e->config || !e->driverName) {
+      free(e->config);
+      free(e->driverName);
+      free(e);
+      e = NULL;
+      goto out;
+   }
+
+   e->next = driver_config_cache;
+   driver_config_cache = e;
+
+   if (!e->next)
+      atexit(clear_driver_config_cache);
+
+out:
+   pthread_mutex_unlock(&driver_config_mutex);
+
+   return e ? e->config : NULL;
+}
 
 static GLboolean
 has_damage_post(Display * dpy)
@@ -274,8 +357,6 @@ static const __DRIdamageExtension damageExtension = {
    .reportDamage        = __glXReportDamage,
 };
 
-#endif
-
 static GLboolean
 __glXDRIGetDrawableInfo(__DRIdrawable * drawable,
                         unsigned int *index, unsigned int *stamp,