Added few more stubs so that control reaches to DestroyDevice().
[mesa.git] / src / glx / dri_glx.c
index 03237d40ba89d04256cef420b32c88b2f62d5a7b..3e0873524c065b062f70502007843548718a9d10 100644 (file)
@@ -40,7 +40,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "glxclient.h"
 #include "xf86dri.h"
 #include "dri2.h"
-#include "sarea.h"
+#include "dri_sarea.h"
 #include <dlfcn.h>
 #include <sys/types.h>
 #include <sys/mman.h>
@@ -90,8 +90,6 @@ struct dri_drawable
    __DRIdrawable *driDrawable;
 };
 
-static const struct glx_context_vtable dri_context_vtable;
-
 /*
  * Given a display pointer and screen number, determine the name of
  * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc).
@@ -150,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];
@@ -169,6 +167,70 @@ glXGetScreenDriver(Display * dpy, int scrNum)
    return NULL;
 }
 
+/* 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;
+}
+
 /*
  * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
  *
@@ -177,20 +239,44 @@ glXGetScreenDriver(Display * dpy, int scrNum)
  *
  * If the driver was not found or does not support configuration NULL is
  * returned.
- *
- * Note: The driver remains opened after this function returns.
  */
-_X_EXPORT const char *
+_GLX_PUBLIC const char *
 glXGetDriverConfig(const char *driverName)
 {
-   void *handle = driOpenDriver(driverName);
-   if (handle)
-      return dlsym(handle, "__driConfigOptions");
-   else
-      return NULL;
-}
+   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);
 
-#ifdef XDAMAGE_1_1_INTERFACE
+   return e ? e->config : NULL;
+}
 
 static GLboolean
 has_damage_post(Display * dpy)
@@ -260,11 +346,10 @@ __glXReportDamage(__DRIdrawable * driDraw,
 }
 
 static const __DRIdamageExtension damageExtension = {
-   {__DRI_DAMAGE, __DRI_DAMAGE_VERSION},
-   __glXReportDamage,
-};
+   .base = {__DRI_DAMAGE, 1 },
 
-#endif
+   .reportDamage        = __glXReportDamage,
+};
 
 static GLboolean
 __glXDRIGetDrawableInfo(__DRIdrawable * drawable,
@@ -288,16 +373,15 @@ __glXDRIGetDrawableInfo(__DRIdrawable * drawable,
 }
 
 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
-   {__DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION},
-   __glXDRIGetDrawableInfo
+   .base = {__DRI_GET_DRAWABLE_INFO, 1 },
+
+   .getDrawableInfo     = __glXDRIGetDrawableInfo
 };
 
 static const __DRIextension *loader_extensions[] = {
    &systemTimeExtension.base,
    &getDrawableInfoExtension.base,
-#ifdef XDAMAGE_1_1_INTERFACE
    &damageExtension.base,
-#endif
    NULL
 };
 
@@ -407,7 +491,7 @@ CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
                              &framebuffer.size, &framebuffer.stride,
                              &framebuffer.dev_priv_size,
                              &framebuffer.dev_priv)) {
-      ErrorMessageF("XF86DRIGetDeviceInfo failed");
+      ErrorMessageF("XF86DRIGetDeviceInfo failed\n");
       goto handle_error;
    }
 
@@ -418,7 +502,7 @@ CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
    status = drmMap(fd, hFB, framebuffer.size,
                    (drmAddressPtr) & framebuffer.base);
    if (status != 0) {
-      ErrorMessageF("drmMap of framebuffer failed (%s)", strerror(-status));
+      ErrorMessageF("drmMap of framebuffer failed (%s)\n", strerror(-status));
       goto handle_error;
    }
 
@@ -427,7 +511,7 @@ CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
     */
    status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
    if (status != 0) {
-      ErrorMessageF("drmMap of SAREA failed (%s)", strerror(-status));
+      ErrorMessageF("drmMap of SAREA failed (%s)\n", strerror(-status));
       goto handle_error;
    }
 
