glx: Add an error message when a direct renderer's createScreen() routine fails
[mesa.git] / src / glx / dri3_glx.c
index 4aae182199ca7406dd3e93cd75e7c3f576e57b61..55eed391a794ba92325f6d5946288be3628da35d 100644 (file)
@@ -65,9 +65,7 @@
 #include <xcb/dri3.h>
 #include <xcb/present.h>
 #include <GL/gl.h>
-#include "glapi.h"
 #include "glxclient.h"
-#include "xf86dri.h"
 #include <dlfcn.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/mman.h>
 #include <sys/time.h>
 
-#include "xf86drm.h"
 #include "dri_common.h"
 #include "dri3_priv.h"
+#include "loader.h"
+#include "dri2.h"
 
 static const struct glx_context_vtable dri3_context_vtable;
 
@@ -268,6 +267,16 @@ dri3_create_context(struct glx_screen *base,
 static void
 dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer);
 
+static void
+dri3_update_num_back(struct dri3_drawable *priv)
+{
+   priv->num_back = 1;
+   if (priv->flipping)
+      priv->num_back++;
+   if (priv->swap_interval == 0)
+      priv->num_back++;
+}
+
 static void
 dri3_destroy_drawable(__GLXDRIdrawable *base)
 {
@@ -325,6 +334,8 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable,
       break;
    }
 
+   dri3_update_num_back(pdraw);
+
    (void) __glXInitialize(psc->base.dpy);
 
    /* Create a new drawable */
@@ -364,10 +375,26 @@ dri3_handle_present_event(struct dri3_drawable *priv, xcb_present_generic_event_
    case XCB_PRESENT_COMPLETE_NOTIFY: {
       xcb_present_complete_notify_event_t *ce = (void *) ge;
 
-      if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP)
-         priv->present_event_serial = ce->serial;
-      else
-         priv->present_msc_event_serial = ce->serial;
+      /* Compute the processed SBC number from the received 32-bit serial number merged
+       * with the upper 32-bits of the sent 64-bit serial number while checking for
+       * wrap
+       */
+      if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) {
+         priv->recv_sbc = (priv->send_sbc & 0xffffffff00000000LL) | ce->serial;
+         if (priv->recv_sbc > priv->send_sbc)
+            priv->recv_sbc -= 0x100000000;
+         switch (ce->mode) {
+         case XCB_PRESENT_COMPLETE_MODE_FLIP:
+            priv->flipping = true;
+            break;
+         case XCB_PRESENT_COMPLETE_MODE_COPY:
+            priv->flipping = false;
+            break;
+         }
+         dri3_update_num_back(priv);
+      } else {
+         priv->recv_msc_serial = ce->serial;
+      }
       priv->ust = ce->ust;
       priv->msc = ce->msc;
       break;
@@ -381,6 +408,10 @@ dri3_handle_present_event(struct dri3_drawable *priv, xcb_present_generic_event_
 
          if (buf && buf->pixmap == ie->pixmap) {
             buf->busy = 0;
+            if (priv->num_back <= b && b < DRI3_MAX_BACK) {
+               dri3_free_render_buffer(priv, buf);
+               priv->buffers[b] = NULL;
+            }
             break;
          }
       }
@@ -390,20 +421,41 @@ dri3_handle_present_event(struct dri3_drawable *priv, xcb_present_generic_event_
    free(ge);
 }
 