@@ -442,15 +526,17 @@ CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
                                           &driver_configs, psc);
 
    if (psp == NULL) {
-      ErrorMessageF("Calling driver entry point failed");
+      ErrorMessageF("Calling driver entry point failed\n");
       goto handle_error;
    }
 
    configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
    visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
 
-   if (!configs || !visuals)
+   if (!configs || !visuals) {
+       ErrorMessageF("No matching fbConfigs or visuals found\n");
        goto handle_error;
+   }
 
    glx_config_destroy_list(psc->base.configs);
    psc->base.configs = configs;
@@ -464,14 +550,14 @@ CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
     * non-conformant to prevent apps from picking them up accidentally.
     */
    for (visual = psc->base.visuals; visual; visual = visual->next) {
-      XVisualInfo template;
+      XVisualInfo templ;
       XVisualInfo *visuals;
       int num_visuals;
       long mask;
 
-      template.visualid = visual->visualID;
+      templ.visualid = visual->visualID;
       mask = VisualIDMask;
-      visuals = XGetVisualInfo(dpy, mask, &template, &num_visuals);
+      visuals = XGetVisualInfo(dpy, mask, &templ, &num_visuals);
 
       if (visuals) {
          if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
@@ -556,15 +642,15 @@ dri_unbind_context(struct glx_context *context, struct glx_context *new)
 }
 
 static const struct glx_context_vtable dri_context_vtable = {
-   dri_destroy_context,
-   dri_bind_context,
-   dri_unbind_context,
-   NULL,
-   NULL,
-   DRI_glXUseXFont,
-   NULL,
-   NULL,
-   NULL, /* get_proc_address */
+   .destroy             = dri_destroy_context,
+   .bind                = dri_bind_context,
+   .unbind              = dri_unbind_context,
+   .wait_gl             = NULL,
+   .wait_x              = NULL,
+   .use_x_font          = DRI_glXUseXFont,
+   .bind_tex_image      = NULL,
+   .release_tex_image   = NULL,
+   .get_proc_address    = NULL,
 };
 
 static struct glx_context *
@@ -581,6 +667,10 @@ dri_create_context(struct glx_screen *base,
    if (!psc->base.driScreen)
       return NULL;
 
+   /* Check the renderType value */
+   if (!validate_renderType_against_config(config_base, renderType))
+       return NULL;
+
    if (shareList) {
       /* If the shareList context is not a DRI context, we cannot possibly
        * create a DRI context that shares it.
@@ -602,6 +692,8 @@ dri_create_context(struct glx_screen *base,
       return NULL;
    }
 
+   pcp->base.renderType = renderType;
+
    if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr,
                                        config->base.visualID,
                                        &pcp->hwContextID, &hwContext)) {
@@ -684,22 +776,30 @@ driCreateDrawable(struct glx_screen *base,
 
 static int64_t
 driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
-              int64_t unused3)
+              int64_t unused3, Bool flush)
 {
    struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
 
+   if (flush) {
+      glFlush();
+   }
+
    (*psc->core->swapBuffers) (pdp->driDrawable);
    return 0;
 }
 
 static void
 driCopySubBuffer(__GLXDRIdrawable * pdraw,
-                 int x, int y, int width, int height)
+                 int x, int y, int width, int height, Bool flush)
 {
    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
    struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
 
+   if (flush) {
+      glFlush();
+   }
+
    (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
                                            x, y, width, height);
 }
@@ -718,72 +818,19 @@ driDestroyScreen(struct glx_screen *base)
       dlclose(psc->driver);
 }
 
-#ifdef __DRI_SWAP_BUFFER_COUNTER
-
-static int
-driDrawableGetMSC(struct glx_screen *base, __GLXDRIdrawable *pdraw,
-                  int64_t *ust, int64_t *msc, int64_t *sbc)
-{
-   struct dri_screen *psc = (struct dri_screen *) base;
-   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
-
-   if (pdp && psc->sbc && psc->msc)
-      return ( (*psc->msc->getMSC)(psc->driScreen, msc) == 0 &&
-              (*psc->sbc->getSBC)(pdp->driDrawable, sbc) == 0 && 
-              __glXGetUST(ust) == 0 );
-}
-
-static int
-driWaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
-              int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
-{
-   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
-   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
-
-   if (pdp != NULL && psc->msc != NULL) {
-      ret = (*psc->msc->waitForMSC) (pdp->driDrawable, target_msc,
-                                    divisor, remainder, msc, sbc);
-
-      /* __glXGetUST returns zero on success and non-zero on failure.
-       * This function returns True on success and False on failure.
-       */
-      return ret == 0 && __glXGetUST(ust) == 0;
-   }
-}
-
-static int
-driWaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
-              int64_t *msc, int64_t *sbc)
-{
-   struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
-
-   if (pdp != NULL && psc->sbc != NULL) {
-      ret =
-         (*psc->sbc->waitForSBC) (pdp->driDrawable, target_sbc, msc, sbc);
-
-      /* __glXGetUST returns zero on success and non-zero on failure.
-       * This function returns True on success and False on failure.
-       */
-      return ((ret == 0) && (__glXGetUST(ust) == 0));
-   }
-
-   return DRI2WaitSBC(pdp->base.psc->dpy,
-                     pdp->base.xDrawable, target_sbc, ust, msc, sbc);
-}
-
-#endif
-
 static int
 driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
 {
    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
-   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
 
-   if (psc->swapControl != NULL && pdraw != NULL) {
-      psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
-      return 0;
-   }
+   if (pdraw != NULL) {
+      struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
 
+      if (psc->swapControl != NULL) {
+         psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
+         return 0;
+      }
+   }
    return GLX_BAD_CONTEXT;
 }
 