+static bool
+dri3_wait_for_event(__GLXDRIdrawable *pdraw)
+{
+   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
+   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+   xcb_generic_event_t *ev;
+   xcb_present_generic_event_t *ge;
+
+   xcb_flush(c);
+   ev = xcb_wait_for_special_event(c, priv->special_event);
+   if (!ev)
+      return false;
+   ge = (void *) ev;
+   dri3_handle_present_event(priv, ge);
+   return true;
+}
+
+/** dri3_wait_for_msc
+ *
+ * Get the X server to send an event when the target msc/divisor/remainder is
+ * reached.
+ */
 static int
 dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
                   int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc)
 {
    xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
-   xcb_generic_event_t *ev;
-   xcb_present_generic_event_t *ge;
+   uint32_t msc_serial;
 
    /* Ask for the an event for the target MSC */
-   ++priv->present_msc_request_serial;
+   msc_serial = ++priv->send_msc_serial;
    xcb_present_notify_msc(c,
                           priv->base.xDrawable,
-                          priv->present_msc_request_serial,
+                          msc_serial,
                           target_msc,
                           divisor,
                           remainder);
@@ -412,22 +464,24 @@ dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
 
    /* Wait for the event */
    if (priv->special_event) {
-      while (priv->present_msc_request_serial != priv->present_msc_event_serial) {
-         ev = xcb_wait_for_special_event(c, priv->special_event);
-         if (!ev)
-            break;
-         ge = (void *) ev;
-         dri3_handle_present_event(priv, ge);
+      while ((int32_t) (msc_serial - priv->recv_msc_serial) > 0) {
+         if (!dri3_wait_for_event(pdraw))
+            return 0;
       }
    }
 
    *ust = priv->ust;
    *msc = priv->msc;
-   *sbc = priv->sbc;
+   *sbc = priv->recv_sbc;
 
    return 1;
 }
 
+/** dri3_drawable_get_msc
+ *
+ * Return the current UST/MSC/SBC triplet by asking the server
+ * for an event
+ */
 static int
 dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
                       int64_t *ust, int64_t *msc, int64_t *sbc)
@@ -437,12 +491,9 @@ dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw,
 
 /** dri3_wait_for_sbc
  *
- * Wait for the swap buffer count to increase. The only way this
- * can happen is if some other thread is doing swap buffers as
- * we no longer share swap buffer counts with other processes.
- *
- * I'm not sure this is actually useful as such, and so this
- * implementation is a kludge that just polls once a second
+ * Wait for the completed swap buffer count to reach the specified
+ * target. Presumably the application knows that this will be reached with
+ * outstanding complete events, or we're going to be here awhile.
  */
 static int
 dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