@@ -791,11 +838,13 @@ static int
 driGetSwapInterval(__GLXDRIdrawable *pdraw)
 {
    struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
-   struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
 
-   if (psc->swapControl != NULL && pdraw != NULL)
-      return psc->swapControl->getSwapInterval(pdp->driDrawable);
+   if (pdraw != NULL) {
+      struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
 
+      if (psc->swapControl != NULL)
+         return psc->swapControl->getSwapInterval(pdp->driDrawable);
+   }
    return 0;
 }
 
@@ -832,8 +881,10 @@ driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
 }
 
 static const struct glx_screen_vtable dri_screen_vtable = {
-   dri_create_context,
-   NULL
+   .create_context         = dri_create_context,
+   .create_context_attribs = NULL,
+   .query_renderer_integer = NULL,
+   .query_renderer_string  = NULL,
 };
 
 static struct glx_screen *
@@ -859,12 +910,7 @@ driCreateScreen(int screen, struct glx_display *priv)
       goto cleanup;
    }
 
-   psc->driver = driOpenDriver(driverName);
-   free(driverName);
-   if (psc->driver == NULL)
-      goto cleanup;
-
-   extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS);
+   extensions = driOpenDriver(driverName, &psc->driver);
    if (extensions == NULL) {
       ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
       goto cleanup;
@@ -899,20 +945,18 @@ driCreateScreen(int screen, struct glx_display *priv)
    psp->createDrawable = driCreateDrawable;
    psp->swapBuffers = driSwapBuffers;
 
-#ifdef __DRI_SWAP_BUFFER_COUNTER
-   psp->getDrawableMSC = driDrawableGetMSC;
-   psp->waitForMSC = driWaitForMSC;
-   psp->waitForSBC = driWaitForSBC;
-#endif
-
    psp->setSwapInterval = driSetSwapInterval;
    psp->getSwapInterval = driGetSwapInterval;
 
+   free(driverName);
+
    return &psc->base;
 
 cleanup:
    CriticalErrorMessageF("failed to load driver: %s\n", driverName);
 
+   free(driverName);
+
    if (psc->driver)
       dlclose(psc->driver);
    glx_screen_cleanup(&psc->base);