@@ -450,10 +501,15 @@ dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust,
 {
    struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
 
-   while (priv->sbc < target_sbc) {
-      sleep(1);
+   while (priv->recv_sbc < target_sbc) {
+      if (!dri3_wait_for_event(pdraw))
+         return 0;
    }
-   return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc, sbc);
+
+   *ust = priv->ust;
+   *msc = priv->msc;
+   *sbc = priv->recv_sbc;
+   return 1;
 }
 
 /**
@@ -904,6 +960,7 @@ image_format_to_fourcc(int format)
 
    /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */
    switch (format) {
+   case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888;
    case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565;
    case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888;
    case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888;
@@ -1033,16 +1090,16 @@ dri3_find_back(xcb_connection_t *c, struct dri3_drawable *priv)
    xcb_present_generic_event_t *ge;
 
    for (;;) {
+      for (b = 0; b < priv->num_back; b++) {
+         int id = DRI3_BACK_ID((b + priv->cur_back) % priv->num_back);
+         struct dri3_buffer *buffer = priv->buffers[id];
 
-      for (b = 0; b < DRI3_NUM_BACK; b++) {
-         int                    id = DRI3_BACK_ID(b);
-         struct dri3_buffer        *buffer = priv->buffers[id];
-
-         if (!buffer)
-            return b;
-         if (!buffer->busy)
-            return b;
+         if (!buffer || !buffer->busy) {
+            priv->cur_back = id;
+            return id;
+         }
       }
+      xcb_flush(c);
       ev = xcb_wait_for_special_event(c, priv->special_event);
       if (!ev)
          return -1;
@@ -1067,13 +1124,10 @@ dri3_get_buffer(__DRIdrawable *driDrawable,
    int                  buf_id;
 
    if (buffer_type == dri3_buffer_back) {
-      int back = dri3_find_back(c, priv);
+      buf_id = dri3_find_back(c, priv);
 
-      if (back < 0)
+      if (buf_id < 0)
          return NULL;
-
-      priv->cur_back = back;
-      buf_id = DRI3_BACK_ID(priv->cur_back);
    } else {
       buf_id = DRI3_FRONT_ID;
    }
@@ -1150,7 +1204,7 @@ dri3_free_buffers(__DRIdrawable *driDrawable,
    switch (buffer_type) {
    case dri3_buffer_back:
       first_id = DRI3_BACK_ID(0);
-      n_id = DRI3_NUM_BACK;
+      n_id = DRI3_MAX_BACK;
       break;
    case dri3_buffer_front:
       first_id = DRI3_FRONT_ID;
@@ -1248,9 +1302,16 @@ dri3_get_buffers(__DRIdrawable *driDrawable,
 /* The image loader extension record for DRI3
  */
 static const __DRIimageLoaderExtension imageLoaderExtension = {
-   {__DRI_IMAGE_LOADER, __DRI_IMAGE_LOADER_VERSION},
-   .getBuffers = dri3_get_buffers,
-   .flushFrontBuffer = dri3_flush_front_buffer,
+   .base = { __DRI_IMAGE_LOADER, 1 },
+
+   .getBuffers          = dri3_get_buffers,
+   .flushFrontBuffer    = dri3_flush_front_buffer,
+};
+
+static const __DRIextension *loader_extensions[] = {
+   &imageLoaderExtension.base,
+   &systemTimeExtension.base,
+   NULL
 };
 
 /** dri3_swap_buffers
@@ -1281,15 +1342,16 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
       /* Compute when we want the frame shown by taking the last known successful
        * MSC and adding in a swap interval for each outstanding swap request
        */
-      ++priv->present_request_serial;
+      ++priv->send_sbc;
       if (target_msc == 0)
-         target_msc = priv->msc + priv->swap_interval * (priv->present_request_serial - priv->present_event_serial);
+         target_msc = priv->msc + priv->swap_interval * (priv->send_sbc - priv->recv_sbc);
 
       priv->buffers[buf_id]->busy = 1;
+      priv->buffers[buf_id]->last_swap = priv->send_sbc;
       xcb_present_pixmap(c,
                          priv->base.xDrawable,
                          priv->buffers[buf_id]->pixmap,
-                         priv->present_request_serial,
+                         (uint32_t) priv->send_sbc,
                          0,                                    /* valid */
                          0,                                    /* update */
                          0,                                    /* x_off */
@@ -1301,7 +1363,7 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
                          target_msc,
                          divisor,
                          remainder, 0, NULL);
-      ret = ++priv->sbc;
+      ret = (int64_t) priv->send_sbc;
 
       /* If there's a fake front, then copy the source back buffer
        * to the fake front to keep it up to date. This needs
@@ -1325,6 +1387,22 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor,
    return ret;
 }
 
+static int
+dri3_get_buffer_age(__GLXDRIdrawable *pdraw)
+{
+   xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy);
+   struct dri3_drawable *priv = (struct dri3_drawable *) pdraw;
+   int back_id = DRI3_BACK_ID(dri3_find_back(c, priv));
+
+   if (back_id < 0 || !priv->buffers[back_id])
+      return 0;
+
+   if (priv->buffers[back_id]->last_swap != 0)
+      return priv->send_sbc - priv->buffers[back_id]->last_swap + 1;
+   else
+      return 0;
+}
+
 /** dri3_open
  *
  * Wrapper around xcb_dri3_open
@@ -1337,14 +1415,13 @@ dri3_open(Display *dpy,
    xcb_dri3_open_cookie_t       cookie;
    xcb_dri3_open_reply_t        *reply;
    xcb_connection_t             *c = XGetXCBConnection(dpy);
-   xcb_generic_error_t          *error;
    int                          fd;
 
    cookie = xcb_dri3_open(c,
                           root,
                           provider);
 
-   reply = xcb_dri3_open_reply(c, cookie, &error);
+   reply = xcb_dri3_open_reply(c, cookie, NULL);
    if (!reply)
       return -1;
 
@@ -1403,6 +1480,7 @@ dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval)
    }
 
    priv->swap_interval = interval;
+   dri3_update_num_back(priv);
 
    return 0;
 }
@@ -1456,7 +1534,8 @@ dri3_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
    if (pdraw != NULL) {
       psc = (struct dri3_screen *) base->psc;
 
-      if (psc->texBuffer->releaseTexBuffer)
+      if (psc->texBuffer->base.version >= 3 &&
+          psc->texBuffer->releaseTexBuffer != NULL)
          (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
                                               pdraw->base.textureTarget,
                                               pdraw->driDrawable);
@@ -1464,15 +1543,15 @@ dri3_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
 }
 
 static const struct glx_context_vtable dri3_context_vtable = {
-   dri3_destroy_context,
-   dri3_bind_context,
-   dri3_unbind_context,
-   dri3_wait_gl,
-   dri3_wait_x,
-   DRI_glXUseXFont,
-   dri3_bind_tex_image,
-   dri3_release_tex_image,
-   NULL, /* get_proc_address */
+   .destroy             = dri3_destroy_context,
+   .bind                = dri3_bind_context,
+   .unbind              = dri3_unbind_context,
+   .wait_gl             = dri3_wait_gl,
+   .wait_x              = dri3_wait_x,
+   .use_x_font          = DRI_glXUseXFont,
+   .bind_tex_image      = dri3_bind_tex_image,
+   .release_tex_image   = dri3_release_tex_image,
+   .get_proc_address    = NULL,
 };
 
 /** dri3_bind_extensions
@@ -1493,23 +1572,7 @@ dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
    __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
    __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
    __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
-
-   /*
-    * GLX_INTEL_swap_event is broken on the server side, where it's
-    * currently unconditionally enabled. This completely breaks
-    * systems running on drivers which don't support that extension.
-    * There's no way to test for its presence on this side, so instead
-    * of disabling it unconditionally, just disable it for drivers
-    * which are known to not support it, or for DDX drivers supporting
-    * only an older (pre-ScheduleSwap) version of DRI2.
-    *
-    * This is a hack which is required until:
-    * http://lists.x.org/archives/xorg-devel/2013-February/035449.html
-    * is merged and updated xserver makes it's way into distros:
-    */
-//   if (pdp->swapAvailable && strcmp(driverName, "vmwgfx") != 0) {
-//      __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
-//   }
+   __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event");
 
    mask = psc->image_driver->getAPIMask(psc->driScreen);
 
@@ -1537,12 +1600,19 @@ dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv,
       if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
          __glXEnableDirectExtension(&psc->base,
                                     "GLX_ARB_create_context_robustness");
+
+      if (strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) {
+         psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i];
+         __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
+      }
    }
 }
 
 static const struct glx_screen_vtable dri3_screen_vtable = {
-   dri3_create_context,
-   dri3_create_context_attribs
+   .create_context         = dri3_create_context,
+   .create_context_attribs = dri3_create_context_attribs,
+   .query_renderer_integer = dri3_query_renderer_integer,
+   .query_renderer_string  = dri3_query_renderer_string,
 };
 
 /** dri3_create_screen
@@ -1597,7 +1667,7 @@ dri3_create_screen(int screen, struct glx_display * priv)
    }
    deviceName = NULL;
 
-   driverName = dri3_get_driver_for_fd(psc->fd);
+   driverName = loader_get_driver_for_fd(psc->fd, 0);
    if (!driverName) {
       ErrorMessageF("No driver found\n");
       goto handle_error;
@@ -1633,8 +1703,7 @@ dri3_create_screen(int screen, struct glx_display * priv)
 
    psc->driScreen =
       psc->image_driver->createNewScreen2(screen, psc->fd,
-                                          (const __DRIextension **)
-                                          &pdp->loader_extensions[0],
+                                          pdp->loader_extensions,
                                           extensions,
                                           &driver_configs, psc);
 
@@ -1672,8 +1741,10 @@ dri3_create_screen(int screen, struct glx_display * priv)
    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;
@@ -1699,6 +1770,9 @@ dri3_create_screen(int screen, struct glx_display * priv)
    psp->copySubBuffer = dri3_copy_sub_buffer;
    __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
 
+   psp->getBufferAge = dri3_get_buffer_age;
+   __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age");
+
    free(driverName);
    free(deviceName);
 
@@ -1748,7 +1822,6 @@ _X_HIDDEN __GLXDRIdisplay *
 dri3_create_display(Display * dpy)
 {
    struct dri3_display                  *pdp;
-   int                                  i;
    xcb_connection_t                     *c = XGetXCBConnection(dpy);
    xcb_dri3_query_version_cookie_t      dri3_cookie;
    xcb_dri3_query_version_reply_t       *dri3_reply;
@@ -1798,17 +1871,14 @@ dri3_create_display(Display * dpy)
    }
    pdp->presentMajor = present_reply->major_version;
    pdp->presentMinor = present_reply->minor_version;
+   free(present_reply);
 
    pdp->base.destroyDisplay = dri3_destroy_display;
    pdp->base.createScreen = dri3_create_screen;
 
-   i = 0;
-
-   pdp->loader_extensions[i++] = &imageLoaderExtension.base;
-
-   pdp->loader_extensions[i++] = &systemTimeExtension.base;
+   loader_set_logger(dri_message);
 
-   pdp->loader_extensions[i++] = NULL;
+   pdp->loader_extensions = loader_extensions;
 
    return &pdp->base;
 no_extension: